View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.ws.commons.schema;
21  
22  import org.apache.ws.commons.schema.constants.Constants;
23  import org.apache.ws.commons.schema.utils.NamespaceContextOwner;
24  import org.apache.ws.commons.schema.utils.NamespacePrefixList;
25  import org.w3c.dom.Document;
26  
27  import javax.xml.namespace.QName;
28  import javax.xml.transform.*;
29  import javax.xml.transform.dom.DOMSource;
30  import javax.xml.transform.stream.StreamResult;
31  import javax.xml.transform.stream.StreamSource;
32  import java.io.IOException;
33  import java.io.OutputStream;
34  import java.io.OutputStreamWriter;
35  import java.io.Writer;
36  import java.io.ByteArrayInputStream;
37  import java.util.Map;
38  import java.util.HashMap;
39  import java.util.Iterator;
40  
41  
42  /**
43   * Contains the definition of a schema. All XML Schema definition language (XSD)
44   * elements are children of the schema element. Represents the World Wide Web
45   * Consortium (W3C) schema element
46   */
47  
48  // Oct 15th - momo - initial impl
49  // Oct 17th - vidyanand - add SimpleType + element
50  // Oct 18th - momo - add ComplexType
51  // Oct 19th - vidyanand - handle external
52  // Dec 6th - Vidyanand - changed RuntimeExceptions thrown to XmlSchemaExceptions
53  // Jan 15th - Vidyanand - made changes to SchemaBuilder.handleElement to look for an element ref.
54  // Feb 20th - Joni - Change the getXmlSchemaFromLocation schema
55  //            variable to name s.
56  // Feb 21th - Joni - Port to XMLDomUtil and Tranformation.
57  
58  public class XmlSchema extends XmlSchemaAnnotated implements NamespaceContextOwner {
59      static final String SCHEMA_NS = "http://www.w3.org/2001/XMLSchema";
60      XmlSchemaForm attributeFormDefault, elementFormDefault;
61  
62      XmlSchemaObjectTable attributeGroups,
63              attributes, elements, groups,
64              notations, schemaTypes;
65      XmlSchemaDerivationMethod blockDefault, finalDefault;
66      XmlSchemaObjectCollection includes, items;
67      boolean isCompiled;
68      String syntacticalTargetNamespace, logicalTargetNamespace, version;
69      String schema_ns_prefix = "";
70      XmlSchemaCollection parent;
71  
72      private NamespacePrefixList namespaceContext;
73      //keep the encoding of the input
74      private String inputEncoding;
75  
76      public void setInputEncoding(String encoding){
77          this.inputEncoding = encoding;
78      }
79      /**
80       * Creates new XmlSchema
81       */
82      public XmlSchema(XmlSchemaCollection parent) {
83          this.parent = parent;
84          attributeFormDefault = new XmlSchemaForm(XmlSchemaForm.UNQUALIFIED);
85          elementFormDefault = new XmlSchemaForm(XmlSchemaForm.UNQUALIFIED);
86          blockDefault = new XmlSchemaDerivationMethod(Constants.BlockConstants.NONE);
87          finalDefault = new XmlSchemaDerivationMethod(Constants.BlockConstants.NONE);
88          items = new XmlSchemaObjectCollection();
89          includes = new XmlSchemaObjectCollection();
90          elements = new XmlSchemaObjectTable();
91          attributeGroups = new XmlSchemaObjectTable();
92          attributes = new XmlSchemaObjectTable();
93          groups = new XmlSchemaObjectTable();
94          notations = new XmlSchemaObjectTable();
95          schemaTypes = new XmlSchemaObjectTable();
96      }
97  
98      public XmlSchema(String namespace, XmlSchemaCollection parent) {
99          this(parent);
100         syntacticalTargetNamespace = logicalTargetNamespace = namespace;
101     }
102 
103     public XmlSchemaForm getAttributeFormDefault() {
104         return attributeFormDefault;
105     }
106 
107     public void setAttributeFormDefault(XmlSchemaForm value) {
108         attributeFormDefault = value;
109     }
110 
111     public XmlSchemaObjectTable getAttributeGroups() {
112         return attributeGroups;
113     }
114 
115     public XmlSchemaObjectTable getAttributes() {
116         return attributes;
117     }
118 
119     public XmlSchemaDerivationMethod getBlockDefault() {
120         return blockDefault;
121     }
122 
123     public void setBlockDefault(XmlSchemaDerivationMethod blockDefault) {
124         this.blockDefault = blockDefault;
125     }
126 
127     public XmlSchemaForm getElementFormDefault() {
128         return elementFormDefault;
129     }
130 
131     public void setElementFormDefault(XmlSchemaForm elementFormDefault) {
132         this.elementFormDefault = elementFormDefault;
133     }
134 
135     public XmlSchemaObjectTable getElements() {
136         return elements;
137     }
138 
139     public XmlSchemaElement getElementByName(QName name) {
140         return (XmlSchemaElement)elements.getItem(name);
141     }
142 
143     public XmlSchemaType getTypeByName(QName name) {
144         return (XmlSchemaType)schemaTypes.getItem(name);
145     }
146 
147     public XmlSchemaDerivationMethod getFinalDefault() {
148         return finalDefault;
149     }
150 
151     public void setFinalDefault(XmlSchemaDerivationMethod finalDefault) {
152         this.finalDefault = finalDefault;
153     }
154 
155     public XmlSchemaObjectTable getGroups() {
156         return groups;
157     }
158 
159     public XmlSchemaObjectCollection getIncludes() {
160         return includes;
161     }
162 
163     public boolean isCompiled() {
164         return isCompiled;
165     }
166 
167     public XmlSchemaObjectCollection getItems() {
168         return items;
169     }
170 
171     public XmlSchemaObjectTable getNotations() {
172         return notations;
173     }
174 
175     public XmlSchemaObjectTable getSchemaTypes() {
176         return schemaTypes;
177     }
178 
179     public String getTargetNamespace() {
180         return syntacticalTargetNamespace;
181     }
182 
183     public void setTargetNamespace(String targetNamespace) {
184         if (!targetNamespace.equals("")) {
185             syntacticalTargetNamespace = logicalTargetNamespace = targetNamespace;
186         }
187     }
188 
189     public String getVersion() {
190         return version;
191     }
192 
193     public void compile(ValidationEventHandler eh) {
194 
195     }
196 
197     /**
198      * Serialize the schema into the given output stream
199      * @param out - the output stream to write to
200      */
201     public void write(OutputStream out) {
202         write(new OutputStreamWriter(out));
203     }
204 
205     /**
206      * Serialize the schema into the given output stream
207      * @param out - the output stream to write to
208      * @param options -  a map of options
209      */
210     public void write(OutputStream out, Map options) {
211         write(new OutputStreamWriter(out),options);
212     }
213 
214     /**
215      * Serialie the schema to a given writer
216      * @param writer - the writer to write this
217      */
218     public void write(Writer writer,Map options) {
219         serialize_internal(this, writer,options);
220     }
221     /**
222      * Serialie the schema to a given writer
223      * @param writer - the writer to write this
224      */
225     public void write(Writer writer) {
226         serialize_internal(this, writer,null);
227     }
228 
229     public Document[] getAllSchemas() {
230         try {
231 
232             XmlSchemaSerializer xser = new XmlSchemaSerializer();
233             xser.setExtReg(this.parent.getExtReg());
234             return xser.serializeSchema(this, true);
235 
236         } catch (XmlSchemaSerializer.XmlSchemaSerializerException e) {
237             throw new XmlSchemaException(e.getMessage());
238         }
239     }
240 
241     /**
242      * serialize the schema - this is the method tht does to work
243      * @param schema
244      * @param out
245      * @param options
246      */
247     private  void serialize_internal(XmlSchema schema, Writer out, Map options) {
248 
249         try {
250             XmlSchemaSerializer xser = new XmlSchemaSerializer();
251             xser.setExtReg(this.parent.getExtReg());
252             Document[] serializedSchemas = xser.serializeSchema(schema, false);
253             TransformerFactory trFac = TransformerFactory.newInstance();
254 
255             try {
256                 trFac.setAttribute("indent-number", "4");
257             } catch (IllegalArgumentException e) {
258                 //do nothing - we'll just silently let this pass if it
259                 //was not compatible
260             }
261 
262             Source source = new DOMSource(serializedSchemas[0]);
263             Result result = new StreamResult(out);
264             javax.xml.transform.Transformer tr = trFac.newTransformer();
265 
266             //use the input encoding if there is one one
267             if (schema.inputEncoding!= null &&
268                     "".equals(schema.inputEncoding)){
269                 tr.setOutputProperty(OutputKeys.ENCODING,schema.inputEncoding);
270             }
271 
272             //let these be configured from outside  if any is present
273             //Note that one can enforce the encoding by passing the necessary
274             //property in options
275             
276             if (options==null){
277                 options = new HashMap();
278                 loadDefaultOptions(options);
279             }
280             Iterator keys = options.keySet().iterator();
281             while (keys.hasNext()) {
282                 Object key = keys.next();
283                 tr.setOutputProperty((String)key, (String)options.get(key));
284             }
285 
286             tr.transform(source, result);
287             out.flush();
288         } catch (TransformerConfigurationException e) {
289             throw new XmlSchemaException(e.getMessage());
290         } catch (TransformerException e) {
291             throw new XmlSchemaException(e.getMessage());
292         } catch (XmlSchemaSerializer.XmlSchemaSerializerException e) {
293             throw new XmlSchemaException(e.getMessage());
294         } catch (IOException e) {
295             throw new XmlSchemaException(e.getMessage());
296         }
297     }
298 
299     /**
300      * Load the default options
301      * @param options  - the map of
302      */
303     private void loadDefaultOptions(Map options) {
304         options.put(OutputKeys.OMIT_XML_DECLARATION, "yes");
305         options.put(OutputKeys.INDENT, "yes");
306     }
307 
308     public void addType(XmlSchemaType type) {
309         QName qname = type.getQName();
310         if (schemaTypes.contains(qname)) {
311             throw new RuntimeException("Schema for namespace '" +
312                     syntacticalTargetNamespace + "' already contains type '" +
313                     qname.getLocalPart());
314         }
315         schemaTypes.add(qname, type);
316     }
317 
318     public NamespacePrefixList getNamespaceContext() {
319         return namespaceContext;
320     }
321 
322     /**
323      * Sets the schema elements namespace context. This may be used for schema
324      * serialization, until a better mechanism was found.
325      */
326     public void setNamespaceContext(NamespacePrefixList namespaceContext) {
327         this.namespaceContext = namespaceContext;
328     }
329 
330     /**
331      * Override the equals(Object) method with equivalence checking
332      * that is specific to this class.
333      */
334     public boolean equals(Object what) {
335 
336         //Note: this method may no longer be required when line number/position are used correctly in XmlSchemaObject.
337         //Currently they are simply initialized to zero, but they are used in XmlSchemaObject.equals 
338         //which can result in a false positive (e.g. if a WSDL contains 2 inlined schemas).
339 
340         if (what == this) {
341             return true;
342         }
343 
344         //If the inherited behaviour determines that the objects are NOT equal, return false. 
345         //Otherwise, do some further equivalence checking.
346 
347         if(!super.equals(what)) {
348             return false;
349         }
350 
351         if (!(what instanceof XmlSchema)) {
352             return false;
353         }
354 
355         XmlSchema xs = (XmlSchema) what;
356 
357         if (this.id != null) {
358             if (!this.id.equals(xs.id)) {
359                 return false;
360             }
361         } else {
362             if (xs.id != null) {
363                 return false;
364             }
365         }
366 
367         if (this.syntacticalTargetNamespace != null) {
368             if (!this.syntacticalTargetNamespace.equals(xs.syntacticalTargetNamespace)) {
369                 return false;
370             }
371         } else {
372             if (xs.syntacticalTargetNamespace != null) {
373                 return false;
374             }
375         }
376 
377         //TODO decide if further schema content should be checked for equivalence.
378 
379         return true;
380     }
381 }