feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View File

@@ -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;
}
}

View File

@@ -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";
}

View File

@@ -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;
}
});
}
}

View File

@@ -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 &lt;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);
}
}

View File

@@ -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&lt;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 &lt;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();
}
}
}

View File

@@ -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 );
}
}

View File

@@ -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;
}
}
}

View File

@@ -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
* &lt;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 &lt;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 );
}

View File

@@ -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 &lt;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 &lt;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 &lt;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., &lt;jaxb:class>)
*
* @param target
* XML Schema element under which the declaration should move.
* For example, &lt;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);
}
}

View File

@@ -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);
}
}

View File

@@ -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";
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -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"));
}

View File

@@ -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.
}
}