src/share/jaxws_classes/com/sun/xml/internal/ws/model/ExternalMetadataReader.java

changeset 368
0989ad8c0860
child 408
b0610cd08440
equal deleted inserted replaced
366:8c0b6bccfe47 368:0989ad8c0860
1 /*
2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.xml.internal.ws.model;
27
28 import com.oracle.xmlns.internal.webservices.jaxws_databinding.JavaMethod;
29 import com.oracle.xmlns.internal.webservices.jaxws_databinding.JavaParam;
30 import com.oracle.xmlns.internal.webservices.jaxws_databinding.JavaWsdlMappingType;
31 import com.oracle.xmlns.internal.webservices.jaxws_databinding.ObjectFactory;
32 import com.sun.xml.internal.bind.api.JAXBRIContext;
33 import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil;
34 import com.sun.xml.internal.ws.util.xml.XmlUtil;
35 import org.w3c.dom.Element;
36 import org.xml.sax.SAXException;
37
38 import javax.xml.bind.JAXBContext;
39 import javax.xml.bind.JAXBElement;
40 import javax.xml.bind.JAXBException;
41 import javax.xml.bind.Unmarshaller;
42 import javax.xml.bind.util.JAXBResult;
43 import javax.xml.stream.XMLInputFactory;
44 import javax.xml.stream.XMLStreamException;
45 import javax.xml.stream.XMLStreamReader;
46 import javax.xml.transform.Source;
47 import javax.xml.transform.Transformer;
48 import javax.xml.transform.TransformerException;
49 import javax.xml.transform.TransformerFactory;
50 import javax.xml.transform.stream.StreamSource;
51 import javax.xml.validation.Schema;
52 import javax.xml.validation.SchemaFactory;
53 import java.io.*;
54 import java.lang.annotation.Annotation;
55 import java.lang.reflect.Method;
56 import java.net.URL;
57 import java.util.*;
58
59 import static com.oracle.xmlns.internal.webservices.jaxws_databinding.ExistingAnnotationsType.MERGE;
60
61 /**
62 * Metadata Reader able to read from either class annotations or external metadata files or combine both,
63 * depending on configuration provided in xml file itself.
64 *
65 * @author shih-chang.chen@oracle.com, miroslav.kos@oracle.com
66 */
67 public class ExternalMetadataReader extends ReflectAnnotationReader {
68
69 private static final String NAMESPACE_WEBLOGIC_WSEE_DATABINDING = "http://xmlns.oracle.com/weblogic/weblogic-wsee-databinding";
70 private static final String NAMESPACE_JAXWS_RI_EXTERNAL_METADATA = "http://xmlns.oracle.com/webservices/jaxws-databinding";
71
72 /**
73 * map of readers for defined java types
74 */
75 private Map<String, JavaWsdlMappingType> readers = new HashMap<String, JavaWsdlMappingType>();
76
77 public ExternalMetadataReader(Collection<File> files, Collection<String> resourcePaths, ClassLoader classLoader,
78 boolean xsdValidation, boolean disableSecureXmlProcessing) {
79
80 if (files != null) {
81 for (File file : files) {
82 try {
83 String namespace = Util.documentRootNamespace(newSource(file), disableSecureXmlProcessing);
84 JavaWsdlMappingType externalMapping = parseMetadata(xsdValidation, newSource(file), namespace, disableSecureXmlProcessing);
85 readers.put(externalMapping.getJavaTypeName(), externalMapping);
86 } catch (Exception e) {
87 throw new RuntimeModelerException("runtime.modeler.external.metadata.unable.to.read", file.getAbsolutePath());
88 }
89 }
90 }
91
92 if (resourcePaths != null) {
93 for (String resourcePath : resourcePaths) {
94 try {
95 String namespace = Util.documentRootNamespace(newSource(resourcePath, classLoader), disableSecureXmlProcessing);
96 JavaWsdlMappingType externalMapping = parseMetadata(xsdValidation, newSource(resourcePath, classLoader), namespace, disableSecureXmlProcessing);
97 readers.put(externalMapping.getJavaTypeName(), externalMapping);
98 } catch (Exception e) {
99 throw new RuntimeModelerException("runtime.modeler.external.metadata.unable.to.read", resourcePath);
100 }
101 }
102 }
103 }
104
105 private StreamSource newSource(String resourcePath, ClassLoader classLoader) {
106 InputStream is = classLoader.getResourceAsStream(resourcePath);
107 return new StreamSource(is);
108 }
109
110 private JavaWsdlMappingType parseMetadata(boolean xsdValidation, StreamSource source, String namespace, boolean disableSecureXmlProcessing) throws JAXBException, IOException, TransformerException {
111 if (NAMESPACE_WEBLOGIC_WSEE_DATABINDING.equals(namespace)) {
112 return Util.transformAndRead(source, disableSecureXmlProcessing);
113 } if (NAMESPACE_JAXWS_RI_EXTERNAL_METADATA.equals(namespace)) {
114 return Util.read(source, xsdValidation, disableSecureXmlProcessing);
115 } else {
116 throw new RuntimeModelerException("runtime.modeler.external.metadata.unsupported.schema", namespace, Arrays.asList(NAMESPACE_WEBLOGIC_WSEE_DATABINDING, NAMESPACE_JAXWS_RI_EXTERNAL_METADATA).toString());
117 }
118 }
119
120 private StreamSource newSource(File file) {
121 try {
122 return new StreamSource(new FileInputStream(file));
123 } catch (FileNotFoundException e) {
124 throw new RuntimeModelerException("runtime.modeler.external.metadata.unable.to.read", file.getAbsolutePath());
125 }
126 }
127
128 public <A extends Annotation> A getAnnotation(Class<A> annType, Class<?> cls) {
129 JavaWsdlMappingType r = reader(cls);
130 return r == null ? super.getAnnotation(annType, cls) : Util.annotation(r, annType);
131 }
132
133 private JavaWsdlMappingType reader(Class<?> cls) {
134 return readers.get(cls.getName());
135 }
136
137 Annotation[] getAnnotations(List<Object> objects) {
138 ArrayList<Annotation> list = new ArrayList<Annotation>();
139 for (Object a : objects) {
140 if (Annotation.class.isInstance(a)) {
141 list.add(Annotation.class.cast(a));
142 }
143 }
144 return list.toArray(new Annotation[list.size()]);
145 }
146
147 public Annotation[] getAnnotations(final Class<?> c) {
148
149 Merger<Annotation[]> merger = new Merger<Annotation[]>(reader(c)) {
150 Annotation[] reflection() {
151 return ExternalMetadataReader.super.getAnnotations(c);
152 }
153
154 Annotation[] external() {
155 return getAnnotations(reader.getClassAnnotation());
156 }
157 };
158 return merger.merge();
159 }
160
161 public Annotation[] getAnnotations(final Method m) {
162 Merger<Annotation[]> merger = new Merger<Annotation[]>(reader(m.getDeclaringClass())) {
163 Annotation[] reflection() {
164 return ExternalMetadataReader.super.getAnnotations(m);
165 }
166
167 Annotation[] external() {
168 JavaMethod jm = getJavaMethod(m, reader);
169 return (jm == null) ? new Annotation[0] : getAnnotations(jm.getMethodAnnotation());
170 }
171 };
172 return merger.merge();
173 }
174
175 @SuppressWarnings("unchecked")
176 public <A extends Annotation> A getAnnotation(final Class<A> annType, final Method m) {
177 Merger<Annotation> merger = new Merger<Annotation>(reader(m.getDeclaringClass())) {
178 Annotation reflection() {
179 return ExternalMetadataReader.super.getAnnotation(annType, m);
180 }
181
182 Annotation external() {
183 JavaMethod jm = getJavaMethod(m, reader);
184 return Util.annotation(jm, annType);
185 }
186 };
187 return (A) merger.merge();
188 }
189
190 public Annotation[][] getParameterAnnotations(final Method m) {
191 Merger<Annotation[][]> merger = new Merger<Annotation[][]>(reader(m.getDeclaringClass())) {
192 Annotation[][] reflection() {
193 return ExternalMetadataReader.super.getParameterAnnotations(m);
194 }
195
196 Annotation[][] external() {
197 JavaMethod jm = getJavaMethod(m, reader);
198 Annotation[][] a = m.getParameterAnnotations();
199 for (int i = 0; i < m.getParameterTypes().length; i++) {
200 if (jm == null) continue;
201 JavaParam jp = jm.getJavaParams().getJavaParam().get(i);
202 a[i] = getAnnotations(jp.getParamAnnotation());
203 }
204 return a;
205 }
206 };
207 return merger.merge();
208 }
209
210 public void getProperties(final Map<String, Object> prop, final Class<?> cls) {
211
212 JavaWsdlMappingType r = reader(cls);
213
214 // no external reader or it requires annotations merging ...
215 if (r == null || MERGE.equals(r.getExistingAnnotations())) {
216 super.getProperties(prop, cls);
217 }
218
219 }
220
221 public void getProperties(final Map<String, Object> prop, final Method m) {
222
223 JavaWsdlMappingType r = reader(m.getDeclaringClass());
224
225 // no external reader or it requires annotations merging ...
226 if (r == null || MERGE.equals(r.getExistingAnnotations())) {
227 super.getProperties(prop, m);
228 }
229
230 if (r != null) {
231 JavaMethod jm = getJavaMethod(m, r);
232 Element[] e = Util.annotation(jm);
233 prop.put("eclipselink-oxm-xml.xml-element", findXmlElement(e));
234 }
235
236 }
237
238 public void getProperties(final Map<String, Object> prop, final Method m, int pos) {
239
240 JavaWsdlMappingType r = reader(m.getDeclaringClass());
241
242 // no external reader or it requires annotations merging ...
243 if (r == null || MERGE.equals(r.getExistingAnnotations())) {
244 super.getProperties(prop, m, pos);
245 }
246
247 if (r != null) {
248 JavaMethod jm = getJavaMethod(m, r);
249 if (jm == null) return;
250 JavaParam jp = jm.getJavaParams().getJavaParam().get(pos);
251 Element[] e = Util.annotation(jp);
252 prop.put("eclipselink-oxm-xml.xml-element", findXmlElement(e));
253 }
254 }
255
256 JavaMethod getJavaMethod(Method method, JavaWsdlMappingType r) {
257
258 JavaWsdlMappingType.JavaMethods javaMethods = r.getJavaMethods();
259 if (javaMethods == null) {
260 return null;
261 }
262
263 List<JavaMethod> sameName = new ArrayList<JavaMethod>();
264 for (JavaMethod jm : javaMethods.getJavaMethod()) {
265 if (method.getName().equals(jm.getName())) {
266 sameName.add(jm);
267 }
268 }
269
270 if (sameName.isEmpty()) {
271 return null;
272 } else {
273 if (sameName.size() == 1) {
274 return sameName.get(0);
275 } else {
276 Class<?>[] argCls = method.getParameterTypes();
277 for (JavaMethod jm : sameName) {
278 JavaMethod.JavaParams params = jm.getJavaParams();
279 if (params != null && params.getJavaParam() != null && params.getJavaParam().size() == argCls.length) {
280 int count = 0;
281 for (int i = 0; i < argCls.length; i++) {
282 JavaParam jp = params.getJavaParam().get(i);
283 if (argCls[i].getName().equals(jp.getJavaType())) {
284 count++;
285 }
286 }
287 if (count == argCls.length) {
288 return jm;
289 }
290 }
291 }
292 }
293 }
294 return null;
295 }
296
297 Element findXmlElement(Element[] xa) {
298 if (xa == null) return null;
299 for (Element e : xa) {
300 if (e.getLocalName().equals("java-type")) return e;
301 if (e.getLocalName().equals("xml-element")) return e;
302 }
303 return null;
304 }
305
306 /**
307 * Helper class to merge two different arrays of annotation objects. It merges annotations based on attribute
308 * <code>existing-annotations</code> in external customization file.
309 * <p/>
310 * We suppose that in the result array there wouldn't be two annotations of same type:
311 * annotation.annotationType().getName(); if there are found such annotations the one from reflection is
312 * considered overriden and is thrown away.
313 * <p/>
314 * The helper can work either with one and two dimensional array, but it can be used for two single Annotation
315 * objects;
316 */
317 static abstract class Merger<T> {
318
319 JavaWsdlMappingType reader;
320
321 Merger(JavaWsdlMappingType r) {
322 this.reader = r;
323 }
324
325 abstract T reflection();
326
327 abstract T external();
328
329 @SuppressWarnings("unchecked")
330 T merge() {
331 T reflection = reflection();
332 if (reader == null) {
333 return reflection;
334 }
335
336 T external = external();
337 if (!MERGE.equals(reader.getExistingAnnotations())) {
338 return external;
339 }
340
341 if (reflection instanceof Annotation) {
342 return (T) doMerge((Annotation) reflection, (Annotation) external);
343 } else if (reflection instanceof Annotation[][]) {
344 return (T) doMerge((Annotation[][]) reflection, (Annotation[][]) external);
345 } else {
346 return (T) doMerge((Annotation[]) reflection, (Annotation[]) external);
347 }
348 }
349
350 private Annotation doMerge(Annotation reflection, Annotation external) {
351 return external != null ? external : reflection;
352 }
353
354 private Annotation[][] doMerge(Annotation[][] reflection, Annotation[][] external) {
355 for (int i = 0; i < reflection.length; i++) {
356 reflection[i] = doMerge(reflection[i], external.length > i ? external[i] : null);
357 }
358 return reflection;
359 }
360
361 private Annotation[] doMerge(Annotation[] annotations, Annotation[] externalAnnotations) {
362 HashMap<String, Annotation> mergeMap = new HashMap<String, Annotation>();
363 if (annotations != null) {
364 for (Annotation reflectionAnnotation : annotations) {
365 mergeMap.put(reflectionAnnotation.annotationType().getName(), reflectionAnnotation);
366 }
367 }
368
369 // overriding happens here, based on annotationType().getName() ...
370 if (externalAnnotations != null) {
371 for (Annotation externalAnnotation : externalAnnotations) {
372 mergeMap.put(externalAnnotation.annotationType().getName(), externalAnnotation);
373 }
374 }
375 Collection<Annotation> values = mergeMap.values();
376 int size = values.size();
377 return size == 0 ? null : values.toArray(new Annotation[size]);
378 }
379
380 }
381
382 static class Util {
383
384 //private static final String DATABINDING_XSD = "com/sun/xml/internal/ws/model/jaxws-databinding.xsd";
385 private static final String DATABINDING_XSD = "jaxws-databinding.xsd";
386 //private static final String TRANSLATE_NAMESPACES_XSL = "/com/sun/xml/internal/ws/model/jaxws-databinding-translate-namespaces.xml";
387 private static final String TRANSLATE_NAMESPACES_XSL = "jaxws-databinding-translate-namespaces.xml";
388
389 static Schema schema;
390 static JAXBContext jaxbContext;
391
392 static {
393 SchemaFactory sf = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
394 try {
395 URL xsdUrl = getResource();
396 if (xsdUrl != null) {
397 schema = sf.newSchema(xsdUrl);
398 }
399 } catch (SAXException e1) {
400 // e1.printStackTrace();
401 }
402
403 jaxbContext = createJaxbContext(false);
404 }
405
406 private static URL getResource() {
407 ClassLoader classLoader = Util.class.getClassLoader();
408 return classLoader != null ? classLoader.getResource(DATABINDING_XSD) : ClassLoader.getSystemResource(DATABINDING_XSD);
409 }
410
411 private static JAXBContext createJaxbContext(boolean disableXmlSecurity) {
412 Class[] cls = {ObjectFactory.class};
413 try {
414 if (disableXmlSecurity) {
415 Map<String, Object> properties = new HashMap<String, Object>();
416 properties.put(JAXBRIContext.DISABLE_XML_SECURITY, disableXmlSecurity);
417 return JAXBContext.newInstance(cls, properties);
418 } else {
419 return JAXBContext.newInstance(cls);
420 }
421 } catch (JAXBException e) {
422 e.printStackTrace();
423 return null;
424 }
425 }
426
427 @SuppressWarnings("unchecked")
428 public static JavaWsdlMappingType read(Source src, boolean xsdValidation, boolean disableSecureXmlProcessing) throws IOException, JAXBException {
429 JAXBContext ctx = jaxbContext(disableSecureXmlProcessing);
430 try {
431 Unmarshaller um = ctx.createUnmarshaller();
432 if (xsdValidation) {
433 if (schema == null) {
434 //TODO 0 warning for schema == null
435 }
436 um.setSchema(schema);
437 }
438 Object o = um.unmarshal(src);
439 return getJavaWsdlMapping(o);
440 } catch (JAXBException e) {
441 // throw new
442 // WebServiceException(WsDatabindingMessages.mappingFileCannotRead
443 // (src.getSystemId()), e);
444 URL url = new URL(src.getSystemId());
445 Source s = new StreamSource(url.openStream());
446 Unmarshaller um = ctx.createUnmarshaller();
447 if (xsdValidation) {
448 if (schema == null) {
449 //TODO 0 warning for schema == null
450 }
451 um.setSchema(schema);
452 }
453 Object o = um.unmarshal(s);
454 return getJavaWsdlMapping(o);
455 }
456 }
457
458 private static JAXBContext jaxbContext(boolean disableSecureXmlProcessing) {
459 // as it is supposed to have security enabled in most cases, we create and don't cache
460 // "insecure" JAXBContext - these should be corner cases
461 return disableSecureXmlProcessing ? createJaxbContext(true) : jaxbContext;
462 }
463
464 public static JavaWsdlMappingType transformAndRead(Source src, boolean disableSecureXmlProcessing) throws TransformerException, JAXBException {
465 Source xsl = new StreamSource(Util.class.getResourceAsStream(TRANSLATE_NAMESPACES_XSL));
466 JAXBResult result = new JAXBResult(jaxbContext(disableSecureXmlProcessing));
467 TransformerFactory tf = XmlUtil.newTransformerFactory(!disableSecureXmlProcessing);
468 Transformer transformer = tf.newTemplates(xsl).newTransformer();
469 transformer.transform(src, result);
470 return getJavaWsdlMapping(result.getResult());
471 }
472
473
474 static JavaWsdlMappingType getJavaWsdlMapping(Object o) {
475 Object val = (o instanceof JAXBElement) ? ((JAXBElement) o).getValue() : o;
476 if (val instanceof JavaWsdlMappingType) return (JavaWsdlMappingType) val;
477 // else if (val instanceof JavaWsdlMappings)
478 // for (JavaWsdlMappingType m: ((JavaWsdlMappings) val).getJavaWsdlMapping())
479 // if (seiName.equals(m.javaTypeName)) return m;
480 return null;
481 }
482
483 static <T> T findInstanceOf(Class<T> type, List<Object> objects) {
484 for (Object o : objects) {
485 if (type.isInstance(o)) {
486 return type.cast(o);
487 }
488 }
489 return null;
490 }
491
492 static public <T> T annotation(JavaWsdlMappingType jwse, Class<T> anntype) {
493 if (jwse == null || jwse.getClassAnnotation() == null) {
494 return null;
495 }
496 return findInstanceOf(anntype, jwse.getClassAnnotation());
497 }
498
499 static public <T> T annotation(JavaMethod jm, Class<T> anntype) {
500 if (jm == null || jm.getMethodAnnotation() == null) {
501 return null;
502 }
503 return findInstanceOf(anntype, jm.getMethodAnnotation());
504 }
505
506 static public <T> T annotation(JavaParam jp, Class<T> anntype) {
507 if (jp == null || jp.getParamAnnotation() == null) {
508 return null;
509 }
510 return findInstanceOf(anntype, jp.getParamAnnotation());
511 }
512
513 static public Element[] annotation(JavaMethod jm) {
514 if (jm == null || jm.getMethodAnnotation() == null) {
515 return null;
516 }
517 return findElements(jm.getMethodAnnotation());
518 }
519
520 static public Element[] annotation(JavaParam jp) {
521 if (jp == null || jp.getParamAnnotation() == null) {
522 return null;
523 }
524 return findElements(jp.getParamAnnotation());
525 }
526
527 private static Element[] findElements(List<Object> objects) {
528 List<Element> elems = new ArrayList<Element>();
529 for (Object o : objects) {
530 if (o instanceof Element) {
531 elems.add((Element) o);
532 }
533 }
534 return elems.toArray(new Element[elems.size()]);
535 }
536
537 static String documentRootNamespace(Source src, boolean disableSecureXmlProcessing) throws XMLStreamException {
538 XMLInputFactory factory;
539 factory = XmlUtil.newXMLInputFactory(!disableSecureXmlProcessing);
540 XMLStreamReader streamReader = factory.createXMLStreamReader(src);
541 XMLStreamReaderUtil.nextElementContent(streamReader);
542 String namespaceURI = streamReader.getName().getNamespaceURI();
543 XMLStreamReaderUtil.close(streamReader);
544 return namespaceURI;
545 }
546 }
547
548
549 }

mercurial