feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2012, 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 com.sun.istack.internal.SAXParseException2;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.Locator;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
import org.xml.sax.helpers.XMLFilterImpl;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
/**
|
||||
* XMLFilter that finds references to other schema files from
|
||||
* SAX events.
|
||||
* <p/>
|
||||
* This implementation is a base implementation for typical case
|
||||
* where we just need to look for a particular attribute which
|
||||
* contains an URL to another schema file.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
|
||||
*/
|
||||
public abstract class AbstractReferenceFinderImpl extends XMLFilterImpl {
|
||||
|
||||
protected final DOMForest parent;
|
||||
|
||||
protected AbstractReferenceFinderImpl(DOMForest _parent) {
|
||||
this.parent = _parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* IF the given element contains a reference to an external resource,
|
||||
* return its URL.
|
||||
*
|
||||
* @param nsURI Namespace URI of the current element
|
||||
* @param localName Local name of the current element
|
||||
* @return It's OK to return a relative URL.
|
||||
*/
|
||||
protected abstract String findExternalResource(String nsURI, String localName, Attributes atts);
|
||||
|
||||
@Override
|
||||
public void startElement(String namespaceURI, String localName, String qName, Attributes atts)
|
||||
throws SAXException {
|
||||
super.startElement(namespaceURI, localName, qName, atts);
|
||||
|
||||
String relativeRef = findExternalResource(namespaceURI, localName, atts);
|
||||
if (relativeRef == null) {
|
||||
return; // not found
|
||||
}
|
||||
try {
|
||||
// absolutize URL.
|
||||
String lsi = locator.getSystemId();
|
||||
String ref;
|
||||
URI relRefURI = new URI(relativeRef);
|
||||
if (relRefURI.isAbsolute())
|
||||
ref = relativeRef;
|
||||
else {
|
||||
if (lsi.startsWith("jar:")) {
|
||||
int bangIdx = lsi.indexOf('!');
|
||||
if (bangIdx > 0) {
|
||||
ref = lsi.substring(0, bangIdx + 1)
|
||||
+ new URI(lsi.substring(bangIdx + 1)).resolve(new URI(relativeRef)).toString();
|
||||
} else {
|
||||
ref = relativeRef;
|
||||
}
|
||||
} else {
|
||||
ref = new URI(lsi).resolve(new URI(relativeRef)).toString();
|
||||
}
|
||||
}
|
||||
|
||||
// then parse this schema as well,
|
||||
// but don't mark this document as a root.
|
||||
if (parent != null) { // this is there to allow easier testing
|
||||
parent.parse(ref, false);
|
||||
}
|
||||
} catch (URISyntaxException e) {
|
||||
String msg = e.getMessage();
|
||||
if (new File(relativeRef).exists()) {
|
||||
msg = Messages.format(Messages.ERR_FILENAME_IS_NOT_URI) + ' ' + msg;
|
||||
}
|
||||
|
||||
SAXParseException spe = new SAXParseException2(
|
||||
Messages.format(Messages.ERR_UNABLE_TO_PARSE, relativeRef, msg),
|
||||
locator, e);
|
||||
|
||||
fatalError(spe);
|
||||
throw spe;
|
||||
} catch (IOException e) {
|
||||
SAXParseException spe = new SAXParseException2(
|
||||
Messages.format(Messages.ERR_UNABLE_TO_PARSE, relativeRef, e.getMessage()),
|
||||
locator, e);
|
||||
|
||||
fatalError(spe);
|
||||
throw spe;
|
||||
}
|
||||
}
|
||||
|
||||
private Locator locator;
|
||||
|
||||
@Override
|
||||
public void setDocumentLocator(Locator locator) {
|
||||
super.setDocumentLocator(locator);
|
||||
this.locator = locator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, 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 javax.xml.XMLConstants;
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXNotRecognizedException;
|
||||
import org.xml.sax.SAXNotSupportedException;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.AttributesImpl;
|
||||
import org.xml.sax.helpers.XMLFilterImpl;
|
||||
|
||||
/**
|
||||
* {@link XMLReader} filter for supporting
|
||||
* <tt>http://xml.org/sax/features/namespace-prefixes</tt> feature.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
final class ContentHandlerNamespacePrefixAdapter extends XMLFilterImpl {
|
||||
/**
|
||||
* True if <tt>http://xml.org/sax/features/namespace-prefixes</tt> is set to true.
|
||||
*/
|
||||
private boolean namespacePrefixes = false;
|
||||
|
||||
private String[] nsBinding = new String[8];
|
||||
private int len;
|
||||
|
||||
public ContentHandlerNamespacePrefixAdapter() {
|
||||
}
|
||||
|
||||
public ContentHandlerNamespacePrefixAdapter(XMLReader parent) {
|
||||
setParent(parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getFeature(String name) throws SAXNotRecognizedException, SAXNotSupportedException {
|
||||
if(name.equals(PREFIX_FEATURE))
|
||||
return namespacePrefixes;
|
||||
return super.getFeature(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFeature(String name, boolean value) throws SAXNotRecognizedException, SAXNotSupportedException {
|
||||
if(name.equals(PREFIX_FEATURE)) {
|
||||
this.namespacePrefixes = value;
|
||||
return;
|
||||
}
|
||||
if(name.equals(NAMESPACE_FEATURE) && value)
|
||||
return;
|
||||
super.setFeature(name, value);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void startPrefixMapping(String prefix, String uri) throws SAXException {
|
||||
if (XMLConstants.XML_NS_URI.equals(uri)) return; //xml prefix shall not be declared based on jdk api javadoc
|
||||
if(len==nsBinding.length) {
|
||||
// reallocate
|
||||
String[] buf = new String[nsBinding.length*2];
|
||||
System.arraycopy(nsBinding,0,buf,0,nsBinding.length);
|
||||
nsBinding = buf;
|
||||
}
|
||||
nsBinding[len++] = prefix;
|
||||
nsBinding[len++] = uri;
|
||||
super.startPrefixMapping(prefix,uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
|
||||
if(namespacePrefixes) {
|
||||
this.atts.setAttributes(atts);
|
||||
// add namespace bindings back as attributes
|
||||
for( int i=0; i<len; i+=2 ) {
|
||||
String prefix = nsBinding[i];
|
||||
if(prefix.length()==0)
|
||||
this.atts.addAttribute(XMLConstants.XML_NS_URI,"xmlns","xmlns","CDATA",nsBinding[i+1]);
|
||||
else
|
||||
this.atts.addAttribute(XMLConstants.XML_NS_URI,prefix,"xmlns:"+prefix,"CDATA",nsBinding[i+1]);
|
||||
}
|
||||
atts = this.atts;
|
||||
}
|
||||
len=0;
|
||||
super.startElement(uri, localName, qName, atts);
|
||||
}
|
||||
|
||||
private final AttributesImpl atts = new AttributesImpl();
|
||||
|
||||
private static final String PREFIX_FEATURE = "http://xml.org/sax/features/namespace-prefixes";
|
||||
private static final String NAMESPACE_FEATURE = "http://xml.org/sax/features/namespaces";
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* Simple utility ensuring that the value is cached only in case it is non-internal implementation
|
||||
*/
|
||||
abstract class ContextClassloaderLocal<V> {
|
||||
|
||||
private static final String FAILED_TO_CREATE_NEW_INSTANCE = "FAILED_TO_CREATE_NEW_INSTANCE";
|
||||
|
||||
private WeakHashMap<ClassLoader, V> CACHE = new WeakHashMap<ClassLoader, V>();
|
||||
|
||||
public V get() throws Error {
|
||||
ClassLoader tccl = getContextClassLoader();
|
||||
V instance = CACHE.get(tccl);
|
||||
if (instance == null) {
|
||||
instance = createNewInstance();
|
||||
CACHE.put(tccl, instance);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void set(V instance) {
|
||||
CACHE.put(getContextClassLoader(), instance);
|
||||
}
|
||||
|
||||
protected abstract V initialValue() throws Exception;
|
||||
|
||||
private V createNewInstance() {
|
||||
try {
|
||||
return initialValue();
|
||||
} catch (Exception e) {
|
||||
throw new Error(format(FAILED_TO_CREATE_NEW_INSTANCE, getClass().getName()), e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String format(String property, Object... args) {
|
||||
String text = ResourceBundle.getBundle(ContextClassloaderLocal.class.getName()).getString(property);
|
||||
return MessageFormat.format(text, args);
|
||||
}
|
||||
|
||||
private static ClassLoader getContextClassLoader() {
|
||||
return (ClassLoader)
|
||||
AccessController.doPrivileged(new PrivilegedAction() {
|
||||
public Object run() {
|
||||
ClassLoader cl = null;
|
||||
try {
|
||||
cl = Thread.currentThread().getContextClassLoader();
|
||||
} catch (SecurityException ex) {
|
||||
}
|
||||
return cl;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, 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.util.Set;
|
||||
|
||||
import com.sun.tools.internal.xjc.reader.Const;
|
||||
import com.sun.xml.internal.bind.marshaller.SAX2DOMEx;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.Locator;
|
||||
|
||||
/**
|
||||
* Builds DOM while keeping the location information.
|
||||
*
|
||||
* <p>
|
||||
* This class also looks for outer most <jaxb:bindings>
|
||||
* customizations.
|
||||
*
|
||||
* @author
|
||||
* Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
|
||||
*/
|
||||
class DOMBuilder extends SAX2DOMEx {
|
||||
/**
|
||||
* Grows a DOM tree under the given document, and
|
||||
* stores location information to the given table.
|
||||
*
|
||||
* @param outerMostBindings
|
||||
* This set will receive newly found outermost
|
||||
* jaxb:bindings customizations.
|
||||
*/
|
||||
public DOMBuilder( Document dom, LocatorTable ltable, Set outerMostBindings ) {
|
||||
super( dom );
|
||||
this.locatorTable = ltable;
|
||||
this.outerMostBindings = outerMostBindings;
|
||||
}
|
||||
|
||||
/** Location information will be stored into this object. */
|
||||
private final LocatorTable locatorTable;
|
||||
|
||||
private final Set outerMostBindings;
|
||||
|
||||
private Locator locator;
|
||||
|
||||
public void setDocumentLocator(Locator locator) {
|
||||
this.locator = locator;
|
||||
super.setDocumentLocator(locator);
|
||||
}
|
||||
|
||||
|
||||
public void startElement(String namespaceURI, String localName, String qName, Attributes atts) {
|
||||
super.startElement(namespaceURI, localName, qName, atts);
|
||||
|
||||
Element e = getCurrentElement();
|
||||
locatorTable.storeStartLocation( e, locator );
|
||||
|
||||
// check if this element is an outer-most <jaxb:bindings>
|
||||
if( Const.JAXB_NSURI.equals(e.getNamespaceURI())
|
||||
&& "bindings".equals(e.getLocalName()) ) {
|
||||
|
||||
// if this is the root node (meaning that this file is an
|
||||
// external binding file) or if the parent is XML Schema element
|
||||
// (meaning that this is an "inlined" external binding)
|
||||
Node p = e.getParentNode();
|
||||
if( p instanceof Document
|
||||
||( p instanceof Element && !e.getNamespaceURI().equals(p.getNamespaceURI()))) {
|
||||
outerMostBindings.add(e); // remember this value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void endElement(String namespaceURI, String localName, String qName) {
|
||||
locatorTable.storeEndLocation( getCurrentElement(), locator );
|
||||
super.endElement(namespaceURI, localName, qName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,574 @@
|
||||
/*
|
||||
* 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 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.*;
|
||||
import org.xml.sax.helpers.XMLFilterImpl;
|
||||
|
||||
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 java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.util.*;
|
||||
|
||||
import static com.sun.xml.internal.bind.v2.util.XmlFactory.allowExternalAccess;
|
||||
import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI;
|
||||
|
||||
|
||||
/**
|
||||
* Builds a DOM forest and maintains association from
|
||||
* system IDs to DOM trees.
|
||||
*
|
||||
* <p>
|
||||
* 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.
|
||||
*
|
||||
* <p>
|
||||
* 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<String,Document> core = new HashMap<String,Document>();
|
||||
|
||||
/**
|
||||
* To correctly feed documents to a schema parser, we need to remember
|
||||
* which documents (of the forest) were given as the root
|
||||
* documents, and which of them are read as included/imported
|
||||
* documents.
|
||||
*
|
||||
* <p>
|
||||
* Set of system ids as strings.
|
||||
*/
|
||||
private final Set<String> rootDocuments = new HashSet<String>();
|
||||
|
||||
/** Stores location information for all the trees in this forest. */
|
||||
public final LocatorTable locatorTable = new LocatorTable();
|
||||
|
||||
/** Stores all the outer-most <jaxb:bindings> customizations. */
|
||||
public final Set<Element> outerMostBindings = new HashSet<Element>();
|
||||
|
||||
/** Used to resolve references to other schema documents. */
|
||||
private EntityResolver entityResolver = null;
|
||||
|
||||
/** Errors encountered during the parsing will be sent to this object. */
|
||||
private ErrorReceiver errorReceiver = null;
|
||||
|
||||
/** Schema language dependent part of the processing. */
|
||||
protected final InternalizationLogic logic;
|
||||
|
||||
private final SAXParserFactory parserFactory;
|
||||
private final DocumentBuilder documentBuilder;
|
||||
|
||||
private final Options options;
|
||||
|
||||
public DOMForest(
|
||||
SAXParserFactory parserFactory, DocumentBuilder documentBuilder,
|
||||
InternalizationLogic logic ) {
|
||||
|
||||
this.parserFactory = parserFactory;
|
||||
this.documentBuilder = documentBuilder;
|
||||
this.logic = logic;
|
||||
this.options = null;
|
||||
}
|
||||
|
||||
public DOMForest( InternalizationLogic logic, Options opt ) {
|
||||
|
||||
if (opt == null) throw new AssertionError("Options object null");
|
||||
this.options = opt;
|
||||
|
||||
try {
|
||||
DocumentBuilderFactory dbf = XmlFactory.createDocumentBuilderFactory(opt.disableXmlSecurity);
|
||||
this.documentBuilder = dbf.newDocumentBuilder();
|
||||
this.parserFactory = XmlFactory.createParserFactory(opt.disableXmlSecurity);
|
||||
} catch( ParserConfigurationException e ) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
||||
this.logic = logic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the DOM tree associated with the specified system ID,
|
||||
* or null if none is found.
|
||||
*/
|
||||
public Document get( String systemId ) {
|
||||
Document doc = core.get(systemId);
|
||||
|
||||
if( doc==null && systemId.startsWith("file:/") && !systemId.startsWith("file://") ) {
|
||||
// As of JDK1.4, java.net.URL.toExternal method returns URLs like
|
||||
// "file:/abc/def/ghi" which is an incorrect file protocol URL according to RFC1738.
|
||||
// Some other correctly functioning parts return the correct URLs ("file:///abc/def/ghi"),
|
||||
// and this descripancy breaks DOM look up by system ID.
|
||||
|
||||
// this extra check solves this problem.
|
||||
doc = core.get( "file://"+systemId.substring(5) );
|
||||
}
|
||||
|
||||
if( doc==null && systemId.startsWith("file:") ) {
|
||||
// on Windows, filenames are case insensitive.
|
||||
// perform case-insensitive search for improved user experience
|
||||
String systemPath = getPath(systemId);
|
||||
for (String key : core.keySet()) {
|
||||
if(key.startsWith("file:") && getPath(key).equalsIgnoreCase(systemPath)) {
|
||||
doc = core.get(key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips off the leading 'file:///' portion from an URL.
|
||||
*/
|
||||
private String getPath(String key) {
|
||||
key = key.substring(5); // skip 'file:'
|
||||
while(key.length()>0 && key.charAt(0)=='/') {
|
||||
key = key.substring(1);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a read-only set of root document system IDs.
|
||||
*/
|
||||
public Set<String> getRootDocuments() {
|
||||
return Collections.unmodifiableSet(rootDocuments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Picks one document at random and returns it.
|
||||
*/
|
||||
public Document getOneDocument() {
|
||||
for (Document dom : core.values()) {
|
||||
if (!dom.getDocumentElement().getNamespaceURI().equals(Const.JAXB_NSURI))
|
||||
return dom;
|
||||
}
|
||||
// we should have caught this error very early on
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the correctness of the XML Schema documents and return true
|
||||
* if it's OK.
|
||||
*
|
||||
* <p>
|
||||
* 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<String> roots = getRootDocuments();
|
||||
Source[] sources = new Source[roots.size()];
|
||||
int i=0;
|
||||
for (String root : roots) {
|
||||
sources[i++] = new DOMSource(get(root),root);
|
||||
}
|
||||
sf.newSchema(sources);
|
||||
return !filter.hadError();
|
||||
} catch (SAXException e) {
|
||||
// the errors should have been reported
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the system ID from which the given DOM is parsed.
|
||||
* <p>
|
||||
* Poor-man's base URI.
|
||||
*/
|
||||
public String getSystemId( Document dom ) {
|
||||
for (Map.Entry<String,Document> e : core.entrySet()) {
|
||||
if (e.getValue() == dom)
|
||||
return e.getKey();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Document parse( InputSource source, boolean root ) throws SAXException {
|
||||
if( source.getSystemId()==null )
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
return parse( source.getSystemId(), source, root );
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an XML at the given location (
|
||||
* and XMLs referenced by it) into DOM trees
|
||||
* and stores them to this forest.
|
||||
*
|
||||
* @return the parsed DOM document object.
|
||||
*/
|
||||
public Document parse( String systemId, boolean root ) throws SAXException, IOException {
|
||||
|
||||
systemId = Options.normalizeSystemId(systemId);
|
||||
|
||||
if( core.containsKey(systemId) )
|
||||
// this document has already been parsed. Just ignore.
|
||||
return core.get(systemId);
|
||||
|
||||
InputSource is=null;
|
||||
|
||||
// allow entity resolver to find the actual byte stream.
|
||||
if( entityResolver!=null )
|
||||
is = entityResolver.resolveEntity(null,systemId);
|
||||
if( is==null )
|
||||
is = new InputSource(systemId);
|
||||
|
||||
// but we still use the original system Id as the key.
|
||||
return parse( systemId, is, root );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link ContentHandler} to feed SAX events into.
|
||||
*
|
||||
* <p>
|
||||
* 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.
|
||||
*
|
||||
* <p>
|
||||
* 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.
|
||||
*
|
||||
* <p>
|
||||
* 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.
|
||||
*
|
||||
* <p>
|
||||
* 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.)
|
||||
*
|
||||
* <p>
|
||||
* To receive errors, use {@link SchemaFactory#setErrorHandler(ErrorHandler)}.
|
||||
*/
|
||||
public void weakSchemaCorrectnessCheck(SchemaFactory sf) {
|
||||
List<SAXSource> sources = new ArrayList<SAXSource>();
|
||||
for( String systemId : getRootDocuments() ) {
|
||||
Document dom = get(systemId);
|
||||
if (dom.getDocumentElement().getNamespaceURI().equals(Const.JAXB_NSURI))
|
||||
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
|
||||
|
||||
SAXSource ss = createSAXSource(systemId);
|
||||
try {
|
||||
ss.getXMLReader().setFeature("http://xml.org/sax/features/namespace-prefixes",true);
|
||||
} catch (SAXException e) {
|
||||
throw new AssertionError(e); // Xerces wants this. See 6395322.
|
||||
}
|
||||
sources.add(ss);
|
||||
}
|
||||
|
||||
try {
|
||||
allowExternalAccess(sf, "file,http", options.disableXmlSecurity).newSchema(sources.toArray(new SAXSource[0]));
|
||||
} catch (SAXException e) {
|
||||
// error should have been reported.
|
||||
} catch (RuntimeException re) {
|
||||
// JAXP RI isn't very trustworthy when it comes to schema error check,
|
||||
// and we know some cases where it just dies with NPE. So handle it gracefully.
|
||||
// this masks a bug in the JAXP RI, but we need a release that we have to make.
|
||||
try {
|
||||
sf.getErrorHandler().warning(
|
||||
new SAXParseException(Messages.format(
|
||||
Messages.ERR_GENERAL_SCHEMA_CORRECTNESS_ERROR,re.getMessage()),
|
||||
null,null,-1,-1,re));
|
||||
} catch (SAXException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link SAXSource} that, when parsed, reads from this {@link DOMForest}
|
||||
* (instead of parsing the original source identified by the system ID.)
|
||||
*/
|
||||
public @NotNull SAXSource createSAXSource(String systemId) {
|
||||
ContentHandlerNamespacePrefixAdapter reader = new ContentHandlerNamespacePrefixAdapter(new XMLFilterImpl() {
|
||||
// XMLReader that uses XMLParser to parse. We need to use XMLFilter to indrect
|
||||
// handlers, since SAX allows handlers to be changed while parsing.
|
||||
@Override
|
||||
public void parse(InputSource input) throws SAXException, IOException {
|
||||
createParser().parse(input, this, this, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parse(String systemId) throws SAXException, IOException {
|
||||
parse(new InputSource(systemId));
|
||||
}
|
||||
});
|
||||
|
||||
return new SAXSource(reader,new InputSource(systemId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link XMLParser} for XSOM which reads documents from
|
||||
* this DOMForest rather than doing a fresh parse.
|
||||
*
|
||||
* The net effect is that XSOM will read transformed XML Schemas
|
||||
* instead of the original documents.
|
||||
*/
|
||||
public XMLParser createParser() {
|
||||
return new DOMForestParser(this, new JAXPParser(XmlFactory.createParserFactory(options.disableXmlSecurity)));
|
||||
}
|
||||
|
||||
public EntityResolver getEntityResolver() {
|
||||
return entityResolver;
|
||||
}
|
||||
|
||||
public void setEntityResolver(EntityResolver entityResolver) {
|
||||
this.entityResolver = entityResolver;
|
||||
}
|
||||
|
||||
public ErrorReceiver getErrorHandler() {
|
||||
return errorReceiver;
|
||||
}
|
||||
|
||||
public void setErrorHandler(ErrorReceiver errorHandler) {
|
||||
this.errorReceiver = errorHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the parsed documents.
|
||||
*/
|
||||
public Document[] listDocuments() {
|
||||
return core.values().toArray(new Document[core.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the system IDs of the documents.
|
||||
*/
|
||||
public String[] listSystemIDs() {
|
||||
return core.keySet().toArray(new String[core.keySet().size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps the contents of the forest to the specified stream.
|
||||
*
|
||||
* This is a debug method. As such, error handling is sloppy.
|
||||
*/
|
||||
@SuppressWarnings("CallToThreadDumpStack")
|
||||
public void dump( OutputStream out ) throws IOException {
|
||||
try {
|
||||
// create identity transformer
|
||||
boolean disableXmlSecurity = false;
|
||||
if (options != null) {
|
||||
disableXmlSecurity = options.disableXmlSecurity;
|
||||
}
|
||||
TransformerFactory tf = XmlFactory.createTransformerFactory(disableXmlSecurity);
|
||||
Transformer it = tf.newTransformer();
|
||||
|
||||
for (Map.Entry<String, Document> e : core.entrySet()) {
|
||||
out.write( ("---<< "+e.getKey()+'\n').getBytes() );
|
||||
|
||||
DataWriter dw = new DataWriter(new OutputStreamWriter(out),null);
|
||||
dw.setIndentStep(" ");
|
||||
it.transform( new DOMSource(e.getValue()),
|
||||
new SAXResult(dw));
|
||||
|
||||
out.write( "\n\n\n".getBytes() );
|
||||
}
|
||||
} catch( TransformerException e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, 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 com.sun.xml.internal.xsom.parser.XMLParser;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.EntityResolver;
|
||||
import org.xml.sax.ErrorHandler;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
|
||||
/**
|
||||
* {@link XMLParser} implementation that
|
||||
* parses XML from a DOM forest instead of parsing it from
|
||||
* its original location.
|
||||
*
|
||||
* @author
|
||||
* Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
|
||||
*/
|
||||
class DOMForestParser implements XMLParser {
|
||||
|
||||
/** DOM forest to be "parsed". */
|
||||
private final DOMForest forest;
|
||||
|
||||
/** Scanner object will do the actual SAX events generation. */
|
||||
private final DOMForestScanner scanner;
|
||||
|
||||
private final XMLParser fallbackParser;
|
||||
|
||||
/**
|
||||
* @param fallbackParser
|
||||
* This parser will be used when DOMForestParser needs to parse
|
||||
* documents that are not in the forest.
|
||||
*/
|
||||
DOMForestParser( DOMForest forest, XMLParser fallbackParser ) {
|
||||
this.forest = forest;
|
||||
this.scanner = new DOMForestScanner(forest);
|
||||
this.fallbackParser = fallbackParser;
|
||||
}
|
||||
|
||||
public void parse(
|
||||
InputSource source,
|
||||
ContentHandler contentHandler,
|
||||
ErrorHandler errorHandler,
|
||||
EntityResolver entityResolver )
|
||||
throws SAXException, IOException {
|
||||
|
||||
String systemId = source.getSystemId();
|
||||
Document dom = forest.get(systemId);
|
||||
|
||||
if(dom==null) {
|
||||
// if no DOM tree is built for it,
|
||||
// let the fall back parser parse the original document.
|
||||
//
|
||||
// for example, XSOM parses datatypes.xsd (XML Schema part 2)
|
||||
// but this will never be built into the forest.
|
||||
fallbackParser.parse( source, contentHandler, errorHandler, entityResolver );
|
||||
return;
|
||||
}
|
||||
|
||||
scanner.scan( dom, contentHandler );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, 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 com.sun.xml.internal.bind.unmarshaller.DOMScanner;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.Locator;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.XMLFilterImpl;
|
||||
|
||||
/**
|
||||
* Produces a complete series of SAX events from any DOM node
|
||||
* in the DOMForest.
|
||||
*
|
||||
* <p>
|
||||
* This class hides a logic of re-associating {@link Locator}
|
||||
* to the generated SAX event stream.
|
||||
*
|
||||
* @author
|
||||
* Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
|
||||
*/
|
||||
public class DOMForestScanner {
|
||||
|
||||
private final DOMForest forest;
|
||||
|
||||
/**
|
||||
* Scans DOM nodes of the given forest.
|
||||
*
|
||||
* DOM node parameters to the scan method must be a part of
|
||||
* this forest.
|
||||
*/
|
||||
public DOMForestScanner( DOMForest _forest ) {
|
||||
this.forest = _forest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the whole set of SAX events by treating
|
||||
* element e as if it's a root element.
|
||||
*/
|
||||
public void scan( Element e, ContentHandler contentHandler ) throws SAXException {
|
||||
DOMScanner scanner = new DOMScanner();
|
||||
|
||||
// insert the location resolver into the pipe line
|
||||
LocationResolver resolver = new LocationResolver(scanner);
|
||||
resolver.setContentHandler(contentHandler);
|
||||
|
||||
// parse this DOM.
|
||||
scanner.setContentHandler(resolver);
|
||||
scanner.scan(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the whole set of SAX events from the given Document
|
||||
* in the DOMForest.
|
||||
*/
|
||||
public void scan( Document d, ContentHandler contentHandler ) throws SAXException {
|
||||
scan( d.getDocumentElement(), contentHandler );
|
||||
}
|
||||
|
||||
/**
|
||||
* Intercepts the invocation of the setDocumentLocator method
|
||||
* and passes itself as the locator.
|
||||
*
|
||||
* If the client calls one of the methods on the Locator interface,
|
||||
* use the LocatorTable to resolve the source location.
|
||||
*/
|
||||
private class LocationResolver extends XMLFilterImpl implements Locator {
|
||||
LocationResolver( DOMScanner _parent ) {
|
||||
this.parent = _parent;
|
||||
}
|
||||
|
||||
private final DOMScanner parent;
|
||||
|
||||
/**
|
||||
* Flag that tells us whether we are processing a start element event
|
||||
* or an end element event.
|
||||
*
|
||||
* DOMScanner's getCurrentLocation method doesn't tell us which, but
|
||||
* this information is necessary to return the correct source line information.
|
||||
*
|
||||
* Thus we set this flag appropriately before we pass an event to
|
||||
* the next ContentHandler, thereby making it possible to figure
|
||||
* out which location to return.
|
||||
*/
|
||||
private boolean inStart = false;
|
||||
|
||||
@Override
|
||||
public void setDocumentLocator(Locator locator) {
|
||||
// ignore one set by the parent.
|
||||
|
||||
super.setDocumentLocator(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
|
||||
inStart = false;
|
||||
super.endElement(namespaceURI, localName, qName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startElement(String namespaceURI, String localName, String qName, Attributes atts)
|
||||
throws SAXException {
|
||||
inStart = true;
|
||||
super.startElement(namespaceURI, localName, qName, atts);
|
||||
}
|
||||
|
||||
private Locator findLocator() {
|
||||
Node n = parent.getCurrentLocation();
|
||||
if( n instanceof Element ) {
|
||||
Element e = (Element)n;
|
||||
if( inStart )
|
||||
return forest.locatorTable.getStartLocation( e );
|
||||
else
|
||||
return forest.locatorTable.getEndLocation( e );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// Locator methods
|
||||
//
|
||||
//
|
||||
public int getColumnNumber() {
|
||||
Locator l = findLocator();
|
||||
if(l!=null) return l.getColumnNumber();
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int getLineNumber() {
|
||||
Locator l = findLocator();
|
||||
if(l!=null) return l.getLineNumber();
|
||||
return -1;
|
||||
}
|
||||
|
||||
public String getPublicId() {
|
||||
Locator l = findLocator();
|
||||
if(l!=null) return l.getPublicId();
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getSystemId() {
|
||||
Locator l = findLocator();
|
||||
if(l!=null) return l.getSystemId();
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, 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 org.w3c.dom.Element;
|
||||
import org.xml.sax.helpers.XMLFilterImpl;
|
||||
|
||||
/**
|
||||
* Encapsulates schema-language dependent internalization logic.
|
||||
*
|
||||
* {@link Internalizer} and {@link DOMForest} are responsible for
|
||||
* doing schema language independent part, and this object is responsible
|
||||
* for schema language dependent part.
|
||||
*
|
||||
* @author
|
||||
* Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
|
||||
*/
|
||||
public interface InternalizationLogic {
|
||||
/**
|
||||
* Creates a new instance of XMLFilter that can be used to
|
||||
* find references to external schemas.
|
||||
*
|
||||
* <p>
|
||||
* Schemas that are included/imported need to be a part of
|
||||
* {@link DOMForest}, and this filter will be expected to
|
||||
* find such references.
|
||||
*
|
||||
* <p>
|
||||
* Once such a reference is found, the filter is expected to
|
||||
* call the parse method of DOMForest.
|
||||
*
|
||||
* <p>
|
||||
* {@link DOMForest} will register ErrorHandler to the returned
|
||||
* object, so any error should be sent to that error handler.
|
||||
*
|
||||
* @return
|
||||
* This method returns {@link XMLFilterImpl} because
|
||||
* the filter has to be usable for two directions
|
||||
* (wrapping a reader and wrapping a ContentHandler)
|
||||
*/
|
||||
XMLFilterImpl createExternalReferenceFinder( DOMForest parent );
|
||||
|
||||
/**
|
||||
* Checks if the specified element is a valid target node
|
||||
* to attach a customization.
|
||||
*
|
||||
* @param parent
|
||||
* The owner DOMForest object. Probably useful only
|
||||
* to obtain context information, such as error handler.
|
||||
* @param bindings
|
||||
* <jaxb:bindings> element or a customization element.
|
||||
* @return
|
||||
* true if it's OK, false if not.
|
||||
*/
|
||||
boolean checkIfValidTargetNode( DOMForest parent, Element bindings, Element target );
|
||||
|
||||
/**
|
||||
* Prepares an element that actually receives customizations.
|
||||
*
|
||||
* <p>
|
||||
* For example, in XML Schema, target nodes can be any schema
|
||||
* element but it is always the <xsd:appinfo> element that
|
||||
* receives customization.
|
||||
*
|
||||
* @param target
|
||||
* The target node designated by the customization.
|
||||
* @return
|
||||
* Always return non-null valid object
|
||||
*/
|
||||
Element refineTarget( Element target );
|
||||
}
|
||||
@@ -0,0 +1,615 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2014, 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.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.text.ParseException;
|
||||
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import com.sun.istack.internal.SAXParseException2;
|
||||
import com.sun.istack.internal.NotNull;
|
||||
import com.sun.istack.internal.Nullable;
|
||||
import com.sun.tools.internal.xjc.ErrorReceiver;
|
||||
import com.sun.tools.internal.xjc.reader.Const;
|
||||
import com.sun.tools.internal.xjc.util.DOMUtils;
|
||||
import com.sun.xml.internal.bind.v2.util.EditDistance;
|
||||
import com.sun.xml.internal.bind.v2.util.XmlFactory;
|
||||
import com.sun.xml.internal.xsom.SCD;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.xml.XMLConstants;
|
||||
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
/**
|
||||
* Internalizes external binding declarations.
|
||||
*
|
||||
* <p>
|
||||
* The {@link #transform(DOMForest,boolean)} method is the entry point.
|
||||
*
|
||||
* @author
|
||||
* Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
|
||||
*/
|
||||
class Internalizer {
|
||||
|
||||
private static final String WSDL_NS = "http://schemas.xmlsoap.org/wsdl/";
|
||||
|
||||
private final XPath xpath;
|
||||
|
||||
/**
|
||||
* Internalize all <jaxb:bindings> customizations in the given forest.
|
||||
*
|
||||
* @return
|
||||
* if the SCD support is enabled, the return bindings need to be applied
|
||||
* after schema components are parsed.
|
||||
* If disabled, the returned binding set will be empty.
|
||||
* SCDs are only for XML Schema, and doesn't make any sense for other
|
||||
* schema languages.
|
||||
*/
|
||||
static SCDBasedBindingSet transform( DOMForest forest, boolean enableSCD, boolean disableSecureProcessing ) {
|
||||
return new Internalizer(forest, enableSCD, disableSecureProcessing).transform();
|
||||
}
|
||||
|
||||
|
||||
private Internalizer(DOMForest forest, boolean enableSCD, boolean disableSecureProcessing) {
|
||||
this.errorHandler = forest.getErrorHandler();
|
||||
this.forest = forest;
|
||||
this.enableSCD = enableSCD;
|
||||
xpath = XmlFactory.createXPathFactory(disableSecureProcessing).newXPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* DOMForest object currently being processed.
|
||||
*/
|
||||
private final DOMForest forest;
|
||||
|
||||
/**
|
||||
* All errors found during the transformation is sent to this object.
|
||||
*/
|
||||
private ErrorReceiver errorHandler;
|
||||
|
||||
/**
|
||||
* If true, the SCD-based target selection is supported.
|
||||
*/
|
||||
private boolean enableSCD;
|
||||
|
||||
|
||||
private SCDBasedBindingSet transform() {
|
||||
|
||||
// either target nodes are conventional DOM nodes (as per spec),
|
||||
Map<Element,List<Node>> targetNodes = new HashMap<Element,List<Node>>();
|
||||
// ... or it will be schema components by means of SCD (RI extension)
|
||||
SCDBasedBindingSet scd = new SCDBasedBindingSet(forest);
|
||||
|
||||
//
|
||||
// identify target nodes for all <jaxb:bindings>
|
||||
//
|
||||
for (Element jaxbBindings : forest.outerMostBindings) {
|
||||
// initially, the inherited context is itself
|
||||
buildTargetNodeMap(jaxbBindings, jaxbBindings, null, targetNodes, scd);
|
||||
}
|
||||
|
||||
//
|
||||
// then move them to their respective positions.
|
||||
//
|
||||
for (Element jaxbBindings : forest.outerMostBindings) {
|
||||
move(jaxbBindings, targetNodes);
|
||||
}
|
||||
|
||||
return scd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates attributes of a <jaxb:bindings> element.
|
||||
*/
|
||||
private void validate( Element bindings ) {
|
||||
NamedNodeMap atts = bindings.getAttributes();
|
||||
for( int i=0; i<atts.getLength(); i++ ) {
|
||||
Attr a = (Attr)atts.item(i);
|
||||
if( a.getNamespaceURI()!=null )
|
||||
continue; // all foreign namespace OK.
|
||||
if( a.getLocalName().equals("node") )
|
||||
continue;
|
||||
if( a.getLocalName().equals("schemaLocation"))
|
||||
continue;
|
||||
if( a.getLocalName().equals("scd") )
|
||||
continue;
|
||||
|
||||
// enhancements
|
||||
if( a.getLocalName().equals("required") ) //
|
||||
continue;
|
||||
if( a.getLocalName().equals("multiple") ) //
|
||||
continue;
|
||||
|
||||
|
||||
// TODO: flag error for this undefined attribute
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the target node of the "bindings" element
|
||||
* by using the inherited target node, then put
|
||||
* the result into the "result" map and the "scd" map.
|
||||
*
|
||||
* @param inheritedTarget
|
||||
* The current target node. This always exists, even if
|
||||
* the user starts specifying targets via SCD (in that case
|
||||
* this inherited target is just not going to be used.)
|
||||
* @param inheritedSCD
|
||||
* If the ancestor <bindings> node specifies @scd to
|
||||
* specify the target via SCD, then this parameter represents that context.
|
||||
*/
|
||||
private void buildTargetNodeMap( Element bindings, @NotNull Node inheritedTarget,
|
||||
@Nullable SCDBasedBindingSet.Target inheritedSCD,
|
||||
Map<Element,List<Node>> result, SCDBasedBindingSet scdResult ) {
|
||||
// start by the inherited target
|
||||
Node target = inheritedTarget;
|
||||
ArrayList<Node> targetMultiple = null;
|
||||
|
||||
validate(bindings); // validate this node
|
||||
|
||||
boolean required = true;
|
||||
boolean multiple = false;
|
||||
|
||||
if(bindings.getAttribute("required") != null) {
|
||||
String requiredAttr = bindings.getAttribute("required");
|
||||
|
||||
if(requiredAttr.equals("no") || requiredAttr.equals("false") || requiredAttr.equals("0"))
|
||||
required = false;
|
||||
}
|
||||
|
||||
if(bindings.getAttribute("multiple") != null) {
|
||||
String requiredAttr = bindings.getAttribute("multiple");
|
||||
|
||||
if(requiredAttr.equals("yes") || requiredAttr.equals("true") || requiredAttr.equals("1"))
|
||||
multiple = true;
|
||||
}
|
||||
|
||||
|
||||
// look for @schemaLocation
|
||||
if( bindings.getAttributeNode("schemaLocation")!=null ) {
|
||||
String schemaLocation = bindings.getAttribute("schemaLocation");
|
||||
|
||||
// enhancement - schemaLocation="*" = bind to all schemas..
|
||||
if(schemaLocation.equals("*")) {
|
||||
for(String systemId : forest.listSystemIDs()) {
|
||||
if (result.get(bindings) == null)
|
||||
result.put(bindings, new ArrayList<Node>());
|
||||
result.get(bindings).add(forest.get(systemId).getDocumentElement());
|
||||
|
||||
Element[] children = DOMUtils.getChildElements(bindings, Const.JAXB_NSURI, "bindings");
|
||||
for (Element value : children)
|
||||
buildTargetNodeMap(value, forest.get(systemId).getDocumentElement(), inheritedSCD, result, scdResult);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
try {
|
||||
// TODO: use the URI class
|
||||
// TODO: honor xml:base
|
||||
URL loc = new URL(
|
||||
new URL(forest.getSystemId(bindings.getOwnerDocument())), schemaLocation
|
||||
);
|
||||
schemaLocation = loc.toExternalForm();
|
||||
target = forest.get(schemaLocation);
|
||||
if ((target == null) && (loc.getProtocol().startsWith("file"))) {
|
||||
File f = new File(loc.getFile());
|
||||
schemaLocation = new File(f.getCanonicalPath()).toURI().toString();
|
||||
}
|
||||
} catch( MalformedURLException e ) {
|
||||
} catch( IOException e ) {
|
||||
Logger.getLogger(Internalizer.class.getName()).log(Level.FINEST, e.getLocalizedMessage());
|
||||
}
|
||||
|
||||
target = forest.get(schemaLocation);
|
||||
if(target==null) {
|
||||
reportError( bindings,
|
||||
Messages.format(Messages.ERR_INCORRECT_SCHEMA_REFERENCE,
|
||||
schemaLocation,
|
||||
EditDistance.findNearest(schemaLocation,forest.listSystemIDs())));
|
||||
|
||||
return; // abort processing this <jaxb:bindings>
|
||||
}
|
||||
|
||||
target = ((Document)target).getDocumentElement();
|
||||
}
|
||||
}
|
||||
|
||||
// look for @node
|
||||
if( bindings.getAttributeNode("node")!=null ) {
|
||||
String nodeXPath = bindings.getAttribute("node");
|
||||
|
||||
// evaluate this XPath
|
||||
NodeList nlst;
|
||||
try {
|
||||
xpath.setNamespaceContext(new NamespaceContextImpl(bindings));
|
||||
nlst = (NodeList)xpath.evaluate(nodeXPath,target,XPathConstants.NODESET);
|
||||
} catch (XPathExpressionException e) {
|
||||
if(required) {
|
||||
reportError( bindings,
|
||||
Messages.format(Messages.ERR_XPATH_EVAL,e.getMessage()), e );
|
||||
return; // abort processing this <jaxb:bindings>
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if( nlst.getLength()==0 ) {
|
||||
if(required)
|
||||
reportError( bindings,
|
||||
Messages.format(Messages.NO_XPATH_EVAL_TO_NO_TARGET, nodeXPath) );
|
||||
return; // abort
|
||||
}
|
||||
|
||||
if( nlst.getLength()!=1 ) {
|
||||
if(!multiple) {
|
||||
reportError( bindings,
|
||||
Messages.format(Messages.NO_XPATH_EVAL_TOO_MANY_TARGETS, nodeXPath,nlst.getLength()) );
|
||||
|
||||
return; // abort
|
||||
} else {
|
||||
if(targetMultiple == null) targetMultiple = new ArrayList<Node>();
|
||||
for(int i = 0; i < nlst.getLength(); i++) {
|
||||
targetMultiple.add(nlst.item(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check
|
||||
if(!multiple || nlst.getLength() == 1) {
|
||||
Node rnode = nlst.item(0);
|
||||
if (!(rnode instanceof Element)) {
|
||||
reportError(bindings,
|
||||
Messages.format(Messages.NO_XPATH_EVAL_TO_NON_ELEMENT, nodeXPath));
|
||||
return; // abort
|
||||
}
|
||||
|
||||
if (!forest.logic.checkIfValidTargetNode(forest, bindings, (Element) rnode)) {
|
||||
reportError(bindings,
|
||||
Messages.format(Messages.XPATH_EVAL_TO_NON_SCHEMA_ELEMENT,
|
||||
nodeXPath, rnode.getNodeName()));
|
||||
return; // abort
|
||||
}
|
||||
|
||||
target = rnode;
|
||||
} else {
|
||||
for(Node rnode : targetMultiple) {
|
||||
if (!(rnode instanceof Element)) {
|
||||
reportError(bindings,
|
||||
Messages.format(Messages.NO_XPATH_EVAL_TO_NON_ELEMENT, nodeXPath));
|
||||
return; // abort
|
||||
}
|
||||
|
||||
if (!forest.logic.checkIfValidTargetNode(forest, bindings, (Element) rnode)) {
|
||||
reportError(bindings,
|
||||
Messages.format(Messages.XPATH_EVAL_TO_NON_SCHEMA_ELEMENT,
|
||||
nodeXPath, rnode.getNodeName()));
|
||||
return; // abort
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// look for @scd
|
||||
if( bindings.getAttributeNode("scd")!=null ) {
|
||||
String scdPath = bindings.getAttribute("scd");
|
||||
if(!enableSCD) {
|
||||
// SCD selector was found, but it's not activated. report an error
|
||||
// but recover by handling it anyway. this also avoids repeated error messages.
|
||||
reportError(bindings,
|
||||
Messages.format(Messages.SCD_NOT_ENABLED));
|
||||
enableSCD = true;
|
||||
}
|
||||
|
||||
try {
|
||||
inheritedSCD = scdResult.createNewTarget( inheritedSCD, bindings,
|
||||
SCD.create(scdPath, new NamespaceContextImpl(bindings)) );
|
||||
} catch (ParseException e) {
|
||||
reportError( bindings, Messages.format(Messages.ERR_SCD_EVAL,e.getMessage()),e );
|
||||
return; // abort processing this bindings
|
||||
}
|
||||
}
|
||||
|
||||
// update the result map
|
||||
if (inheritedSCD != null) {
|
||||
inheritedSCD.addBinidng(bindings);
|
||||
} else if (!multiple || targetMultiple == null) {
|
||||
if (result.get(bindings) == null)
|
||||
result.put(bindings, new ArrayList<Node>());
|
||||
result.get(bindings).add(target);
|
||||
} else {
|
||||
for (Node rnode : targetMultiple) {
|
||||
if (result.get(bindings) == null)
|
||||
result.put(bindings, new ArrayList<Node>());
|
||||
|
||||
result.get(bindings).add(rnode);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// look for child <jaxb:bindings> and process them recursively
|
||||
Element[] children = DOMUtils.getChildElements( bindings, Const.JAXB_NSURI, "bindings" );
|
||||
for (Element value : children)
|
||||
if(!multiple || targetMultiple == null)
|
||||
buildTargetNodeMap(value, target, inheritedSCD, result, scdResult);
|
||||
else {
|
||||
for(Node rnode : targetMultiple) {
|
||||
buildTargetNodeMap(value, rnode, inheritedSCD, result, scdResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves JAXB customizations under their respective target nodes.
|
||||
*/
|
||||
private void move(Element bindings, Map<Element, List<Node>> targetNodes) {
|
||||
List<Node> nodelist = targetNodes.get(bindings);
|
||||
|
||||
if(nodelist == null) {
|
||||
return; // abort
|
||||
}
|
||||
|
||||
for (Node target : nodelist) {
|
||||
if (target == null) // this must be the result of an error on the external binding.
|
||||
// recover from the error by ignoring this node
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (Element item : DOMUtils.getChildElements(bindings)) {
|
||||
String localName = item.getLocalName();
|
||||
|
||||
if ("bindings".equals(localName)) {
|
||||
// process child <jaxb:bindings> recursively
|
||||
move(item, targetNodes);
|
||||
} else if ("globalBindings".equals(localName)) {
|
||||
// <jaxb:globalBindings> always go to the root of document.
|
||||
Element root = forest.getOneDocument().getDocumentElement();
|
||||
if (root.getNamespaceURI().equals(WSDL_NS)) {
|
||||
NodeList elements = root.getElementsByTagNameNS(XMLConstants.W3C_XML_SCHEMA_NS_URI, "schema");
|
||||
if ((elements == null) || (elements.getLength() < 1)) {
|
||||
reportError(item, Messages.format(Messages.ORPHANED_CUSTOMIZATION, item.getNodeName()));
|
||||
return;
|
||||
} else {
|
||||
moveUnder(item, (Element)elements.item(0));
|
||||
}
|
||||
} else {
|
||||
moveUnder(item, root);
|
||||
}
|
||||
} else {
|
||||
if (!(target instanceof Element)) {
|
||||
reportError(item,
|
||||
Messages.format(Messages.CONTEXT_NODE_IS_NOT_ELEMENT));
|
||||
return; // abort
|
||||
}
|
||||
|
||||
if (!forest.logic.checkIfValidTargetNode(forest, item, (Element) target)) {
|
||||
reportError(item,
|
||||
Messages.format(Messages.ORPHANED_CUSTOMIZATION, item.getNodeName()));
|
||||
return; // abort
|
||||
}
|
||||
|
||||
// move this node under the target
|
||||
moveUnder(item, (Element) target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the "decl" node under the "target" node.
|
||||
*
|
||||
* @param decl
|
||||
* A JAXB customization element (e.g., <jaxb:class>)
|
||||
*
|
||||
* @param target
|
||||
* XML Schema element under which the declaration should move.
|
||||
* For example, <xs:element>
|
||||
*/
|
||||
private void moveUnder( Element decl, Element target ) {
|
||||
Element realTarget = forest.logic.refineTarget(target);
|
||||
|
||||
declExtensionNamespace( decl, target );
|
||||
|
||||
// copy in-scope namespace declarations of the decl node
|
||||
// to the decl node itself so that this move won't change
|
||||
// the in-scope namespace bindings.
|
||||
Element p = decl;
|
||||
Set<String> inscopes = new HashSet<String>();
|
||||
while(true) {
|
||||
NamedNodeMap atts = p.getAttributes();
|
||||
for( int i=0; i<atts.getLength(); i++ ) {
|
||||
Attr a = (Attr)atts.item(i);
|
||||
if( Const.XMLNS_URI.equals(a.getNamespaceURI()) ) {
|
||||
String prefix;
|
||||
if( a.getName().indexOf(':')==-1 ) prefix = "";
|
||||
else prefix = a.getLocalName();
|
||||
|
||||
if( inscopes.add(prefix) && p!=decl ) {
|
||||
// if this is the first time we see this namespace bindings,
|
||||
// copy the declaration.
|
||||
// if p==decl, there's no need to. Note that
|
||||
// we want to add prefix to inscopes even if p==Decl
|
||||
|
||||
decl.setAttributeNodeNS( (Attr)a.cloneNode(true) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( p.getParentNode() instanceof Document )
|
||||
break;
|
||||
|
||||
p = (Element)p.getParentNode();
|
||||
}
|
||||
|
||||
if( !inscopes.contains("") ) {
|
||||
// if the default namespace was undeclared in the context of decl,
|
||||
// it must be explicitly set to "" since the new environment might
|
||||
// have a different default namespace URI.
|
||||
decl.setAttributeNS(Const.XMLNS_URI,"xmlns","");
|
||||
}
|
||||
|
||||
|
||||
// finally move the declaration to the target node.
|
||||
if( realTarget.getOwnerDocument()!=decl.getOwnerDocument() ) {
|
||||
// if they belong to different DOM documents, we need to clone them
|
||||
Element original = decl;
|
||||
decl = (Element)realTarget.getOwnerDocument().importNode(decl,true);
|
||||
|
||||
// this effectively clones a ndoe,, so we need to copy locators.
|
||||
copyLocators( original, decl );
|
||||
}
|
||||
|
||||
realTarget.appendChild( decl );
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively visits sub-elements and declare all used namespaces.
|
||||
* TODO: the fact that we recognize all namespaces in the extension
|
||||
* is a bad design.
|
||||
*/
|
||||
private void declExtensionNamespace(Element decl, Element target) {
|
||||
// if this comes from external namespaces, add the namespace to
|
||||
// @extensionBindingPrefixes.
|
||||
if( !Const.JAXB_NSURI.equals(decl.getNamespaceURI()) )
|
||||
declareExtensionNamespace( target, decl.getNamespaceURI() );
|
||||
|
||||
NodeList lst = decl.getChildNodes();
|
||||
for( int i=0; i<lst.getLength(); i++ ) {
|
||||
Node n = lst.item(i);
|
||||
if( n instanceof Element )
|
||||
declExtensionNamespace( (Element)n, target );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Attribute name. */
|
||||
private static final String EXTENSION_PREFIXES = "extensionBindingPrefixes";
|
||||
|
||||
/**
|
||||
* Adds the specified namespace URI to the jaxb:extensionBindingPrefixes
|
||||
* attribute of the target document.
|
||||
*/
|
||||
private void declareExtensionNamespace( Element target, String nsUri ) {
|
||||
// look for the attribute
|
||||
Element root = target.getOwnerDocument().getDocumentElement();
|
||||
Attr att = root.getAttributeNodeNS(Const.JAXB_NSURI,EXTENSION_PREFIXES);
|
||||
if( att==null ) {
|
||||
String jaxbPrefix = allocatePrefix(root,Const.JAXB_NSURI);
|
||||
// no such attribute. Create one.
|
||||
att = target.getOwnerDocument().createAttributeNS(
|
||||
Const.JAXB_NSURI,jaxbPrefix+':'+EXTENSION_PREFIXES);
|
||||
root.setAttributeNodeNS(att);
|
||||
}
|
||||
|
||||
String prefix = allocatePrefix(root,nsUri);
|
||||
if( att.getValue().indexOf(prefix)==-1 )
|
||||
// avoid redeclaring the same namespace twice.
|
||||
att.setValue( att.getValue()+' '+prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Declares a new prefix on the given element and associates it
|
||||
* with the specified namespace URI.
|
||||
* <p>
|
||||
* Note that this method doesn't use the default namespace
|
||||
* even if it can.
|
||||
*/
|
||||
private String allocatePrefix( Element e, String nsUri ) {
|
||||
// look for existing namespaces.
|
||||
NamedNodeMap atts = e.getAttributes();
|
||||
for( int i=0; i<atts.getLength(); i++ ) {
|
||||
Attr a = (Attr)atts.item(i);
|
||||
if( Const.XMLNS_URI.equals(a.getNamespaceURI()) ) {
|
||||
if( a.getName().indexOf(':')==-1 ) continue;
|
||||
|
||||
if( a.getValue().equals(nsUri) )
|
||||
return a.getLocalName(); // found one
|
||||
}
|
||||
}
|
||||
|
||||
// none found. allocate new.
|
||||
while(true) {
|
||||
String prefix = "p"+(int)(Math.random()*1000000)+'_';
|
||||
if(e.getAttributeNodeNS(Const.XMLNS_URI,prefix)!=null)
|
||||
continue; // this prefix is already allocated.
|
||||
|
||||
e.setAttributeNS(Const.XMLNS_URI,"xmlns:"+prefix,nsUri);
|
||||
return prefix;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copies location information attached to the "src" node to the "dst" node.
|
||||
*/
|
||||
private void copyLocators( Element src, Element dst ) {
|
||||
forest.locatorTable.storeStartLocation(
|
||||
dst, forest.locatorTable.getStartLocation(src) );
|
||||
forest.locatorTable.storeEndLocation(
|
||||
dst, forest.locatorTable.getEndLocation(src) );
|
||||
|
||||
// recursively process child elements
|
||||
Element[] srcChilds = DOMUtils.getChildElements(src);
|
||||
Element[] dstChilds = DOMUtils.getChildElements(dst);
|
||||
|
||||
for( int i=0; i<srcChilds.length; i++ )
|
||||
copyLocators( srcChilds[i], dstChilds[i] );
|
||||
}
|
||||
|
||||
|
||||
private void reportError( Element errorSource, String formattedMsg ) {
|
||||
reportError( errorSource, formattedMsg, null );
|
||||
}
|
||||
|
||||
private void reportError( Element errorSource,
|
||||
String formattedMsg, Exception nestedException ) {
|
||||
|
||||
SAXParseException e = new SAXParseException2( formattedMsg,
|
||||
forest.locatorTable.getStartLocation(errorSource),
|
||||
nestedException );
|
||||
errorHandler.error(e);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, 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.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
import org.xml.sax.Locator;
|
||||
import org.xml.sax.helpers.LocatorImpl;
|
||||
|
||||
/**
|
||||
* Stores {@link Locator} objects for every {@link Element}.
|
||||
*
|
||||
* @author
|
||||
* Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
|
||||
*/
|
||||
public final class LocatorTable {
|
||||
/** Locations of the start element. */
|
||||
private final Map startLocations = new HashMap();
|
||||
|
||||
/** Locations of the end element. */
|
||||
private final Map endLocations = new HashMap();
|
||||
|
||||
public void storeStartLocation( Element e, Locator loc ) {
|
||||
startLocations.put(e,new LocatorImpl(loc));
|
||||
}
|
||||
|
||||
public void storeEndLocation( Element e, Locator loc ) {
|
||||
endLocations.put(e,new LocatorImpl(loc));
|
||||
}
|
||||
|
||||
public Locator getStartLocation( Element e ) {
|
||||
return (Locator)startLocations.get(e);
|
||||
}
|
||||
|
||||
public Locator getEndLocation( Element e ) {
|
||||
return (Locator)endLocations.get(e);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, 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.text.MessageFormat;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* Formats error messages.
|
||||
*/
|
||||
class Messages
|
||||
{
|
||||
/** Loads a string resource and formats it with specified arguments. */
|
||||
static String format( String property, Object... args ) {
|
||||
String text = ResourceBundle.getBundle(Messages.class.getPackage().getName() +".MessageBundle").getString(property);
|
||||
return MessageFormat.format(text,args);
|
||||
}
|
||||
|
||||
static final String ERR_INCORRECT_SCHEMA_REFERENCE = // args:2
|
||||
"Internalizer.IncorrectSchemaReference";
|
||||
static final String ERR_XPATH_EVAL = // arg:1
|
||||
"Internalizer.XPathEvaluationError";
|
||||
static final String NO_XPATH_EVAL_TO_NO_TARGET = // arg:1
|
||||
"Internalizer.XPathEvaluatesToNoTarget";
|
||||
static final String NO_XPATH_EVAL_TOO_MANY_TARGETS = // arg:2
|
||||
"Internalizer.XPathEvaulatesToTooManyTargets";
|
||||
static final String NO_XPATH_EVAL_TO_NON_ELEMENT = // arg:1
|
||||
"Internalizer.XPathEvaluatesToNonElement";
|
||||
static final String XPATH_EVAL_TO_NON_SCHEMA_ELEMENT = // arg:2
|
||||
"Internalizer.XPathEvaluatesToNonSchemaElement";
|
||||
static final String SCD_NOT_ENABLED = // arg:0
|
||||
"SCD_NOT_ENABLED";
|
||||
static final String ERR_SCD_EVAL = // arg: 1
|
||||
"ERR_SCD_EVAL";
|
||||
static final String ERR_SCD_EVALUATED_EMPTY = // arg:1
|
||||
"ERR_SCD_EVALUATED_EMPTY";
|
||||
static final String ERR_SCD_MATCHED_MULTIPLE_NODES = // arg:2
|
||||
"ERR_SCD_MATCHED_MULTIPLE_NODES";
|
||||
static final String ERR_SCD_MATCHED_MULTIPLE_NODES_FIRST = // arg:1
|
||||
"ERR_SCD_MATCHED_MULTIPLE_NODES_FIRST";
|
||||
static final String ERR_SCD_MATCHED_MULTIPLE_NODES_SECOND = // arg:1
|
||||
"ERR_SCD_MATCHED_MULTIPLE_NODES_SECOND";
|
||||
static final String CONTEXT_NODE_IS_NOT_ELEMENT = // arg:0
|
||||
"Internalizer.ContextNodeIsNotElement";
|
||||
static final String ERR_INCORRECT_VERSION = // arg:0
|
||||
"Internalizer.IncorrectVersion";
|
||||
static final String ERR_VERSION_NOT_FOUND = // arg:0
|
||||
"Internalizer.VersionNotPresent";
|
||||
static final String TWO_VERSION_ATTRIBUTES = // arg:0
|
||||
"Internalizer.TwoVersionAttributes";
|
||||
static final String ORPHANED_CUSTOMIZATION = // arg:1
|
||||
"Internalizer.OrphanedCustomization";
|
||||
static final String ERR_UNABLE_TO_PARSE = // arg:2
|
||||
"AbstractReferenceFinderImpl.UnableToParse";
|
||||
static final String ERR_FILENAME_IS_NOT_URI = // arg:0
|
||||
"ERR_FILENAME_IS_NOT_URI";
|
||||
static final String ERR_GENERAL_SCHEMA_CORRECTNESS_ERROR = // arg:1
|
||||
"ERR_GENERAL_SCHEMA_CORRECTNESS_ERROR";
|
||||
static final String DOMFOREST_INPUTSOURCE_IOEXCEPTION = // arg:2
|
||||
"DOMFOREST_INPUTSOURCE_IOEXCEPTION";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* reserved comment block
|
||||
* DO NOT REMOVE OR ALTER!
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, 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.
|
||||
*
|
||||
* THIS FILE WAS MODIFIED BY SUN MICROSYSTEMS, INC.
|
||||
*/
|
||||
|
||||
package com.sun.tools.internal.xjc.reader.internalizer;
|
||||
|
||||
import java.util.Iterator;
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.namespace.NamespaceContext;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* Implements {@link NamespaceContext} by looking at the in-scope
|
||||
* namespace binding of a DOM element.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
final class NamespaceContextImpl implements NamespaceContext {
|
||||
private final Element e;
|
||||
|
||||
public NamespaceContextImpl(Element e) {
|
||||
this.e = e;
|
||||
}
|
||||
|
||||
public String getNamespaceURI(String prefix) {
|
||||
Node parent = e;
|
||||
String namespace = null;
|
||||
final String prefixColon = prefix + ':';
|
||||
|
||||
if (prefix.equals("xml")) {
|
||||
namespace = XMLConstants.XML_NS_URI;
|
||||
} else {
|
||||
int type;
|
||||
|
||||
while ((null != parent) && (null == namespace)
|
||||
&& (((type = parent.getNodeType()) == Node.ELEMENT_NODE)
|
||||
|| (type == Node.ENTITY_REFERENCE_NODE))) {
|
||||
if (type == Node.ELEMENT_NODE) {
|
||||
if (parent.getNodeName().startsWith(prefixColon))
|
||||
return parent.getNamespaceURI();
|
||||
NamedNodeMap nnm = parent.getAttributes();
|
||||
|
||||
for (int i = 0; i < nnm.getLength(); i++) {
|
||||
Node attr = nnm.item(i);
|
||||
String aname = attr.getNodeName();
|
||||
boolean isPrefix = aname.startsWith("xmlns:");
|
||||
|
||||
if (isPrefix || aname.equals("xmlns")) {
|
||||
int index = aname.indexOf(':');
|
||||
String p = isPrefix ? aname.substring(index + 1) : "";
|
||||
|
||||
if (p.equals(prefix)) {
|
||||
namespace = attr.getNodeValue();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parent = parent.getParentNode();
|
||||
}
|
||||
}
|
||||
|
||||
if(prefix.equals(""))
|
||||
return ""; // default namespace
|
||||
return namespace;
|
||||
}
|
||||
|
||||
public String getPrefix(String namespaceURI) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Iterator getPrefixes(String namespaceURI) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, 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.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import javax.xml.bind.UnmarshallerHandler;
|
||||
import javax.xml.validation.ValidatorHandler;
|
||||
|
||||
import com.sun.istack.internal.NotNull;
|
||||
import com.sun.istack.internal.SAXParseException2;
|
||||
import com.sun.tools.internal.xjc.ErrorReceiver;
|
||||
import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIDeclaration;
|
||||
import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BindInfo;
|
||||
import com.sun.tools.internal.xjc.util.ForkContentHandler;
|
||||
import com.sun.tools.internal.xjc.util.DOMUtils;
|
||||
import com.sun.xml.internal.xsom.SCD;
|
||||
import com.sun.xml.internal.xsom.XSAnnotation;
|
||||
import com.sun.xml.internal.xsom.XSComponent;
|
||||
import com.sun.xml.internal.xsom.XSSchemaSet;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
/**
|
||||
* Set of binding nodes that have target nodes specified via SCD.
|
||||
*
|
||||
* This is parsed during {@link Internalizer} works on the tree,
|
||||
* but applying this has to wait for {@link XSSchemaSet} to be parsed.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
* @see SCD
|
||||
*/
|
||||
public final class SCDBasedBindingSet {
|
||||
|
||||
/**
|
||||
* Represents the target schema component of the
|
||||
* customization identified by SCD.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
final class Target {
|
||||
/**
|
||||
* SCDs can be specified via multiple steps, like:
|
||||
*
|
||||
* <xmp>
|
||||
* <bindings scd="foo/bar">
|
||||
* <bindings scd="zot/xyz">
|
||||
* </xmp>
|
||||
*
|
||||
* This field and {@link #nextSibling} form a single-linked list that
|
||||
* represent the children that shall be evaluated within this target.
|
||||
* Think of it as {@code List<Target>}.
|
||||
*/
|
||||
private Target firstChild;
|
||||
private final Target nextSibling;
|
||||
|
||||
/**
|
||||
* Compiled SCD.
|
||||
*/
|
||||
private final @NotNull SCD scd;
|
||||
|
||||
/**
|
||||
* The element on which SCD was found.
|
||||
*/
|
||||
private final @NotNull Element src;
|
||||
|
||||
/**
|
||||
* Bindings that apply to this SCD.
|
||||
*/
|
||||
private final List<Element> bindings = new ArrayList<Element>();
|
||||
|
||||
private Target(Target parent, Element src, SCD scd) {
|
||||
if(parent==null) {
|
||||
this.nextSibling = topLevel;
|
||||
topLevel = this;
|
||||
} else {
|
||||
this.nextSibling = parent.firstChild;
|
||||
parent.firstChild = this;
|
||||
}
|
||||
this.src = src;
|
||||
this.scd = scd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new binding declaration to be associated to the schema component
|
||||
* identified by {@link #scd}.
|
||||
*/
|
||||
void addBinidng(Element binding) {
|
||||
bindings.add(binding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies bindings to the schema component for this and its siblings.
|
||||
*/
|
||||
private void applyAll(Collection<? extends XSComponent> contextNode) {
|
||||
for( Target self=this; self!=null; self=self.nextSibling )
|
||||
self.apply(contextNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies bindings to the schema component for just this node.
|
||||
*/
|
||||
private void apply(Collection<? extends XSComponent> contextNode) {
|
||||
// apply the SCD...
|
||||
Collection<XSComponent> childNodes = scd.select(contextNode);
|
||||
if(childNodes.isEmpty()) {
|
||||
// no node matched
|
||||
if(src.getAttributeNode("if-exists")!=null) {
|
||||
// if this attribute exists, it's not an error if SCD didn't match.
|
||||
return;
|
||||
}
|
||||
|
||||
reportError( src, Messages.format(Messages.ERR_SCD_EVALUATED_EMPTY,scd) );
|
||||
return;
|
||||
}
|
||||
|
||||
if(firstChild!=null)
|
||||
firstChild.applyAll(childNodes);
|
||||
|
||||
if(!bindings.isEmpty()) {
|
||||
// error to match more than one components
|
||||
Iterator<XSComponent> itr = childNodes.iterator();
|
||||
XSComponent target = itr.next();
|
||||
if(itr.hasNext()) {
|
||||
reportError( src, Messages.format(Messages.ERR_SCD_MATCHED_MULTIPLE_NODES,scd,childNodes.size()) );
|
||||
errorReceiver.error( target.getLocator(), Messages.format(Messages.ERR_SCD_MATCHED_MULTIPLE_NODES_FIRST) );
|
||||
errorReceiver.error( itr.next().getLocator(), Messages.format(Messages.ERR_SCD_MATCHED_MULTIPLE_NODES_SECOND) );
|
||||
}
|
||||
|
||||
// apply bindings to the target
|
||||
for (Element binding : bindings) {
|
||||
for (Element item : DOMUtils.getChildElements(binding)) {
|
||||
String localName = item.getLocalName();
|
||||
|
||||
if ("bindings".equals(localName))
|
||||
continue; // this should be already in Target.bindings of some SpecVersion.
|
||||
|
||||
try {
|
||||
new DOMForestScanner(forest).scan(item,loader);
|
||||
BIDeclaration decl = (BIDeclaration)unmarshaller.getResult();
|
||||
|
||||
// add this binding to the target
|
||||
XSAnnotation ann = target.getAnnotation(true);
|
||||
BindInfo bi = (BindInfo)ann.getAnnotation();
|
||||
if(bi==null) {
|
||||
bi = new BindInfo();
|
||||
ann.setAnnotation(bi);
|
||||
}
|
||||
bi.addDecl(decl);
|
||||
} catch (SAXException e) {
|
||||
// the error should have already been reported.
|
||||
} catch (JAXBException e) {
|
||||
// if validation didn't fail, then unmarshalling can't go wrong
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Target topLevel;
|
||||
|
||||
/**
|
||||
* The forest where binding elements came from. Needed to report line numbers for errors.
|
||||
*/
|
||||
private final DOMForest forest;
|
||||
|
||||
|
||||
// variables used only during the apply method
|
||||
//
|
||||
private ErrorReceiver errorReceiver;
|
||||
private UnmarshallerHandler unmarshaller;
|
||||
private ForkContentHandler loader; // unmarshaller+validator
|
||||
|
||||
SCDBasedBindingSet(DOMForest forest) {
|
||||
this.forest = forest;
|
||||
}
|
||||
|
||||
Target createNewTarget(Target parent, Element src, SCD scd) {
|
||||
return new Target(parent,src,scd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the additional binding customizations.
|
||||
*/
|
||||
public void apply(XSSchemaSet schema, ErrorReceiver errorReceiver) {
|
||||
if(topLevel!=null) {
|
||||
this.errorReceiver = errorReceiver;
|
||||
Unmarshaller u = BindInfo.getCustomizationUnmarshaller();
|
||||
this.unmarshaller = u.getUnmarshallerHandler();
|
||||
ValidatorHandler v = BindInfo.bindingFileSchema.newValidator();
|
||||
v.setErrorHandler(errorReceiver);
|
||||
loader = new ForkContentHandler(v,unmarshaller);
|
||||
|
||||
topLevel.applyAll(schema.getSchemas());
|
||||
|
||||
this.loader = null;
|
||||
this.unmarshaller = null;
|
||||
this.errorReceiver = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void reportError( Element errorSource, String formattedMsg ) {
|
||||
reportError( errorSource, formattedMsg, null );
|
||||
}
|
||||
|
||||
private void reportError( Element errorSource,
|
||||
String formattedMsg, Exception nestedException ) {
|
||||
|
||||
SAXParseException e = new SAXParseException2( formattedMsg,
|
||||
forest.locatorTable.getStartLocation(errorSource),
|
||||
nestedException );
|
||||
errorReceiver.error(e);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, 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.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.sun.tools.internal.xjc.reader.Const;
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.EntityResolver;
|
||||
import org.xml.sax.ErrorHandler;
|
||||
import org.xml.sax.Locator;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.LocatorImpl;
|
||||
import org.xml.sax.helpers.XMLFilterImpl;
|
||||
|
||||
/**
|
||||
* Checks the jaxb:version attribute on a XML Schema document.
|
||||
*
|
||||
* jaxb:version is optional if no binding customization is used,
|
||||
* but if present, its value must be "1.0".
|
||||
*
|
||||
* @author
|
||||
* Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
|
||||
*/
|
||||
public class VersionChecker extends XMLFilterImpl {
|
||||
|
||||
/**
|
||||
* We store the value of the version attribute in this variable
|
||||
* when we hit the root element.
|
||||
*/
|
||||
private String version = null ;
|
||||
|
||||
/** Will be set to true once we hit the root element. */
|
||||
private boolean seenRoot = false;
|
||||
|
||||
/** Will be set to true once we hit a binding declaration. */
|
||||
private boolean seenBindings = false;
|
||||
|
||||
private Locator locator;
|
||||
|
||||
/**
|
||||
* Stores the location of the start tag of the root tag.
|
||||
*/
|
||||
private Locator rootTagStart;
|
||||
|
||||
public VersionChecker( XMLReader parent ) {
|
||||
setParent(parent);
|
||||
}
|
||||
|
||||
public VersionChecker( ContentHandler handler,ErrorHandler eh,EntityResolver er ) {
|
||||
setContentHandler(handler);
|
||||
if(eh!=null) setErrorHandler(eh);
|
||||
if(er!=null) setEntityResolver(er);
|
||||
}
|
||||
|
||||
public void startElement(String namespaceURI, String localName, String qName, Attributes atts)
|
||||
throws SAXException {
|
||||
|
||||
super.startElement(namespaceURI, localName, qName, atts);
|
||||
|
||||
if(!seenRoot) {
|
||||
// if this is the root element
|
||||
seenRoot = true;
|
||||
rootTagStart = new LocatorImpl(locator);
|
||||
|
||||
version = atts.getValue(Const.JAXB_NSURI,"version");
|
||||
if( namespaceURI.equals(Const.JAXB_NSURI) ) {
|
||||
String version2 = atts.getValue("","version");
|
||||
if( version!=null && version2!=null ) {
|
||||
// we have both @version and @jaxb:version. error.
|
||||
SAXParseException e = new SAXParseException(
|
||||
Messages.format( Messages.TWO_VERSION_ATTRIBUTES ), locator );
|
||||
getErrorHandler().error(e);
|
||||
}
|
||||
if( version==null )
|
||||
version = version2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if( Const.JAXB_NSURI.equals(namespaceURI) )
|
||||
seenBindings = true;
|
||||
}
|
||||
|
||||
public void endDocument() throws SAXException {
|
||||
super.endDocument();
|
||||
|
||||
if( seenBindings && version==null ) {
|
||||
// if we see a binding declaration but not version attribute
|
||||
SAXParseException e = new SAXParseException(
|
||||
Messages.format(Messages.ERR_VERSION_NOT_FOUND),rootTagStart);
|
||||
getErrorHandler().error(e);
|
||||
}
|
||||
|
||||
// if present, the value must be either 1.0 or 2.0
|
||||
if( version!=null && !VERSIONS.contains(version) ) {
|
||||
SAXParseException e = new SAXParseException(
|
||||
Messages.format(Messages.ERR_INCORRECT_VERSION),rootTagStart);
|
||||
getErrorHandler().error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setDocumentLocator(Locator locator) {
|
||||
super.setDocumentLocator(locator);
|
||||
this.locator = locator;
|
||||
}
|
||||
|
||||
private static final Set<String> VERSIONS = new HashSet<String>(Arrays.asList("1.0","2.0","2.1"));
|
||||
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, 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 com.sun.xml.internal.bind.WhiteSpaceProcessor;
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.EntityResolver;
|
||||
import org.xml.sax.ErrorHandler;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.XMLFilterImpl;
|
||||
|
||||
/**
|
||||
* Strips ignorable whitespace from SAX event stream.
|
||||
*
|
||||
* <p>
|
||||
* This filter works only when the event stream doesn't
|
||||
* contain any mixed content.
|
||||
*
|
||||
* @author
|
||||
* Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
|
||||
*/
|
||||
class WhitespaceStripper extends XMLFilterImpl {
|
||||
|
||||
private int state = 0;
|
||||
|
||||
private char[] buf = new char[1024];
|
||||
private int bufLen = 0;
|
||||
|
||||
private static final int AFTER_START_ELEMENT = 1;
|
||||
private static final int AFTER_END_ELEMENT = 2;
|
||||
|
||||
public WhitespaceStripper(XMLReader reader) {
|
||||
setParent(reader);
|
||||
}
|
||||
|
||||
public WhitespaceStripper(ContentHandler handler,ErrorHandler eh,EntityResolver er) {
|
||||
setContentHandler(handler);
|
||||
if(eh!=null) setErrorHandler(eh);
|
||||
if(er!=null) setEntityResolver(er);
|
||||
}
|
||||
|
||||
public void characters(char[] ch, int start, int length) throws SAXException {
|
||||
switch(state) {
|
||||
case AFTER_START_ELEMENT:
|
||||
// we have to store the characters here, even if it consists entirely
|
||||
// of whitespaces. This is because successive characters event might
|
||||
// include non-whitespace char, in which case all the whitespaces in
|
||||
// this event may suddenly become significant.
|
||||
if( bufLen+length>buf.length ) {
|
||||
// reallocate buffer
|
||||
char[] newBuf = new char[Math.max(bufLen+length,buf.length*2)];
|
||||
System.arraycopy(buf,0,newBuf,0,bufLen);
|
||||
buf = newBuf;
|
||||
}
|
||||
System.arraycopy(ch,start,buf,bufLen,length);
|
||||
bufLen += length;
|
||||
break;
|
||||
case AFTER_END_ELEMENT:
|
||||
// check if this is ignorable.
|
||||
int len = start+length;
|
||||
for( int i=start; i<len; i++ )
|
||||
if( !WhiteSpaceProcessor.isWhiteSpace(ch[i]) ) {
|
||||
super.characters(ch, start, length);
|
||||
return;
|
||||
}
|
||||
// if it's entirely whitespace, ignore it.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
|
||||
processPendingText();
|
||||
super.startElement(uri, localName, qName, atts);
|
||||
state = AFTER_START_ELEMENT;
|
||||
bufLen = 0;
|
||||
}
|
||||
|
||||
public void endElement(String uri, String localName, String qName) throws SAXException {
|
||||
processPendingText();
|
||||
super.endElement(uri, localName, qName);
|
||||
state = AFTER_END_ELEMENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwars the buffered characters if it contains any non-whitespace
|
||||
* character.
|
||||
*/
|
||||
private void processPendingText() throws SAXException {
|
||||
if(state==AFTER_START_ELEMENT) {
|
||||
for( int i=bufLen-1; i>=0; i-- )
|
||||
if( !WhiteSpaceProcessor.isWhiteSpace(buf[i]) ) {
|
||||
super.characters(buf, 0, bufLen);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
|
||||
// ignore completely.
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user