001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */package org.apache.cxf.jaxws.support;
019:
020: import java.lang.reflect.Method;
021: import java.lang.reflect.ParameterizedType;
022: import java.lang.reflect.Type;
023: import java.util.ArrayList;
024: import java.util.Arrays;
025: import java.util.List;
026: import java.util.logging.Logger;
027:
028: import javax.wsdl.Operation;
029: import javax.xml.namespace.QName;
030: import javax.xml.ws.AsyncHandler;
031: import javax.xml.ws.Service;
032: import javax.xml.ws.Service.Mode;
033:
034: import org.apache.cxf.binding.AbstractBindingFactory;
035: import org.apache.cxf.common.i18n.Message;
036: import org.apache.cxf.common.logging.LogUtils;
037: import org.apache.cxf.databinding.source.SourceDataBinding;
038: import org.apache.cxf.endpoint.Endpoint;
039: import org.apache.cxf.endpoint.EndpointException;
040: import org.apache.cxf.frontend.SimpleMethodDispatcher;
041: import org.apache.cxf.helpers.CastUtils;
042: import org.apache.cxf.jaxws.JAXWSMethodDispatcher;
043: import org.apache.cxf.jaxws.interceptors.DispatchInDatabindingInterceptor;
044: import org.apache.cxf.jaxws.interceptors.DispatchOutDatabindingInterceptor;
045: import org.apache.cxf.jaxws.interceptors.WebFaultOutInterceptor;
046: import org.apache.cxf.service.factory.AbstractServiceConfiguration;
047: import org.apache.cxf.service.factory.ReflectionServiceFactoryBean;
048: import org.apache.cxf.service.factory.ServiceConstructionException;
049: import org.apache.cxf.service.invoker.Invoker;
050: import org.apache.cxf.service.model.BindingInfo;
051: import org.apache.cxf.service.model.EndpointInfo;
052: import org.apache.cxf.service.model.FaultInfo;
053: import org.apache.cxf.service.model.InterfaceInfo;
054: import org.apache.cxf.service.model.MessageInfo;
055: import org.apache.cxf.service.model.MessagePartInfo;
056: import org.apache.cxf.service.model.OperationInfo;
057: import org.apache.cxf.wsdl11.WSDLServiceBuilder;
058:
059: /**
060: * Constructs a service model from JAX-WS service endpoint classes. Works
061: * with both @@WebServiceProvider and @@WebService annotated classes.
062: *
063: * @see org.apache.cxf.jaxws.JaxWsServerFactoryBean
064: */
065: public class JaxWsServiceFactoryBean extends
066: ReflectionServiceFactoryBean {
067: private static final Logger LOG = LogUtils
068: .getL7dLogger(JaxWsServiceFactoryBean.class);
069:
070: private AbstractServiceConfiguration jaxWsConfiguration;
071:
072: private JaxWsImplementorInfo implInfo;
073:
074: private JAXWSMethodDispatcher methodDispatcher;
075:
076: public JaxWsServiceFactoryBean() {
077: getIgnoredClasses().add(Service.class.getName());
078: }
079:
080: public JaxWsServiceFactoryBean(JaxWsImplementorInfo implInfo) {
081: this ();
082: this .implInfo = implInfo;
083: initConfiguration(implInfo);
084: this .serviceClass = implInfo.getEndpointClass();
085: }
086:
087: @Override
088: public org.apache.cxf.service.Service create() {
089: org.apache.cxf.service.Service s = super .create();
090:
091: s.put(ENDPOINT_CLASS, implInfo.getEndpointClass());
092:
093: return s;
094: }
095:
096: @Override
097: protected Invoker createInvoker() {
098: return null;
099: }
100:
101: protected SimpleMethodDispatcher getMethodDispatcher() {
102: return methodDispatcher;
103: }
104:
105: @Override
106: protected boolean qualifyWrapperSchema() {
107: //the JAXWS-RI doesn't qualify the schemas for the wrapper types
108: //and thus won't work if we do.
109: return false;
110: }
111:
112: @Override
113: public void setServiceClass(Class<?> serviceClass) {
114: setJaxWsImplementorInfo(new JaxWsImplementorInfo(serviceClass));
115: super .setServiceClass(serviceClass);
116: }
117:
118: @Override
119: protected void initializeDefaultInterceptors() {
120: super .initializeDefaultInterceptors();
121:
122: if (implInfo.isWebServiceProvider()) {
123: Class<?> type = implInfo.getProviderParameterType();
124: Mode mode = implInfo.getServiceMode();
125:
126: getService().getInInterceptors().add(
127: new DispatchInDatabindingInterceptor(type, mode));
128: getService().getOutInterceptors().add(
129: new DispatchOutDatabindingInterceptor(mode));
130: }
131: }
132:
133: @Override
134: protected void initializeFaultInterceptors() {
135: getService().getOutFaultInterceptors().add(
136: new WebFaultOutInterceptor());
137: }
138:
139: @Override
140: public Endpoint createEndpoint(EndpointInfo ei)
141: throws EndpointException {
142: return new JaxWsEndpointImpl(getBus(), getService(), ei,
143: implInfo);
144: }
145:
146: @Override
147: protected void initializeWSDLOperation(InterfaceInfo intf,
148: OperationInfo o, Method method) {
149: method = ((JaxWsServiceConfiguration) jaxWsConfiguration)
150: .getDeclaredMethod(method);
151: super .initializeWSDLOperation(intf, o, method);
152:
153: initializeWrapping(o, method);
154:
155: try {
156: // Find the Async method which returns a Response
157: Method responseMethod = method.getDeclaringClass()
158: .getDeclaredMethod(method.getName() + "Async",
159: method.getParameterTypes());
160:
161: // Find the Async method whic has a Future & AsyncResultHandler
162: List<Class<?>> asyncHandlerParams = Arrays.asList(method
163: .getParameterTypes());
164: //copy it to may it non-readonly
165: asyncHandlerParams = new ArrayList<Class<?>>(
166: asyncHandlerParams);
167: asyncHandlerParams.add(AsyncHandler.class);
168: Method futureMethod = method
169: .getDeclaringClass()
170: .getDeclaredMethod(
171: method.getName() + "Async",
172: asyncHandlerParams
173: .toArray(new Class<?>[asyncHandlerParams
174: .size()]));
175:
176: getMethodDispatcher().bind(o, method, responseMethod,
177: futureMethod);
178:
179: } catch (SecurityException e) {
180: throw new ServiceConstructionException(e);
181: } catch (NoSuchMethodException e) {
182: getMethodDispatcher().bind(o, method);
183: }
184:
185: // rpc out-message-part-info class mapping
186: Operation op = (Operation) o
187: .getProperty(WSDLServiceBuilder.WSDL_OPERATION);
188:
189: initializeClassInfo(o, method, op == null ? null : CastUtils
190: .cast(op.getParameterOrdering(), String.class));
191: }
192:
193: @Override
194: protected void initializeWSDLOperations() {
195: if (implInfo.isWebServiceProvider()) {
196: initializeWSDLOperationsForProvider();
197: } else {
198: super .initializeWSDLOperations();
199: }
200: }
201:
202: protected void initializeWSDLOperationsForProvider() {
203: Type[] genericInterfaces = getServiceClass()
204: .getGenericInterfaces();
205: ParameterizedType pt = (ParameterizedType) genericInterfaces[0];
206: Class c = (Class) pt.getActualTypeArguments()[0];
207:
208: try {
209: Method invoke = getServiceClass().getMethod("invoke", c);
210:
211: // Bind each operation to the invoke method.
212: for (OperationInfo o : getEndpointInfo().getService()
213: .getInterface().getOperations()) {
214: getMethodDispatcher().bind(o, invoke);
215: }
216:
217: } catch (SecurityException e) {
218: throw new ServiceConstructionException(e);
219: } catch (NoSuchMethodException e) {
220: throw new ServiceConstructionException(e);
221: }
222:
223: for (BindingInfo bi : getEndpointInfo().getService()
224: .getBindings()) {
225: bi.setProperty(AbstractBindingFactory.DATABINDING_DISABLED,
226: Boolean.TRUE);
227: }
228: }
229:
230: void initializeWrapping(OperationInfo o, Method selected) {
231: Class responseWrapper = getResponseWrapper(selected);
232: if (responseWrapper != null) {
233: o.getOutput().getMessageParts().get(0).setTypeClass(
234: responseWrapper);
235: }
236: if (getResponseWrapperClassName(selected) != null) {
237: o.getOutput().getMessageParts().get(0).setProperty(
238: "RESPONSE.WRAPPER.CLASSNAME",
239: getResponseWrapperClassName(selected));
240: }
241: Class<?> requestWrapper = getRequestWrapper(selected);
242: if (requestWrapper != null) {
243: o.getInput().getMessageParts().get(0).setTypeClass(
244: requestWrapper);
245: }
246: if (getRequestWrapperClassName(selected) != null) {
247: o.getInput().getMessageParts().get(0).setProperty(
248: "REQUEST.WRAPPER.CLASSNAME",
249: getRequestWrapperClassName(selected));
250: }
251: }
252:
253: /**
254: * Create a mock service model with two operations - invoke and
255: * invokeOneway.
256: */
257: // @Override
258: // protected InterfaceInfo createInterface(ServiceInfo serviceInfo) {
259: // if (jaxWsImplementorInfo.isWebServiceProvider()) {
260: // return createInterfaceForProvider(serviceInfo);
261: // } else {
262: // return super.createInterface(serviceInfo);
263: // }
264: // }
265: //
266: // protected InterfaceInfo createInterfaceForProvider(ServiceInfo
267: // serviceInfo) {
268: //
269: // InterfaceInfo intf = new InterfaceInfo(serviceInfo, getInterfaceName());
270: //
271: // String ns = getServiceNamespace();
272: // OperationInfo invoke = intf.addOperation(new QName(ns, "invoke"));
273: //
274: // MessageInfo input = invoke.createMessage(new QName(ns, "input"));
275: // invoke.setInput("input", input);
276: //
277: // input.addMessagePart("in");
278: //
279: // MessageInfo output = invoke.createMessage(new QName(ns, "output"));
280: // invoke.setOutput("output", output);
281: //
282: // output.addMessagePart("out");
283: // //
284: // // OperationInfo invokeOneWay = intf.addOperation(new
285: // // QName(getServiceNamespace(), "invokeOneWay"));
286: // // invokeOneWay.setInput("input", input);
287: //
288: // return intf;
289: // }
290: private void setFaultClassInfo(OperationInfo o, Method selected) {
291: Class[] types = selected.getExceptionTypes();
292: for (int i = 0; i < types.length; i++) {
293: Class exClass = types[i];
294: Class beanClass = getBeanClass(exClass);
295:
296: QName name = getFaultName(o.getInterface(), o, exClass,
297: beanClass);
298:
299: for (FaultInfo fi : o.getFaults()) {
300: for (MessagePartInfo mpi : fi.getMessageParts()) {
301: String ns = null;
302: if (mpi.isElement()) {
303: ns = mpi.getElementQName().getNamespaceURI();
304: } else {
305: ns = mpi.getTypeQName().getNamespaceURI();
306: }
307: if (mpi.getConcreteName().getLocalPart().equals(
308: name.getLocalPart())
309: && name.getNamespaceURI().equals(ns)) {
310: fi.setProperty(Class.class.getName(), exClass);
311: mpi.setTypeClass(beanClass);
312: }
313: }
314: }
315: }
316: }
317:
318: @Override
319: protected Class<?> getBeanClass(Class<?> exClass) {
320: try {
321: if (java.rmi.ServerException.class
322: .isAssignableFrom(exClass)
323: || java.rmi.RemoteException.class
324: .isAssignableFrom(exClass)) {
325: return null;
326: }
327:
328: Method getFaultInfo = exClass.getMethod("getFaultInfo",
329: new Class[0]);
330:
331: return getFaultInfo.getReturnType();
332: } catch (SecurityException e) {
333: throw new ServiceConstructionException(e);
334: } catch (NoSuchMethodException e) {
335: return super .getBeanClass(exClass);
336: }
337: }
338:
339: /**
340: * set the holder generic type info into message part info
341: *
342: * @param o
343: * @param method
344: */
345: protected void initializeClassInfo(OperationInfo o, Method method,
346: List<String> paramOrder) {
347: if (isWrapped(method)) {
348: if (o.getUnwrappedOperation() == null) {
349: //the "normal" algorithm didn't allow for unwrapping,
350: //but the annotations say unwrap this. We'll need to
351: //make it.
352: WSDLServiceBuilder.checkForWrapped(o, true);
353: }
354:
355: if (o.hasInput()) {
356: MessageInfo input = o.getInput();
357: MessagePartInfo part = input.getMessageParts().get(0);
358: part.setTypeClass(getRequestWrapper(method));
359: part.setProperty("REQUEST.WRAPPER.CLASSNAME",
360: getRequestWrapperClassName(method));
361: part.setIndex(0);
362: }
363:
364: if (o.hasOutput()) {
365: MessageInfo input = o.getOutput();
366: MessagePartInfo part = input.getMessageParts().get(0);
367: part.setTypeClass(getResponseWrapper(method));
368: part.setProperty("RESPONSE.WRAPPER.CLASSNAME",
369: getResponseWrapperClassName(method));
370: part.setIndex(0);
371: }
372:
373: setFaultClassInfo(o, method);
374: o = o.getUnwrappedOperation();
375: } else if (o.isUnwrappedCapable()) {
376: // remove the unwrapped operation because it will break the
377: // the WrapperClassOutInterceptor, and in general makes
378: // life more confusing
379: o.setUnwrappedOperation(null);
380:
381: setFaultClassInfo(o, method);
382: }
383:
384: Class<?>[] paramTypes = method.getParameterTypes();
385: Type[] genericTypes = method.getGenericParameterTypes();
386: for (int i = 0; i < paramTypes.length; i++) {
387: Class paramType = paramTypes[i];
388: Type genericType = genericTypes[i];
389: initializeParameter(o, method, i, paramType, genericType);
390: }
391:
392: // Initialize return type
393: Class paramType = method.getReturnType();
394: Type genericType = method.getGenericReturnType();
395:
396: initializeParameter(o, method, -1, paramType, genericType);
397:
398: setFaultClassInfo(o, method);
399: }
400:
401: private void initializeParameter(OperationInfo o, Method method,
402: int i, Class paramType, Type genericType) {
403: boolean isIn = isInParam(method, i);
404: boolean isOut = isOutParam(method, i);
405:
406: MessagePartInfo part = null;
407: if (isIn && !isOut) {
408: QName name = getInPartName(o, method, i);
409: part = o.getInput().getMessagePart(name);
410: if (part == null) {
411: throw new ServiceConstructionException(new Message(
412: "COULD_NOT_FIND_PART", LOG, name, o.getInput()
413: .getMessagePartsMap().keySet()
414: .toString()));
415: }
416: initializeParameter(part, paramType, genericType);
417: part.setIndex(i);
418: } else if (!isIn && isOut) {
419: QName name = getOutPartName(o, method, i);
420: part = o.getOutput().getMessagePart(name);
421: if (part == null) {
422: throw new ServiceConstructionException(new Message(
423: "COULD_NOT_FIND_PART", LOG, name, o.getOutput()
424: .getMessagePartsMap().keySet()
425: .toString()));
426: }
427: part.setProperty(ReflectionServiceFactoryBean.MODE_OUT,
428: Boolean.TRUE);
429: initializeParameter(part, paramType, genericType);
430: part.setIndex(i + 1);
431: } else if (isIn && isOut) {
432: QName name = getInPartName(o, method, i);
433: part = o.getInput().getMessagePart(name);
434: if (part == null) {
435: throw new ServiceConstructionException(new Message(
436: "COULD_NOT_FIND_PART", LOG, name, o.getInput()
437: .getMessagePartsMap().keySet()
438: .toString()));
439: }
440: part.setProperty(ReflectionServiceFactoryBean.MODE_INOUT,
441: Boolean.TRUE);
442: initializeParameter(part, paramType, genericType);
443: part.setIndex(i);
444:
445: part = o.getOutput().getMessagePart(name);
446: part.setProperty(ReflectionServiceFactoryBean.MODE_INOUT,
447: Boolean.TRUE);
448: initializeParameter(part, paramType, genericType);
449: part.setIndex(i + 1);
450: }
451: }
452:
453: public void setJaxWsConfiguration(
454: JaxWsServiceConfiguration jaxWsConfiguration) {
455: this .jaxWsConfiguration = jaxWsConfiguration;
456: }
457:
458: public JaxWsImplementorInfo getJaxWsImplementorInfo() {
459: return implInfo;
460: }
461:
462: public void setJaxWsImplementorInfo(
463: JaxWsImplementorInfo jaxWsImplementorInfo) {
464: this .implInfo = jaxWsImplementorInfo;
465:
466: initConfiguration(jaxWsImplementorInfo);
467: }
468:
469: protected final void initConfiguration(JaxWsImplementorInfo ii) {
470: if (ii.isWebServiceProvider()) {
471: jaxWsConfiguration = new WebServiceProviderConfiguration();
472: getServiceConfigurations().add(0, jaxWsConfiguration);
473: setWrapped(false);
474: setDataBinding(new SourceDataBinding());
475: } else {
476: jaxWsConfiguration = new JaxWsServiceConfiguration();
477: jaxWsConfiguration.setServiceFactory(this );
478: getServiceConfigurations().add(0, jaxWsConfiguration);
479: }
480: methodDispatcher = new JAXWSMethodDispatcher(implInfo);
481: }
482: }
|