001: /*
002: * Portions Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.tools.internal.ws.wsdl.parser;
027:
028: import java.io.IOException;
029: import java.util.Iterator;
030:
031: import javax.xml.parsers.DocumentBuilder;
032: import javax.xml.parsers.DocumentBuilderFactory;
033: import javax.xml.parsers.FactoryConfigurationError;
034: import javax.xml.parsers.ParserConfigurationException;
035:
036: import org.w3c.dom.Attr;
037: import org.w3c.dom.Document;
038: import org.w3c.dom.Element;
039: import org.xml.sax.ErrorHandler;
040: import org.xml.sax.InputSource;
041: import org.xml.sax.SAXException;
042: import org.xml.sax.SAXParseException;
043:
044: import com.sun.xml.internal.ws.util.xml.NamedNodeMapIterator;
045: import com.sun.tools.internal.ws.util.xml.NullEntityResolver;
046: import com.sun.tools.internal.ws.wsdl.document.schema.Schema;
047: import com.sun.tools.internal.ws.wsdl.document.schema.SchemaAttribute;
048: import com.sun.tools.internal.ws.wsdl.document.schema.SchemaConstants;
049: import com.sun.tools.internal.ws.wsdl.document.schema.SchemaDocument;
050: import com.sun.tools.internal.ws.wsdl.document.schema.SchemaElement;
051: import com.sun.tools.internal.ws.wsdl.framework.ParseException;
052: import com.sun.tools.internal.ws.wsdl.framework.ParserContext;
053: import com.sun.tools.internal.ws.wsdl.framework.ValidationException;
054: import com.sun.xml.internal.ws.util.xml.XmlUtil;
055:
056: /**
057: * A parser for XML Schema, including the fragments found inside a WSDL document.
058: *
059: * @author WS Development Team
060: */
061: public class SchemaParser {
062:
063: public SchemaParser() {
064: }
065:
066: public boolean getFollowImports() {
067: return _followImports;
068: }
069:
070: public void setFollowImports(boolean b) {
071: _followImports = b;
072: }
073:
074: public SchemaDocument parse(InputSource source) {
075: SchemaDocument schemaDocument = new SchemaDocument();
076: schemaDocument.setSystemId(source.getSystemId());
077: ParserContext context = new ParserContext(schemaDocument, null);
078: context.setFollowImports(_followImports);
079: schemaDocument.setSchema(parseSchema(context, source, null));
080: return schemaDocument;
081: }
082:
083: public Schema parseSchema(ParserContext context,
084: InputSource source, String expectedTargetNamespaceURI) {
085: Schema schema = parseSchemaNoImport(context, source,
086: expectedTargetNamespaceURI);
087: schema.defineAllEntities();
088: processImports(context, source, schema);
089: return schema;
090: }
091:
092: public Schema parseSchema(ParserContext context, Element e,
093: String expectedTargetNamespaceURI) {
094: Schema schema = parseSchemaNoImport(context, e,
095: expectedTargetNamespaceURI);
096: schema.defineAllEntities();
097: processImports(context, null, schema);
098: return schema;
099: }
100:
101: protected void processImports(ParserContext context,
102: InputSource source, Schema schema) {
103: for (Iterator iter = schema.getContent().children(); iter
104: .hasNext();) {
105: SchemaElement child = (SchemaElement) iter.next();
106: if (child.getQName().equals(SchemaConstants.QNAME_IMPORT)) {
107: String location = child
108: .getValueOfAttributeOrNull(Constants.ATTR_SCHEMA_LOCATION);
109: String namespace = child
110: .getValueOfAttributeOrNull(Constants.ATTR_NAMESPACE);
111: //bug fix: 4857762, add adjustedLocation to teh importDocuments and ignore if it
112: //exists, to avoid duplicates
113: if (location != null) {
114: String adjustedLocation = null;
115: if (source != null && source.getSystemId() != null) {
116: adjustedLocation = Util
117: .processSystemIdWithBase(source
118: .getSystemId(), location);
119: }
120: //bug fix: 4856674
121: if (adjustedLocation == null) {
122: adjustedLocation = context.getWSDLLocation() == null ? location
123: : Util.processSystemIdWithBase(context
124: .getWSDLLocation(), location);
125: }
126: if (!context.getDocument().isImportedDocument(
127: adjustedLocation)) {
128: context.getDocument().addImportedEntity(
129: parseSchema(context, new InputSource(
130: adjustedLocation), namespace));
131: context.getDocument().addImportedDocument(
132: adjustedLocation);
133: }
134: }
135: } else if (child.getQName().equals(
136: SchemaConstants.QNAME_INCLUDE)
137: && (schema.getTargetNamespaceURI() != null)) {
138: String location = child
139: .getValueOfAttributeOrNull(Constants.ATTR_SCHEMA_LOCATION);
140: if (location != null
141: && !context.getDocument().isIncludedDocument(
142: location)) {
143: context.getDocument().addIncludedDocument(location);
144: String adjustedLocation = null;
145: if (source != null && source.getSystemId() != null) {
146: adjustedLocation = Util
147: .processSystemIdWithBase(source
148: .getSystemId(), location);
149: }
150: if (adjustedLocation == null) {
151: adjustedLocation = context.getDocument()
152: .getSystemId() == null ? location
153: : Util.processSystemIdWithBase(context
154: .getDocument().getSystemId(),
155: location);
156: }
157: context.getDocument().addIncludedEntity(
158: parseSchema(context, new InputSource(
159: adjustedLocation), schema
160: .getTargetNamespaceURI()));
161: }
162: } else if (child.getQName().equals(
163: SchemaConstants.QNAME_REDEFINE)) {
164: // not supported
165: Util.fail("validation.unsupportedSchemaFeature",
166: "redefine");
167: }
168: }
169: }
170:
171: protected Schema parseSchemaNoImport(ParserContext context,
172: InputSource source, String expectedTargetNamespaceURI) {
173: try {
174: DocumentBuilderFactory builderFactory = DocumentBuilderFactory
175: .newInstance();
176: builderFactory.setNamespaceAware(true);
177: builderFactory.setValidating(false);
178: DocumentBuilder builder = builderFactory
179: .newDocumentBuilder();
180: builder.setErrorHandler(new ErrorHandler() {
181: public void error(SAXParseException e)
182: throws SAXParseException {
183: throw e;
184: }
185:
186: public void fatalError(SAXParseException e)
187: throws SAXParseException {
188: throw e;
189: }
190:
191: public void warning(SAXParseException err)
192: throws SAXParseException {
193: // do nothing
194: }
195: });
196: builder.setEntityResolver(new NullEntityResolver());
197:
198: try {
199: Document document = builder.parse(source);
200: return parseSchemaNoImport(context, document,
201: expectedTargetNamespaceURI);
202: } catch (IOException e) {
203: throw new ParseException("parsing.ioException", e);
204: } catch (SAXException e) {
205: throw new ParseException("parsing.saxException", e);
206: }
207: } catch (ParserConfigurationException e) {
208: throw new ParseException("parsing.parserConfigException", e);
209: } catch (FactoryConfigurationError e) {
210: throw new ParseException("parsing.factoryConfigException",
211: e);
212: }
213: }
214:
215: protected Schema parseSchemaNoImport(ParserContext context,
216: Document doc, String expectedTargetNamespaceURI) {
217: Element root = doc.getDocumentElement();
218: Util.verifyTagNSRootElement(root, SchemaConstants.QNAME_SCHEMA);
219: return parseSchemaNoImport(context, root,
220: expectedTargetNamespaceURI);
221: }
222:
223: protected Schema parseSchemaNoImport(ParserContext context,
224: Element e, String expectedTargetNamespaceURI) {
225: Schema schema = new Schema(context.getDocument());
226: String targetNamespaceURI = XmlUtil.getAttributeOrNull(e,
227: Constants.ATTR_TARGET_NAMESPACE);
228: //bug 4849754 fix, in both the case of xsd:include and xsd:import this should work
229: if (targetNamespaceURI != null
230: && expectedTargetNamespaceURI != null
231: && !expectedTargetNamespaceURI
232: .equals(targetNamespaceURI)) {
233: throw new ValidationException(
234: "validation.incorrectTargetNamespace",
235: new Object[] { targetNamespaceURI,
236: expectedTargetNamespaceURI });
237: }
238: if (targetNamespaceURI == null)
239: schema.setTargetNamespaceURI(expectedTargetNamespaceURI);
240: else
241: schema.setTargetNamespaceURI(targetNamespaceURI);
242:
243: // snapshot the current prefixes
244: for (Iterator iter = context.getPrefixes(); iter.hasNext();) {
245: String prefix = (String) iter.next();
246: String nsURI = context.getNamespaceURI(prefix);
247: if (nsURI == null) {
248: // should not happen
249: throw new ParseException("parsing.shouldNotHappen");
250: }
251: schema.addPrefix(prefix, nsURI);
252: }
253:
254: context.push();
255: context.registerNamespaces(e);
256:
257: // just internalize the XML fragment
258: SchemaElement schemaElement = new SchemaElement(
259: SchemaConstants.QNAME_SCHEMA);
260:
261: copyNamespaceDeclarations(schemaElement, e);
262: copyAttributesNoNs(schemaElement, e);
263: copyElementContent(schemaElement, e);
264:
265: schema.setContent(schemaElement);
266: schemaElement.setSchema(schema);
267:
268: context.pop();
269: context.fireDoneParsingEntity(SchemaConstants.QNAME_SCHEMA,
270: schema);
271: return schema;
272: }
273:
274: protected void copyAttributesNoNs(SchemaElement target,
275: Element source) {
276: for (Iterator iter = new NamedNodeMapIterator(source
277: .getAttributes()); iter.hasNext();) {
278: Attr attr = (Attr) iter.next();
279: if (attr.getName().equals(PREFIX_XMLNS)
280: || attr.getName().startsWith(PREFIX_XMLNS_COLON)) {
281: continue;
282: }
283:
284: SchemaAttribute attribute = new SchemaAttribute(attr
285: .getLocalName());
286: attribute.setNamespaceURI(attr.getNamespaceURI());
287: attribute.setValue(attr.getValue());
288: target.addAttribute(attribute);
289: }
290: }
291:
292: protected void copyNamespaceDeclarations(SchemaElement target,
293: Element source) {
294: for (Iterator iter = new NamedNodeMapIterator(source
295: .getAttributes()); iter.hasNext();) {
296: Attr attr = (Attr) iter.next();
297: if (attr.getName().equals(PREFIX_XMLNS)) {
298: // default namespace declaration
299: target.addPrefix("", attr.getValue());
300: } else {
301: String prefix = XmlUtil.getPrefix(attr.getName());
302: if (prefix != null && prefix.equals(PREFIX_XMLNS)) {
303: String nsPrefix = XmlUtil.getLocalPart(attr
304: .getName());
305: String uri = attr.getValue();
306: target.addPrefix(nsPrefix, uri);
307: }
308: }
309: }
310: }
311:
312: protected void copyElementContent(SchemaElement target,
313: Element source) {
314: for (Iterator iter = XmlUtil.getAllChildren(source); iter
315: .hasNext();) {
316: Element e2 = Util.nextElementIgnoringCharacterContent(iter);
317: if (e2 == null)
318: break;
319: SchemaElement newElement = new SchemaElement(e2
320: .getLocalName());
321: newElement.setNamespaceURI(e2.getNamespaceURI());
322: copyNamespaceDeclarations(newElement, e2);
323: copyAttributesNoNs(newElement, e2);
324: copyElementContent(newElement, e2);
325: target.addChild(newElement);
326: newElement.setParent(target);
327: }
328: }
329:
330: private boolean _followImports;
331:
332: private final static String PREFIX_XMLNS = "xmlns";
333: private final static String PREFIX_XMLNS_COLON = "xmlns:";
334: }
|