summaryrefslogtreecommitdiffstats
path: root/branches/sca-java-1.2/modules/interface-java-jaxws/src/main
diff options
context:
space:
mode:
authordims <dims@13f79535-47bb-0310-9956-ffa450edef68>2008-06-17 00:23:01 +0000
committerdims <dims@13f79535-47bb-0310-9956-ffa450edef68>2008-06-17 00:23:01 +0000
commitbdd0a41aed7edf21ec2a65cfa17a86af2ef8c48a (patch)
tree38a92061c0793434c4be189f1d70c3458b6bc41d /branches/sca-java-1.2/modules/interface-java-jaxws/src/main
Move Tuscany from Incubator to top level.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@668359 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'branches/sca-java-1.2/modules/interface-java-jaxws/src/main')
-rw-r--r--branches/sca-java-1.2/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/JAXWSFaultExceptionMapper.java253
-rw-r--r--branches/sca-java-1.2/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/JAXWSJavaInterfaceProcessor.java197
2 files changed, 450 insertions, 0 deletions
diff --git a/branches/sca-java-1.2/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/JAXWSFaultExceptionMapper.java b/branches/sca-java-1.2/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/JAXWSFaultExceptionMapper.java
new file mode 100644
index 0000000000..ab4ce1587e
--- /dev/null
+++ b/branches/sca-java-1.2/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/JAXWSFaultExceptionMapper.java
@@ -0,0 +1,253 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.interfacedef.java.jaxws;
+
+import java.beans.BeanInfo;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+import javax.xml.namespace.QName;
+import javax.xml.ws.WebFault;
+
+import org.apache.tuscany.sca.databinding.DataBindingExtensionPoint;
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.FaultExceptionMapper;
+import org.apache.tuscany.sca.interfacedef.util.FaultException;
+import org.apache.tuscany.sca.interfacedef.util.XMLType;
+import org.osoa.sca.ServiceRuntimeException;
+
+/**
+ * JAX-WS ExceptionHandler
+ *
+ * @version $Rev$ $Date$
+ */
+public class JAXWSFaultExceptionMapper implements FaultExceptionMapper {
+ private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class[0];
+ private DataBindingExtensionPoint dataBindingExtensionPoint;
+
+ public JAXWSFaultExceptionMapper(DataBindingExtensionPoint dataBindingExtensionPoint) {
+ super();
+ this.dataBindingExtensionPoint = dataBindingExtensionPoint;
+ }
+
+ /**
+ * The following is quoted from the JAX-WS spec v2.1
+ * <ul>
+ * <li>WrapperException(String message, FaultBean faultInfo) <br>
+ * A constructor where WrapperException is replaced with the name of the
+ * generated wrapper exception and FaultBean is replaced by the name of the
+ * generated fault bean.
+ * <li> WrapperException(String message, FaultBean faultInfo, Throwable
+ * cause) <br>
+ * A constructor where WrapperException is replaced with the name of the
+ * generated wrapper exception and FaultBean is replaced by the name of the
+ * generated fault bean. The last argument, cause, may be used to convey
+ * protocol specific fault information
+ * </ul>
+ */
+ @SuppressWarnings("unchecked")
+ public Throwable wrapFaultInfo(DataType<DataType> exceptionType, String message, Object faultInfo, Throwable cause) {
+ Class<?> exceptionClass = exceptionType.getPhysical();
+ if (exceptionClass.isInstance(faultInfo)) {
+ return (Throwable)faultInfo;
+ }
+ DataType<?> faultBeanType = exceptionType.getLogical();
+ Class<?> faultBeanClass = faultBeanType.getPhysical();
+ try {
+ Exception exc = null;
+ try {
+ Constructor<?> constructor =
+ exceptionClass.getConstructor(new Class[] {String.class, faultBeanClass, Throwable.class});
+ exc = (Exception)constructor.newInstance(new Object[] {message, faultInfo, cause});
+ } catch (NoSuchMethodException e) {
+ // Create a generic fault exception
+ exc = new FaultException(message, faultInfo, cause);
+ }
+ // Include the elem name into the FaultException we build so it can be used for matching in the DataTransformationInterceptor
+ //
+ // Note this may happen even if we find a constructor above, that is the type of the non-generic fault exc may be an instance
+ // of FaultException
+ //
+ if ((exc instanceof FaultException) && (faultBeanType.getLogical() instanceof XMLType)) {
+ FaultException faultExc = (FaultException)exc;
+ DataType<XMLType> faultBeanXMLType = (DataType<XMLType>)faultBeanType;
+ XMLType faultLogical = faultBeanXMLType.getLogical();
+ faultExc.setFaultName(faultLogical.getElementName());
+ }
+ return exc;
+ } catch (Throwable e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ public Object getFaultInfo(Throwable exception, Class<?> faultBeanClass) {
+ if (exception == null) {
+ return null;
+ }
+
+ // Check if it's the generic FaultException
+ if (exception instanceof FaultException) {
+ return ((FaultException)exception).getFaultInfo();
+ }
+
+ try {
+ Method method = exception.getClass().getMethod("getFaultInfo", EMPTY_CLASS_ARRAY);
+ return method.invoke(exception, (Object[])null);
+ } catch (NoSuchMethodException e) {
+ // Follow the JAX-WS v2.1 spec section 3.7
+ return createFaultBean(exception, faultBeanClass);
+ } catch (Throwable e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ private Object createFaultBean(Throwable exception, Class<?> faultBeanClass) {
+ /**
+ * For each getter in the exception and its superclasses, a property of the same
+ * type and name is added to the bean. The getCause, getLocalizedMessage and
+ * getStackTrace getters from java.lang.Throwable and the getClass getter from
+ * java.lang.Object are excluded from the list of getters to be mapped.
+ */
+ // Return the exception as-is if it's already the fault bean
+ if (faultBeanClass.isInstance(exception)) {
+ return exception;
+ }
+ try {
+ Object faultBean = null;
+ for (Constructor<?> ctor : faultBeanClass.getConstructors()) {
+ Class<?>[] params = ctor.getParameterTypes();
+ if (params.length == 1 && String.class == params[0]) {
+ faultBean = ctor.newInstance(exception.getMessage());
+ } else if (params.length == 2 && String.class == params[0]
+ && Throwable.class.isAssignableFrom(params[1])) {
+ faultBean = ctor.newInstance(exception.getMessage(), exception);
+ } else if (params.length == 0) {
+ faultBean = ctor.newInstance();
+ }
+ if (faultBean != null) {
+ break;
+ }
+ }
+ if (faultBean == null) {
+ return exception;
+ }
+ BeanInfo beanInfo = Introspector.getBeanInfo(exception.getClass());
+ for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
+ Method getter = pd.getReadMethod();
+ String name = getter.getName();
+ if ("getClass".equals(name) || "getStackTrace".equals(name)
+ || "getCause".equals(name)
+ || "getLocalizedMessage".equals(name)) {
+ continue;
+ }
+ String prefix = "get";
+ if (name.startsWith("get")) {
+ prefix = "get";
+ } else if (name.startsWith("is")) {
+ prefix = "is";
+ }
+ Method setter = null;
+ try {
+ setter =
+ faultBeanClass.getMethod("set" + name.substring(prefix.length()), new Class[] {getter
+ .getReturnType()});
+ } catch (NoSuchMethodException e) {
+ continue;
+ }
+ Object prop = setter.invoke(faultBean, getter.invoke(exception, (Object[])null));
+ setter.invoke(faultBean, prop);
+ }
+ return faultBean;
+ } catch (Throwable ex) {
+ throw new IllegalArgumentException(ex);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public boolean introspectFaultDataType(DataType<DataType> exceptionType) {
+ QName faultName = null;
+ boolean result = false;
+
+ Class<?> cls = exceptionType.getPhysical();
+ if (cls == FaultException.class) {
+ return true;
+ }
+ DataType faultType = (DataType)exceptionType.getLogical();
+ Class<?> faultBean = null;
+ WebFault fault = cls.getAnnotation(WebFault.class);
+ if (fault != null) {
+ faultName = new QName(fault.targetNamespace(), fault.name());
+ XMLType xmlType = new XMLType(faultName, null);
+ faultType.setLogical(xmlType);
+ if (!"".equals(fault.faultBean())) {
+ try {
+ faultBean = Class.forName(fault.faultBean(), false, cls.getClassLoader());
+ } catch (ClassNotFoundException e) {
+ throw new ServiceRuntimeException(e);
+ }
+ } else {
+ Method m;
+ try {
+ m = cls.getMethod("getFaultInfo", (Class[])null);
+ faultBean = m.getReturnType();
+ } catch (NoSuchMethodException e) {
+ // Ignore
+ }
+ }
+ }
+
+ if (faultBean == null) {
+ String faultBeanClassName = cls.getPackage().getName() + ".jaxws." + cls.getSimpleName() + "Bean";
+ try {
+ faultBean = Class.forName(faultBeanClassName, false, cls.getClassLoader());
+ } catch (ClassNotFoundException e) {
+ faultBean = cls;
+ }
+ }
+
+ faultType.setPhysical(faultBean);
+ // TODO: Use the databinding framework to introspect the fault bean class
+ if (dataBindingExtensionPoint != null) {
+ result =
+ dataBindingExtensionPoint.introspectType(faultType, null, Throwable.class.isAssignableFrom(faultBean));
+ }
+
+ /*
+ The introspection of the fault DT may not have calculated the correct element name,
+ though we may have already done this in this method. Let's look at the DataType now
+ that introspection is done, and, if it has an XMLType, let's set the element to the
+ 'faultName' if we calculated one.
+ */
+ if ((faultName != null) && (faultType.getLogical() instanceof XMLType)) {
+ XMLType faultTypeXML = (XMLType)faultType.getLogical();
+ // The element name (if set) should match the fault name
+ faultTypeXML.setElementName(faultName);
+ }
+
+ return result;
+ }
+
+ public void setDataBindingExtensionPoint(DataBindingExtensionPoint dataBindingExtensionPoint) {
+ this.dataBindingExtensionPoint = dataBindingExtensionPoint;
+ }
+
+}
diff --git a/branches/sca-java-1.2/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/JAXWSJavaInterfaceProcessor.java b/branches/sca-java-1.2/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/JAXWSJavaInterfaceProcessor.java
new file mode 100644
index 0000000000..d75f8b2fde
--- /dev/null
+++ b/branches/sca-java-1.2/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/JAXWSJavaInterfaceProcessor.java
@@ -0,0 +1,197 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.interfacedef.java.jaxws;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jws.Oneway;
+import javax.jws.WebMethod;
+import javax.jws.WebParam;
+import javax.jws.WebResult;
+import javax.jws.WebService;
+import javax.jws.soap.SOAPBinding;
+import javax.xml.namespace.QName;
+import javax.xml.ws.RequestWrapper;
+import javax.xml.ws.ResponseWrapper;
+
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.FaultExceptionMapper;
+import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterface;
+import org.apache.tuscany.sca.interfacedef.java.introspect.JavaInterfaceVisitor;
+import org.apache.tuscany.sca.interfacedef.util.ElementInfo;
+import org.apache.tuscany.sca.interfacedef.util.WrapperInfo;
+import org.apache.tuscany.sca.interfacedef.util.XMLType;
+
+/**
+ * Introspect the java class/interface with JSR-181 and JAXWS annotations
+ *
+ * @version $Rev$ $Date$
+ */
+public class JAXWSJavaInterfaceProcessor implements JavaInterfaceVisitor {
+ private static final String JAXB_DATABINDING = "javax.xml.bind.JAXBElement";
+ private FaultExceptionMapper faultExceptionMapper;
+
+ public JAXWSJavaInterfaceProcessor(FaultExceptionMapper faultExceptionMapper) {
+ super();
+ this.faultExceptionMapper = faultExceptionMapper;
+ }
+
+ public JAXWSJavaInterfaceProcessor() {
+ super();
+ }
+
+ public void visitInterface(JavaInterface contract) throws InvalidInterfaceException {
+
+ Class<?> clazz = contract.getJavaClass();
+ WebService webService = clazz.getAnnotation(WebService.class);
+ String tns = "";
+ if (webService != null) {
+ tns = webService.targetNamespace();
+ // Mark SEI as Remotable
+ contract.setRemotable(true);
+ }
+ if (!contract.isRemotable()) {
+ return;
+ }
+
+ // SOAP binding (doc/lit/wrapped|bare or rpc/lit)
+ SOAPBinding soapBinding = clazz.getAnnotation(SOAPBinding.class);
+
+ Map<String, Operation> operations = new HashMap<String, Operation>();
+ for (Operation op : contract.getOperations()) {
+ operations.put(op.getName(), op);
+ }
+ for (Method method : clazz.getMethods()) {
+ Operation operation = operations.get(method.getName());
+ introspectFaultTypes(operation);
+
+ // SOAP binding (doc/lit/wrapped|bare or rpc/lit)
+ SOAPBinding methodSOAPBinding = method.getAnnotation(SOAPBinding.class);
+ if (methodSOAPBinding == null) {
+ methodSOAPBinding = soapBinding;
+ }
+ if (methodSOAPBinding != null) {
+ operation.setWrapperStyle(methodSOAPBinding.parameterStyle() == SOAPBinding.ParameterStyle.WRAPPED);
+ }
+
+ // WebMethod
+ WebMethod webMethod = method.getAnnotation(WebMethod.class);
+ if (webMethod == null) {
+ continue;
+ }
+
+ // Is one way?
+ Oneway oneway = method.getAnnotation(Oneway.class);
+ if (oneway != null) {
+ // JSR 181
+ assert method.getReturnType() == void.class;
+ operation.setNonBlocking(true);
+ }
+
+ // Handle BARE mapping
+ if (!operation.isWrapperStyle()) {
+ for (int i = 0; i < method.getParameterTypes().length; i++) {
+ WebParam param = getAnnotation(method, i, WebParam.class);
+ if (param != null) {
+ QName element = new QName(param.targetNamespace(), param.name());
+ Object logical = operation.getInputType().getLogical().get(i).getLogical();
+ if (logical instanceof XMLType) {
+ ((XMLType)logical).setElementName(element);
+ }
+ }
+ }
+ WebResult result = method.getAnnotation(WebResult.class);
+ if (result != null) {
+ QName element = new QName(result.targetNamespace(), result.name());
+ Object logical = operation.getOutputType().getLogical();
+ if (logical instanceof XMLType) {
+ ((XMLType)logical).setElementName(element);
+ }
+ }
+ }
+
+ String operationName = getValue(webMethod.operationName(), operation.getName());
+ operation.setName(operationName);
+
+ RequestWrapper requestWrapper = method.getAnnotation(RequestWrapper.class);
+ ResponseWrapper responseWrapper = method.getAnnotation(ResponseWrapper.class);
+ if (requestWrapper == null) {
+ continue;
+ }
+
+ String ns = getValue(requestWrapper.targetNamespace(), tns);
+ String name = getValue(requestWrapper.localName(), operationName);
+ QName inputWrapper = new QName(ns, name);
+
+ ns = getValue(responseWrapper.targetNamespace(), tns);
+ name = getValue(responseWrapper.localName(), operationName + "Response");
+
+ QName outputWrapper = new QName(ns, name);
+
+ List<ElementInfo> inputElements = new ArrayList<ElementInfo>();
+ for (int i = 0; i < method.getParameterTypes().length; i++) {
+ WebParam param = getAnnotation(method, i, WebParam.class);
+ assert param != null;
+ inputElements.add(new ElementInfo(new QName(param.targetNamespace(), param.name()), null));
+ }
+
+ List<ElementInfo> outputElements = new ArrayList<ElementInfo>();
+ WebResult result = method.getAnnotation(WebResult.class);
+ outputElements.add(new ElementInfo(new QName(result.targetNamespace(), result.name()), null));
+
+ WrapperInfo wrapperInfo =
+ new WrapperInfo(JAXB_DATABINDING, new ElementInfo(inputWrapper, null), new ElementInfo(outputWrapper,
+ null),
+ inputElements, outputElements);
+ operation.setWrapper(wrapperInfo);
+ // operation.setDataBinding(JAXB_DATABINDING); // could be JAXB or SDO
+
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void introspectFaultTypes(Operation operation) {
+ for (DataType exceptionType : operation.getFaultTypes()) {
+ faultExceptionMapper.introspectFaultDataType(exceptionType);
+ }
+ }
+
+ private <T extends Annotation> T getAnnotation(Method method, int index, Class<T> annotationType) {
+ Annotation[] annotations = method.getParameterAnnotations()[index];
+ for (Annotation annotation : annotations) {
+ if (annotation.annotationType() == annotationType) {
+ return annotationType.cast(annotation);
+ }
+ }
+ return null;
+ }
+
+ private static String getValue(String value, String defaultValue) {
+ return "".equals(value) ? defaultValue : value;
+ }
+
+}