001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     * 
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     * 
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */ 
017    
018    package org.apache.commons.betwixt.schema;
019    
020    import java.beans.IntrospectionException;
021    import java.util.ArrayList;
022    import java.util.Collection;
023    import java.util.Iterator;
024    import java.util.List;
025    
026    import org.apache.commons.betwixt.ElementDescriptor;
027    import org.apache.commons.betwixt.XMLBeanInfo;
028    import org.apache.commons.betwixt.XMLIntrospector;
029    
030    /**
031     * Model for top level element in an XML Schema
032     * 
033     * @author <a href='http://commons.apache.org/'>Apache Commons Team</a>
034     * @version $Revision: 561314 $
035     */
036    public class Schema {
037            
038            private List elements = new ArrayList();
039            private List complexTypes = new ArrayList();
040            private List simpleTypes = new ArrayList(); 
041        
042        private XMLIntrospector introspector;
043            
044        public Schema() {
045            this(new XMLIntrospector());
046        }
047        
048        public Schema(XMLIntrospector introspector) {
049            this.introspector = introspector;
050        }
051        
052        /**
053         * Introspects the given type giving an <code>XMLBeanInfo</code>.
054         * @param type Class to introspect, not null
055         * @return <code>XMLBeanInfo</code>, not null
056         * @throws IntrospectionException
057         */
058        public XMLBeanInfo introspect(Class type) throws IntrospectionException {
059             return introspector.introspect(type);
060        }
061        
062        /**
063         * Gets the complex types defined
064         * @return list of <code>ComplexType</code>'s not null
065         */
066        public List getComplexTypes() {
067            return complexTypes;
068        }
069    
070    
071            /**
072             * Adds a new complex type to those defined
073             * @param complexType not null
074             */
075            public void addComplexType(GlobalComplexType complexType) {
076                    complexTypes.add(complexType);
077            }
078            
079    
080        /**
081         * Gets the elements definied
082         * @return list of <code>Element</code>s not null
083         */
084        public List getElements() {
085            return elements;
086        }
087    
088            /**
089             * Adds a new element to those defined.
090             * @param element not null
091             */
092            public void addElement(GlobalElement element) {
093                    elements.add(element);
094            }
095    
096        /**
097         * Gets the simple types defined.
098         * @return list of <code>SimpleType</code>s not null
099         */
100        public List getSimpleTypes() {
101            return simpleTypes;
102        }
103    
104            /**
105             * Adds a new simple type to those defined.
106             * @param simpleType
107             */
108            public void addSimpleType(SimpleType simpleType) {
109                    simpleTypes.add(simpleType);
110            }
111    
112    
113        /**
114         * Adds global (top level) element and type declarations matching the given descriptor.
115         * @param elementDescriptor ElementDescriptor not null
116         */
117        public void addGlobalElementType(TranscriptionConfiguration configuration, ElementDescriptor elementDescriptor) throws IntrospectionException {
118            // need to create a global element declaration and a complex type 
119            // use the fully qualified class name as the type name
120            GlobalElement element = new GlobalElement(
121                                elementDescriptor.getLocalName(), 
122                                configuration.getSchemaTypeNamingStrategy().nameSchemaType(elementDescriptor));
123            addElement(element);
124            addGlobalComplexType(configuration, elementDescriptor);
125        }   
126        
127        /**
128         * Adds a new global complex type definition matching the given element descriptor.
129         * If this element descriptor has already been mapped to a global type then 
130         * that is returned.
131         * @since 0.7
132         * @param configuration <code>TranscriptionConfiguration</code>, not null
133         * @param elementDescriptor <code>ElementDescriptor</code>, not null
134         * @return <code>GlobalComplexType</code>
135         * @throws IntrospectionException
136         */
137        public GlobalComplexType addGlobalComplexType(TranscriptionConfiguration configuration, ElementDescriptor elementDescriptor) throws IntrospectionException  {
138            GlobalComplexType type = null;
139            for (Iterator it = complexTypes.iterator(); it.hasNext();) {
140                GlobalComplexType complexType = (GlobalComplexType) it.next();
141                if (complexType.matches( elementDescriptor )) {
142                    type = complexType;
143                    break;
144                }
145            }
146            if (type == null) {
147                 type = new GlobalComplexType(configuration, elementDescriptor, this);
148                            addComplexType(type);
149                            type.fill(configuration, elementDescriptor, this);
150            }
151            return type;
152        }
153            
154        public boolean equals(Object obj) {
155            boolean result = false;
156            if (obj instanceof Schema) {
157                    Schema schema = (Schema) obj;
158                    result = 
159                        equalContents(elements, schema.elements) &&
160                        equalContents(complexTypes, schema.complexTypes) &&
161                        equalContents(simpleTypes, schema.simpleTypes);
162            }
163            return result;
164        }
165        
166        private boolean equalContents(Collection one, Collection two)
167        {
168            // doesn't check cardinality but should be ok
169            if (one.size() != two.size()) {
170                return false;
171            }
172            for (Iterator it=one.iterator();it.hasNext();) {
173                Object object = it.next();
174                if (!two.contains(object)) {
175                    return false;
176                }
177            }
178            return true;
179        }
180    
181        public int hashCode() {
182            return 0;
183        }
184        
185    
186    
187        public String toString() {
188            StringBuffer buffer = new StringBuffer();
189            buffer.append("<?xml version='1.0'?>");
190            buffer.append("<xsd:schema xmlns:xsd='http://www.w3c.org/2001/XMLSchema'>");
191            
192            for (Iterator it=simpleTypes.iterator(); it.hasNext();) {
193                  buffer.append(it.next());    
194            }    
195            
196            for (Iterator it=complexTypes.iterator(); it.hasNext();) {
197                  buffer.append(it.next());    
198            }
199            
200      
201            for (Iterator it=elements.iterator(); it.hasNext();) {
202                  buffer.append(it.next());    
203            } 
204            buffer.append("</xsd:schema>");
205            return buffer.toString();
206        }
207    }