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

changeset 286
f50545b5e2f1
child 368
0989ad8c0860
equal deleted inserted replaced
284:88b85470e72c 286:f50545b5e2f1
1 /*
2 * Copyright (c) 1997, 2011, 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.sun.istack.internal.NotNull;
29 import com.sun.xml.internal.ws.api.BindingID;
30 import com.sun.xml.internal.ws.api.SOAPVersion;
31 import com.sun.xml.internal.ws.api.WSBinding;
32 import com.sun.xml.internal.ws.api.databinding.DatabindingConfig;
33 import com.sun.xml.internal.ws.api.databinding.MetadataReader;
34 import com.sun.xml.internal.ws.api.model.ExceptionType;
35 import com.sun.xml.internal.ws.api.model.MEP;
36 import com.sun.xml.internal.ws.api.model.Parameter;
37 import com.sun.xml.internal.ws.api.model.ParameterBinding;
38 import com.sun.xml.internal.ws.api.model.wsdl.WSDLBoundOperation;
39 import com.sun.xml.internal.ws.api.model.wsdl.WSDLInput;
40 import com.sun.xml.internal.ws.api.model.wsdl.WSDLPart;
41 import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort;
42 import com.sun.xml.internal.ws.binding.WebServiceFeatureList;
43 import com.sun.xml.internal.ws.model.soap.SOAPBindingImpl;
44 import com.sun.xml.internal.ws.resources.ModelerMessages;
45 import com.sun.xml.internal.ws.resources.ServerMessages;
46 import com.sun.xml.internal.ws.spi.db.BindingContext;
47 import com.sun.xml.internal.ws.spi.db.BindingHelper;
48 import com.sun.xml.internal.ws.spi.db.TypeInfo;
49 import com.sun.xml.internal.ws.spi.db.WrapperComposite;
50 import com.sun.xml.internal.ws.util.localization.Localizable;
51 import com.sun.xml.internal.org.jvnet.ws.databinding.DatabindingMode;
52
53 import javax.jws.*;
54 import javax.jws.WebParam.Mode;
55 import javax.jws.soap.SOAPBinding;
56 import javax.jws.soap.SOAPBinding.Style;
57 import javax.xml.bind.annotation.XmlElement;
58 import javax.xml.bind.annotation.XmlSeeAlso;
59 import javax.xml.namespace.QName;
60 import javax.xml.ws.*;
61 import javax.xml.ws.soap.MTOM;
62 import javax.xml.ws.soap.MTOMFeature;
63 import java.lang.annotation.Annotation;
64 import java.lang.reflect.Method;
65 import java.lang.reflect.Modifier;
66 import java.lang.reflect.ParameterizedType;
67 import java.lang.reflect.Type;
68 import java.rmi.RemoteException;
69 import java.security.AccessController;
70 import java.util.HashSet;
71 import java.util.Map;
72 import java.util.Set;
73 import java.util.StringTokenizer;
74 import java.util.TreeMap;
75 import java.util.concurrent.Future;
76 import java.util.logging.Logger;
77
78 import static javax.jws.soap.SOAPBinding.ParameterStyle.WRAPPED;
79
80 /**
81 * Creates a runtime model of a SEI (portClass).
82 *
83 * @author WS Developement Team
84 */
85 public class RuntimeModeler {
86 private final WebServiceFeatureList features;
87 private BindingID bindingId;
88 private WSBinding wsBinding;
89 private final Class portClass;
90 private AbstractSEIModelImpl model;
91 private SOAPBindingImpl defaultBinding;
92 // can be empty but never null
93 private String packageName;
94 private String targetNamespace;
95 private boolean isWrapped = true;
96 private ClassLoader classLoader;
97 private final WSDLPort binding;
98 private QName serviceName;
99 private QName portName;
100 private Set<Class> classUsesWebMethod;
101 private DatabindingConfig config;
102 private MetadataReader metadataReader;
103 /**
104 *
105 */
106 public static final String PD_JAXWS_PACKAGE_PD = ".jaxws.";
107 /**
108 *
109 */
110 public static final String JAXWS_PACKAGE_PD = "jaxws.";
111 public static final String RESPONSE = "Response";
112 public static final String RETURN = "return";
113 public static final String BEAN = "Bean";
114 public static final String SERVICE = "Service";
115 public static final String PORT = "Port";
116 public static final Class HOLDER_CLASS = Holder.class;
117 public static final Class<RemoteException> REMOTE_EXCEPTION_CLASS = RemoteException.class;
118 public static final Class<RuntimeException> RUNTIME_EXCEPTION_CLASS = RuntimeException.class;
119 public static final Class<Exception> EXCEPTION_CLASS = Exception.class;
120
121 /*public RuntimeModeler(@NotNull Class portClass, @NotNull QName serviceName, @NotNull BindingID bindingId, @NotNull WebServiceFeature... features) {
122 this(portClass, serviceName, null, bindingId, features);
123 }*/
124
125 /**
126 *
127 * creates an instance of RunTimeModeler given a <code>sei</code> and <code>binding</code>
128 * @param portClass The SEI class to be modeled.
129 * @param serviceName The ServiceName to use instead of one calculated from the implementation class
130 * @param wsdlPort {@link com.sun.xml.internal.ws.api.model.wsdl.WSDLPort}
131 * @param features web service features
132 */
133 /*public RuntimeModeler(@NotNull Class portClass, @NotNull QName serviceName, @NotNull WSDLPortImpl wsdlPort, @NotNull WebServiceFeature... features){
134 this(portClass, serviceName, wsdlPort, wsdlPort.getBinding().getBindingId(), features);
135 }*/
136
137 /*private RuntimeModeler(@NotNull Class portClass, @NotNull QName serviceName, WSDLPortImpl binding, BindingID bindingId, @NotNull WebServiceFeature... features) {
138 this.portClass = portClass;
139 this.serviceName = serviceName;
140 this.binding = binding;
141 this.bindingId = bindingId;
142 this.features = features;
143 }*/
144
145 public RuntimeModeler(@NotNull DatabindingConfig config){
146 this.portClass = (config.getEndpointClass() != null)? config.getEndpointClass() : config.getContractClass();
147 this.serviceName = config.getMappingInfo().getServiceName();
148 this.binding = config.getWsdlPort();
149 this.classLoader = config.getClassLoader();
150 this.portName = config.getMappingInfo().getPortName();
151 this.config = config;
152 this.wsBinding = config.getWSBinding();
153 metadataReader = config.getMetadataReader();
154 if (metadataReader == null) metadataReader = new ReflectAnnotationReader();
155 if (wsBinding != null) {
156 this.bindingId = wsBinding.getBindingId();
157 if (config.getFeatures() != null) wsBinding.getFeatures().mergeFeatures(config.getFeatures(), false);
158 if (binding != null) wsBinding.getFeatures().mergeFeatures(binding.getFeatures(), false);
159 this.features = WebServiceFeatureList.toList(wsBinding.getFeatures());
160 } else {
161 this.bindingId = config.getMappingInfo().getBindingID();
162 if (binding != null) bindingId = binding.getBinding().getBindingId();
163 if (bindingId == null) bindingId = getDefaultBindingID();
164 this.features = WebServiceFeatureList.toList(config.getFeatures());
165 if (!features.contains(MTOMFeature.class)) {
166 MTOM mtomAn = getAnnotation(portClass, MTOM.class);
167 if (mtomAn != null) features.add(WebServiceFeatureList.getFeature(mtomAn));
168 }
169 this.wsBinding = bindingId.createBinding(features);
170 }
171 }
172
173 private BindingID getDefaultBindingID() {
174 BindingType bt = getAnnotation(portClass, BindingType.class);
175 String id = (bt != null) ? bt.value() : javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_BINDING;
176 return BindingID.parse(id);
177 }
178
179 /**
180 * sets the classloader to be used when loading classes by the <code>RuntimeModeler</code>.
181 * @param classLoader ClassLoader used to load classes
182 */
183 public void setClassLoader(ClassLoader classLoader) {
184 this.classLoader = classLoader;
185 }
186
187 /**
188 * sets the PortName to be used by the <code>RuntimeModeler</code>.
189 * @param portName The PortName to be used instead of the PortName
190 * retrieved via annotations
191 */
192 public void setPortName(QName portName) {
193 this.portName = portName;
194 }
195
196 private <T extends Annotation> T getAnnotation(final Class<?> clazz, final Class<T> T) {
197 return metadataReader.getAnnotation(T, clazz);
198 // return AccessController.doPrivileged(new PrivilegedAction<T>() {
199 // public T run() {
200 // return clazz.getAnnotation(T);
201 // }
202 // });
203 }
204
205 private <T extends Annotation> T getAnnotation(final Method method, final Class<T> T) {
206 return metadataReader.getAnnotation(T, method);
207 // return AccessController.doPrivileged(new PrivilegedAction<T>() {
208 // public T run() {
209 // return method.getAnnotation(T);
210 // }
211 // });
212 }
213
214 private Annotation[] getAnnotations(final Method method) {
215 return metadataReader.getAnnotations(method);
216 }
217
218 private Annotation[] getAnnotations(final Class<?> c) {
219 return metadataReader.getAnnotations(c);
220 }
221 private Annotation[][] getParamAnnotations(final Method method) {
222 return metadataReader.getParameterAnnotations(method);
223 // return AccessController.doPrivileged(new PrivilegedAction<Annotation[][]>() {
224 // public Annotation[][] run() {
225 // return method.getParameterAnnotations();
226 // }
227 // });
228 }
229
230 private static final Logger logger =
231 Logger.getLogger(
232 com.sun.xml.internal.ws.util.Constants.LoggingDomain + ".server");
233
234 //currently has many local vars which will be eliminated after debugging issues
235 //first draft
236 /**
237 * builds the runtime model from the <code>portClass</code> using the binding ID <code>bindingId</code>.
238 * @return the runtime model for the <code>portClass</code>.
239 */
240 public AbstractSEIModelImpl buildRuntimeModel() {
241 model = new SOAPSEIModel(features);
242 model.contractClass = config.getContractClass();
243 model.endpointClass = config.getEndpointClass();
244 model.classLoader = this.classLoader;
245 model.wsBinding = wsBinding;
246 model.databindingInfo.properties().putAll(config.properties());
247 if (model.contractClass == null) model.contractClass = portClass;
248 if (model.endpointClass == null && !portClass.isInterface()) model.endpointClass = portClass;
249 Class<?> seiClass = portClass;
250 metadataReader.getProperties(model.databindingInfo.properties(), portClass);
251 WebService webService = getAnnotation(portClass, WebService.class);
252 if (webService == null) {
253 throw new RuntimeModelerException("runtime.modeler.no.webservice.annotation",
254 portClass.getCanonicalName());
255 }
256 Class<?> seiFromConfig = configEndpointInterface();
257 if (webService.endpointInterface().length() > 0 || seiFromConfig != null) {
258 if (seiFromConfig != null) {
259 seiClass = seiFromConfig;
260 } else {
261 seiClass = getClass(webService.endpointInterface(), ModelerMessages.localizableRUNTIME_MODELER_CLASS_NOT_FOUND(webService.endpointInterface()));
262 }
263 model.contractClass = seiClass;
264 model.endpointClass = portClass;
265 WebService seiService = getAnnotation(seiClass, WebService.class);
266 if (seiService == null) {
267 throw new RuntimeModelerException("runtime.modeler.endpoint.interface.no.webservice",
268 webService.endpointInterface());
269 }
270
271 //check if @SOAPBinding is defined on the impl class
272 SOAPBinding sbPortClass = getAnnotation(portClass, SOAPBinding.class);
273 SOAPBinding sbSei = getAnnotation(seiClass, SOAPBinding.class);
274 if(sbPortClass != null){
275 if(sbSei == null || sbSei.style() != sbPortClass.style()|| sbSei.use() != sbPortClass.use()){
276 logger.warning(ServerMessages.RUNTIMEMODELER_INVALIDANNOTATION_ON_IMPL("@SOAPBinding", portClass.getName(), seiClass.getName()));
277 }
278 }
279 }
280 if (serviceName == null)
281 serviceName = getServiceName(portClass, metadataReader);
282 model.setServiceQName(serviceName);
283
284 // String portLocalName = portClass.getSimpleName()+PORT;
285 // if (webService.portName().length() >0) {
286 // portLocalName = webService.portName();
287 // } else if (webService.name().length() >0) {
288 // portLocalName = webService.name()+PORT;
289 // }
290 //
291 // if (portName == null)
292 // portName = new QName(serviceName.getNamespaceURI(), portLocalName);
293 // if (!portName.getNamespaceURI().equals(serviceName.getNamespaceURI())) {
294 // throw new RuntimeModelerException("runtime.modeler.portname.servicename.namespace.mismatch",
295 // serviceName, portName);
296 // }
297
298 if (portName == null) portName = getPortName(portClass, serviceName.getNamespaceURI(), metadataReader);
299 model.setPortName(portName);
300
301 // Check if databinding is overridden in annotation.
302 DatabindingMode dbm = getAnnotation(portClass, DatabindingMode.class);
303 if (dbm != null) model.databindingInfo.setDatabindingMode(dbm.value());
304
305 processClass(seiClass);
306 if (model.getJavaMethods().size() == 0)
307 throw new RuntimeModelerException("runtime.modeler.no.operations",
308 portClass.getName());
309 model.postProcess();
310
311 // Make the configured databinding mode available to the
312 // DatabindingConfig.
313 config.properties().put(BindingContext.class.getName(),
314 model.bindingContext);
315
316 // TODO: this needs to be fixed properly --
317 // when we are building RuntimeModel first before building WSDLModel,
318 // we still need to do this correctly
319 if(binding!=null)
320 model.freeze(binding);
321 return model;
322 }
323
324 private Class configEndpointInterface() {
325 if (config.getEndpointClass() == null ||
326 config.getEndpointClass().isInterface() ) return null; //client proxy Interface
327 return config.getContractClass();
328 }
329
330 /**
331 * utility method to load classes
332 * @param className the name of the class to load
333 * @param errorMessage
334 * Error message to use when the resolution fails.
335 * @return the class specified by <code>className</code>
336 */
337 private Class getClass(String className, Localizable errorMessage) {
338 try {
339 if (classLoader == null)
340 return Thread.currentThread().getContextClassLoader().loadClass(className);
341 else
342 return classLoader.loadClass(className);
343 } catch (ClassNotFoundException e) {
344 throw new RuntimeModelerException(errorMessage);
345 }
346 }
347
348 private Class getRequestWrapperClass(String className, Method method, QName reqElemName) {
349 ClassLoader loader = (classLoader == null) ? Thread.currentThread().getContextClassLoader() : classLoader;
350 try {
351 return loader.loadClass(className);
352 } catch (ClassNotFoundException e) {
353 logger.fine("Dynamically creating request wrapper Class " + className);
354 return WrapperBeanGenerator.createRequestWrapperBean(className, method, reqElemName, loader);
355 }
356 }
357
358 private Class getResponseWrapperClass(String className, Method method, QName resElemName) {
359 ClassLoader loader = (classLoader == null) ? Thread.currentThread().getContextClassLoader() : classLoader;
360 try {
361 return loader.loadClass(className);
362 } catch (ClassNotFoundException e) {
363 logger.fine("Dynamically creating response wrapper bean Class " + className);
364 return WrapperBeanGenerator.createResponseWrapperBean(className, method, resElemName, loader);
365 }
366 }
367
368
369 private Class getExceptionBeanClass(String className, Class exception, String name, String namespace) {
370 ClassLoader loader = (classLoader == null) ? Thread.currentThread().getContextClassLoader() : classLoader;
371 try {
372 return loader.loadClass(className);
373 } catch (ClassNotFoundException e) {
374 logger.fine("Dynamically creating exception bean Class " + className);
375 return WrapperBeanGenerator.createExceptionBean(className, exception, targetNamespace, name, namespace, loader);
376 }
377 }
378
379 protected void determineWebMethodUse(Class clazz) {
380 if (clazz == null)
381 return;
382 if (!clazz.isInterface()) {
383 if (clazz == Object.class)
384 return;
385 WebMethod webMethod;
386 for (Method method : clazz.getMethods()) {
387 if (method.getDeclaringClass()!=clazz)
388 continue;
389 webMethod = getAnnotation(method, WebMethod.class);
390 if (webMethod != null && !webMethod.exclude()) {
391 classUsesWebMethod.add(clazz);
392 break;
393 }
394 }
395 }
396 determineWebMethodUse(clazz.getSuperclass());
397 }
398
399 void processClass(Class clazz) {
400 classUsesWebMethod = new HashSet<Class>();
401 determineWebMethodUse(clazz);
402 WebService webService = getAnnotation(clazz, WebService.class);
403 QName portTypeName = getPortTypeName(clazz, targetNamespace, metadataReader);
404 // String portTypeLocalName = clazz.getSimpleName();
405 // if (webService.name().length() >0)
406 // portTypeLocalName = webService.name();
407 //
408 // targetNamespace = webService.targetNamespace();
409 packageName = "";
410 if (clazz.getPackage() != null)
411 packageName = clazz.getPackage().getName();
412 // if (targetNamespace.length() == 0) {
413 // targetNamespace = getNamespace(packageName);
414 // }
415 // model.setTargetNamespace(targetNamespace);
416 // QName portTypeName = new QName(targetNamespace, portTypeLocalName);
417 targetNamespace = portTypeName.getNamespaceURI();
418 model.setPortTypeName(portTypeName);
419 model.setTargetNamespace(targetNamespace);
420 model.setWSDLLocation(webService.wsdlLocation());
421
422 SOAPBinding soapBinding = getAnnotation(clazz, SOAPBinding.class);
423 if (soapBinding != null) {
424 if (soapBinding.style() == SOAPBinding.Style.RPC && soapBinding.parameterStyle() == SOAPBinding.ParameterStyle.BARE) {
425 throw new RuntimeModelerException("runtime.modeler.invalid.soapbinding.parameterstyle",
426 soapBinding, clazz);
427
428 }
429 isWrapped = soapBinding.parameterStyle()== WRAPPED;
430 }
431 defaultBinding = createBinding(soapBinding);
432 /*
433 * if clazz != portClass then there is an SEI. If there is an
434 * SEI, then all methods should be processed. However, if there is
435 * no SEI, and the implementation class uses at least one
436 * WebMethod annotation, then only methods with this annotation
437 * will be processed.
438 */
439 /* if (clazz == portClass) {
440 WebMethod webMethod;
441 for (Method method : clazz.getMethods()) {
442 webMethod = getPrivMethodAnnotation(method, WebMethod.class);
443 if (webMethod != null &&
444 !webMethod.exclude()) {
445 usesWebMethod = true;
446 break;
447 }
448 }
449 }*/
450
451 for (Method method : clazz.getMethods()) {
452 if (!clazz.isInterface()) { // if clazz is SEI, then all methods are web methods
453 if (!getBooleanSystemProperty("com.sun.xml.internal.ws.legacyWebMethod")) { // legacy webMethod computation behaviour to be used
454 if (!isWebMethodBySpec(method, clazz))
455 continue;
456 } else {
457 if (method.getDeclaringClass() == Object.class || !isWebMethod(method))
458 continue;
459 }
460 }
461 // TODO: binding can be null. We need to figure out how to post-process
462 // RuntimeModel to link to WSDLModel
463 processMethod(method);
464 }
465 //Add additional jaxb classes referenced by {@link XmlSeeAlso}
466 XmlSeeAlso xmlSeeAlso = getAnnotation(clazz, XmlSeeAlso.class);
467 if(xmlSeeAlso != null)
468 model.addAdditionalClasses(xmlSeeAlso.value());
469 }
470
471 /*
472 * Section 3.3 of spec
473 * Otherwise, the class implicitly defines a service endpoint interface (SEI) which
474 * comprises all of the public methods that satisfy one of the following conditions:
475 * 1. They are annotated with the javax.jws.WebMethod annotation with the exclude element set to
476 * false or missing (since false is the default for this annotation element).
477 * 2. They are not annotated with the javax.jws.WebMethod annotation but their declaring class has a
478 * javax.jws.WebService annotation.
479 *
480 * also the method should non-static or non-final
481 */
482 private boolean isWebMethodBySpec(Method method, Class clazz) {
483
484 int modifiers = method.getModifiers();
485 boolean staticFinal = Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers);
486
487 assert Modifier.isPublic(modifiers);
488 assert !clazz.isInterface();
489
490 WebMethod webMethod = getAnnotation(method, WebMethod.class);
491 if (webMethod != null) {
492 if (webMethod.exclude()) {
493 return false; // @WebMethod(exclude="true")
494 }
495 if (staticFinal) {
496 throw new RuntimeModelerException(ModelerMessages.localizableRUNTIME_MODELER_WEBMETHOD_MUST_BE_NONSTATICFINAL(method));
497 }
498 return true; // @WebMethod
499 }
500
501 if (staticFinal) {
502 return false;
503 }
504
505 Class declClass = method.getDeclaringClass();
506 return getAnnotation(declClass, WebService.class) != null;
507 }
508
509 private boolean isWebMethod(Method method) {
510 int modifiers = method.getModifiers();
511 if (Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers))
512 return false;
513
514 Class clazz = method.getDeclaringClass();
515 boolean declHasWebService = getAnnotation(clazz, WebService.class) != null;
516 WebMethod webMethod = getAnnotation(method, WebMethod.class);
517 if (webMethod != null && !webMethod.exclude() && declHasWebService)
518 return true;
519 return declHasWebService && !classUsesWebMethod.contains(clazz);
520 }
521
522 /**
523 * creates a runtime model <code>SOAPBinding</code> from a <code>javax.jws.soap.SOAPBinding</code> object
524 * @param soapBinding the <code>javax.jws.soap.SOAPBinding</code> to model
525 * @return returns the runtime model SOAPBinding corresponding to <code>soapBinding</code>
526 */
527 protected SOAPBindingImpl createBinding(SOAPBinding soapBinding) {
528 SOAPBindingImpl rtSOAPBinding = new SOAPBindingImpl();
529 Style style = soapBinding!=null ? soapBinding.style() : Style.DOCUMENT;
530 rtSOAPBinding.setStyle(style);
531 assert bindingId != null;
532 model.bindingId = bindingId;
533 SOAPVersion soapVersion = bindingId.getSOAPVersion();
534 rtSOAPBinding.setSOAPVersion(soapVersion);
535 return rtSOAPBinding;
536 }
537
538 /**
539 * gets the namespace <code>String</code> for a given <code>packageName</code>
540 * @param packageName the name of the package used to find a namespace.
541 * can be empty.
542 * @return the namespace for the specified <code>packageName</code>
543 */
544 public static String getNamespace(@NotNull String packageName) {
545 if (packageName.length() == 0)
546 return null;
547
548 StringTokenizer tokenizer = new StringTokenizer(packageName, ".");
549 String[] tokens;
550 if (tokenizer.countTokens() == 0) {
551 tokens = new String[0];
552 } else {
553 tokens = new String[tokenizer.countTokens()];
554 for (int i=tokenizer.countTokens()-1; i >= 0; i--) {
555 tokens[i] = tokenizer.nextToken();
556 }
557 }
558 StringBuilder namespace = new StringBuilder("http://");
559 for (int i=0; i<tokens.length; i++) {
560 if (i!=0)
561 namespace.append('.');
562 namespace.append(tokens[i]);
563 }
564 namespace.append('/');
565 return namespace.toString();
566 }
567
568 /*
569 * Returns true if an exception is service specific exception as per JAX-WS rules.
570 * @param exception
571 * @return
572 */
573 private boolean isServiceException(Class<?> exception) {
574 return EXCEPTION_CLASS.isAssignableFrom(exception) &&
575 !(RUNTIME_EXCEPTION_CLASS.isAssignableFrom(exception) || REMOTE_EXCEPTION_CLASS.isAssignableFrom(exception));
576 }
577
578 /**
579 * creates the runtime model for a method on the <code>portClass</code>
580 * @param method the method to model
581 */
582 private void processMethod(Method method) {
583 int mods = method.getModifiers();
584 WebMethod webMethod = getAnnotation(method, WebMethod.class);
585 /*
586 validations are already done
587
588 if (!Modifier.isPublic(mods) || Modifier.isStatic(mods)) {
589 if(webMethod != null) {
590 // if the user put @WebMethod on these non-qualifying method,
591 // it's an error
592 if(Modifier.isStatic(mods))
593 throw new RuntimeModelerException(ModelerMessages.localizableRUNTIME_MODELER_WEBMETHOD_MUST_BE_NONSTATIC(method));
594 else
595 throw new RuntimeModelerException(ModelerMessages.localizableRUNTIME_MODELER_WEBMETHOD_MUST_BE_PUBLIC(method));
596 }
597 return;
598 }
599
600 if (webMethod != null && webMethod.exclude())
601 return;
602 */
603
604 String methodName = method.getName();
605 boolean isOneway = (getAnnotation(method, Oneway.class) != null);
606
607 //Check that oneway methods don't thorw any checked exceptions
608 if (isOneway) {
609 for (Class<?> exception : method.getExceptionTypes()) {
610 if(isServiceException(exception)) {
611 throw new RuntimeModelerException("runtime.modeler.oneway.operation.no.checked.exceptions",
612 portClass.getCanonicalName(), methodName, exception.getName());
613 }
614 }
615 }
616
617 JavaMethodImpl javaMethod;
618 //Class implementorClass = portClass;
619 if (method.getDeclaringClass()==portClass) {
620 javaMethod = new JavaMethodImpl(model,method,method,metadataReader);
621 } else {
622 try {
623 Method tmpMethod = portClass.getMethod(method.getName(),
624 method.getParameterTypes());
625 javaMethod = new JavaMethodImpl(model,tmpMethod,method,metadataReader);
626 } catch (NoSuchMethodException e) {
627 throw new RuntimeModelerException("runtime.modeler.method.not.found",
628 method.getName(), portClass.getName());
629 }
630 }
631
632
633
634 //set MEP -oneway, async, req/resp
635 MEP mep = getMEP(method);
636 javaMethod.setMEP(mep);
637
638 String action = null;
639
640
641 String operationName = method.getName();
642 if (webMethod != null ) {
643 action = webMethod.action();
644 operationName = webMethod.operationName().length() > 0 ?
645 webMethod.operationName() :
646 operationName;
647 }
648
649 //override the @WebMethod.action value by the one from the WSDL
650 if(binding != null){
651 WSDLBoundOperation bo = binding.getBinding().get(new QName(targetNamespace, operationName));
652 if(bo != null){
653 WSDLInput wsdlInput = bo.getOperation().getInput();
654 String wsaAction = wsdlInput.getAction();
655 if(wsaAction != null && !wsdlInput.isDefaultAction())
656 action = wsaAction;
657 else
658 action = bo.getSOAPAction();
659 }
660 }
661
662 javaMethod.setOperationQName(new QName(targetNamespace,operationName));
663 SOAPBinding methodBinding = getAnnotation(method, SOAPBinding.class);
664 if(methodBinding != null && methodBinding.style() == SOAPBinding.Style.RPC) {
665 logger.warning(ModelerMessages.RUNTIMEMODELER_INVALID_SOAPBINDING_ON_METHOD(methodBinding, method.getName(), method.getDeclaringClass().getName()));
666 } else if (methodBinding == null && !method.getDeclaringClass().equals(portClass)) {
667 methodBinding = getAnnotation(method.getDeclaringClass(), SOAPBinding.class);
668 if (methodBinding != null && methodBinding.style() == SOAPBinding.Style.RPC && methodBinding.parameterStyle() == SOAPBinding.ParameterStyle.BARE) {
669 throw new RuntimeModelerException("runtime.modeler.invalid.soapbinding.parameterstyle",
670 methodBinding, method.getDeclaringClass());
671 }
672 }
673
674 if(methodBinding!= null && defaultBinding.getStyle() != methodBinding.style()) {
675 throw new RuntimeModelerException("runtime.modeler.soapbinding.conflict",
676 methodBinding.style(), method.getName(),defaultBinding.getStyle());
677 }
678
679 boolean methodIsWrapped = isWrapped;
680 Style style = defaultBinding.getStyle();
681 if (methodBinding != null) {
682 SOAPBindingImpl mySOAPBinding = createBinding(methodBinding);
683 style = mySOAPBinding.getStyle();
684 if (action != null)
685 mySOAPBinding.setSOAPAction(action);
686 methodIsWrapped = methodBinding.parameterStyle().equals(
687 WRAPPED);
688 javaMethod.setBinding(mySOAPBinding);
689 } else {
690 SOAPBindingImpl sb = new SOAPBindingImpl(defaultBinding);
691 if (action != null) {
692 sb.setSOAPAction(action);
693 } else {
694 String defaults = SOAPVersion.SOAP_11 == sb.getSOAPVersion() ? "" : null;
695 sb.setSOAPAction(defaults);
696 }
697 javaMethod.setBinding(sb);
698 }
699 if (!methodIsWrapped) {
700 processDocBareMethod(javaMethod, operationName, method);
701 } else if (style.equals(Style.DOCUMENT)) {
702 processDocWrappedMethod(javaMethod, methodName, operationName,
703 method);
704 } else {
705 processRpcMethod(javaMethod, methodName, operationName, method);
706 }
707 model.addJavaMethod(javaMethod);
708 }
709
710 private MEP getMEP(Method m){
711 if (getAnnotation(m, Oneway.class)!= null) {
712 return MEP.ONE_WAY;
713 }
714 if(Response.class.isAssignableFrom(m.getReturnType())){
715 return MEP.ASYNC_POLL;
716 }else if(Future.class.isAssignableFrom(m.getReturnType())){
717 return MEP.ASYNC_CALLBACK;
718 }
719 return MEP.REQUEST_RESPONSE;
720 }
721
722 /**
723 * models a document/literal wrapped method
724 * @param javaMethod the runtime model <code>JavaMethod</code> instance being created
725 * @param methodName the runtime model <code>JavaMethod</code> instance being created
726 * @param operationName the runtime model <code>JavaMethod</code> instance being created
727 * @param method the <code>method</code> to model
728 */
729 protected void processDocWrappedMethod(JavaMethodImpl javaMethod, String methodName,
730 String operationName, Method method) {
731 boolean methodHasHeaderParams = false;
732 boolean isOneway = getAnnotation(method, Oneway.class)!= null;
733 RequestWrapper reqWrapper = getAnnotation(method,RequestWrapper.class);
734 ResponseWrapper resWrapper = getAnnotation(method,ResponseWrapper.class);
735 String beanPackage = packageName + PD_JAXWS_PACKAGE_PD;
736 if (packageName == null || (packageName != null && packageName.length() == 0))
737 beanPackage = JAXWS_PACKAGE_PD;
738 String requestClassName;
739 if(reqWrapper != null && reqWrapper.className().length()>0){
740 requestClassName = reqWrapper.className();
741 }else{
742 requestClassName = beanPackage + capitalize(method.getName());
743 }
744
745
746 String responseClassName;
747 if(resWrapper != null && resWrapper.className().length()>0){
748 responseClassName = resWrapper.className();
749 }else{
750 responseClassName = beanPackage + capitalize(method.getName()) + RESPONSE;
751 }
752
753 String reqName = operationName;
754 String reqNamespace = targetNamespace;
755 String reqPartName = "parameters";
756 if (reqWrapper != null) {
757 if (reqWrapper.targetNamespace().length() > 0)
758 reqNamespace = reqWrapper.targetNamespace();
759 if (reqWrapper.localName().length() > 0)
760 reqName = reqWrapper.localName();
761 try {
762 if (reqWrapper.partName().length() > 0)
763 reqPartName = reqWrapper.partName();
764 } catch(LinkageError e) {
765 //2.1 API dopes n't have this method
766 //Do nothing, just default to "parameters"
767 }
768 }
769 QName reqElementName = new QName(reqNamespace, reqName);
770 javaMethod.setRequestPayloadName(reqElementName);
771 Class requestClass = getRequestWrapperClass(requestClassName, method, reqElementName);
772
773 Class responseClass = null;
774 String resName = operationName+"Response";
775 String resNamespace = targetNamespace;
776 QName resElementName = null;
777 String resPartName = "parameters";
778 if (!isOneway) {
779 if (resWrapper != null) {
780 if (resWrapper.targetNamespace().length() > 0)
781 resNamespace = resWrapper.targetNamespace();
782 if (resWrapper.localName().length() > 0)
783 resName = resWrapper.localName();
784 try {
785 if (resWrapper.partName().length() > 0)
786 resPartName = resWrapper.partName();
787 } catch (LinkageError e) {
788 //2.1 API does n't have this method
789 //Do nothing, just default to "parameters"
790 }
791 }
792 resElementName = new QName(resNamespace, resName);
793 responseClass = getResponseWrapperClass(responseClassName, method, resElementName);
794 }
795
796 TypeInfo typeRef =
797 new TypeInfo(reqElementName, requestClass);
798 typeRef.setNillable(false);
799 WrapperParameter requestWrapper = new WrapperParameter(javaMethod, typeRef,
800 Mode.IN, 0);
801 requestWrapper.setPartName(reqPartName);
802 requestWrapper.setBinding(ParameterBinding.BODY);
803 javaMethod.addParameter(requestWrapper);
804 WrapperParameter responseWrapper = null;
805 if (!isOneway) {
806 typeRef = new TypeInfo(resElementName, responseClass);
807 typeRef.setNillable(false);
808 responseWrapper = new WrapperParameter(javaMethod, typeRef, Mode.OUT, -1);
809 javaMethod.addParameter(responseWrapper);
810 responseWrapper.setBinding(ParameterBinding.BODY);
811 }
812
813 // return value
814
815
816 WebResult webResult = getAnnotation(method, WebResult.class);
817 XmlElement xmlElem = getAnnotation(method, XmlElement.class);
818 QName resultQName = getReturnQName(method, webResult, xmlElem);
819 Class returnType = method.getReturnType();
820 boolean isResultHeader = false;
821 if (webResult != null) {
822 isResultHeader = webResult.header();
823 methodHasHeaderParams = isResultHeader || methodHasHeaderParams;
824 if (isResultHeader && xmlElem != null) {
825 throw new RuntimeModelerException("@XmlElement cannot be specified on method "+method+" as the return value is bound to header");
826 }
827 if (resultQName.getNamespaceURI().length() == 0 && webResult.header()) {
828 // headers must have a namespace
829 resultQName = new QName(targetNamespace, resultQName.getLocalPart());
830 }
831 }
832
833 if(javaMethod.isAsync()){
834 returnType = getAsyncReturnType(method, returnType);
835 resultQName = new QName(RETURN);
836 }
837
838 if (!isOneway && (returnType != null) && (!returnType.getName().equals("void"))) {
839 Annotation[] rann = getAnnotations(method);
840 if (resultQName.getLocalPart() != null) {
841 TypeInfo rTypeReference = new TypeInfo(resultQName, returnType, rann);
842 metadataReader.getProperties(rTypeReference.properties(), method);
843 ParameterImpl returnParameter = new ParameterImpl(javaMethod, rTypeReference, Mode.OUT, -1);
844 if (isResultHeader) {
845 returnParameter.setBinding(ParameterBinding.HEADER);
846 javaMethod.addParameter(returnParameter);
847 } else {
848 returnParameter.setBinding(ParameterBinding.BODY);
849 responseWrapper.addWrapperChild(returnParameter);
850 }
851 }
852 }
853
854 //get WebParam
855 Class<?>[] parameterTypes = method.getParameterTypes();
856 Type[] genericParameterTypes = method.getGenericParameterTypes();
857 Annotation[][] pannotations = getParamAnnotations(method);
858 int pos = 0;
859 for (Class clazzType : parameterTypes) {
860 String partName=null;
861 String paramName = "arg"+pos;
862 //String paramNamespace = "";
863 boolean isHeader = false;
864
865 if(javaMethod.isAsync() && AsyncHandler.class.isAssignableFrom(clazzType)){
866 continue;
867 }
868
869 boolean isHolder = HOLDER_CLASS.isAssignableFrom(clazzType);
870 //set the actual type argument of Holder in the TypeReference
871 if (isHolder) {
872 if(clazzType==Holder.class){
873 clazzType = BindingHelper.erasure(((ParameterizedType)genericParameterTypes[pos]).getActualTypeArguments()[0]);
874 }
875 }
876 Mode paramMode = isHolder ? Mode.INOUT : Mode.IN;
877 WebParam webParam = null;
878 xmlElem = null;
879 for (Annotation annotation : pannotations[pos]) {
880 if (annotation.annotationType() == WebParam.class)
881 webParam = (WebParam)annotation;
882 else if (annotation.annotationType() == XmlElement.class)
883 xmlElem = (XmlElement)annotation;
884 }
885
886 QName paramQName = getParameterQName(method, webParam, xmlElem, paramName);
887 if (webParam != null) {
888 isHeader = webParam.header();
889 methodHasHeaderParams = isHeader || methodHasHeaderParams;
890 if (isHeader && xmlElem != null) {
891 throw new RuntimeModelerException("@XmlElement cannot be specified on method "+method+" parameter that is bound to header");
892 }
893 if(webParam.partName().length() > 0)
894 partName = webParam.partName();
895 else
896 partName = paramQName.getLocalPart();
897 if (isHeader && paramQName.getNamespaceURI().equals("")) { // headers cannot be in empty namespace
898 paramQName = new QName(targetNamespace, paramQName.getLocalPart());
899 }
900 paramMode = webParam.mode();
901 if (isHolder && paramMode == Mode.IN)
902 paramMode = Mode.INOUT;
903 }
904 typeRef =
905 new TypeInfo(paramQName, clazzType, pannotations[pos]);
906 metadataReader.getProperties(typeRef.properties(), method, pos);
907 ParameterImpl param = new ParameterImpl(javaMethod, typeRef, paramMode, pos++);
908
909 if (isHeader) {
910 param.setBinding(ParameterBinding.HEADER);
911 javaMethod.addParameter(param);
912 param.setPartName(partName);
913 } else {
914 param.setBinding(ParameterBinding.BODY);
915 if (paramMode!=Mode.OUT) {
916 requestWrapper.addWrapperChild(param);
917 }
918 if (paramMode!=Mode.IN) {
919 if (isOneway) {
920 throw new RuntimeModelerException("runtime.modeler.oneway.operation.no.out.parameters",
921 portClass.getCanonicalName(), methodName);
922 }
923 responseWrapper.addWrapperChild(param);
924 }
925 }
926 }
927
928 //If the method has any parameter or return type that is bound to a header, use "result" as part name to avoid
929 // name collison of same input part name and output part name ("parameters") shown up as param names on the
930 // client mapping.
931 if(methodHasHeaderParams) {
932 resPartName = "result";
933 }
934 if(responseWrapper != null)
935 responseWrapper.setPartName(resPartName);
936 processExceptions(javaMethod, method);
937 }
938
939
940 /**
941 * models a rpc/literal method
942 * @param javaMethod the runtime model <code>JavaMethod</code> instance being created
943 * @param methodName the name of the <code>method</code> being modeled.
944 * @param operationName the WSDL operation name for this <code>method</code>
945 * @param method the runtime model <code>JavaMethod</code> instance being created
946 */
947 protected void processRpcMethod(JavaMethodImpl javaMethod, String methodName,
948 String operationName, Method method) {
949 boolean isOneway = getAnnotation(method, Oneway.class) != null;
950
951 // use Map to build parameters in the part order when they are known.
952 // if part is unbound, we just put them at the end, and for that we
953 // use a large index (10000+) to avoid colliding with ordered ones.
954 // this assumes that there's no operation with # of parameters > 10000,
955 // but I think it's a pretty safe assumption - KK.
956 Map<Integer, ParameterImpl> resRpcParams = new TreeMap<Integer, ParameterImpl>();
957 Map<Integer, ParameterImpl> reqRpcParams = new TreeMap<Integer, ParameterImpl>();
958
959 //Lets take the service namespace and overwrite it with the one we get it from wsdl
960 String reqNamespace = targetNamespace;
961 String respNamespace = targetNamespace;
962
963 if(binding != null && Style.RPC.equals(binding.getBinding().getStyle())){
964 QName opQName = new QName(binding.getBinding().getPortTypeName().getNamespaceURI(), operationName);
965 WSDLBoundOperation op = binding.getBinding().get(opQName);
966 if(op != null){
967 //it cant be null, but lets not fail and try to work with service namespce
968 if(op.getRequestNamespace() != null){
969 reqNamespace = op.getRequestNamespace();
970 }
971
972 //it cant be null, but lets not fail and try to work with service namespce
973 if(op.getResponseNamespace() != null){
974 respNamespace = op.getResponseNamespace();
975 }
976 }
977 }
978
979 QName reqElementName = new QName(reqNamespace, operationName);
980 javaMethod.setRequestPayloadName(reqElementName);
981 QName resElementName = null;
982 if (!isOneway) {
983 resElementName = new QName(respNamespace, operationName+RESPONSE);
984 }
985
986 Class wrapperType = WrapperComposite.class;
987 TypeInfo typeRef = new TypeInfo(reqElementName, wrapperType);
988 WrapperParameter requestWrapper = new WrapperParameter(javaMethod, typeRef, Mode.IN, 0);
989 requestWrapper.setInBinding(ParameterBinding.BODY);
990 javaMethod.addParameter(requestWrapper);
991 WrapperParameter responseWrapper = null;
992 if (!isOneway) {
993 typeRef = new TypeInfo(resElementName, wrapperType);
994 responseWrapper = new WrapperParameter(javaMethod, typeRef, Mode.OUT, -1);
995 responseWrapper.setOutBinding(ParameterBinding.BODY);
996 javaMethod.addParameter(responseWrapper);
997 }
998
999 Class returnType = method.getReturnType();
1000 String resultName = RETURN;
1001 String resultTNS = targetNamespace;
1002 String resultPartName = resultName;
1003 boolean isResultHeader = false;
1004 WebResult webResult = getAnnotation(method, WebResult.class);
1005
1006 if (webResult != null) {
1007 isResultHeader = webResult.header();
1008 if (webResult.name().length() > 0)
1009 resultName = webResult.name();
1010 if (webResult.partName().length() > 0) {
1011 resultPartName = webResult.partName();
1012 if (!isResultHeader)
1013 resultName = resultPartName;
1014 } else
1015 resultPartName = resultName;
1016 if (webResult.targetNamespace().length() > 0)
1017 resultTNS = webResult.targetNamespace();
1018 isResultHeader = webResult.header();
1019 }
1020 QName resultQName;
1021 if (isResultHeader)
1022 resultQName = new QName(resultTNS, resultName);
1023 else
1024 resultQName = new QName(resultName);
1025
1026 if(javaMethod.isAsync()){
1027 returnType = getAsyncReturnType(method, returnType);
1028 }
1029
1030 if (!isOneway && returnType!=null && returnType!=void.class) {
1031 Annotation[] rann = getAnnotations(method);
1032 TypeInfo rTypeReference = new TypeInfo(resultQName, returnType, rann);
1033 metadataReader.getProperties(rTypeReference.properties(), method);
1034 rTypeReference.setGenericType(method.getGenericReturnType());
1035 ParameterImpl returnParameter = new ParameterImpl(javaMethod, rTypeReference, Mode.OUT, -1);
1036 returnParameter.setPartName(resultPartName);
1037 if(isResultHeader){
1038 returnParameter.setBinding(ParameterBinding.HEADER);
1039 javaMethod.addParameter(returnParameter);
1040 rTypeReference.setGlobalElement(true);
1041 }else{
1042 ParameterBinding rb = getBinding(operationName, resultPartName, false, Mode.OUT);
1043 returnParameter.setBinding(rb);
1044 if(rb.isBody()){
1045 rTypeReference.setGlobalElement(false);
1046 WSDLPart p = getPart(new QName(targetNamespace,operationName), resultPartName, Mode.OUT);
1047 if(p == null)
1048 resRpcParams.put(resRpcParams.size()+10000, returnParameter);
1049 else
1050 resRpcParams.put(p.getIndex(), returnParameter);
1051 }else{
1052 javaMethod.addParameter(returnParameter);
1053 }
1054 }
1055 }
1056
1057 //get WebParam
1058 Class<?>[] parameterTypes = method.getParameterTypes();
1059 Type[] genericParameterTypes = method.getGenericParameterTypes();
1060 Annotation[][] pannotations = getParamAnnotations(method);
1061 int pos = 0;
1062 for (Class clazzType : parameterTypes) {
1063 String paramName = "";
1064 String paramNamespace = "";
1065 String partName = "";
1066 boolean isHeader = false;
1067
1068 if(javaMethod.isAsync() && AsyncHandler.class.isAssignableFrom(clazzType)){
1069 continue;
1070 }
1071
1072 boolean isHolder = HOLDER_CLASS.isAssignableFrom(clazzType);
1073 //set the actual type argument of Holder in the TypeReference
1074 if (isHolder) {
1075 if (clazzType==Holder.class)
1076 clazzType = BindingHelper.erasure(((ParameterizedType)genericParameterTypes[pos]).getActualTypeArguments()[0]);
1077 }
1078 Mode paramMode = isHolder ? Mode.INOUT : Mode.IN;
1079 for (Annotation annotation : pannotations[pos]) {
1080 if (annotation.annotationType() == javax.jws.WebParam.class) {
1081 javax.jws.WebParam webParam = (javax.jws.WebParam) annotation;
1082 paramName = webParam.name();
1083 partName = webParam.partName();
1084 isHeader = webParam.header();
1085 WebParam.Mode mode = webParam.mode();
1086 paramNamespace = webParam.targetNamespace();
1087 if (isHolder && mode == Mode.IN)
1088 mode = Mode.INOUT;
1089 paramMode = mode;
1090 break;
1091 }
1092 }
1093
1094 if (paramName.length() == 0) {
1095 paramName = "arg"+pos;
1096 }
1097 if (partName.length() == 0) {
1098 partName = paramName;
1099 } else if (!isHeader) {
1100 paramName = partName;
1101 }
1102 if (partName.length() == 0) {
1103 partName = paramName;
1104 }
1105
1106 QName paramQName;
1107 if (!isHeader) {
1108 //its rpclit body param, set namespace to ""
1109 paramQName = new QName("", paramName);
1110 } else {
1111 if (paramNamespace.length() == 0)
1112 paramNamespace = targetNamespace;
1113 paramQName = new QName(paramNamespace, paramName);
1114 }
1115 typeRef =
1116 new TypeInfo(paramQName, clazzType, pannotations[pos]);
1117 metadataReader.getProperties(typeRef.properties(), method, pos);
1118 typeRef.setGenericType(genericParameterTypes[pos]);
1119 ParameterImpl param = new ParameterImpl(javaMethod, typeRef, paramMode, pos++);
1120 param.setPartName(partName);
1121
1122 if(paramMode == Mode.INOUT){
1123 ParameterBinding pb = getBinding(operationName, partName, isHeader, Mode.IN);
1124 param.setInBinding(pb);
1125 pb = getBinding(operationName, partName, isHeader, Mode.OUT);
1126 param.setOutBinding(pb);
1127 }else{
1128 if (isHeader) {
1129 typeRef.setGlobalElement(true);
1130 param.setBinding(ParameterBinding.HEADER);
1131 } else {
1132 ParameterBinding pb = getBinding(operationName, partName, false, paramMode);
1133 param.setBinding(pb);
1134 }
1135 }
1136 if(param.getInBinding().isBody()){
1137 typeRef.setGlobalElement(false);
1138 if(!param.isOUT()){
1139 WSDLPart p = getPart(new QName(targetNamespace,operationName), partName, Mode.IN);
1140 if(p == null)
1141 reqRpcParams.put(reqRpcParams.size()+10000, param);
1142 else
1143 reqRpcParams.put(p.getIndex(), param);
1144 }
1145
1146 if(!param.isIN()){
1147 if (isOneway) {
1148 throw new RuntimeModelerException("runtime.modeler.oneway.operation.no.out.parameters",
1149 portClass.getCanonicalName(), methodName);
1150 }
1151 WSDLPart p = getPart(new QName(targetNamespace,operationName), partName, Mode.OUT);
1152 if(p == null)
1153 resRpcParams.put(resRpcParams.size()+10000, param);
1154 else
1155 resRpcParams.put(p.getIndex(), param);
1156 }
1157 }else{
1158 javaMethod.addParameter(param);
1159 }
1160 }
1161 for (ParameterImpl p : reqRpcParams.values())
1162 requestWrapper.addWrapperChild(p);
1163 for (ParameterImpl p : resRpcParams.values())
1164 responseWrapper.addWrapperChild(p);
1165 processExceptions(javaMethod, method);
1166 }
1167
1168 /**
1169 * models the exceptions thrown by <code>method</code> and adds them to the <code>javaMethod</code>
1170 * runtime model object
1171 * @param javaMethod the runtime model object to add the exception model objects to
1172 * @param method the <code>method</code> from which to find the exceptions to model
1173 */
1174 protected void processExceptions(JavaMethodImpl javaMethod, Method method) {
1175 Action actionAnn = getAnnotation(method, Action.class);
1176 FaultAction[] faultActions = {};
1177 if(actionAnn != null)
1178 faultActions = actionAnn.fault();
1179 for (Class<?> exception : method.getExceptionTypes()) {
1180
1181 //Exclude RuntimeException, RemoteException and Error etc
1182 if (!EXCEPTION_CLASS.isAssignableFrom(exception))
1183 continue;
1184 if (RUNTIME_EXCEPTION_CLASS.isAssignableFrom(exception) || REMOTE_EXCEPTION_CLASS.isAssignableFrom(exception))
1185 continue;
1186
1187 Class exceptionBean;
1188 Annotation[] anns;
1189 WebFault webFault = getAnnotation(exception, WebFault.class);
1190 Method faultInfoMethod = getWSDLExceptionFaultInfo(exception);
1191 ExceptionType exceptionType = ExceptionType.WSDLException;
1192 String namespace = targetNamespace;
1193 String name = exception.getSimpleName();
1194 String beanPackage = packageName + PD_JAXWS_PACKAGE_PD;
1195 if (packageName.length() == 0)
1196 beanPackage = JAXWS_PACKAGE_PD;
1197 String className = beanPackage+ name + BEAN;
1198 String messageName = exception.getSimpleName();
1199 if (webFault != null) {
1200 if (webFault.faultBean().length()>0)
1201 className = webFault.faultBean();
1202 if (webFault.name().length()>0)
1203 name = webFault.name();
1204 if (webFault.targetNamespace().length()>0)
1205 namespace = webFault.targetNamespace();
1206 if (webFault.messageName().length()>0)
1207 messageName = webFault.messageName();
1208 }
1209 if (faultInfoMethod == null) {
1210 exceptionBean = getExceptionBeanClass(className, exception, name, namespace);
1211 exceptionType = ExceptionType.UserDefined;
1212 anns = getAnnotations(exceptionBean);
1213 } else {
1214 exceptionBean = faultInfoMethod.getReturnType();
1215 anns = getAnnotations(faultInfoMethod);
1216 }
1217 QName faultName = new QName(namespace, name);
1218 TypeInfo typeRef = new TypeInfo(faultName, exceptionBean, anns);
1219 CheckedExceptionImpl checkedException =
1220 new CheckedExceptionImpl(javaMethod, exception, typeRef, exceptionType);
1221 checkedException.setMessageName(messageName);
1222 for(FaultAction fa: faultActions) {
1223 if(fa.className().equals(exception) && !fa.value().equals("")) {
1224 checkedException.setFaultAction(fa.value());
1225 break;
1226 }
1227 }
1228 javaMethod.addException(checkedException);
1229 }
1230 }
1231
1232 /**
1233 * returns the method that corresponds to "getFaultInfo". Returns null if this is not an
1234 * exception generated from a WSDL
1235 * @param exception the class to search for the "getFaultInfo" method
1236 * @return the method named "getFaultInfo" if this is an exception generated from WSDL or an
1237 * exception that contains the <code>WebFault</code> annotation. Otherwise it returns null
1238 */
1239 protected Method getWSDLExceptionFaultInfo(Class exception) {
1240 // if (!exception.isAnnotationPresent(WebFault.class))
1241 if (getAnnotation(exception, WebFault.class) == null)
1242 return null;
1243 try {
1244 return exception.getMethod("getFaultInfo");
1245 } catch (NoSuchMethodException e) {
1246 return null;
1247 }
1248 }
1249
1250 /**
1251 * models a document/literal bare method
1252 * @param javaMethod the runtime model <code>JavaMethod</code> instance being created
1253 * @param operationName the runtime model <code>JavaMethod</code> instance being created
1254 * @param method the runtime model <code>JavaMethod</code> instance being created
1255 */
1256 protected void processDocBareMethod(JavaMethodImpl javaMethod,
1257 String operationName, Method method) {
1258
1259 String resultName = operationName+RESPONSE;
1260 String resultTNS = targetNamespace;
1261 String resultPartName = null;
1262 boolean isResultHeader = false;
1263 WebResult webResult = getAnnotation(method, WebResult.class);
1264 if (webResult != null) {
1265 if (webResult.name().length() > 0)
1266 resultName = webResult.name();
1267 if (webResult.targetNamespace().length() > 0)
1268 resultTNS = webResult.targetNamespace();
1269 resultPartName = webResult.partName();
1270 isResultHeader = webResult.header();
1271 }
1272
1273 Class returnType = method.getReturnType();
1274 Type gReturnType = method.getGenericReturnType();
1275 if(javaMethod.isAsync()){
1276 returnType = getAsyncReturnType(method, returnType);
1277 }
1278
1279 if ((returnType != null) && (!returnType.getName().equals("void"))) {
1280 Annotation[] rann = getAnnotations(method);
1281 if (resultName != null) {
1282 QName responseQName = new QName(resultTNS, resultName);
1283 TypeInfo rTypeReference = new TypeInfo(responseQName, returnType, rann);
1284 rTypeReference.setGenericType(gReturnType);
1285 metadataReader.getProperties(rTypeReference.properties(), method);
1286 ParameterImpl returnParameter = new ParameterImpl(javaMethod, rTypeReference, Mode.OUT, -1);
1287
1288 if(resultPartName == null || (resultPartName.length() == 0)){
1289 resultPartName = resultName;
1290 }
1291 returnParameter.setPartName(resultPartName);
1292 if(isResultHeader){
1293 returnParameter.setBinding(ParameterBinding.HEADER);
1294 }else{
1295 ParameterBinding rb = getBinding(operationName, resultPartName, false, Mode.OUT);
1296 returnParameter.setBinding(rb);
1297 }
1298 javaMethod.addParameter(returnParameter);
1299 }
1300 }
1301
1302 //get WebParam
1303 Class<?>[] parameterTypes = method.getParameterTypes();
1304 Type[] genericParameterTypes = method.getGenericParameterTypes();
1305 Annotation[][] pannotations = getParamAnnotations(method);
1306 int pos = 0;
1307 for (Class clazzType : parameterTypes) {
1308 String paramName = operationName; //method.getName();
1309 String partName = null;
1310 String requestNamespace = targetNamespace;
1311 boolean isHeader = false;
1312
1313 //async
1314 if(javaMethod.isAsync() && AsyncHandler.class.isAssignableFrom(clazzType)){
1315 continue;
1316 }
1317
1318 boolean isHolder = HOLDER_CLASS.isAssignableFrom(clazzType);
1319 //set the actual type argument of Holder in the TypeReference
1320 if (isHolder) {
1321 if (clazzType==Holder.class)
1322 clazzType = BindingHelper.erasure(((ParameterizedType)genericParameterTypes[pos]).getActualTypeArguments()[0]);
1323 }
1324
1325 Mode paramMode = isHolder ? Mode.INOUT : Mode.IN;
1326 for (Annotation annotation : pannotations[pos]) {
1327 if (annotation.annotationType() == javax.jws.WebParam.class) {
1328 javax.jws.WebParam webParam = (javax.jws.WebParam) annotation;
1329 paramMode = webParam.mode();
1330 if (isHolder && paramMode == Mode.IN)
1331 paramMode = Mode.INOUT;
1332 isHeader = webParam.header();
1333 if(isHeader)
1334 paramName = "arg"+pos;
1335 if(paramMode == Mode.OUT && !isHeader)
1336 paramName = operationName+RESPONSE;
1337 if (webParam.name().length() > 0)
1338 paramName = webParam.name();
1339 partName = webParam.partName();
1340 if (!webParam.targetNamespace().equals("")) {
1341 requestNamespace = webParam.targetNamespace();
1342 }
1343 break;
1344 }
1345 }
1346
1347 QName requestQName = new QName(requestNamespace, paramName);
1348 if (!isHeader) javaMethod.setRequestPayloadName(requestQName);
1349 //doclit/wrapped
1350 TypeInfo typeRef = //operationName with upper 1 char
1351 new TypeInfo(requestQName, clazzType,
1352 pannotations[pos]);
1353 metadataReader.getProperties(typeRef.properties(), method, pos);
1354 typeRef.setGenericType(genericParameterTypes[pos]);
1355 ParameterImpl param = new ParameterImpl(javaMethod, typeRef, paramMode, pos++);
1356 if(partName == null || (partName.length() == 0)){
1357 partName = paramName;
1358 }
1359 param.setPartName(partName);
1360 if(paramMode == Mode.INOUT){
1361 ParameterBinding pb = getBinding(operationName, partName, isHeader, Mode.IN);
1362 param.setInBinding(pb);
1363 pb = getBinding(operationName, partName, isHeader, Mode.OUT);
1364 param.setOutBinding(pb);
1365 }else{
1366 if (isHeader){
1367 param.setBinding(ParameterBinding.HEADER);
1368 }else{
1369 ParameterBinding pb = getBinding(operationName, partName, false, paramMode);
1370 param.setBinding(pb);
1371 }
1372 }
1373 javaMethod.addParameter(param);
1374 }
1375 validateDocBare(javaMethod);
1376 processExceptions(javaMethod, method);
1377 }
1378
1379 // Does a conservative check if there is only one BODY part for input
1380 // and output message. We are not considering INOUT parameters at this
1381 // time since binding information is not applied. Also, there isn't
1382 // anyway to represent some cases in SEI. For example, a INOUT parameter
1383 // could be bound to body for input message, header for OUTPUT message
1384 // in wsdl:binding
1385 private void validateDocBare(JavaMethodImpl javaMethod) {
1386 int numInBodyBindings = 0;
1387 for(Parameter param : javaMethod.getRequestParameters()){
1388 if(param.getBinding().equals(ParameterBinding.BODY) && param.isIN()){
1389 numInBodyBindings++;
1390 }
1391 if(numInBodyBindings > 1){
1392 throw new RuntimeModelerException(ModelerMessages.localizableNOT_A_VALID_BARE_METHOD(portClass.getName(), javaMethod.getMethod().getName()));
1393 }
1394 }
1395
1396 int numOutBodyBindings = 0;
1397 for(Parameter param : javaMethod.getResponseParameters()){
1398 if(param.getBinding().equals(ParameterBinding.BODY) && param.isOUT()){
1399 numOutBodyBindings++;
1400 }
1401 if(numOutBodyBindings > 1){
1402 throw new RuntimeModelerException(ModelerMessages.localizableNOT_A_VALID_BARE_METHOD(portClass.getName(), javaMethod.getMethod().getName()));
1403 }
1404 }
1405 }
1406
1407 private Class getAsyncReturnType(Method method, Class returnType) {
1408 if(Response.class.isAssignableFrom(returnType)){
1409 Type ret = method.getGenericReturnType();
1410 return BindingHelper.erasure(((ParameterizedType)ret).getActualTypeArguments()[0]);
1411 }else{
1412 Type[] types = method.getGenericParameterTypes();
1413 Class[] params = method.getParameterTypes();
1414 int i = 0;
1415 for(Class cls : params){
1416 if(AsyncHandler.class.isAssignableFrom(cls)){
1417 return BindingHelper.erasure(((ParameterizedType)types[i]).getActualTypeArguments()[0]);
1418 }
1419 i++;
1420 }
1421 }
1422 return returnType;
1423 }
1424
1425 /**
1426 * utility to capitalize the first letter in a string
1427 * @param name the string to capitalize
1428 * @return the capitalized string
1429 */
1430 public static String capitalize(String name) {
1431 if (name == null || name.length() == 0) {
1432 return name;
1433 }
1434 char chars[] = name.toCharArray();
1435 chars[0] = Character.toUpperCase(chars[0]);
1436 return new String(chars);
1437 }
1438
1439 /*
1440 * Return service QName
1441 */
1442 /**
1443 * gets the <code>wsdl:serviceName</code> for a given implementation class
1444 * @param implClass the implementation class
1445 * @return the <code>wsdl:serviceName</code> for the <code>implClass</code>
1446 */
1447 public static QName getServiceName(Class<?> implClass) {
1448 return getServiceName(implClass, null);
1449 }
1450
1451 public static QName getServiceName(Class<?> implClass, boolean isStandard) {
1452 return getServiceName(implClass, null, isStandard);
1453 }
1454
1455 public static QName getServiceName(Class<?> implClass, MetadataReader reader) {
1456 return getServiceName(implClass, reader, true);
1457 }
1458
1459 public static QName getServiceName(Class<?> implClass, MetadataReader reader, boolean isStandard) {
1460 if (implClass.isInterface()) {
1461 throw new RuntimeModelerException("runtime.modeler.cannot.get.serviceName.from.interface",
1462 implClass.getCanonicalName());
1463 }
1464
1465 String name = implClass.getSimpleName()+SERVICE;
1466 String packageName = "";
1467 if (implClass.getPackage() != null)
1468 packageName = implClass.getPackage().getName();
1469
1470 WebService webService = getAnnotation(WebService.class, implClass, reader);
1471 if (isStandard && webService == null) {
1472 throw new RuntimeModelerException("runtime.modeler.no.webservice.annotation",
1473 implClass.getCanonicalName());
1474 }
1475 if (webService != null && webService.serviceName().length() > 0) {
1476 name = webService.serviceName();
1477 }
1478 String targetNamespace = getNamespace(packageName);
1479 if (webService != null && webService.targetNamespace().length() > 0) {
1480 targetNamespace = webService.targetNamespace();
1481 } else if (targetNamespace == null) {
1482 throw new RuntimeModelerException("runtime.modeler.no.package",
1483 implClass.getName());
1484 }
1485 return new QName(targetNamespace, name);
1486 }
1487
1488 /**
1489 * gets the <code>wsdl:portName</code> for a given implementation class
1490 * @param implClass the implementation class
1491 * @param targetNamespace Namespace URI for service name
1492 * @return the <code>wsdl:portName</code> for the <code>implClass</code>
1493 */
1494 public static QName getPortName(Class<?> implClass, String targetNamespace) {
1495 return getPortName(implClass, targetNamespace, null);
1496 }
1497
1498 public static QName getPortName(Class<?> implClass, String targetNamespace, boolean isStandard) {
1499 return getPortName(implClass, targetNamespace, null, isStandard);
1500 }
1501
1502 public static QName getPortName(Class<?> implClass, String targetNamespace, MetadataReader reader) {
1503 return getPortName(implClass, targetNamespace, reader, true);
1504 }
1505
1506 public static QName getPortName(Class<?> implClass, String targetNamespace, MetadataReader reader, boolean isStandard) {
1507 WebService webService = getAnnotation(WebService.class, implClass, reader);
1508 if (isStandard && webService == null) {
1509 throw new RuntimeModelerException("runtime.modeler.no.webservice.annotation",
1510 implClass.getCanonicalName());
1511 }
1512 String name;
1513 if (webService != null && webService.portName().length() > 0) {
1514 name = webService.portName();
1515 } else if (webService != null && webService.name().length() > 0) {
1516 name = webService.name()+PORT;
1517 } else {
1518 name = implClass.getSimpleName()+PORT;
1519 }
1520
1521 if (targetNamespace == null) {
1522 if (webService != null && webService.targetNamespace().length() > 0) {
1523 targetNamespace = webService.targetNamespace();
1524 } else {
1525 String packageName = null;
1526 if (implClass.getPackage() != null) {
1527 packageName = implClass.getPackage().getName();
1528 }
1529 targetNamespace = getNamespace(packageName);
1530 if (targetNamespace == null) {
1531 throw new RuntimeModelerException("runtime.modeler.no.package",
1532 implClass.getName());
1533 }
1534 }
1535
1536 }
1537
1538 return new QName(targetNamespace, name);
1539 }
1540
1541 static <A extends Annotation> A getAnnotation(Class<A> t, Class<?> cls, MetadataReader reader) {
1542 return (reader == null)? cls.getAnnotation(t) : reader.getAnnotation(t, cls);
1543 }
1544
1545 /**
1546 * Gives portType QName from implementatorClass or SEI
1547 * @param implOrSeiClass cant be null
1548 * @return <code>wsdl:portType@name</code>, null if it could not find the annotated class.
1549 */
1550 public static QName getPortTypeName(Class<?> implOrSeiClass){
1551 return getPortTypeName(implOrSeiClass, null, null);
1552 }
1553 public static QName getPortTypeName(Class<?> implOrSeiClass, String tns, MetadataReader reader){
1554 assert(implOrSeiClass != null);
1555 WebService webService = getAnnotation(WebService.class, implOrSeiClass, reader);
1556 Class<?> clazz = implOrSeiClass;
1557 if (webService == null)
1558 throw new RuntimeModelerException("runtime.modeler.no.webservice.annotation",
1559 implOrSeiClass.getCanonicalName());
1560
1561 if (!implOrSeiClass.isInterface()) {
1562 String epi = webService.endpointInterface();
1563 if (epi.length() > 0) {
1564 try {
1565 clazz = Thread.currentThread().getContextClassLoader().loadClass(epi);
1566 } catch (ClassNotFoundException e) {
1567 throw new RuntimeModelerException("runtime.modeler.class.not.found", epi);
1568 }
1569 if (!clazz.isAnnotationPresent(javax.jws.WebService.class)) {
1570 throw new RuntimeModelerException("runtime.modeler.endpoint.interface.no.webservice",
1571 webService.endpointInterface());
1572 }
1573 }
1574 }
1575
1576 webService = getAnnotation(WebService.class, clazz, reader);
1577 String name = webService.name();
1578 if(name.length() == 0){
1579 name = clazz.getSimpleName();
1580 }
1581 tns = webService.targetNamespace();
1582 if (tns == null || "".equals(tns.trim())) tns = webService.targetNamespace();
1583 if (tns.length() == 0)
1584 tns = getNamespace(clazz.getPackage().getName());
1585 if (tns == null) {
1586 throw new RuntimeModelerException("runtime.modeler.no.package", clazz.getName());
1587 }
1588 return new QName(tns, name);
1589 }
1590
1591 private ParameterBinding getBinding(String operation, String part, boolean isHeader, Mode mode){
1592 if(binding == null){
1593 if(isHeader)
1594 return ParameterBinding.HEADER;
1595 else
1596 return ParameterBinding.BODY;
1597 }
1598 QName opName = new QName(binding.getBinding().getPortType().getName().getNamespaceURI(), operation);
1599 return binding.getBinding().getBinding(opName, part, mode);
1600 }
1601
1602 private WSDLPart getPart(QName opName, String partName, Mode mode){
1603 if(binding != null){
1604 WSDLBoundOperation bo = binding.getBinding().get(opName);
1605 if(bo != null)
1606 return bo.getPart(partName, mode);
1607 }
1608 return null;
1609 }
1610
1611 private static Boolean getBooleanSystemProperty(final String prop) {
1612 return AccessController.doPrivileged(
1613 new java.security.PrivilegedAction<Boolean>() {
1614 public Boolean run() {
1615 String value = System.getProperty(prop);
1616 return value != null ? Boolean.valueOf(value) : Boolean.FALSE;
1617 }
1618 }
1619 );
1620 }
1621
1622 private static QName getReturnQName(Method method, WebResult webResult, XmlElement xmlElem) {
1623 String webResultName = null;
1624 if (webResult != null && webResult.name().length() > 0) {
1625 webResultName = webResult.name();
1626 }
1627 String xmlElemName = null;
1628 if (xmlElem != null && !xmlElem.name().equals("##default")) {
1629 xmlElemName = xmlElem.name();
1630 }
1631 if (xmlElemName != null && webResultName != null && !xmlElemName.equals(webResultName)) {
1632 throw new RuntimeModelerException("@XmlElement(name)="+xmlElemName+" and @WebResult(name)="+webResultName+" are different for method " +method);
1633 }
1634 String localPart = RETURN;
1635 if (webResultName != null) {
1636 localPart = webResultName;
1637 } else if (xmlElemName != null) {
1638 localPart = xmlElemName;
1639 }
1640
1641 String webResultNS = null;
1642 if (webResult != null && webResult.targetNamespace().length() > 0) {
1643 webResultNS = webResult.targetNamespace();
1644 }
1645 String xmlElemNS = null;
1646 if (xmlElem != null && !xmlElem.namespace().equals("##default")) {
1647 xmlElemNS = xmlElem.namespace();
1648 }
1649 if (xmlElemNS != null && webResultNS != null && !xmlElemNS.equals(webResultNS)) {
1650 throw new RuntimeModelerException("@XmlElement(namespace)="+xmlElemNS+" and @WebResult(targetNamespace)="+webResultNS+" are different for method " +method);
1651 }
1652 String ns = "";
1653 if (webResultNS != null) {
1654 ns = webResultNS;
1655 } else if (xmlElemNS != null) {
1656 ns = xmlElemNS;
1657 }
1658
1659 return new QName(ns, localPart);
1660 }
1661
1662 private static QName getParameterQName(Method method, WebParam webParam, XmlElement xmlElem, String paramDefault) {
1663 String webParamName = null;
1664 if (webParam != null && webParam.name().length() > 0) {
1665 webParamName = webParam.name();
1666 }
1667 String xmlElemName = null;
1668 if (xmlElem != null && !xmlElem.name().equals("##default")) {
1669 xmlElemName = xmlElem.name();
1670 }
1671 if (xmlElemName != null && webParamName != null && !xmlElemName.equals(webParamName)) {
1672 throw new RuntimeModelerException("@XmlElement(name)="+xmlElemName+" and @WebParam(name)="+webParamName+" are different for method " +method);
1673 }
1674 String localPart = paramDefault;
1675 if (webParamName != null) {
1676 localPart = webParamName;
1677 } else if (xmlElemName != null) {
1678 localPart = xmlElemName;
1679 }
1680
1681 String webParamNS = null;
1682 if (webParam != null && webParam.targetNamespace().length() > 0) {
1683 webParamNS = webParam.targetNamespace();
1684 }
1685 String xmlElemNS = null;
1686 if (xmlElem != null && !xmlElem.namespace().equals("##default")) {
1687 xmlElemNS = xmlElem.namespace();
1688 }
1689 if (xmlElemNS != null && webParamNS != null && !xmlElemNS.equals(webParamNS)) {
1690 throw new RuntimeModelerException("@XmlElement(namespace)="+xmlElemNS+" and @WebParam(targetNamespace)="+webParamNS+" are different for method " +method);
1691 }
1692 String ns = "";
1693 if (webParamNS != null) {
1694 ns = webParamNS;
1695 } else if (xmlElemNS != null) {
1696 ns = xmlElemNS;
1697 }
1698
1699 return new QName(ns, localPart);
1700 }
1701
1702
1703 }

mercurial