aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: package com.sun.tools.internal.xjc.reader.internalizer; aoqi@0: aoqi@0: import com.sun.istack.internal.NotNull; aoqi@0: import com.sun.istack.internal.XMLStreamReaderToContentHandler; aoqi@0: import com.sun.tools.internal.xjc.ErrorReceiver; aoqi@0: import com.sun.tools.internal.xjc.Options; aoqi@0: import com.sun.tools.internal.xjc.reader.Const; aoqi@0: import com.sun.tools.internal.xjc.util.ErrorReceiverFilter; aoqi@0: import com.sun.xml.internal.bind.marshaller.DataWriter; aoqi@0: import com.sun.xml.internal.bind.v2.util.XmlFactory; aoqi@0: import com.sun.xml.internal.xsom.parser.JAXPParser; aoqi@0: import com.sun.xml.internal.xsom.parser.XMLParser; aoqi@0: import org.w3c.dom.Document; aoqi@0: import org.w3c.dom.Element; aoqi@0: import org.xml.sax.*; aoqi@0: import org.xml.sax.helpers.XMLFilterImpl; aoqi@0: aoqi@0: import javax.xml.parsers.DocumentBuilder; aoqi@0: import javax.xml.parsers.DocumentBuilderFactory; aoqi@0: import javax.xml.parsers.ParserConfigurationException; aoqi@0: import javax.xml.parsers.SAXParserFactory; aoqi@0: import javax.xml.stream.XMLStreamException; aoqi@0: import javax.xml.stream.XMLStreamReader; aoqi@0: import javax.xml.transform.Source; aoqi@0: import javax.xml.transform.Transformer; aoqi@0: import javax.xml.transform.TransformerException; aoqi@0: import javax.xml.transform.TransformerFactory; aoqi@0: import javax.xml.transform.dom.DOMSource; aoqi@0: import javax.xml.transform.sax.SAXResult; aoqi@0: import javax.xml.transform.sax.SAXSource; aoqi@0: import javax.xml.validation.SchemaFactory; aoqi@0: import java.io.IOException; aoqi@0: import java.io.OutputStream; aoqi@0: import java.io.OutputStreamWriter; aoqi@0: import java.util.*; aoqi@0: aoqi@0: import static com.sun.xml.internal.bind.v2.util.XmlFactory.allowExternalAccess; aoqi@0: import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; aoqi@0: aoqi@0: aoqi@0: /** aoqi@0: * Builds a DOM forest and maintains association from aoqi@0: * system IDs to DOM trees. aoqi@0: * aoqi@0: *

aoqi@0: * A forest is a transitive reflexive closure of referenced documents. aoqi@0: * IOW, if a document is in a forest, all the documents referenced from aoqi@0: * it is in a forest, too. To support this semantics, {@link DOMForest} aoqi@0: * uses {@link InternalizationLogic} to find referenced documents. aoqi@0: * aoqi@0: *

aoqi@0: * Some documents are marked as "root"s, meaning those documents were aoqi@0: * put into a forest explicitly, not because it is referenced from another aoqi@0: * document. (However, a root document can be referenced from other aoqi@0: * documents, too.) aoqi@0: * aoqi@0: * @author aoqi@0: * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) aoqi@0: */ aoqi@0: public final class DOMForest { aoqi@0: /** actual data storage map<SystemId,Document>. */ aoqi@0: private final Map core = new HashMap(); aoqi@0: aoqi@0: /** aoqi@0: * To correctly feed documents to a schema parser, we need to remember aoqi@0: * which documents (of the forest) were given as the root aoqi@0: * documents, and which of them are read as included/imported aoqi@0: * documents. aoqi@0: * aoqi@0: *

aoqi@0: * Set of system ids as strings. aoqi@0: */ aoqi@0: private final Set rootDocuments = new HashSet(); aoqi@0: aoqi@0: /** Stores location information for all the trees in this forest. */ aoqi@0: public final LocatorTable locatorTable = new LocatorTable(); aoqi@0: aoqi@0: /** Stores all the outer-most <jaxb:bindings> customizations. */ aoqi@0: public final Set outerMostBindings = new HashSet(); aoqi@0: aoqi@0: /** Used to resolve references to other schema documents. */ aoqi@0: private EntityResolver entityResolver = null; aoqi@0: aoqi@0: /** Errors encountered during the parsing will be sent to this object. */ aoqi@0: private ErrorReceiver errorReceiver = null; aoqi@0: aoqi@0: /** Schema language dependent part of the processing. */ aoqi@0: protected final InternalizationLogic logic; aoqi@0: aoqi@0: private final SAXParserFactory parserFactory; aoqi@0: private final DocumentBuilder documentBuilder; aoqi@0: aoqi@0: private final Options options; aoqi@0: aoqi@0: public DOMForest( aoqi@0: SAXParserFactory parserFactory, DocumentBuilder documentBuilder, aoqi@0: InternalizationLogic logic ) { aoqi@0: aoqi@0: this.parserFactory = parserFactory; aoqi@0: this.documentBuilder = documentBuilder; aoqi@0: this.logic = logic; aoqi@0: this.options = null; aoqi@0: } aoqi@0: aoqi@0: public DOMForest( InternalizationLogic logic, Options opt ) { aoqi@0: aoqi@0: if (opt == null) throw new AssertionError("Options object null"); aoqi@0: this.options = opt; aoqi@0: aoqi@0: try { aoqi@0: DocumentBuilderFactory dbf = XmlFactory.createDocumentBuilderFactory(opt.disableXmlSecurity); aoqi@0: this.documentBuilder = dbf.newDocumentBuilder(); aoqi@0: this.parserFactory = XmlFactory.createParserFactory(opt.disableXmlSecurity); aoqi@0: } catch( ParserConfigurationException e ) { aoqi@0: throw new AssertionError(e); aoqi@0: } aoqi@0: aoqi@0: this.logic = logic; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Gets the DOM tree associated with the specified system ID, aoqi@0: * or null if none is found. aoqi@0: */ aoqi@0: public Document get( String systemId ) { aoqi@0: Document doc = core.get(systemId); aoqi@0: aoqi@0: if( doc==null && systemId.startsWith("file:/") && !systemId.startsWith("file://") ) { aoqi@0: // As of JDK1.4, java.net.URL.toExternal method returns URLs like aoqi@0: // "file:/abc/def/ghi" which is an incorrect file protocol URL according to RFC1738. aoqi@0: // Some other correctly functioning parts return the correct URLs ("file:///abc/def/ghi"), aoqi@0: // and this descripancy breaks DOM look up by system ID. aoqi@0: aoqi@0: // this extra check solves this problem. aoqi@0: doc = core.get( "file://"+systemId.substring(5) ); aoqi@0: } aoqi@0: aoqi@0: if( doc==null && systemId.startsWith("file:") ) { aoqi@0: // on Windows, filenames are case insensitive. aoqi@0: // perform case-insensitive search for improved user experience aoqi@0: String systemPath = getPath(systemId); aoqi@0: for (String key : core.keySet()) { aoqi@0: if(key.startsWith("file:") && getPath(key).equalsIgnoreCase(systemPath)) { aoqi@0: doc = core.get(key); aoqi@0: break; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: return doc; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Strips off the leading 'file:///' portion from an URL. aoqi@0: */ aoqi@0: private String getPath(String key) { aoqi@0: key = key.substring(5); // skip 'file:' aoqi@0: while(key.length()>0 && key.charAt(0)=='/') { aoqi@0: key = key.substring(1); aoqi@0: } aoqi@0: return key; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Returns a read-only set of root document system IDs. aoqi@0: */ aoqi@0: public Set getRootDocuments() { aoqi@0: return Collections.unmodifiableSet(rootDocuments); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Picks one document at random and returns it. aoqi@0: */ aoqi@0: public Document getOneDocument() { aoqi@0: for (Document dom : core.values()) { aoqi@0: if (!dom.getDocumentElement().getNamespaceURI().equals(Const.JAXB_NSURI)) aoqi@0: return dom; aoqi@0: } aoqi@0: // we should have caught this error very early on aoqi@0: throw new AssertionError(); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Checks the correctness of the XML Schema documents and return true aoqi@0: * if it's OK. aoqi@0: * aoqi@0: *

aoqi@0: * This method performs a weaker version of the tests where error messages aoqi@0: * are provided without line number information. So whenever possible aoqi@0: * use {@link SchemaConstraintChecker}. aoqi@0: * aoqi@0: * @see SchemaConstraintChecker aoqi@0: */ aoqi@0: public boolean checkSchemaCorrectness(ErrorReceiver errorHandler) { aoqi@0: try { aoqi@0: boolean disableXmlSecurity = false; aoqi@0: if (options != null) { aoqi@0: disableXmlSecurity = options.disableXmlSecurity; aoqi@0: } aoqi@0: SchemaFactory sf = XmlFactory.createSchemaFactory(W3C_XML_SCHEMA_NS_URI, disableXmlSecurity); aoqi@0: ErrorReceiverFilter filter = new ErrorReceiverFilter(errorHandler); aoqi@0: sf.setErrorHandler(filter); aoqi@0: Set roots = getRootDocuments(); aoqi@0: Source[] sources = new Source[roots.size()]; aoqi@0: int i=0; aoqi@0: for (String root : roots) { aoqi@0: sources[i++] = new DOMSource(get(root),root); aoqi@0: } aoqi@0: sf.newSchema(sources); aoqi@0: return !filter.hadError(); aoqi@0: } catch (SAXException e) { aoqi@0: // the errors should have been reported aoqi@0: return false; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Gets the system ID from which the given DOM is parsed. aoqi@0: *

aoqi@0: * Poor-man's base URI. aoqi@0: */ aoqi@0: public String getSystemId( Document dom ) { aoqi@0: for (Map.Entry e : core.entrySet()) { aoqi@0: if (e.getValue() == dom) aoqi@0: return e.getKey(); aoqi@0: } aoqi@0: return null; aoqi@0: } aoqi@0: aoqi@0: public Document parse( InputSource source, boolean root ) throws SAXException { aoqi@0: if( source.getSystemId()==null ) aoqi@0: throw new IllegalArgumentException(); aoqi@0: aoqi@0: return parse( source.getSystemId(), source, root ); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Parses an XML at the given location ( aoqi@0: * and XMLs referenced by it) into DOM trees aoqi@0: * and stores them to this forest. aoqi@0: * aoqi@0: * @return the parsed DOM document object. aoqi@0: */ aoqi@0: public Document parse( String systemId, boolean root ) throws SAXException, IOException { aoqi@0: aoqi@0: systemId = Options.normalizeSystemId(systemId); aoqi@0: aoqi@0: if( core.containsKey(systemId) ) aoqi@0: // this document has already been parsed. Just ignore. aoqi@0: return core.get(systemId); aoqi@0: aoqi@0: InputSource is=null; aoqi@0: aoqi@0: // allow entity resolver to find the actual byte stream. aoqi@0: if( entityResolver!=null ) aoqi@0: is = entityResolver.resolveEntity(null,systemId); aoqi@0: if( is==null ) aoqi@0: is = new InputSource(systemId); aoqi@0: aoqi@0: // but we still use the original system Id as the key. aoqi@0: return parse( systemId, is, root ); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Returns a {@link ContentHandler} to feed SAX events into. aoqi@0: * aoqi@0: *

aoqi@0: * The client of this class can feed SAX events into the handler aoqi@0: * to parse a document into this DOM forest. aoqi@0: * aoqi@0: * This version requires that the DOM object to be created and registered aoqi@0: * to the map beforehand. aoqi@0: */ aoqi@0: private ContentHandler getParserHandler( Document dom ) { aoqi@0: ContentHandler handler = new DOMBuilder(dom,locatorTable,outerMostBindings); aoqi@0: handler = new WhitespaceStripper(handler,errorReceiver,entityResolver); aoqi@0: handler = new VersionChecker(handler,errorReceiver,entityResolver); aoqi@0: aoqi@0: // insert the reference finder so that aoqi@0: // included/imported schemas will be also parsed aoqi@0: XMLFilterImpl f = logic.createExternalReferenceFinder(this); aoqi@0: f.setContentHandler(handler); aoqi@0: aoqi@0: if(errorReceiver!=null) aoqi@0: f.setErrorHandler(errorReceiver); aoqi@0: if(entityResolver!=null) aoqi@0: f.setEntityResolver(entityResolver); aoqi@0: aoqi@0: return f; aoqi@0: } aoqi@0: aoqi@0: public interface Handler extends ContentHandler { aoqi@0: /** aoqi@0: * Gets the DOM that was built. aoqi@0: */ aoqi@0: public Document getDocument(); aoqi@0: } aoqi@0: aoqi@0: private static abstract class HandlerImpl extends XMLFilterImpl implements Handler { aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Returns a {@link ContentHandler} to feed SAX events into. aoqi@0: * aoqi@0: *

aoqi@0: * The client of this class can feed SAX events into the handler aoqi@0: * to parse a document into this DOM forest. aoqi@0: */ aoqi@0: public Handler getParserHandler( String systemId, boolean root ) { aoqi@0: final Document dom = documentBuilder.newDocument(); aoqi@0: core.put( systemId, dom ); aoqi@0: if(root) aoqi@0: rootDocuments.add(systemId); aoqi@0: aoqi@0: ContentHandler handler = getParserHandler(dom); aoqi@0: aoqi@0: // we will register the DOM to the map once the system ID becomes available. aoqi@0: // but the SAX allows the event source to not to provide that information, aoqi@0: // so be prepared for such case. aoqi@0: HandlerImpl x = new HandlerImpl() { aoqi@0: public Document getDocument() { aoqi@0: return dom; aoqi@0: } aoqi@0: }; aoqi@0: x.setContentHandler(handler); aoqi@0: aoqi@0: return x; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Parses the given document and add it to the DOM forest. aoqi@0: * aoqi@0: * @return aoqi@0: * null if there was a parse error. otherwise non-null. aoqi@0: */ aoqi@0: public Document parse( String systemId, InputSource inputSource, boolean root ) throws SAXException { aoqi@0: Document dom = documentBuilder.newDocument(); aoqi@0: aoqi@0: systemId = Options.normalizeSystemId(systemId); aoqi@0: aoqi@0: // put into the map before growing a tree, to aoqi@0: // prevent recursive reference from causing infinite loop. aoqi@0: core.put( systemId, dom ); aoqi@0: if(root) aoqi@0: rootDocuments.add(systemId); aoqi@0: aoqi@0: try { aoqi@0: XMLReader reader = parserFactory.newSAXParser().getXMLReader(); aoqi@0: reader.setContentHandler(getParserHandler(dom)); aoqi@0: if(errorReceiver!=null) aoqi@0: reader.setErrorHandler(errorReceiver); aoqi@0: if(entityResolver!=null) aoqi@0: reader.setEntityResolver(entityResolver); aoqi@0: reader.parse(inputSource); aoqi@0: } catch( ParserConfigurationException e ) { aoqi@0: // in practice, this exception won't happen. aoqi@0: errorReceiver.error(e.getMessage(),e); aoqi@0: core.remove(systemId); aoqi@0: rootDocuments.remove(systemId); aoqi@0: return null; aoqi@0: } catch( IOException e ) { aoqi@0: errorReceiver.error(Messages.format(Messages.DOMFOREST_INPUTSOURCE_IOEXCEPTION, systemId, e.toString()),e); aoqi@0: core.remove(systemId); aoqi@0: rootDocuments.remove(systemId); aoqi@0: return null; aoqi@0: } aoqi@0: aoqi@0: return dom; aoqi@0: } aoqi@0: aoqi@0: public Document parse( String systemId, XMLStreamReader parser, boolean root ) throws XMLStreamException { aoqi@0: Document dom = documentBuilder.newDocument(); aoqi@0: aoqi@0: systemId = Options.normalizeSystemId(systemId); aoqi@0: aoqi@0: if(root) aoqi@0: rootDocuments.add(systemId); aoqi@0: aoqi@0: if(systemId==null) aoqi@0: throw new IllegalArgumentException("system id cannot be null"); aoqi@0: core.put( systemId, dom ); aoqi@0: aoqi@0: new XMLStreamReaderToContentHandler(parser,getParserHandler(dom),false,false).bridge(); aoqi@0: aoqi@0: return dom; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Performs internalization. aoqi@0: * aoqi@0: * This method should be called only once, only after all the aoqi@0: * schemas are parsed. aoqi@0: * aoqi@0: * @return aoqi@0: * the returned bindings need to be applied after schema aoqi@0: * components are built. aoqi@0: */ aoqi@0: public SCDBasedBindingSet transform(boolean enableSCD) { aoqi@0: return Internalizer.transform(this, enableSCD, options.disableXmlSecurity); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Performs the schema correctness check by using JAXP 1.3. aoqi@0: * aoqi@0: *

aoqi@0: * This is "weak", because {@link SchemaFactory#newSchema(Source[])} aoqi@0: * doesn't handle inclusions very correctly (it ends up parsing it aoqi@0: * from its original source, not in this tree), and because aoqi@0: * it doesn't handle two documents for the same namespace very aoqi@0: * well. aoqi@0: * aoqi@0: *

aoqi@0: * We should eventually fix JAXP (and Xerces), but meanwhile aoqi@0: * this weaker and potentially wrong correctness check is still aoqi@0: * better than nothing when used inside JAX-WS (JAXB CLI and Ant aoqi@0: * does a better job of checking this.) aoqi@0: * aoqi@0: *

aoqi@0: * To receive errors, use {@link SchemaFactory#setErrorHandler(ErrorHandler)}. aoqi@0: */ aoqi@0: public void weakSchemaCorrectnessCheck(SchemaFactory sf) { aoqi@0: List sources = new ArrayList(); aoqi@0: for( String systemId : getRootDocuments() ) { aoqi@0: Document dom = get(systemId); aoqi@0: if (dom.getDocumentElement().getNamespaceURI().equals(Const.JAXB_NSURI)) aoqi@0: continue; // this isn't a schema. we have to do a negative check because if we see completely unrelated ns, we want to report that as an error aoqi@0: aoqi@0: SAXSource ss = createSAXSource(systemId); aoqi@0: try { aoqi@0: ss.getXMLReader().setFeature("http://xml.org/sax/features/namespace-prefixes",true); aoqi@0: } catch (SAXException e) { aoqi@0: throw new AssertionError(e); // Xerces wants this. See 6395322. aoqi@0: } aoqi@0: sources.add(ss); aoqi@0: } aoqi@0: aoqi@0: try { aoqi@0: allowExternalAccess(sf, "file,http", options.disableXmlSecurity).newSchema(sources.toArray(new SAXSource[0])); aoqi@0: } catch (SAXException e) { aoqi@0: // error should have been reported. aoqi@0: } catch (RuntimeException re) { aoqi@0: // JAXP RI isn't very trustworthy when it comes to schema error check, aoqi@0: // and we know some cases where it just dies with NPE. So handle it gracefully. aoqi@0: // this masks a bug in the JAXP RI, but we need a release that we have to make. aoqi@0: try { aoqi@0: sf.getErrorHandler().warning( aoqi@0: new SAXParseException(Messages.format( aoqi@0: Messages.ERR_GENERAL_SCHEMA_CORRECTNESS_ERROR,re.getMessage()), aoqi@0: null,null,-1,-1,re)); aoqi@0: } catch (SAXException e) { aoqi@0: // ignore aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Creates a {@link SAXSource} that, when parsed, reads from this {@link DOMForest} aoqi@0: * (instead of parsing the original source identified by the system ID.) aoqi@0: */ aoqi@0: public @NotNull SAXSource createSAXSource(String systemId) { aoqi@0: ContentHandlerNamespacePrefixAdapter reader = new ContentHandlerNamespacePrefixAdapter(new XMLFilterImpl() { aoqi@0: // XMLReader that uses XMLParser to parse. We need to use XMLFilter to indrect aoqi@0: // handlers, since SAX allows handlers to be changed while parsing. aoqi@0: @Override aoqi@0: public void parse(InputSource input) throws SAXException, IOException { aoqi@0: createParser().parse(input, this, this, this); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void parse(String systemId) throws SAXException, IOException { aoqi@0: parse(new InputSource(systemId)); aoqi@0: } aoqi@0: }); aoqi@0: aoqi@0: return new SAXSource(reader,new InputSource(systemId)); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Creates {@link XMLParser} for XSOM which reads documents from aoqi@0: * this DOMForest rather than doing a fresh parse. aoqi@0: * aoqi@0: * The net effect is that XSOM will read transformed XML Schemas aoqi@0: * instead of the original documents. aoqi@0: */ aoqi@0: public XMLParser createParser() { aoqi@0: return new DOMForestParser(this, new JAXPParser(XmlFactory.createParserFactory(options.disableXmlSecurity))); aoqi@0: } aoqi@0: aoqi@0: public EntityResolver getEntityResolver() { aoqi@0: return entityResolver; aoqi@0: } aoqi@0: aoqi@0: public void setEntityResolver(EntityResolver entityResolver) { aoqi@0: this.entityResolver = entityResolver; aoqi@0: } aoqi@0: aoqi@0: public ErrorReceiver getErrorHandler() { aoqi@0: return errorReceiver; aoqi@0: } aoqi@0: aoqi@0: public void setErrorHandler(ErrorReceiver errorHandler) { aoqi@0: this.errorReceiver = errorHandler; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Gets all the parsed documents. aoqi@0: */ aoqi@0: public Document[] listDocuments() { aoqi@0: return core.values().toArray(new Document[core.size()]); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Gets all the system IDs of the documents. aoqi@0: */ aoqi@0: public String[] listSystemIDs() { aoqi@0: return core.keySet().toArray(new String[core.keySet().size()]); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Dumps the contents of the forest to the specified stream. aoqi@0: * aoqi@0: * This is a debug method. As such, error handling is sloppy. aoqi@0: */ aoqi@0: @SuppressWarnings("CallToThreadDumpStack") aoqi@0: public void dump( OutputStream out ) throws IOException { aoqi@0: try { aoqi@0: // create identity transformer aoqi@0: boolean disableXmlSecurity = false; aoqi@0: if (options != null) { aoqi@0: disableXmlSecurity = options.disableXmlSecurity; aoqi@0: } aoqi@0: TransformerFactory tf = XmlFactory.createTransformerFactory(disableXmlSecurity); aoqi@0: Transformer it = tf.newTransformer(); aoqi@0: aoqi@0: for (Map.Entry e : core.entrySet()) { aoqi@0: out.write( ("---<< "+e.getKey()+'\n').getBytes() ); aoqi@0: aoqi@0: DataWriter dw = new DataWriter(new OutputStreamWriter(out),null); aoqi@0: dw.setIndentStep(" "); aoqi@0: it.transform( new DOMSource(e.getValue()), aoqi@0: new SAXResult(dw)); aoqi@0: aoqi@0: out.write( "\n\n\n".getBytes() ); aoqi@0: } aoqi@0: } catch( TransformerException e ) { aoqi@0: e.printStackTrace(); aoqi@0: } aoqi@0: } aoqi@0: }