summaryrefslogtreecommitdiffstats
path: root/sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl
diff options
context:
space:
mode:
Diffstat (limited to 'sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl')
-rw-r--r--sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceContractImpl.java53
-rw-r--r--sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceFactoryImpl.java95
-rw-r--r--sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceImpl.java367
-rw-r--r--sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceIntrospectorImpl.java393
-rw-r--r--sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceUtil.java223
-rw-r--r--sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaOperationImpl.java100
-rw-r--r--sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/PolicyJavaInterfaceVisitor.java278
7 files changed, 1509 insertions, 0 deletions
diff --git a/sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceContractImpl.java b/sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceContractImpl.java
new file mode 100644
index 0000000000..cb0d5f3b27
--- /dev/null
+++ b/sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceContractImpl.java
@@ -0,0 +1,53 @@
+/*
+ * 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.impl;
+
+import org.apache.tuscany.sca.interfacedef.InterfaceContract;
+import org.apache.tuscany.sca.interfacedef.impl.InterfaceContractImpl;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract;
+
+/**
+ * Represents a Java interface contract.
+ *
+ * @version $Rev$ $Date$
+ */
+public class JavaInterfaceContractImpl extends InterfaceContractImpl implements JavaInterfaceContract {
+
+ // A cached WSDL version of the Java contract use during normalized
+ // interface comparison
+ private InterfaceContract normailizedWSDLInterfaceContract;
+
+ protected JavaInterfaceContractImpl() {
+ }
+
+ @Override
+ public JavaInterfaceContractImpl clone() throws CloneNotSupportedException {
+ return (JavaInterfaceContractImpl) super.clone();
+ }
+
+ @Override
+ public InterfaceContract getNormalizedWSDLContract() {
+ return normailizedWSDLInterfaceContract;
+ }
+
+ @Override
+ public void setNormailizedWSDLContract(InterfaceContract wsdlInterfaceContract) {
+ normailizedWSDLInterfaceContract = wsdlInterfaceContract;
+ }
+}
diff --git a/sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceFactoryImpl.java b/sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceFactoryImpl.java
new file mode 100644
index 0000000000..dbedf1d55a
--- /dev/null
+++ b/sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceFactoryImpl.java
@@ -0,0 +1,95 @@
+/*
+ * 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.impl;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterface;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory;
+import org.apache.tuscany.sca.interfacedef.java.JavaOperation;
+import org.apache.tuscany.sca.interfacedef.java.introspect.JavaInterfaceVisitor;
+
+/**
+ * A factory for the Java model.
+ *
+ * @version $Rev$ $Date$
+ */
+public abstract class JavaInterfaceFactoryImpl implements JavaInterfaceFactory {
+
+ private List<JavaInterfaceVisitor> visitors = new ArrayList<JavaInterfaceVisitor>();
+ private JavaInterfaceIntrospectorImpl introspector;
+ private Map<Class<?>, JavaInterface> cache = Collections.synchronizedMap(new WeakHashMap<Class<?>, JavaInterface>());
+
+ public JavaInterfaceFactoryImpl() {
+ introspector = new JavaInterfaceIntrospectorImpl(this);
+ }
+
+ public JavaInterface createJavaInterface() {
+ return new JavaInterfaceImpl();
+ }
+
+ public JavaInterface createJavaInterface(Class<?> interfaceClass) throws InvalidInterfaceException {
+ // TODO: Review if the sharing of JavaInterface is ok
+ synchronized (interfaceClass) {
+ JavaInterface javaInterface = cache.get(interfaceClass);
+ if (javaInterface == null) {
+ javaInterface = createJavaInterface();
+ introspector.introspectInterface(javaInterface, interfaceClass);
+ // Now that all introspection is complete we can mark the interface resolved
+ javaInterface.setUnresolved(false);
+ cache.put(interfaceClass, javaInterface);
+ }
+ return javaInterface;
+ }
+ }
+
+ public void createJavaInterface(JavaInterface javaInterface, Class<?> interfaceClass) throws InvalidInterfaceException {
+ introspector.introspectInterface(javaInterface, interfaceClass);
+ }
+
+ public JavaInterfaceContract createJavaInterfaceContract() {
+ return new JavaInterfaceContractImpl();
+ }
+
+ public void addInterfaceVisitor(JavaInterfaceVisitor extension) {
+ visitors.add(extension);
+ }
+
+ public void removeInterfaceVisitor(JavaInterfaceVisitor extension) {
+ visitors.remove(extension);
+ }
+
+ public List<JavaInterfaceVisitor> getInterfaceVisitors() {
+ return visitors;
+ }
+
+ public JavaOperation createJavaOperation(Method method) {
+ JavaOperation op = new JavaOperationImpl();
+ op.setJavaMethod(method);
+ op.setName(method.getName());
+ return op;
+ }
+}
diff --git a/sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceImpl.java b/sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceImpl.java
new file mode 100644
index 0000000000..1dcd89ce2a
--- /dev/null
+++ b/sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceImpl.java
@@ -0,0 +1,367 @@
+/*
+ * 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.impl;
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.ArrayList;
+import java.util.List;
+import java.lang.reflect.ParameterizedType;
+
+import javax.xml.namespace.QName;
+
+import org.apache.tuscany.sca.assembly.xml.Constants;
+import org.apache.tuscany.sca.contribution.Contribution;
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.interfacedef.impl.DataTypeImpl;
+import org.apache.tuscany.sca.interfacedef.impl.InterfaceImpl;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterface;
+import org.apache.tuscany.sca.interfacedef.java.JavaOperation;
+import org.apache.tuscany.sca.interfacedef.util.XMLType;
+import org.apache.tuscany.sca.policy.Intent;
+
+import org.oasisopen.sca.ResponseDispatch;
+
+/**
+ * Represents a Java interface.
+ *
+ * @version $Rev$ $Date$
+ */
+public class JavaInterfaceImpl extends InterfaceImpl implements JavaInterface {
+
+ private String className;
+ private WeakReference<Class<?>> javaClass;
+ private Class<?> callbackClass;
+ private QName qname;
+ private String jaxwsWSDLLocation;
+ private String jaxwsJavaInterfaceName;
+ private Contribution contributionContainingClass;
+
+ protected JavaInterfaceImpl() {
+ super();
+ // Mark the interface as unresolved until all the basic processing is complete
+ // including Intent & Policy introspection
+ this.setUnresolved(true);
+ }
+
+ public String getName() {
+ if (isUnresolved()) {
+ return className;
+ } else if (javaClass != null) {
+ return javaClass.get().getName();
+ } else {
+ return null;
+ }
+ }
+
+ public void setName(String className) {
+ if (!isUnresolved()) {
+ throw new IllegalStateException();
+ }
+ this.className = className;
+ }
+
+ public QName getQName() {
+ return qname;
+ }
+
+ public void setQName(QName interfacename) {
+ qname = interfacename;
+ }
+
+ public Class<?> getJavaClass() {
+ if (javaClass != null){
+ return javaClass.get();
+ } else {
+ return null;
+ }
+ }
+
+ public void setJavaClass(Class<?> javaClass) {
+ this.javaClass = new WeakReference<Class<?>>(javaClass);
+ if (javaClass != null) {
+ this.className = javaClass.getName();
+ }
+ }
+
+ public Class<?> getCallbackClass() {
+ return callbackClass;
+ }
+
+ public void setCallbackClass(Class<?> callbackClass) {
+ this.callbackClass = callbackClass;
+ }
+
+ @Override
+ public String toString() {
+ return getName();
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((className == null) ? 0 : className.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ JavaInterfaceImpl other = (JavaInterfaceImpl)obj;
+ if (isUnresolved() || other.isUnresolved()) {
+ if (className == null) {
+ if (other.className != null)
+ return false;
+ } else if (!className.equals(other.className))
+ return false;
+ } else {
+ if (javaClass == null) {
+ if (other.javaClass != null)
+ return false;
+ } else if (!javaClass.get().equals(other.javaClass.get()))
+ return false;
+ if (callbackClass == null) {
+ if (other.callbackClass != null)
+ return false;
+ } else if (!callbackClass.equals(other.callbackClass))
+ return false;
+ }
+
+ return true;
+ }
+
+ public List<Operation> getOperations() {
+ if( !isUnresolved() && isAsyncServer() ) {
+ return equivalentSyncOperations();
+ } else {
+ return super.getOperations();
+ }
+ } // end method getOperations
+
+
+ private List<Operation> syncOperations = null;
+ private List<Operation> equivalentSyncOperations() {
+ if( syncOperations != null ) return syncOperations;
+ List<Operation> allOperations = super.getOperations();
+ syncOperations = new ArrayList<Operation>();
+ for( Operation operation: allOperations) {
+ syncOperations.add( getSyncFormOfOperation( (JavaOperation) operation ) );
+ // Store the actual async operations under the attribute "ASYNC-SERVER-OPERATIONS"
+ this.getAttributes().put("ASYNC-SERVER-OPERATIONS", allOperations);
+ } // end for
+
+ return syncOperations;
+ } // end method equivalentSyncOperations
+
+ private static final String UNKNOWN_DATABINDING = null;
+ /**
+ * Prepares the synchronous form of an asynchronous operation
+ * - async form: void someOperationAsync( FooType inputParam, DispatchResponse<BarType> )
+ * - sync form: BarType someOperation( FooType inputParam )
+ * @param operation - the operation to convert
+ * @return - the synchronous form of the operation - for an input operation that is not async server in form, this
+ * method simply returns the original operation unchanged
+ */
+ private Operation getSyncFormOfOperation( JavaOperation operation ) {
+ if( isAsyncServerOperation( operation ) ) {
+ JavaOperation syncOperation = new JavaOperationImpl();
+ String opName = operation.getName().substring(0, operation.getName().length() - 5 );
+
+ // Prepare the list of equivalent input parameters, which simply excludes the (final) DispatchResponse object
+ // and the equivalent return parameter, which is the (generic) type from the DispatchResponse object
+ DataType<List<DataType>> requestParams = operation.getInputType();
+
+ DataType<List<DataType>> inputType = prepareSyncInputParams( requestParams );
+ DataType<List<DataType>> returnDataType = prepareSyncReturnParam( requestParams );
+ List<DataType> faultDataTypes = prepareSyncFaults( operation );
+
+ syncOperation.setName(opName);
+ syncOperation.setAsyncServer(true);
+ syncOperation.setInputType(inputType);
+ syncOperation.setOutputType(returnDataType);
+ syncOperation.setFaultTypes(faultDataTypes);
+ syncOperation.setNonBlocking(operation.isNonBlocking());
+ syncOperation.setJavaMethod(operation.getJavaMethod());
+ syncOperation.setInterface(this);
+ return syncOperation;
+ } else {
+ // If it's not Async form, then it's a synchronous operation
+ return operation;
+ } // end if
+ } // end getSyncFormOfOperation
+
+ /**
+ * Produce the equivalent sync method input parameters from the input parameters of the async method
+ * @param requestParams - async method input parameters
+ * @return - the equivalent sync method input parameters
+ */
+ private DataType<List<DataType>> prepareSyncInputParams( DataType<List<DataType>> requestParams ) {
+ List<DataType> requestLogical = requestParams.getLogical();
+ int paramCount = requestLogical.size();
+
+ // Copy the list of async parameters, removing the final DispatchResponse
+ List<DataType> asyncParams = new ArrayList<DataType>( paramCount - 1);
+ for( int i = 0 ; i < (paramCount - 1) ; i++ ) {
+ asyncParams.add( requestLogical.get(i) );
+ } // end for
+
+ DataType<List<DataType>> inputType =
+ new DataTypeImpl<List<DataType>>(requestParams.getDataBinding(),
+ requestParams.getPhysical(), asyncParams);
+ return inputType;
+ } // end method prepareSyncInputParams
+
+ /**
+ * Prepare the return data type of the equivalent sync operation, based on the parameterization of the ResponseDispatch object
+ * of the async operation - the return data type is the Generic type of the final DispatchResponse<?>
+ * @param requestParams - - async method input parameters
+ * @return - the sync method return parameter
+ */
+ private DataType<List<DataType>> prepareSyncReturnParam( DataType<List<DataType>> requestParams ) {
+ List<DataType> requestLogical = requestParams.getLogical();
+ int paramCount = requestLogical.size();
+
+ DataType<?> finalParam = requestLogical.get( paramCount - 1 );
+ ParameterizedType t = (ParameterizedType)finalParam.getGenericType();
+ XMLType returnXMLType = (XMLType)finalParam.getLogical();
+
+ String namespace = null;
+ if( returnXMLType.isElement() ) {
+ namespace = returnXMLType.getElementName().getNamespaceURI();
+ } else {
+ namespace = returnXMLType.getTypeName().getNamespaceURI();
+ }
+
+ Type[] typeArgs = t.getActualTypeArguments();
+ if( typeArgs.length != 1 ) throw new IllegalArgumentException( "ResponseDispatch parameter is not parameterized correctly");
+
+ Class<?> returnType = (Class<?>)typeArgs[0];
+
+ // Set outputType to null for void
+ XMLType xmlReturnType = new XMLType(new QName(namespace, "return"), null);
+ DataType<XMLType> returnDataType =
+ returnType == void.class ? null : new DataTypeImpl<XMLType>(UNKNOWN_DATABINDING, returnType, xmlReturnType);
+
+ ArrayList<DataType> returnTypes = new ArrayList<DataType>();
+ returnTypes.add(returnDataType);
+
+ DataType<List<DataType>> outputType =
+ new DataTypeImpl<List<DataType>>(requestParams.getDataBinding(),
+ requestParams.getPhysical(), returnTypes);
+
+ return outputType;
+ } // end method prepareSyncReturnParam
+
+ /**
+ * Prepare the set of equivalent sync faults for a given async operation
+ * @return - the list of faults
+ */
+ private List<DataType> prepareSyncFaults( JavaOperation operation ) {
+ //TODO - deal with Faults - for now just copy through whatever is associated with the async operation
+ return operation.getFaultTypes();
+ }
+
+ /**
+ * Determines if an interface operation has the form of an async server operation
+ * - async form: void someOperationAsync( FooType inputParam, ...., DispatchResponse<BarType> )
+ * @param operation - the operation to examine
+ * @return - true if the operation has the form of an async operation, false otherwise
+ */
+ private boolean isAsyncServerOperation( Operation operation ) {
+ // Async form operations have:
+ // 1) void return type
+ // 2) name ending in "Async"
+ // 3) final parameter which is of ResponseDispatch<?> type
+ DataType<?> response = operation.getOutputType().getLogical().get(0);
+ if( response != null ) {
+ if ( response.getPhysical() != void.class ) return false;
+ } // end if
+
+ if ( !operation.getName().endsWith("Async") ) return false;
+
+ DataType<List<DataType>> requestParams = operation.getInputType();
+ int paramCount = requestParams.getLogical().size();
+ if( paramCount < 1 ) return false;
+ DataType<?> finalParam = requestParams.getLogical().get( paramCount - 1 );
+ if ( finalParam.getPhysical() != ResponseDispatch.class ) return false;
+
+ return true;
+ } // end method isAsyncServerOperation
+
+ static QName ASYNC_INVOCATION = new QName(Constants.SCA11_NS, "asyncInvocation");
+ /**
+ * Indicates if this interface is an Async Server interface
+ * @return true if the interface is Async Server, false otherwise
+ */
+ private boolean isAsyncServer() {
+
+ List<Intent> intents = getRequiredIntents();
+ for( Intent intent: intents ) {
+ if ( intent.getName().equals(ASYNC_INVOCATION) ) {
+ return true;
+ }
+ } // end for
+ return false;
+ } // end method isAsyncServer
+
+ public String getJAXWSWSDLLocation() {
+ return jaxwsWSDLLocation;
+ }
+
+ public void setJAXWSWSDLLocation(String wsdlLocation) {
+ this.jaxwsWSDLLocation = wsdlLocation;
+ }
+
+ public String getJAXWSJavaInterfaceName() {
+ return jaxwsJavaInterfaceName;
+ }
+
+ public void setJAXWSJavaInterfaceName(String javaInterfaceName) {
+ this.jaxwsJavaInterfaceName = javaInterfaceName;
+ }
+
+ /**
+ * A Java class may reference a WSDL file via a JAXWS annotation. We need to resolve
+ * the WSDL file location in the context of the same contribution that holds the
+ * Java file. In order to do this we need to remember the actual contribution that
+ * was used to resolve a Java class.
+ *
+ * @return
+ */
+ public Contribution getContributionContainingClass() {
+ return contributionContainingClass;
+ }
+
+ public void setContributionContainingClass(Contribution contributionContainingClass) {
+ this.contributionContainingClass = contributionContainingClass;
+ }
+}
diff --git a/sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceIntrospectorImpl.java b/sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceIntrospectorImpl.java
new file mode 100644
index 0000000000..a4629333d5
--- /dev/null
+++ b/sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceIntrospectorImpl.java
@@ -0,0 +1,393 @@
+/*
+ * 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.impl;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Future;
+
+import javax.xml.namespace.QName;
+import javax.xml.ws.AsyncHandler;
+import javax.xml.ws.Holder;
+import javax.xml.ws.Response;
+
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.InvalidAnnotationException;
+import org.apache.tuscany.sca.interfacedef.InvalidCallbackException;
+import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException;
+import org.apache.tuscany.sca.interfacedef.InvalidOperationException;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.interfacedef.OverloadedOperationException;
+import org.apache.tuscany.sca.interfacedef.ParameterMode;
+import org.apache.tuscany.sca.interfacedef.impl.DataTypeImpl;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterface;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory;
+import org.apache.tuscany.sca.interfacedef.java.JavaOperation;
+import org.apache.tuscany.sca.interfacedef.java.introspect.JavaInterfaceVisitor;
+import org.apache.tuscany.sca.interfacedef.util.JavaXMLMapper;
+import org.apache.tuscany.sca.interfacedef.util.XMLType;
+import org.oasisopen.sca.annotation.AsyncFault;
+import org.oasisopen.sca.annotation.OneWay;
+import org.oasisopen.sca.annotation.Remotable;
+
+/**
+ * Default implementation of a Java interface introspector.
+ *
+ * @version $Rev$ $Date$
+ */
+public class JavaInterfaceIntrospectorImpl {
+ public static final String IDL_INPUT = "idl:input";
+ public static final String IDL_OUTPUT = "idl:output";
+
+ private static final String UNKNOWN_DATABINDING = null;
+
+ private JavaInterfaceFactory javaFactory = null;
+ private List<JavaInterfaceVisitor> visitors = new ArrayList<JavaInterfaceVisitor>();
+ private boolean loadedVisitors;
+
+ public JavaInterfaceIntrospectorImpl(JavaInterfaceFactory javaFactory) {
+ this.javaFactory = javaFactory;
+ }
+
+ public void introspectInterface(JavaInterface javaInterface, Class<?> clazz) throws InvalidInterfaceException {
+
+ if(!loadedVisitors) {
+ this.visitors = javaFactory.getInterfaceVisitors();
+ }
+
+ javaInterface.setJavaClass(clazz);
+
+ boolean remotable = clazz.isAnnotationPresent(Remotable.class);
+
+ // Consider @javax.ejb.Remote, java.rmi.Remote and javax.ejb.EJBObject
+ // equivalent to @Remotable
+ if (!remotable) {
+ for (Annotation annotation : clazz.getAnnotations()) {
+ if ("javax.ejb.Remote".equals(annotation.annotationType().getName())) {
+ remotable = true;
+ break;
+ }
+ }
+ }
+ if (!remotable) {
+ for (Class<?> superInterface : clazz.getInterfaces()) {
+ if (Remote.class == superInterface || "javax.ejb.EJBObject".equals(superInterface.getName())) {
+ remotable = true;
+ break;
+ }
+ }
+ }
+
+ if (remotable) {
+ if (javaInterface.isRemotableSet() && javaInterface.isRemotable() == false) {
+ throw new InvalidAnnotationException("[JCA30005] @Remotable annotation present in a interface marked as not remotable in the SCDL", Remotable.class);
+ }
+ } else {
+ if (javaInterface.isRemotableSet()) {
+ remotable = javaInterface.isRemotable();
+ }
+ }
+
+ javaInterface.setRemotable(remotable);
+
+ Class<?> callbackClass = null;
+ org.oasisopen.sca.annotation.Callback callback = clazz.getAnnotation(org.oasisopen.sca.annotation.Callback.class);
+ if (callback != null && !Void.class.equals(callback.value())) {
+ callbackClass = callback.value();
+ if (remotable && !callbackClass.isAnnotationPresent(Remotable.class)) {
+ throw new InvalidCallbackException("Callback " + callbackClass.getName() +
+ " must be remotable on remotable interface " + clazz.getName());
+ }
+ if (!remotable && callbackClass.isAnnotationPresent(Remotable.class)) {
+ throw new InvalidCallbackException("Callback" + callbackClass.getName() +
+ " must not be remotable on local interface " + clazz.getName());
+ }
+ } else if (callback != null && Void.class.equals(callback.value())) {
+ throw new InvalidCallbackException("No callback interface specified on callback annotation in " + clazz.getName());
+ }
+
+ javaInterface.setCallbackClass(callbackClass);
+
+ String ns = JavaXMLMapper.getNamespace(clazz);
+ javaInterface.getOperations().addAll(getOperations(clazz, remotable, ns));
+
+ for (JavaInterfaceVisitor extension : visitors) {
+ extension.visitInterface(javaInterface);
+ }
+ }
+
+ private Class<?>[] getActualTypes(Type[] types, Class<?>[] rawTypes, Map<String, Type> typeBindings) {
+ Class<?>[] actualTypes = new Class<?>[types.length];
+ for (int i = 0; i < actualTypes.length; i++) {
+ actualTypes[i] = getActualType(types[i], rawTypes[i], typeBindings);
+ }
+ return actualTypes;
+ }
+
+ private Class<?> getActualType(Type type, Class<?> rawType, Map<String, Type> typeBindings) {
+ if (type instanceof TypeVariable<?>) {
+ TypeVariable<?> typeVariable = (TypeVariable<?>)type;
+ type = typeBindings.get(typeVariable.getName());
+ if (type instanceof Class<?>) {
+ return (Class<?>)type;
+ }
+ }
+ return rawType;
+ }
+
+ private <T> List<Operation> getOperations(Class<T> clazz,
+ boolean remotable,
+ String ns) throws InvalidInterfaceException {
+
+ Set<Type> genericInterfaces = new HashSet<Type>();
+ for (Type t : clazz.getGenericInterfaces()) {
+ genericInterfaces.add(t);
+ }
+ Map<String, Type> typeBindings = new HashMap<String, Type>();
+ for (Type genericInterface : genericInterfaces) {
+ if (genericInterface instanceof ParameterizedType) {
+ ParameterizedType parameterizedType = (ParameterizedType)genericInterface;
+ TypeVariable<?>[] typeVariables = ((Class<?>)parameterizedType.getRawType()).getTypeParameters();
+ Type[] typeArguments = parameterizedType.getActualTypeArguments();
+ for (int i = 0; i < typeArguments.length; i++) {
+ typeBindings.put(typeVariables[i].getName(), typeArguments[i]);
+ }
+ }
+ }
+
+ Method[] methods = clazz.getMethods();
+ List<Operation> operations = new ArrayList<Operation>(methods.length);
+ Set<String> names = remotable ? new HashSet<String>() : null;
+ for (Method method : methods) {
+ boolean hasHolders = false;
+ if (method.getDeclaringClass() == Object.class) {
+ // Skip the methods on the Object.class
+ continue;
+ }
+ String name = method.getName();
+ if (remotable && names.contains(name)) {
+ throw new OverloadedOperationException(method);
+ }
+ if (remotable && !jaxwsAsyncMethod(method)) {
+ names.add(name);
+ }
+
+ Class<?> returnType = getActualType(method.getGenericReturnType(), method.getReturnType(), typeBindings);
+ Class<?>[] parameterTypes =
+ getActualTypes(method.getGenericParameterTypes(), method.getParameterTypes(), typeBindings);
+ Class<?>[] faultTypes =
+ getActualTypes(method.getGenericExceptionTypes(), method.getExceptionTypes(), typeBindings);
+ Class<?>[] allOutputTypes = getOutputTypes(returnType, parameterTypes);
+
+ // For async server interfaces, faults are described using the @AsyncFaults annotation
+ if( method.isAnnotationPresent(AsyncFault.class) ) {
+ faultTypes = readAsyncFaultTypes( method );
+ } // end if
+
+ boolean nonBlocking = method.isAnnotationPresent(OneWay.class);
+ if (nonBlocking) {
+ if (!(returnType == void.class)) {
+ throw new InvalidOperationException(
+ "Method should return 'void' when declared with an @OneWay annotation. " + method,
+ method);
+ }
+ if (!(faultTypes.length == 0)) {
+ throw new InvalidOperationException(
+ "Method should not declare exceptions with an @OneWay annotation. " + method,
+ method);
+ }
+ }
+
+ JavaOperation operation = new JavaOperationImpl();
+ operation.setName(name);
+
+ // Set outputType to null for void
+ XMLType xmlReturnType = new XMLType(new QName(ns, "return"), null);
+ DataType<XMLType> returnDataType =
+ returnType == void.class ? null : new DataTypeImpl<XMLType>(UNKNOWN_DATABINDING, returnType, method
+ .getGenericReturnType(), xmlReturnType);
+
+
+ // Handle Input Types
+ List<DataType> paramDataTypes = new ArrayList<DataType>(parameterTypes.length);
+ List<Type> genericHolderTypes = new ArrayList<Type>();
+ List<Class<?>> physicalHolderTypes = new ArrayList<Class<?>>();
+ Type[] genericParamTypes = method.getGenericParameterTypes();
+ for (int i = 0; i < parameterTypes.length; i++) {
+ Class<?> paramType = parameterTypes[i];
+ XMLType xmlParamType = new XMLType(new QName(ns, "arg" + i), null);
+
+ DataTypeImpl<XMLType> xmlDataType = new DataTypeImpl<XMLType>(
+ UNKNOWN_DATABINDING, paramType, genericParamTypes[i],xmlParamType);
+ ParameterMode mode = ParameterMode.IN;
+ // Holder pattern. Physical types of Holder<T> classes are updated to <T> to aid in transformations.
+ if ( Holder.class == paramType) {
+ hasHolders = true;
+ genericHolderTypes.add(genericParamTypes[i]);
+ Type firstActual = getFirstActualType( genericParamTypes[ i ] );
+ if ( firstActual != null ) {
+ physicalHolderTypes.add((Class<?>)firstActual);
+ xmlDataType.setPhysical( (Class<?>)firstActual );
+ mode = ParameterMode.INOUT;
+ } else {
+ physicalHolderTypes.add(xmlDataType.getPhysical());
+ }
+ }
+ paramDataTypes.add( xmlDataType);
+ operation.getParameterModes().add(mode);
+ }
+
+
+ // Get Output Types
+ List<DataType> outputDataTypes = new ArrayList<DataType>(allOutputTypes.length);
+ Type genericReturnType = method.getGenericReturnType();
+
+ for ( int i=0; i <= genericHolderTypes.size(); i++ ) {
+ Class<?> paramType = allOutputTypes[i];
+ XMLType xmlOutputType = new XMLType(new QName(ns, "out" + i), null);
+
+ if ( i == 0 ) {
+ outputDataTypes.add(returnDataType);
+ } else {
+ DataTypeImpl<XMLType> xmlDataType = xmlDataType = new DataTypeImpl<XMLType>(
+ UNKNOWN_DATABINDING, physicalHolderTypes.get(i-1), genericHolderTypes.get(i-1), xmlOutputType);
+ outputDataTypes.add(xmlDataType);
+ }
+
+ }
+
+ // Fault types
+ List<DataType> faultDataTypes = new ArrayList<DataType>(faultTypes.length);
+ Type[] genericFaultTypes = method.getGenericExceptionTypes();
+ if( method.isAnnotationPresent(AsyncFault.class) ) {
+ genericFaultTypes = readAsyncGenericFaultTypes( method );
+ } // end if
+ for (int i = 0; i < faultTypes.length; i++) {
+ Class<?> faultType = faultTypes[i];
+ // Only add checked exceptions
+ // JAXWS Specification v2.1 section 3.7 says RemoteException should not be mapped
+ if (Exception.class.isAssignableFrom(faultType) && (!RuntimeException.class.isAssignableFrom(faultType))
+ && (!RemoteException.class.isAssignableFrom(faultType))) {
+ XMLType xmlFaultType = new XMLType(new QName(ns, faultType.getSimpleName()), null);
+ DataType<XMLType> faultDataType =
+ new DataTypeImpl<XMLType>(UNKNOWN_DATABINDING, faultType, genericFaultTypes[i], xmlFaultType);
+ faultDataTypes.add(new DataTypeImpl<DataType>(UNKNOWN_DATABINDING, faultType, genericFaultTypes[i],
+ faultDataType));
+ }
+ }
+
+ DataType<List<DataType>> inputType =
+ new DataTypeImpl<List<DataType>>(IDL_INPUT, Object[].class, paramDataTypes);
+ DataType<List<DataType>> outputType =
+ new DataTypeImpl<List<DataType>>(IDL_OUTPUT, Object[].class, outputDataTypes);
+
+ operation.setOutputType(outputType);
+
+ operation.setInputType(inputType);
+ operation.setFaultTypes(faultDataTypes);
+ operation.setNonBlocking(nonBlocking);
+ operation.setJavaMethod(method);
+ operation.setHasHolders(hasHolders);
+ operations.add(operation);
+ }
+ return operations;
+ }
+
+
+ private Class<?>[] getOutputTypes(Class<?> returnType, Class<?>[] parameterTypes) {
+ Class<?>[] returnTypes = new Class<?>[parameterTypes.length + 1];
+ returnTypes[0] = returnType;
+ int idx = 1;
+ for ( Class<?> clazz : parameterTypes ) {
+ if ( Holder.class == clazz )
+ returnTypes[idx++] = clazz;
+ }
+
+ return returnTypes;
+ }
+
+
+
+ /**
+ * Reads the fault types declared in an @AsyncFault annotation on an async server method
+ * @param method - the Method
+ * @return - an array of fault/exception classes
+ */
+ private Class<?>[] readAsyncFaultTypes( Method method ) {
+ AsyncFault theFaults = method.getAnnotation(AsyncFault.class);
+ if ( theFaults == null ) return null;
+ return theFaults.value();
+ } // end method readAsyncFaultTypes
+
+ /**
+ * Reads the generic fault types declared in an @AsyncFault annotation on an async server method
+ * @param method - the Method
+ * @return - an array of fault/exception classes
+ */
+ private Type[] readAsyncGenericFaultTypes( Method method ) {
+ AsyncFault theFaults = method.getAnnotation(AsyncFault.class);
+ if ( theFaults == null ) return null;
+ return theFaults.value();
+ } // end method readAsyncFaultTypes
+
+ private boolean jaxwsAsyncMethod(Method method) {
+ if (method.getName().endsWith("Async")) {
+ if (method.getReturnType().isAssignableFrom(Future.class)) {
+ if (method.getParameterTypes().length > 0) {
+ if (method.getParameterTypes()[method.getParameterTypes().length-1].isAssignableFrom(AsyncHandler.class)) {
+ return true;
+ }
+ }
+ }
+ if (method.getReturnType().isAssignableFrom(Response.class)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ /**
+ * Given a Class<T>, returns T, otherwise null.
+ * @param testClass
+ * @return
+ */
+ protected static Type getFirstActualType(Type genericType) {
+ if (genericType instanceof ParameterizedType) {
+ ParameterizedType pType = (ParameterizedType)genericType;
+ Type[] actualTypes = pType.getActualTypeArguments();
+ if ((actualTypes != null) && (actualTypes.length > 0)) {
+ return actualTypes[0];
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceUtil.java b/sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceUtil.java
new file mode 100644
index 0000000000..352cffeef2
--- /dev/null
+++ b/sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceUtil.java
@@ -0,0 +1,223 @@
+/*
+ * 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.impl;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.Interface;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterface;
+import org.apache.tuscany.sca.interfacedef.java.JavaOperation;
+
+/**
+ * Contains methods for mapping between an operation in a
+ * {@link org.apache.tuscany.spi.model.ServiceContract} and a method defined by
+ * a Java interface
+ *
+ * @version $Rev$ $Date$
+ * @tuscany.spi.extension.asclient
+ */
+public final class JavaInterfaceUtil {
+
+ private JavaInterfaceUtil() {
+ }
+
+ /**
+ * Return the method on the implementation class that matches the operation.
+ *
+ * @param implClass the implementation class or interface
+ * @param operation the operation to match
+ * @return the method described by the operation
+ * @throws NoSuchMethodException if no such method exists
+ * @Deprecated
+ */
+ public static Method findMethod(Class<?> implClass, Operation operation) throws NoSuchMethodException {
+ String name = operation.getName();
+ if (operation instanceof JavaOperation) {
+ if( ((JavaOperation)operation).isAsyncServer() ) {
+ // In this case, the operation is a mapped async server style method and needs special handling
+ return findAsyncServerMethod( implClass, (JavaOperation)operation );
+ } else {
+ name = ((JavaOperation)operation).getJavaMethod().getName();
+ } // end if
+ }
+ Interface interface1 = operation.getInterface();
+ int numParams = operation.getInputType().getLogical().size();
+ if (interface1 != null && interface1.isRemotable()) {
+ List<Method> matchingMethods = new ArrayList<Method>();
+ for (Method m : implClass.getMethods()) {
+ if (m.getName().equals(name) && m.getParameterTypes().length == numParams) {
+ matchingMethods.add(m);
+ }
+ }
+
+ // TUSCANY-2180 If there is only one method then we just match on the name
+ // (this is the same as the existing behaviour)
+ if (matchingMethods.size() == 1) {
+ return matchingMethods.get(0);
+ }
+ if (matchingMethods.size() > 1) {
+ // TUSCANY-2180 We need to check the parameter types too
+ Class<?>[] paramTypes = getPhysicalTypes(operation);
+ return implClass.getMethod(name, paramTypes);
+ }
+
+ // No matching method found
+ throw new NoSuchMethodException("No matching method for operation " + operation.getName()
+ + " is found on "
+ + implClass);
+ }
+ Class<?>[] paramTypes = getPhysicalTypes(operation);
+ return implClass.getMethod(name, paramTypes);
+ }
+
+ /**
+ * Return the method on the implementation class that matches the async server version of the operation.
+ *
+ * @param implClass the implementation class or interface
+ * @param operation the operation to match - this is the sync equivalent of an async server operation
+ * @return the method described by the operation
+ * @throws NoSuchMethodException if no such method exists
+ */
+ public static Method findAsyncServerMethod(Class<?> implClass, JavaOperation operation) throws NoSuchMethodException {
+ String name = operation.getJavaMethod().getName();
+ List<Operation> actualOps = (List<Operation>) operation.getInterface().getAttributes().get("ASYNC-SERVER-OPERATIONS");
+ Operation matchingOp = null;
+ for( Operation op: actualOps ) {
+ if( op.getName().equals(name) ) {
+ matchingOp = op;
+ break;
+ }
+ } // end for
+ if( matchingOp == null ) throw new NoSuchMethodException("No matching async method for operation " + operation.getName());
+
+ int numParams = matchingOp.getInputType().getLogical().size();
+
+ List<Method> matchingMethods = new ArrayList<Method>();
+ for (Method m : implClass.getMethods()) {
+ if (m.getName().equals(name) && m.getParameterTypes().length == (numParams) ) {
+ matchingMethods.add(m);
+ }
+ }
+
+ if (matchingMethods.size() == 1) {
+ return matchingMethods.get(0);
+ }
+ if (matchingMethods.size() > 1) {
+ Class<?>[] paramTypes = getPhysicalTypes(matchingOp);
+ return implClass.getMethod(name, paramTypes);
+ }
+
+ // No matching method found
+ throw new NoSuchMethodException("No matching method for operation " + operation.getName()
+ + " is found on " + implClass);
+
+ } // end method findAsyncServerMethod
+
+ /**
+ * @Deprecated
+ */
+ private static Class<?>[] getPhysicalTypes(Operation operation) {
+ DataType<List<DataType>> inputType = operation.getInputType();
+ if (inputType == null) {
+ return new Class<?>[] {};
+ }
+ List<DataType> types = inputType.getLogical();
+ Class<?>[] javaTypes = new Class<?>[types.size()];
+ for (int i = 0; i < javaTypes.length; i++) {
+ Type physical = types.get(i).getPhysical();
+ if (physical instanceof Class<?>) {
+ javaTypes[i] = (Class<?>)physical;
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+ return javaTypes;
+ }
+
+ /**
+ * Searches a collection of operations for a match against the given method
+ *
+ * @param method the method to match
+ * @param operations the operations to match against
+ * @return a matching operation or null
+ * @Deprecated
+ */
+ public static Operation findOperation(Method method, Collection<Operation> operations) {
+ for (Operation operation : operations) {
+ if (match(operation, method)) {
+ return operation;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Determines if the given operation matches the given method
+ *
+ * @return true if the operation matches, false if does not
+ */
+ private static boolean match(Operation operation, Method method) {
+ Class<?>[] params = method.getParameterTypes();
+ DataType<List<DataType>> inputType = operation.getInputType();
+ List<DataType> types = inputType.getLogical();
+ boolean found = true;
+ if (types.size() == params.length && method.getName().equals(operation.getName())) {
+ for (int i = 0; i < params.length; i++) {
+ Class<?> clazz = params[i];
+ if (!clazz.equals(operation.getInputType().getLogical().get(i).getPhysical())) {
+ found = false;
+ }
+ }
+ } else {
+ found = false;
+ }
+ return found;
+
+ }
+
+ private static String getPackageName(Class<?> cls) {
+ String name = cls.getName();
+ int index = name.lastIndexOf('.');
+ return index == -1 ? "" : name.substring(0, index);
+ }
+
+ public static String getNamespace(Class<?> cls) {
+ String packageName = getPackageName(cls);
+ if ("".equals(packageName)) {
+ return "";
+ }
+ StringBuffer ns = new StringBuffer("http://");
+ String[] names = packageName.split("\\.");
+ for (int i = names.length - 1; i >= 0; i--) {
+ ns.append(names[i]);
+ if (i != 0) {
+ ns.append('.');
+ }
+ }
+ ns.append('/');
+ return ns.toString();
+ }
+
+}
diff --git a/sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaOperationImpl.java b/sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaOperationImpl.java
new file mode 100644
index 0000000000..7169cc164d
--- /dev/null
+++ b/sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaOperationImpl.java
@@ -0,0 +1,100 @@
+/*
+ * 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.impl;
+
+import java.lang.reflect.Method;
+
+import org.apache.tuscany.sca.interfacedef.impl.OperationImpl;
+import org.apache.tuscany.sca.interfacedef.java.JavaOperation;
+
+/**
+ * Represents a Java operation.
+ *
+ * @version $Rev$ $Date$
+ */
+public class JavaOperationImpl extends OperationImpl implements JavaOperation {
+
+ private Method method;
+ private String action;
+ private boolean isAsyncServer = false;
+
+ public Method getJavaMethod() {
+ return method;
+ }
+
+ public void setJavaMethod(Method method) {
+ this.method = method;
+ }
+
+ public String getAction() {
+ return action;
+ }
+
+ public void setAction(String action) {
+ this.action = action;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + ((method == null) ? 0 : method.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final JavaOperationImpl other = (JavaOperationImpl)obj;
+ if (method == null) {
+ if (other.method != null)
+ return false;
+ } else if (!method.equals(other.method))
+ return false;
+ return true;
+ }
+
+ /**
+ * Sets whether this operation has async server style
+ * @param isAsync - "true" marks this operation as async server style
+ */
+ public void setAsyncServer( boolean isAsync ) {
+ isAsyncServer = isAsync;
+ }
+
+ /**
+ * Indicates whether this operation is async server style
+ * @return - true if the operation is async server style
+ */
+ public boolean isAsyncServer() {
+ return isAsyncServer;
+ }
+
+ @Override
+ public String toString() {
+ return method == null ? "null" : method.toGenericString();
+ }
+
+}
diff --git a/sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/PolicyJavaInterfaceVisitor.java b/sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/PolicyJavaInterfaceVisitor.java
new file mode 100644
index 0000000000..1c0333f833
--- /dev/null
+++ b/sandbox/sebastien/java/vhost/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/PolicyJavaInterfaceVisitor.java
@@ -0,0 +1,278 @@
+/*
+ * 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.impl;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.jws.WebParam;
+import javax.jws.WebResult;
+import javax.jws.soap.SOAPBinding;
+import javax.xml.namespace.QName;
+
+import org.apache.tuscany.sca.assembly.xml.Constants;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.FactoryExtensionPoint;
+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.JavaOperation;
+import org.apache.tuscany.sca.interfacedef.java.introspect.JavaInterfaceVisitor;
+import org.apache.tuscany.sca.policy.Intent;
+import org.apache.tuscany.sca.policy.PolicyFactory;
+import org.apache.tuscany.sca.policy.PolicySet;
+import org.apache.tuscany.sca.policy.PolicySubject;
+import org.oasisopen.sca.annotation.PolicySets;
+import org.oasisopen.sca.annotation.Qualifier;
+import org.oasisopen.sca.annotation.Requires;
+
+/**
+ * Processes an {@link org.oasisopen.sca.annotation.Requires} annotation
+ *
+ * @version $Rev$ $Date$
+ */
+public class PolicyJavaInterfaceVisitor implements JavaInterfaceVisitor {
+ private PolicyFactory policyFactory;
+
+ public PolicyJavaInterfaceVisitor(ExtensionPointRegistry registry) {
+ super();
+ this.policyFactory = registry.getExtensionPoint(FactoryExtensionPoint.class).getFactory(PolicyFactory.class);
+ }
+
+ private QName getQName(String intentName) {
+ QName qname;
+ if (intentName.startsWith("{")) {
+ int i = intentName.indexOf('}');
+ if (i != -1) {
+ qname = new QName(intentName.substring(1, i), intentName.substring(i + 1));
+ } else {
+ qname = new QName("", intentName);
+ }
+ } else {
+ qname = new QName("", intentName);
+ }
+ return qname;
+ }
+
+ /**
+ * Read policy intents on the given interface or class
+ * @param clazz
+ * @param requiredIntents
+ */
+ private void readIntentsAndPolicySets(Class<?> clazz, PolicySubject subject) {
+ Requires intentAnnotation = clazz.getAnnotation(Requires.class);
+ if (intentAnnotation != null) {
+ String[] intentNames = intentAnnotation.value();
+ if (intentNames.length != 0) {
+ for (String intentName : intentNames) {
+
+ // Add each intent to the list
+ Intent intent = policyFactory.createIntent();
+ intent.setName(getQName(intentName));
+ subject.getRequiredIntents().add(intent);
+ }
+ }
+ }
+
+ readSpecificIntents(clazz.getAnnotations(), subject.getRequiredIntents());
+
+ PolicySets policySetAnnotation = clazz.getAnnotation(PolicySets.class);
+ if (policySetAnnotation != null) {
+ String[] policySetNames = policySetAnnotation.value();
+ if (policySetNames.length != 0) {
+ for (String policySetName : policySetNames) {
+
+ // Add each intent to the list
+ PolicySet policySet = policyFactory.createPolicySet();
+ policySet.setName(getQName(policySetName));
+ subject.getPolicySets().add(policySet);
+ }
+ }
+ }
+
+ if ( clazz.isAnnotationPresent(SOAPBinding.class) ) {
+ // add soap intent
+ Intent intent = policyFactory.createIntent();
+ intent.setName(Constants.SOAP_INTENT);
+ subject.getRequiredIntents().add(intent);
+ }
+
+
+ }
+
+ private void readIntents(Requires intentAnnotation, List<Intent> requiredIntents) {
+ //Requires intentAnnotation = method.getAnnotation(Requires.class);
+ if (intentAnnotation != null) {
+ String[] intentNames = intentAnnotation.value();
+ if (intentNames.length != 0) {
+ //Operation operation = assemblyFactory.createOperation();
+ //operation.setName(method.getName());
+ //operation.setUnresolved(true);
+ for (String intentName : intentNames) {
+
+ // Add each intent to the list, associated with the
+ // operation corresponding to the annotated method
+ Intent intent = policyFactory.createIntent();
+ intent.setName(getQName(intentName));
+ //intent.getOperations().add(operation);
+ requiredIntents.add(intent);
+ }
+ }
+ }
+ }
+
+ private void readPolicySets(PolicySets policySetAnnotation, List<PolicySet> policySets) {
+ if (policySetAnnotation != null) {
+ String[] policySetNames = policySetAnnotation.value();
+ if (policySetNames.length != 0) {
+ //Operation operation = assemblyFactory.createOperation();
+ //operation.setName(method.getName());
+ //operation.setUnresolved(true);
+ for (String policySetName : policySetNames) {
+ // Add each intent to the list, associated with the
+ // operation corresponding to the annotated method
+ PolicySet policySet = policyFactory.createPolicySet();
+ policySet.setName(getQName(policySetName));
+ //intent.getOperations().add(operation);
+ policySets.add(policySet);
+ }
+ }
+ }
+ }
+
+ public void readWebServicesAnnotations(Method m, Class<?> clazz, List<Intent> requiredIntents) {
+
+ WebResult webResultAnnotation = m.getAnnotation(WebResult.class);
+ if (webResultAnnotation != null) {
+ if (webResultAnnotation.header()) {
+ // Add SOAP intent
+ Intent intent = policyFactory.createIntent();
+ intent.setName(Constants.SOAP_INTENT);
+ requiredIntents.add(intent);
+ return;
+ }
+ }
+
+ Annotation[][] parameterAnnotations = m.getParameterAnnotations();
+ for ( int i=0; i < parameterAnnotations.length; i++ ) {
+ for ( int j=0; j < parameterAnnotations[i].length; j++) {
+ if ( parameterAnnotations[i][j] instanceof WebParam ) {
+ WebParam webParam = (WebParam)parameterAnnotations[i][j];
+ if ( webParam.header() ) {
+ // Add SOAP intent
+ Intent intent = policyFactory.createIntent();
+ intent.setName(Constants.SOAP_INTENT);
+ requiredIntents.add(intent);
+ return;
+ }
+ }
+ }
+ }
+
+ }
+ public void visitInterface(JavaInterface javaInterface) throws InvalidInterfaceException {
+
+ if (javaInterface.getJavaClass() != null) {
+ readIntentsAndPolicySets(javaInterface.getJavaClass(), javaInterface);
+
+ // Read intents on the service interface methods
+ List<Operation> operations = javaInterface.getOperations();
+ for (Operation op : operations) {
+ JavaOperation operation = (JavaOperation)op;
+ Method method = operation.getJavaMethod();
+
+ readIntents(method.getAnnotation(Requires.class), op.getRequiredIntents());
+ readSpecificIntents(method.getAnnotations(), op.getRequiredIntents());
+ readPolicySets(method.getAnnotation(PolicySets.class), op.getPolicySets());
+ readWebServicesAnnotations(method, javaInterface.getJavaClass(), javaInterface.getRequiredIntents());
+ inherit(javaInterface, op);
+ }
+ }
+
+
+
+
+ }
+
+ private void inherit(JavaInterface javaInterface, Operation op) {
+ List<Intent> interfaceIntents = new ArrayList<Intent>(javaInterface.getRequiredIntents());
+ for ( Intent intent : javaInterface.getRequiredIntents() ) {
+
+ for ( Intent operationIntent : op.getRequiredIntents() ) {
+ if ( intent.getExcludedIntents().contains(operationIntent) ||
+ operationIntent.getExcludedIntents().contains(intent) ) {
+ interfaceIntents.remove(intent);
+ continue;
+ }
+ }
+ }
+ op.getRequiredIntents().addAll(interfaceIntents);
+
+ op.getPolicySets().addAll(javaInterface.getPolicySets());
+ }
+
+ private void readSpecificIntents(Annotation[] annotations, List<Intent> requiredIntents) {
+ for (Annotation a : annotations) {
+ org.oasisopen.sca.annotation.Intent intentAnnotation =
+ a.annotationType().getAnnotation(org.oasisopen.sca.annotation.Intent.class);
+ if (intentAnnotation == null) {
+ continue;
+ }
+ QName qname = null;
+ String value = intentAnnotation.value();
+ if (!value.equals("")) {
+ qname = getQName(value);
+ } else {
+ qname = new QName(intentAnnotation.targetNamespace(), intentAnnotation.localPart());
+ }
+ Set<String> qualifiers = new HashSet<String>();
+ for(Method m: a.annotationType().getMethods()) {
+ Qualifier qualifier = m.getAnnotation(Qualifier.class);
+ if (qualifier != null && m.getReturnType() == String[].class) {
+ try {
+ qualifiers.addAll(Arrays.asList((String[]) m.invoke(a)));
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ qualifiers.remove("");
+ if (qualifiers.isEmpty()) {
+ Intent intent = policyFactory.createIntent();
+ intent.setUnresolved(true);
+ intent.setName(qname);
+ requiredIntents.add(intent);
+ } else {
+ for (String q : qualifiers) {
+ Intent intent = policyFactory.createIntent();
+ intent.setUnresolved(true);
+ qname = new QName(qname.getNamespaceURI(), qname.getLocalPart() + "." + q);
+ intent.setName(qname);
+ requiredIntents.add(intent);
+ }
+ }
+ }
+ }
+
+}