diff -r 000000000000 -r 373ffda63c9a src/share/jaxws_classes/com/sun/xml/internal/ws/model/ExternalMetadataReader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/jaxws_classes/com/sun/xml/internal/ws/model/ExternalMetadataReader.java Wed Apr 27 01:27:09 2016 +0800 @@ -0,0 +1,549 @@ +/* + * 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.xml.internal.ws.model; + +import com.oracle.xmlns.internal.webservices.jaxws_databinding.JavaMethod; +import com.oracle.xmlns.internal.webservices.jaxws_databinding.JavaParam; +import com.oracle.xmlns.internal.webservices.jaxws_databinding.JavaWsdlMappingType; +import com.oracle.xmlns.internal.webservices.jaxws_databinding.ObjectFactory; +import com.sun.xml.internal.bind.api.JAXBRIContext; +import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil; +import com.sun.xml.internal.ws.util.xml.XmlUtil; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.bind.util.JAXBResult; +import javax.xml.stream.XMLInputFactory; +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.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import java.io.*; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.net.URL; +import java.util.*; + +import static com.oracle.xmlns.internal.webservices.jaxws_databinding.ExistingAnnotationsType.MERGE; + +/** + * Metadata Reader able to read from either class annotations or external metadata files or combine both, + * depending on configuration provided in xml file itself. + * + * @author shih-chang.chen@oracle.com, miroslav.kos@oracle.com + */ +public class ExternalMetadataReader extends ReflectAnnotationReader { + + private static final String NAMESPACE_WEBLOGIC_WSEE_DATABINDING = "http://xmlns.oracle.com/weblogic/weblogic-wsee-databinding"; + private static final String NAMESPACE_JAXWS_RI_EXTERNAL_METADATA = "http://xmlns.oracle.com/webservices/jaxws-databinding"; + + /** + * map of readers for defined java types + */ + private Map readers = new HashMap(); + + public ExternalMetadataReader(Collection files, Collection resourcePaths, ClassLoader classLoader, + boolean xsdValidation, boolean disableXmlSecurity) { + + if (files != null) { + for (File file : files) { + try { + String namespace = Util.documentRootNamespace(newSource(file), disableXmlSecurity); + JavaWsdlMappingType externalMapping = parseMetadata(xsdValidation, newSource(file), namespace, disableXmlSecurity); + readers.put(externalMapping.getJavaTypeName(), externalMapping); + } catch (Exception e) { + throw new RuntimeModelerException("runtime.modeler.external.metadata.unable.to.read", file.getAbsolutePath()); + } + } + } + + if (resourcePaths != null) { + for (String resourcePath : resourcePaths) { + try { + String namespace = Util.documentRootNamespace(newSource(resourcePath, classLoader), disableXmlSecurity); + JavaWsdlMappingType externalMapping = parseMetadata(xsdValidation, newSource(resourcePath, classLoader), namespace, disableXmlSecurity); + readers.put(externalMapping.getJavaTypeName(), externalMapping); + } catch (Exception e) { + throw new RuntimeModelerException("runtime.modeler.external.metadata.unable.to.read", resourcePath); + } + } + } + } + + private StreamSource newSource(String resourcePath, ClassLoader classLoader) { + InputStream is = classLoader.getResourceAsStream(resourcePath); + return new StreamSource(is); + } + + private JavaWsdlMappingType parseMetadata(boolean xsdValidation, StreamSource source, String namespace, boolean disableXmlSecurity) throws JAXBException, IOException, TransformerException { + if (NAMESPACE_WEBLOGIC_WSEE_DATABINDING.equals(namespace)) { + return Util.transformAndRead(source, disableXmlSecurity); + } if (NAMESPACE_JAXWS_RI_EXTERNAL_METADATA.equals(namespace)) { + return Util.read(source, xsdValidation, disableXmlSecurity); + } else { + throw new RuntimeModelerException("runtime.modeler.external.metadata.unsupported.schema", namespace, Arrays.asList(NAMESPACE_WEBLOGIC_WSEE_DATABINDING, NAMESPACE_JAXWS_RI_EXTERNAL_METADATA).toString()); + } + } + + private StreamSource newSource(File file) { + try { + return new StreamSource(new FileInputStream(file)); + } catch (FileNotFoundException e) { + throw new RuntimeModelerException("runtime.modeler.external.metadata.unable.to.read", file.getAbsolutePath()); + } + } + + public A getAnnotation(Class annType, Class cls) { + JavaWsdlMappingType r = reader(cls); + return r == null ? super.getAnnotation(annType, cls) : Util.annotation(r, annType); + } + + private JavaWsdlMappingType reader(Class cls) { + return readers.get(cls.getName()); + } + + Annotation[] getAnnotations(List objects) { + ArrayList list = new ArrayList(); + for (Object a : objects) { + if (Annotation.class.isInstance(a)) { + list.add(Annotation.class.cast(a)); + } + } + return list.toArray(new Annotation[list.size()]); + } + + public Annotation[] getAnnotations(final Class c) { + + Merger merger = new Merger(reader(c)) { + Annotation[] reflection() { + return ExternalMetadataReader.super.getAnnotations(c); + } + + Annotation[] external() { + return getAnnotations(reader.getClassAnnotation()); + } + }; + return merger.merge(); + } + + public Annotation[] getAnnotations(final Method m) { + Merger merger = new Merger(reader(m.getDeclaringClass())) { + Annotation[] reflection() { + return ExternalMetadataReader.super.getAnnotations(m); + } + + Annotation[] external() { + JavaMethod jm = getJavaMethod(m, reader); + return (jm == null) ? new Annotation[0] : getAnnotations(jm.getMethodAnnotation()); + } + }; + return merger.merge(); + } + + @SuppressWarnings("unchecked") + public A getAnnotation(final Class annType, final Method m) { + Merger merger = new Merger(reader(m.getDeclaringClass())) { + Annotation reflection() { + return ExternalMetadataReader.super.getAnnotation(annType, m); + } + + Annotation external() { + JavaMethod jm = getJavaMethod(m, reader); + return Util.annotation(jm, annType); + } + }; + return (A) merger.merge(); + } + + public Annotation[][] getParameterAnnotations(final Method m) { + Merger merger = new Merger(reader(m.getDeclaringClass())) { + Annotation[][] reflection() { + return ExternalMetadataReader.super.getParameterAnnotations(m); + } + + Annotation[][] external() { + JavaMethod jm = getJavaMethod(m, reader); + Annotation[][] a = m.getParameterAnnotations(); + for (int i = 0; i < m.getParameterTypes().length; i++) { + if (jm == null) continue; + JavaParam jp = jm.getJavaParams().getJavaParam().get(i); + a[i] = getAnnotations(jp.getParamAnnotation()); + } + return a; + } + }; + return merger.merge(); + } + + public void getProperties(final Map prop, final Class cls) { + + JavaWsdlMappingType r = reader(cls); + + // no external reader or it requires annotations merging ... + if (r == null || MERGE.equals(r.getExistingAnnotations())) { + super.getProperties(prop, cls); + } + + } + + public void getProperties(final Map prop, final Method m) { + + JavaWsdlMappingType r = reader(m.getDeclaringClass()); + + // no external reader or it requires annotations merging ... + if (r == null || MERGE.equals(r.getExistingAnnotations())) { + super.getProperties(prop, m); + } + + if (r != null) { + JavaMethod jm = getJavaMethod(m, r); + Element[] e = Util.annotation(jm); + prop.put("eclipselink-oxm-xml.xml-element", findXmlElement(e)); + } + + } + + public void getProperties(final Map prop, final Method m, int pos) { + + JavaWsdlMappingType r = reader(m.getDeclaringClass()); + + // no external reader or it requires annotations merging ... + if (r == null || MERGE.equals(r.getExistingAnnotations())) { + super.getProperties(prop, m, pos); + } + + if (r != null) { + JavaMethod jm = getJavaMethod(m, r); + if (jm == null) return; + JavaParam jp = jm.getJavaParams().getJavaParam().get(pos); + Element[] e = Util.annotation(jp); + prop.put("eclipselink-oxm-xml.xml-element", findXmlElement(e)); + } + } + + JavaMethod getJavaMethod(Method method, JavaWsdlMappingType r) { + + JavaWsdlMappingType.JavaMethods javaMethods = r.getJavaMethods(); + if (javaMethods == null) { + return null; + } + + List sameName = new ArrayList(); + for (JavaMethod jm : javaMethods.getJavaMethod()) { + if (method.getName().equals(jm.getName())) { + sameName.add(jm); + } + } + + if (sameName.isEmpty()) { + return null; + } else { + if (sameName.size() == 1) { + return sameName.get(0); + } else { + Class[] argCls = method.getParameterTypes(); + for (JavaMethod jm : sameName) { + JavaMethod.JavaParams params = jm.getJavaParams(); + if (params != null && params.getJavaParam() != null && params.getJavaParam().size() == argCls.length) { + int count = 0; + for (int i = 0; i < argCls.length; i++) { + JavaParam jp = params.getJavaParam().get(i); + if (argCls[i].getName().equals(jp.getJavaType())) { + count++; + } + } + if (count == argCls.length) { + return jm; + } + } + } + } + } + return null; + } + + Element findXmlElement(Element[] xa) { + if (xa == null) return null; + for (Element e : xa) { + if (e.getLocalName().equals("java-type")) return e; + if (e.getLocalName().equals("xml-element")) return e; + } + return null; + } + + /** + * Helper class to merge two different arrays of annotation objects. It merges annotations based on attribute + * existing-annotations in external customization file. + *

+ * We suppose that in the result array there wouldn't be two annotations of same type: + * annotation.annotationType().getName(); if there are found such annotations the one from reflection is + * considered overriden and is thrown away. + *

+ * The helper can work either with one and two dimensional array, but it can be used for two single Annotation + * objects; + */ + static abstract class Merger { + + JavaWsdlMappingType reader; + + Merger(JavaWsdlMappingType r) { + this.reader = r; + } + + abstract T reflection(); + + abstract T external(); + + @SuppressWarnings("unchecked") + T merge() { + T reflection = reflection(); + if (reader == null) { + return reflection; + } + + T external = external(); + if (!MERGE.equals(reader.getExistingAnnotations())) { + return external; + } + + if (reflection instanceof Annotation) { + return (T) doMerge((Annotation) reflection, (Annotation) external); + } else if (reflection instanceof Annotation[][]) { + return (T) doMerge((Annotation[][]) reflection, (Annotation[][]) external); + } else { + return (T) doMerge((Annotation[]) reflection, (Annotation[]) external); + } + } + + private Annotation doMerge(Annotation reflection, Annotation external) { + return external != null ? external : reflection; + } + + private Annotation[][] doMerge(Annotation[][] reflection, Annotation[][] external) { + for (int i = 0; i < reflection.length; i++) { + reflection[i] = doMerge(reflection[i], external.length > i ? external[i] : null); + } + return reflection; + } + + private Annotation[] doMerge(Annotation[] annotations, Annotation[] externalAnnotations) { + HashMap mergeMap = new HashMap(); + if (annotations != null) { + for (Annotation reflectionAnnotation : annotations) { + mergeMap.put(reflectionAnnotation.annotationType().getName(), reflectionAnnotation); + } + } + + // overriding happens here, based on annotationType().getName() ... + if (externalAnnotations != null) { + for (Annotation externalAnnotation : externalAnnotations) { + mergeMap.put(externalAnnotation.annotationType().getName(), externalAnnotation); + } + } + Collection values = mergeMap.values(); + int size = values.size(); + return size == 0 ? null : values.toArray(new Annotation[size]); + } + + } + + static class Util { + + //private static final String DATABINDING_XSD = "com/sun/xml/internal/ws/model/jaxws-databinding.xsd"; + private static final String DATABINDING_XSD = "jaxws-databinding.xsd"; + //private static final String TRANSLATE_NAMESPACES_XSL = "/com/sun/xml/internal/ws/model/jaxws-databinding-translate-namespaces.xml"; + private static final String TRANSLATE_NAMESPACES_XSL = "jaxws-databinding-translate-namespaces.xml"; + + static Schema schema; + static JAXBContext jaxbContext; + + static { + SchemaFactory sf = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema"); + try { + URL xsdUrl = getResource(); + if (xsdUrl != null) { + schema = sf.newSchema(xsdUrl); + } + } catch (SAXException e1) { + // e1.printStackTrace(); + } + + jaxbContext = createJaxbContext(false); + } + + private static URL getResource() { + ClassLoader classLoader = Util.class.getClassLoader(); + return classLoader != null ? classLoader.getResource(DATABINDING_XSD) : ClassLoader.getSystemResource(DATABINDING_XSD); + } + + private static JAXBContext createJaxbContext(boolean disableXmlSecurity) { + Class[] cls = {ObjectFactory.class}; + try { + if (disableXmlSecurity) { + Map properties = new HashMap(); + properties.put(JAXBRIContext.DISABLE_XML_SECURITY, disableXmlSecurity); + return JAXBContext.newInstance(cls, properties); + } else { + return JAXBContext.newInstance(cls); + } + } catch (JAXBException e) { + e.printStackTrace(); + return null; + } + } + + @SuppressWarnings("unchecked") + public static JavaWsdlMappingType read(Source src, boolean xsdValidation, boolean disableXmlSecurity) throws IOException, JAXBException { + JAXBContext ctx = jaxbContext(disableXmlSecurity); + try { + Unmarshaller um = ctx.createUnmarshaller(); + if (xsdValidation) { + if (schema == null) { + //TODO 0 warning for schema == null + } + um.setSchema(schema); + } + Object o = um.unmarshal(src); + return getJavaWsdlMapping(o); + } catch (JAXBException e) { + // throw new + // WebServiceException(WsDatabindingMessages.mappingFileCannotRead + // (src.getSystemId()), e); + URL url = new URL(src.getSystemId()); + Source s = new StreamSource(url.openStream()); + Unmarshaller um = ctx.createUnmarshaller(); + if (xsdValidation) { + if (schema == null) { + //TODO 0 warning for schema == null + } + um.setSchema(schema); + } + Object o = um.unmarshal(s); + return getJavaWsdlMapping(o); + } + } + + private static JAXBContext jaxbContext(boolean disableXmlSecurity) { + // as it is supposed to have security enabled in most cases, we create and don't cache + // "insecure" JAXBContext - these should be corner cases + return disableXmlSecurity ? createJaxbContext(true) : jaxbContext; + } + + public static JavaWsdlMappingType transformAndRead(Source src, boolean disableXmlSecurity) throws TransformerException, JAXBException { + Source xsl = new StreamSource(Util.class.getResourceAsStream(TRANSLATE_NAMESPACES_XSL)); + JAXBResult result = new JAXBResult(jaxbContext(disableXmlSecurity)); + TransformerFactory tf = XmlUtil.newTransformerFactory(!disableXmlSecurity); + Transformer transformer = tf.newTemplates(xsl).newTransformer(); + transformer.transform(src, result); + return getJavaWsdlMapping(result.getResult()); + } + + + static JavaWsdlMappingType getJavaWsdlMapping(Object o) { + Object val = (o instanceof JAXBElement) ? ((JAXBElement) o).getValue() : o; + if (val instanceof JavaWsdlMappingType) return (JavaWsdlMappingType) val; + // else if (val instanceof JavaWsdlMappings) + // for (JavaWsdlMappingType m: ((JavaWsdlMappings) val).getJavaWsdlMapping()) + // if (seiName.equals(m.javaTypeName)) return m; + return null; + } + + static T findInstanceOf(Class type, List objects) { + for (Object o : objects) { + if (type.isInstance(o)) { + return type.cast(o); + } + } + return null; + } + + static public T annotation(JavaWsdlMappingType jwse, Class anntype) { + if (jwse == null || jwse.getClassAnnotation() == null) { + return null; + } + return findInstanceOf(anntype, jwse.getClassAnnotation()); + } + + static public T annotation(JavaMethod jm, Class anntype) { + if (jm == null || jm.getMethodAnnotation() == null) { + return null; + } + return findInstanceOf(anntype, jm.getMethodAnnotation()); + } + + static public T annotation(JavaParam jp, Class anntype) { + if (jp == null || jp.getParamAnnotation() == null) { + return null; + } + return findInstanceOf(anntype, jp.getParamAnnotation()); + } + + static public Element[] annotation(JavaMethod jm) { + if (jm == null || jm.getMethodAnnotation() == null) { + return null; + } + return findElements(jm.getMethodAnnotation()); + } + + static public Element[] annotation(JavaParam jp) { + if (jp == null || jp.getParamAnnotation() == null) { + return null; + } + return findElements(jp.getParamAnnotation()); + } + + private static Element[] findElements(List objects) { + List elems = new ArrayList(); + for (Object o : objects) { + if (o instanceof Element) { + elems.add((Element) o); + } + } + return elems.toArray(new Element[elems.size()]); + } + + static String documentRootNamespace(Source src, boolean disableXmlSecurity) throws XMLStreamException { + XMLInputFactory factory; + factory = XmlUtil.newXMLInputFactory(!disableXmlSecurity); + XMLStreamReader streamReader = factory.createXMLStreamReader(src); + XMLStreamReaderUtil.nextElementContent(streamReader); + String namespaceURI = streamReader.getName().getNamespaceURI(); + XMLStreamReaderUtil.close(streamReader); + return namespaceURI; + } + } + + +}