/* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.tools.internal.xjc.reader.internalizer; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParserFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.SAXResult; import javax.xml.transform.sax.SAXSource; import javax.xml.validation.SchemaFactory; import com.sun.istack.internal.NotNull; import com.sun.istack.internal.XMLStreamReaderToContentHandler; import com.sun.tools.internal.xjc.ErrorReceiver; import com.sun.tools.internal.xjc.Options; import com.sun.tools.internal.xjc.reader.Const; import com.sun.tools.internal.xjc.util.ErrorReceiverFilter; import com.sun.xml.internal.bind.marshaller.DataWriter; import com.sun.xml.internal.bind.v2.util.XmlFactory; import com.sun.xml.internal.xsom.parser.JAXPParser; import com.sun.xml.internal.xsom.parser.XMLParser; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.ContentHandler; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.XMLFilterImpl; /** * Builds a DOM forest and maintains association from * system IDs to DOM trees. * *
* A forest is a transitive reflexive closure of referenced documents. * IOW, if a document is in a forest, all the documents referenced from * it is in a forest, too. To support this semantics, {@link DOMForest} * uses {@link InternalizationLogic} to find referenced documents. * *
* Some documents are marked as "root"s, meaning those documents were
* put into a forest explicitly, not because it is referenced from another
* document. (However, a root document can be referenced from other
* documents, too.)
*
* @author
* Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
*/
public final class DOMForest {
/** actual data storage map<SystemId,Document>. */
private final Map
* Set of system ids as strings.
*/
private final Set
* This method performs a weaker version of the tests where error messages
* are provided without line number information. So whenever possible
* use {@link SchemaConstraintChecker}.
*
* @see SchemaConstraintChecker
*/
public boolean checkSchemaCorrectness(ErrorReceiver errorHandler) {
try {
boolean disableXmlSecurity = false;
if (options != null) {
disableXmlSecurity = options.disableXmlSecurity;
}
SchemaFactory sf = XmlFactory.createSchemaFactory(W3C_XML_SCHEMA_NS_URI, disableXmlSecurity);
ErrorReceiverFilter filter = new ErrorReceiverFilter(errorHandler);
sf.setErrorHandler(filter);
Set
* Poor-man's base URI.
*/
public String getSystemId( Document dom ) {
for (Map.Entry
* The client of this class can feed SAX events into the handler
* to parse a document into this DOM forest.
*
* This version requires that the DOM object to be created and registered
* to the map beforehand.
*/
private ContentHandler getParserHandler( Document dom ) {
ContentHandler handler = new DOMBuilder(dom,locatorTable,outerMostBindings);
handler = new WhitespaceStripper(handler,errorReceiver,entityResolver);
handler = new VersionChecker(handler,errorReceiver,entityResolver);
// insert the reference finder so that
// included/imported schemas will be also parsed
XMLFilterImpl f = logic.createExternalReferenceFinder(this);
f.setContentHandler(handler);
if(errorReceiver!=null)
f.setErrorHandler(errorReceiver);
if(entityResolver!=null)
f.setEntityResolver(entityResolver);
return f;
}
public interface Handler extends ContentHandler {
/**
* Gets the DOM that was built.
*/
public Document getDocument();
}
private static abstract class HandlerImpl extends XMLFilterImpl implements Handler {
}
/**
* Returns a {@link ContentHandler} to feed SAX events into.
*
*
* The client of this class can feed SAX events into the handler
* to parse a document into this DOM forest.
*/
public Handler getParserHandler( String systemId, boolean root ) {
final Document dom = documentBuilder.newDocument();
core.put( systemId, dom );
if(root)
rootDocuments.add(systemId);
ContentHandler handler = getParserHandler(dom);
// we will register the DOM to the map once the system ID becomes available.
// but the SAX allows the event source to not to provide that information,
// so be prepared for such case.
HandlerImpl x = new HandlerImpl() {
public Document getDocument() {
return dom;
}
};
x.setContentHandler(handler);
return x;
}
/**
* Parses the given document and add it to the DOM forest.
*
* @return
* null if there was a parse error. otherwise non-null.
*/
public Document parse( String systemId, InputSource inputSource, boolean root ) throws SAXException {
Document dom = documentBuilder.newDocument();
systemId = Options.normalizeSystemId(systemId);
// put into the map before growing a tree, to
// prevent recursive reference from causing infinite loop.
core.put( systemId, dom );
if(root)
rootDocuments.add(systemId);
try {
XMLReader reader = parserFactory.newSAXParser().getXMLReader();
reader.setContentHandler(getParserHandler(dom));
if(errorReceiver!=null)
reader.setErrorHandler(errorReceiver);
if(entityResolver!=null)
reader.setEntityResolver(entityResolver);
reader.parse(inputSource);
} catch( ParserConfigurationException e ) {
// in practice, this exception won't happen.
errorReceiver.error(e.getMessage(),e);
core.remove(systemId);
rootDocuments.remove(systemId);
return null;
} catch( IOException e ) {
errorReceiver.error(Messages.format(Messages.DOMFOREST_INPUTSOURCE_IOEXCEPTION, systemId, e.toString()),e);
core.remove(systemId);
rootDocuments.remove(systemId);
return null;
}
return dom;
}
public Document parse( String systemId, XMLStreamReader parser, boolean root ) throws XMLStreamException {
Document dom = documentBuilder.newDocument();
systemId = Options.normalizeSystemId(systemId);
if(root)
rootDocuments.add(systemId);
if(systemId==null)
throw new IllegalArgumentException("system id cannot be null");
core.put( systemId, dom );
new XMLStreamReaderToContentHandler(parser,getParserHandler(dom),false,false).bridge();
return dom;
}
/**
* Performs internalization.
*
* This method should be called only once, only after all the
* schemas are parsed.
*
* @return
* the returned bindings need to be applied after schema
* components are built.
*/
public SCDBasedBindingSet transform(boolean enableSCD) {
return Internalizer.transform(this, enableSCD, options.disableXmlSecurity);
}
/**
* Performs the schema correctness check by using JAXP 1.3.
*
*
* This is "weak", because {@link SchemaFactory#newSchema(Source[])}
* doesn't handle inclusions very correctly (it ends up parsing it
* from its original source, not in this tree), and because
* it doesn't handle two documents for the same namespace very
* well.
*
*
* We should eventually fix JAXP (and Xerces), but meanwhile
* this weaker and potentially wrong correctness check is still
* better than nothing when used inside JAX-WS (JAXB CLI and Ant
* does a better job of checking this.)
*
*
* To receive errors, use {@link SchemaFactory#setErrorHandler(ErrorHandler)}.
*/
public void weakSchemaCorrectnessCheck(SchemaFactory sf) {
List