diff options
Diffstat (limited to 'sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src')
29 files changed, 4176 insertions, 0 deletions
diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/DefaultJavaInterfaceFactory.java b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/DefaultJavaInterfaceFactory.java new file mode 100644 index 0000000000..89b8c7193d --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/DefaultJavaInterfaceFactory.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; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.util.Collection; +import java.util.List; +import java.util.logging.Logger; + +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.extensibility.ServiceDeclaration; +import org.apache.tuscany.sca.interfacedef.java.impl.JavaInterfaceFactoryImpl; +import org.apache.tuscany.sca.interfacedef.java.introspect.JavaInterfaceVisitor; + +/** + * A factory for the Java interface model. + * + * @version $Rev$ $Date$ + * @tuscany.spi.extension.asclient + */ +public class DefaultJavaInterfaceFactory extends JavaInterfaceFactoryImpl implements JavaInterfaceFactory { + private static final Logger logger = Logger.getLogger(DefaultJavaInterfaceFactory.class.getName()); + + private ExtensionPointRegistry registry; + // private Monitor monitor = null; + private boolean loadedVisitors; + + public DefaultJavaInterfaceFactory(ExtensionPointRegistry registry) { + super(); + this.registry = registry; + } + + @Override + public List<JavaInterfaceVisitor> getInterfaceVisitors() { + loadVisitors(); + return super.getInterfaceVisitors(); + } + + /** + * Load visitors declared under META-INF/services + */ + @SuppressWarnings("unchecked") + private synchronized void loadVisitors() { + if (loadedVisitors) + return; + + // Get the databinding service declarations + Collection<ServiceDeclaration> visitorDeclarations; + try { + visitorDeclarations = registry.getServiceDiscovery().getServiceDeclarations(JavaInterfaceVisitor.class, true); + } catch (IOException e) { + throw new IllegalStateException(e); + } + + // Load data bindings + for (ServiceDeclaration visitorDeclaration: visitorDeclarations) { + JavaInterfaceVisitor visitor = null; + try { + Class<JavaInterfaceVisitor> visitorClass = (Class<JavaInterfaceVisitor>)visitorDeclaration.loadClass(); + + try { + Constructor<JavaInterfaceVisitor> constructor = visitorClass.getConstructor(ExtensionPointRegistry.class); + visitor = constructor.newInstance(registry); + } catch (NoSuchMethodException e) { + visitor = visitorClass.newInstance(); + } + + + } catch (Exception e) { + IllegalStateException ie = new IllegalStateException(e); + throw ie; + } + + logger.fine("Adding Java Interface visitor: " + visitor.getClass().getName()); + + addInterfaceVisitor(visitor); + } + + loadedVisitors = true; + } + + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/JavaInterface.java b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/JavaInterface.java new file mode 100644 index 0000000000..e042d863d7 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/JavaInterface.java @@ -0,0 +1,134 @@ +/* + * 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; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.Base; +import org.apache.tuscany.sca.contribution.Contribution; +import org.apache.tuscany.sca.interfacedef.Interface; + +/** + * Represents a Java interface. + * + * @version $Rev$ $Date$ + * @tuscany.spi.extension.asclient + */ +public interface JavaInterface extends Interface, Base { + + /** + * Returns the name of the Java interface class. + * + * @return the name of the Java interface class + */ + String getName(); + + /** + * Sets the name of the Java interface class. + * + * @param className the name of the Java interface class + */ + void setName(String className); + + /** + * Returns the QName of the JAX-WS interface. + * + * @return the QName of the JAX-WS interface + */ + QName getQName(); + + /** + * Sets the QName of the JAX-WS interface. + * + * @param interfaceName the QName of the JAX-WS interface + */ + void setQName(QName interfaceName); + + /** + * Returns the Java interface class. + * + * @return the Java interface class + */ + Class<?> getJavaClass(); + + /** + * Sets the Java interface class. + * + * @param javaClass the Java interface class + */ + void setJavaClass(Class<?> javaClass); + + /** + * Returns the callback class specified in an @Callback annotation. + * + * @return the callback class specified in an @Callback annotation + */ + Class<?> getCallbackClass(); + + /** + * Sets the callback class specified in an @Callback annotation. + * + * @param callbackClass the callback class specified in an @Callback annotation + */ + void setCallbackClass(Class<?> callbackClass); + + /** + * A Java interface may have JAXWS annotations that refer to a + * a WSDL document. The resulting WSDL location is stored here + * so that is can be resolved after the Java interface itself + * has been resolved + * + * @return WSDL interface + */ + String getJAXWSWSDLLocation(); + + /** + * A Java interface may have JAXWS annotations that refer to a + * a WSDL document. The resulting WSDL location is stored here + * so that is can be resolved after the Java interface itself + * has been resolved + * + * @param wsdlInterface + */ + void setJAXWSWSDLLocation(String wsdlLocation); + + /** + * A Java interface may have JAXWS annotations that refer to a + * a Java interface by name. The resulting class name is stored here + * so that is can be resolved after this Java interface + * has been resolved + * + * @return + */ + String getJAXWSJavaInterfaceName(); + + /** + * A Java interface may have JAXWS annotations that refer to a + * a Java interface by name. The resulting class name is stored here + * so that is can be resolved after this Java interface + * has been resolved + * + * @return + */ + void setJAXWSJavaInterfaceName(String javaInterfaceName); + + public Contribution getContributionContainingClass(); + + public void setContributionContainingClass(Contribution contributionContainingClass); +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/JavaInterfaceContract.java b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/JavaInterfaceContract.java new file mode 100644 index 0000000000..25875dbd6a --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/JavaInterfaceContract.java @@ -0,0 +1,33 @@ +/* + * 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; + +import org.apache.tuscany.sca.interfacedef.InterfaceContract; + +/** + * Represents a Java interface contract. + * JavaInterfaceContract + * + * @version $Rev$ $Date$ + * @tuscany.spi.extension.asclient + */ +public interface JavaInterfaceContract extends InterfaceContract { + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/JavaInterfaceFactory.java b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/JavaInterfaceFactory.java new file mode 100644 index 0000000000..4f4e9d8268 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/JavaInterfaceFactory.java @@ -0,0 +1,91 @@ +/* + * 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; + +import java.lang.reflect.Method; +import java.util.List; + +import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException; +import org.apache.tuscany.sca.interfacedef.java.introspect.JavaInterfaceVisitor; + +/** + * Factory for the Java interface model + * + * @version $Rev$ $Date$ + * @tuscany.spi.extension.asclient + */ +public interface JavaInterfaceFactory { + + /** + * Creates a new Java interface model. + * + * @return + */ + JavaInterface createJavaInterface(); + + /** + * Creates a new Java interface model from an interface class. + * @param interfaceClass the interface class to introspect. + * @return + */ + JavaInterface createJavaInterface(Class<?> interfaceClass) throws InvalidInterfaceException; + + /** + * Creates the contents of a Java interface model from an interface class. + * @param javaInterface the Java interface model + * @param interfaceClass the interface class to introspect. + * @return + */ + void createJavaInterface(JavaInterface javaInterface, Class<?> interfaceClass) throws InvalidInterfaceException; + + /** + * Create a JavaOperation + * @param method + * @return + */ + JavaOperation createJavaOperation(Method method); + + /** + * Creates a new Java interface contract. + * + * @return + */ + JavaInterfaceContract createJavaInterfaceContract(); + + /** + * Registers the given visitor. + * + * @param visitor + */ + void addInterfaceVisitor(JavaInterfaceVisitor visitor); + + /** + * Deregisters the given visitor. + * + * @param visitor + */ + void removeInterfaceVisitor(JavaInterfaceVisitor visitor); + + /** + * Returns a list of interface visitors. + * + * @return + */ + List<JavaInterfaceVisitor> getInterfaceVisitors(); +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/JavaOperation.java b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/JavaOperation.java new file mode 100644 index 0000000000..ee8cea8740 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/JavaOperation.java @@ -0,0 +1,82 @@ +/* + * 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; + +import java.lang.reflect.Method; + +import org.apache.tuscany.sca.interfacedef.Operation; + +/** + * Represents a Java operation. + * + * @version $Rev$ $Date$ + * @tuscany.spi.extension.asclient + */ +public interface JavaOperation extends Operation { + + /** + * Returns the Java method defining the operation. + * @return the Java method + */ + Method getJavaMethod(); + + /** + * Sets the Java method defining the operation. + * @param method the Java method + */ + void setJavaMethod(Method method); + + /** + * Returns the JAX-WS @WebMethod action parameter. + * @return the action value + */ + String getAction(); + + /** + * Sets the JAX-WS @WebMethod action parameter. + * @param action the action value + */ + void setAction(String action); + + /** + * Sets whether this operation has async server style + * @param isAsync - "true" marks this operation as async server style + */ + public void setAsyncServer( boolean isAsync ); + + /** + * Indicates whether this operation is async server style + * @return - true if the operation is async server style + */ + public boolean isAsyncServer(); + + /** + * Indicates whether the underlying Java method has void return type. + * @return - true if the Java method has void return type. + */ + public boolean hasReturnTypeVoid(); + + /** + * Sets whether the underlying Java method has void return type. + * @param flag - "true" marks this operation as having void return type. + */ + public void setReturnTypeVoid(boolean flag); + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceContractImpl.java b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceContractImpl.java new file mode 100644 index 0000000000..c3622bf841 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/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 normalizedWSDLInterfaceContract; + + protected JavaInterfaceContractImpl() { + } + + @Override + public JavaInterfaceContractImpl clone() throws CloneNotSupportedException { + return (JavaInterfaceContractImpl) super.clone(); + } + + @Override + public InterfaceContract getNormalizedWSDLContract() { + return normalizedWSDLInterfaceContract; + } + + @Override + public void setNormalizedWSDLContract(InterfaceContract wsdlInterfaceContract) { + normalizedWSDLInterfaceContract = wsdlInterfaceContract; + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceFactoryImpl.java b/sca-java-2.x/branches/2.0-Beta3/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/sca-java-2.x/branches/2.0-Beta3/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/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceImpl.java b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceImpl.java new file mode 100644 index 0000000000..4a2d9a5dd5 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceImpl.java @@ -0,0 +1,370 @@ +/* + * 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 static org.apache.tuscany.sca.interfacedef.Operation.IDL_INPUT; +import static org.apache.tuscany.sca.interfacedef.Operation.IDL_OUTPUT; + +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 + */ + @SuppressWarnings("rawtypes") + 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>>(IDL_OUTPUT, 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 (equivalent to an output logical List of size '0') + // 2) name ending in "Async" + // 3) final parameter which is of ResponseDispatch<?> type + int size = operation.getOutputType().getLogical().size(); + if (size != 0) { + return false; + } + + 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/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceIntrospectorImpl.java b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceIntrospectorImpl.java new file mode 100644 index 0000000000..1ffe9530b7 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceIntrospectorImpl.java @@ -0,0 +1,406 @@ +/* + * 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 static org.apache.tuscany.sca.interfacedef.Operation.IDL_INPUT; +import static org.apache.tuscany.sca.interfacedef.Operation.IDL_OUTPUT; +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 { + + 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); + } // end for + + // Check if any methods have disallowed annotations + // Check if any private methods have illegal annotations that should be raised as errors + Set<Method> methods = JavaIntrospectionHelper.getMethods(clazz); + for (Method method : methods) { + checkMethodAnnotations(method, javaInterface); + } // end for + } // end method introspectInterface + + private void checkMethodAnnotations(Method method, JavaInterface javaInterface) throws InvalidAnnotationException { + for ( Annotation a : method.getAnnotations() ) { + if( a instanceof Remotable ) { + // [JCA90053] @Remotable annotation cannot be on a method that is not a setter method + if( !JavaIntrospectionHelper.isSetter(method) ) { + throw new InvalidAnnotationException("[JCA90053] @Remotable annotation present on an interface method" + + " which is not a Setter method: " + javaInterface.getName() + "/" + method.getName(), Remotable.class); + } // end if + } // end if + } // end for + + // Parameter annotations + for (Annotation[] parmAnnotations : method.getParameterAnnotations()) { + for (Annotation annotation : parmAnnotations) { + if (annotation instanceof Remotable ) { + throw new InvalidAnnotationException("[JCA90053] @Remotable annotation present on an interface method" + + " parameter: " + javaInterface.getName() + "/" + method.getName(), Remotable.class); + } // end if + } // end for + } // end for + method.getParameterAnnotations(); + } // end method checkMethodAnnotations + + 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; + } + + @SuppressWarnings("rawtypes") + 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 hasMultipleOutputs = 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); + + // Given details of Holder mapping, it's easier to handle output first. + List<DataType> outputDataTypes = new ArrayList<DataType>(); + XMLType xmlReturnType = new XMLType(new QName(ns, "return"), null); + DataType<XMLType> returnDataType = null; + if (returnType == void.class) { + operation.setReturnTypeVoid(true); + } else { + returnDataType = new DataTypeImpl<XMLType>(UNKNOWN_DATABINDING, returnType, + method.getGenericReturnType(), xmlReturnType); + operation.setReturnTypeVoid(false); + outputDataTypes.add(returnDataType); + } + + // Handle Input Types + List<DataType> paramDataTypes = new ArrayList<DataType>(parameterTypes.length); + 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) { + hasMultipleOutputs = true; + Type firstActual = getFirstActualType( genericParamTypes[ i ] ); + if ( firstActual != null ) { + xmlDataType.setPhysical( (Class<?>)firstActual ); + mode = ParameterMode.INOUT; + } + outputDataTypes.add(xmlDataType); + } + paramDataTypes.add( xmlDataType); + operation.getParameterModes().add(mode); + } + + // 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.setHasArrayWrappedOutput(hasMultipleOutputs); + operations.add(operation); + } + return operations; + } + + + private Class<?>[] getOutputTypes(Class<?> returnType, Class<?>[] parameterTypes) { + + ArrayList<Class<?>> returnTypes = new ArrayList<Class<?>>(); + returnTypes.add(returnType); + for ( Class<?> clazz : parameterTypes ) { + if ( Holder.class == clazz ) + returnTypes.add(clazz); + } + Class[] arrayType = new Class[0]; + return returnTypes.toArray(arrayType); + } + + + + /** + * 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/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceUtil.java b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceUtil.java new file mode 100644 index 0000000000..922772ab07 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceUtil.java @@ -0,0 +1,237 @@ +/* + * 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.ParameterMode; +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(); + + // Account for OUT-only in matching. (Should we cache this number in JavaOperation?) + List<ParameterMode> parmModes = operation.getParameterModes(); + int numOutOnlyHolders = 0; + for (ParameterMode mode : parmModes) { + if (mode.equals(ParameterMode.OUT)) { + numOutOnlyHolders++; + } + } + numParams += numOutOnlyHolders; + + 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 + */ + //TODO - account for Holder(s) + 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 + */ + //TODO - account for Holder(s) + 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/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaIntrospectionHelper.java b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaIntrospectionHelper.java new file mode 100644 index 0000000000..a363c1ff16 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaIntrospectionHelper.java @@ -0,0 +1,641 @@ +/* + * 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.beans.Introspector; +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.lang.reflect.WildcardType; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.oasisopen.sca.ServiceReference; + +/** + * Implements various reflection-related operations + * + * @version $Rev$ $Date$ + */ +public final class JavaIntrospectionHelper { + private static final Logger logger = Logger.getLogger(JavaIntrospectionHelper.class.getName()); + private static final Class<?>[] EMPTY_CLASS_ARRY = new Class[0]; + + /** + * Hide the constructor + */ + private JavaIntrospectionHelper() { + } + + /** + * Returns a collection of public, and protected fields declared by a class + * or one of its supertypes + */ + public static Set<Field> getAllPublicAndProtectedFields(Class<?> clazz, boolean validating) { + return getAllPublicAndProtectedFields(clazz, new HashSet<Field>(), validating); + } + + private static void checkInvalidAnnotations(AnnotatedElement element) { + for (Annotation a : element.getAnnotations()) { + if (a.annotationType().getName().startsWith("org.oasisopen.sca.annotation.")) { + logger.warning("Invalid annotation " + a + " is found on " + element); + } + } + } + + /** + * Recursively evaluates the type hierarchy to return all fields that are + * public or protected + */ + private static Set<Field> getAllPublicAndProtectedFields(Class<?> clazz, Set<Field> fields, boolean validating) { + if (clazz == null || clazz.isArray() || Object.class.equals(clazz)) { + return fields; + } + fields = getAllPublicAndProtectedFields(clazz.getSuperclass(), fields, validating); + + Field[] declaredFields = null; + + try { + declaredFields = clazz.getDeclaredFields(); + } catch(Throwable t) { + //TUSCANY-3667 - clazz.getDeclaredFields might fail in GAE environment (log and ignore) + logger.log(Level.WARNING, "Error retrieving declared fields from class : " + t.getMessage()); + } + + if( declaredFields != null ) { + for (final Field field : declaredFields) { + int modifiers = field.getModifiers(); + // The field should be non-final and non-static + if ((Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers)) && !Modifier.isStatic(modifiers) && !Modifier.isFinal(modifiers)) { + // Allow privileged access to set accessibility. Requires ReflectPermission + // in security policy. + AccessController.doPrivileged(new PrivilegedAction<Object>() { + public Object run() { + field.setAccessible(true); // ignore Java accessibility + return null; + } + }); + fields.add(field); + } /*else { + if (validating) { + checkInvalidAnnotations(field); + } + }*/ + } + } + return fields; + } + + /** + * Returns a collection of injectable fields declared by a class + * or one of its supertypes + * + * For now we will include final or static fields so that validation problems can be reported + */ + public static Set<Field> getInjectableFields(Class<?> clazz, boolean validating) { + return getInjectableFields(clazz, new HashSet<Field>(), validating); + } + + /** + * Recursively evaluates the type hierarchy to return all fields + */ + private static Set<Field> getInjectableFields(Class<?> clazz, Set<Field> fields, boolean validating) { + if (clazz == null || clazz.isArray() || Object.class.equals(clazz)) { + return fields; + } + + fields = getInjectableFields(clazz.getSuperclass(), fields, validating); + + Field[] declaredFields = null; + + try { + declaredFields = clazz.getDeclaredFields(); + } catch(Throwable t) { + //TUSCANY-3667 - clazz.getDeclaredFields might fail in GAE environment (log and ignore) + logger.log(Level.WARNING, "Error retrieving declared fields from class : " + t.getMessage()); + } + + if( declaredFields != null ) { + for (final Field field : declaredFields) { + int modifiers = field.getModifiers(); + // The field should be non-final and non-static + if (!Modifier.isStatic(modifiers) + // && !Modifier.isFinal(modifiers) + ) { + + // Allow privileged access to set accessibility. Requires ReflectPermission + // in security policy. + AccessController.doPrivileged(new PrivilegedAction<Object>() { + public Object run() { + field.setAccessible(true); // ignore Java accessibility + return null; + } + }); + fields.add(field); + } else { + if (validating) { + checkInvalidAnnotations(field); + } + } + } + } + + + return fields; + } + + /** + * Returns a collection of public and protected methods declared by a class + * or one of its supertypes. Note that overridden methods will not be + * returned in the collection (i.e. only the method override will be). <p/> + * This method can potentially be expensive as reflection information is not + * cached. It is assumed that this method will be used during a + * configuration phase. + */ + public static Set<Method> getAllUniquePublicProtectedMethods(Class<?> clazz, boolean validating) { + return getAllUniqueMethods(clazz, new HashSet<Method>(), validating); + } + + /** + * Recursively evaluates the type hierarchy to return all unique methods + */ + private static Set<Method> getAllUniqueMethods(Class<?> pClass, Set<Method> methods, boolean validating) { + if (pClass == null || pClass.isArray() || Object.class.equals(pClass)) { + return methods; + } + // we first evaluate methods of the subclass and then move to the parent + Method[] declaredMethods = pClass.getDeclaredMethods(); + for (final Method declaredMethod : declaredMethods) { + int modifiers = declaredMethod.getModifiers(); + if ((!Modifier.isPublic(modifiers) && !Modifier.isProtected(modifiers)) || Modifier.isStatic(modifiers)) { + if (validating) { + checkInvalidAnnotations(declaredMethod); + } + continue; + } + if (methods.size() == 0) { + methods.add(declaredMethod); + } else { + List<Method> temp = new ArrayList<Method>(); + boolean matched = false; + for (Method method : methods) { + // only add if not already in the set from a superclass (i.e. + // the method is not overridden) + if (exactMethodMatch(declaredMethod, method)) { + matched = true; + break; + } + } + if (!matched) { + // Allow privileged access to set accessibility. Requires ReflectPermission + // in security policy. + AccessController.doPrivileged(new PrivilegedAction<Object>() { + public Object run() { + declaredMethod.setAccessible(true); + return null; + } + }); + temp.add(declaredMethod); + } + methods.addAll(temp); + temp.clear(); + } + } + // evaluate class hierarchy - this is done last to track inherited + // methods + methods = getAllUniqueMethods(pClass.getSuperclass(), methods, validating); + return methods; + } + + /** + * Finds the closest matching field with the given name, that is, a field of + * the exact specified type or, alternately, of a supertype. + * + * @param name the name of the field + * @param type the field type + * @param fields the collection of fields to search + * @return the matching field or null if not found + */ + public static Field findClosestMatchingField(String name, Class type, Set<Field> fields) { + Field candidate = null; + for (Field field : fields) { + if (field.getName().equals(name)) { + if (field.getType().equals(type)) { + return field; // exact match + } else if (field.getType().isAssignableFrom(type) || (field.getType().isPrimitive() && primitiveAssignable(field + .getType(), + type))) { + // We could have the situation where a field parameter is a + // primitive and the demarshalled value is + // an object counterpart (e.g. Integer and int) + // @spec issue + // either an interface or super class, so keep a reference + // until + // we know there are no closer types + candidate = field; + } + } + } + if (candidate != null) { + return candidate; + } else { + return null; + } + } + + /** + * Finds the closest matching method with the given name, that is, a method + * taking the exact parameter types or, alternately, parameter supertypes. + * + * @param name the name of the method + * @param types the method parameter types + * @param methods the collection of methods to search + * @return the matching method or null if not found + */ + public static Method findClosestMatchingMethod(String name, Class[] types, Set<Method> methods) { + if (types == null) { + types = EMPTY_CLASS_ARRY; + } + Method candidate = null; + for (Method method : methods) { + if (method.getName().equals(name) && method.getParameterTypes().length == types.length) { + Class<?>[] params = method.getParameterTypes(); + boolean disqualify = false; + boolean exactMatch = true; + for (int i = 0; i < params.length; i++) { + if (!params[i].equals(types[i]) && !params[i].isAssignableFrom(types[i])) { + // no match + disqualify = true; + exactMatch = false; + break; + } else if (!params[i].equals(types[i]) && params[i].isAssignableFrom(types[i])) { + // not exact match + exactMatch = false; + } + } + if (disqualify) { + continue; + } else if (exactMatch) { + return method; + } else { + candidate = method; + } + } + } + if (candidate != null) { + return candidate; + } else { + return null; + } + } + + /** + * Determines if two methods "match" - that is, they have the same method + * names and exact parameter types (one is not a supertype of the other) + */ + public static boolean exactMethodMatch(Method method1, Method method2) { + if (!method1.getName().equals(method2.getName())) { + return false; + } + Class<?>[] types1 = method1.getParameterTypes(); + Class<?>[] types2 = method2.getParameterTypes(); + if (types1.length != types2.length) { + return false; + } + boolean matched = true; + for (int i = 0; i < types1.length; i++) { + if (types1[i] != types2[i]) { + matched = false; + break; + } + } + return matched; + } + + /** + * Returns the simple name of a class - i.e. the class name devoid of its + * package qualifier + * + * @param implClass the implementation class + */ + public static String getBaseName(Class<?> implClass) { + return implClass.getSimpleName(); + } + + public static boolean isImmutable(Class<?> clazz) { + return String.class == clazz || clazz.isPrimitive() + || Number.class.isAssignableFrom(clazz) + || Boolean.class.isAssignableFrom(clazz) + || Character.class.isAssignableFrom(clazz) + || Byte.class.isAssignableFrom(clazz); + } + + /** + * Takes a property name and converts it to a getter method name according + * to JavaBean conventions. For example, property + * <code>foo<code> is returned as <code>getFoo</code> + */ + public static String toGetter(String name) { + return "get" + name.toUpperCase().substring(0, 1) + name.substring(1); + } + + /** + * Takes a setter or getter method name and converts it to a property name + * according to JavaBean conventions. For example, <code>setFoo(var)</code> + * is returned as property <code>foo<code> + */ + public static String toPropertyName(String name) { + if (!name.startsWith("set")) { + return name; + } + return Introspector.decapitalize(name.substring(3)); + } + + public static Class<?> getErasure(Type type) { + if (type instanceof Class) { + return (Class<?>)type; + } else if (type instanceof GenericArrayType) { + // FIXME: How to deal with the []? + GenericArrayType arrayType = (GenericArrayType)type; + return getErasure(arrayType.getGenericComponentType()); + } else if (type instanceof ParameterizedType) { + ParameterizedType pType = (ParameterizedType)type; + return getErasure(pType.getRawType()); + } else if (type instanceof WildcardType) { + WildcardType wType = (WildcardType)type; + Type[] types = wType.getUpperBounds(); + return getErasure(types[0]); + } else if (type instanceof TypeVariable) { + TypeVariable var = (TypeVariable)type; + Type[] types = var.getBounds(); + return getErasure(types[0]); + } + return null; + } + + public static Class<?> getBaseType(Class<?> cls, Type genericType) { + if (cls.isArray()) { + return cls.getComponentType(); + } else if (Collection.class.isAssignableFrom(cls)) { + if (genericType instanceof ParameterizedType) { + // Collection<BaseType> + ParameterizedType parameterizedType = (ParameterizedType)genericType; + Type baseType = parameterizedType.getActualTypeArguments()[0]; + if (baseType instanceof GenericArrayType) { + // Base is array + return cls; + } else { + return getErasure(baseType); + } + } else { + return cls; + } + } else { + return cls; + } + } + + public static Type getParameterType(Type type) { + if (type instanceof ParameterizedType) { + // Collection<BaseType> + ParameterizedType parameterizedType = (ParameterizedType)type; + Type baseType = parameterizedType.getActualTypeArguments()[0]; + return baseType; + } else { + return Object.class; + } + } + + public static Class<?> getBusinessInterface(Class<?> cls, Type callableReferenceType) { + if (ServiceReference.class.isAssignableFrom(cls) && callableReferenceType instanceof ParameterizedType) { + // Collection<BaseType> + ParameterizedType parameterizedType = (ParameterizedType)callableReferenceType; + Type baseType = parameterizedType.getActualTypeArguments()[0]; + if (baseType instanceof GenericArrayType) { + // Base is array + return cls; + } else { + return getErasure(baseType); + } + } + return Object.class; + } + + /** + * Takes a property name and converts it to a setter method name according + * to JavaBean conventions. For example, the property + * <code>foo<code> is returned as <code>setFoo(var)</code> + */ + public static String toSetter(String name) { + return "set" + name.toUpperCase().substring(0, 1) + name.substring(1); + } + + /** + * Compares a two types, assuming one is a primitive, to determine if the + * other is its object counterpart + */ + private static boolean primitiveAssignable(Class<?> memberType, Class<?> param) { + if (memberType == Integer.class) { + return param == Integer.TYPE; + } else if (memberType == Double.class) { + return param == Double.TYPE; + } else if (memberType == Float.class) { + return param == Float.TYPE; + } else if (memberType == Short.class) { + return param == Short.TYPE; + } else if (memberType == Character.class) { + return param == Character.TYPE; + } else if (memberType == Boolean.class) { + return param == Boolean.TYPE; + } else if (memberType == Byte.class) { + return param == Byte.TYPE; + } else if (param == Integer.class) { + return memberType == Integer.TYPE; + } else if (param == Double.class) { + return memberType == Double.TYPE; + } else if (param == Float.class) { + return memberType == Float.TYPE; + } else if (param == Short.class) { + return memberType == Short.TYPE; + } else if (param == Character.class) { + return memberType == Character.TYPE; + } else if (param == Boolean.class) { + return memberType == Boolean.TYPE; + } else if (param == Byte.class) { + return memberType == Byte.TYPE; + } else { + return false; + } + } + + /** + * Returns the generic types represented in the given type. Usage as + * follows: <code> + * JavaIntrospectionHelper.getGenerics(field.getGenericType()); + * <p/> + * JavaIntrospectionHelper.getGenerics(m.getGenericParameterTypes()[0];); </code> + * + * @return the generic types in order of declaration or an empty array if + * the type is not genericized + */ + public static List<? extends Type> getGenerics(Type genericType) { + List<Type> classes = new ArrayList<Type>(); + if (genericType instanceof ParameterizedType) { + ParameterizedType ptype = (ParameterizedType)genericType; + // get the type arguments + Type[] targs = ptype.getActualTypeArguments(); + for (Type targ : targs) { + classes.add(targ); + } + } + return classes; + } + + /** + * Returns the generic type specified by the class at the given position as + * in: <p/> <code> public class Foo<Bar,Baz>{ //.. } + * <p/> + * JavaIntrospectionHelper.introspectGeneric(Foo.class,1); <code> + * <p/> + * will return Baz. + */ + public static Class introspectGeneric(Class<?> clazz, int pos) { + assert clazz != null : "No class specified"; + Type type = clazz.getGenericSuperclass(); + if (type instanceof ParameterizedType) { + Type[] args = ((ParameterizedType)type).getActualTypeArguments(); + if (args.length <= pos) { + throw new IllegalArgumentException("Invalid index value for generic class " + clazz.getName()); + } + return (Class)((ParameterizedType)type).getActualTypeArguments()[pos]; + } else { + Type[] interfaces = clazz.getGenericInterfaces(); + for (Type itype : interfaces) { + if (!(itype instanceof ParameterizedType)) { + continue; + } + ParameterizedType interfaceType = (ParameterizedType)itype; + return (Class)interfaceType.getActualTypeArguments()[0]; + } + } + return null; + } + + /** + * Returns the set of interfaces implemented by the given class and its + * ancestors or a blank set if none + */ + public static Set<Class<?>> getAllInterfaces(Class<?> clazz) { + Set<Class<?>> implemented = new HashSet<Class<?>>(); + getAllInterfaces(clazz, implemented); + return implemented; + } + + private static void getAllInterfaces(Class<?> clazz, Set<Class<?>> implemented) { + Class<?>[] interfaces = clazz.getInterfaces(); + for (Class<?> interfaze : interfaces) { + implemented.add(interfaze); + } + Class<?> superClass = clazz.getSuperclass(); + // Object has no superclass so check for null + if (superClass != null && !superClass.equals(Object.class)) { + getAllInterfaces(superClass, implemented); + } + } + + public static boolean isSetter(Method method) { + return (void.class == method.getReturnType() && method.getParameterTypes().length == 1 && method.getName() + .startsWith("set")); + } + + public static boolean isGetter(Method method) { + return (void.class != method.getReturnType() && method.getParameterTypes().length == 0 && method.getName() + .startsWith("get")); + } + + private final static Map<Class<?>, String> signatures = new HashMap<Class<?>, String>(); + static { + signatures.put(boolean.class, "Z"); + signatures.put(byte.class, "B"); + signatures.put(char.class, "C"); + signatures.put(short.class, "S"); + signatures.put(int.class, "I"); + signatures.put(long.class, "J"); + signatures.put(float.class, "F"); + signatures.put(double.class, "D"); + }; + + public static String getSignature(Class<?> cls) { + if (cls.isPrimitive()) { + return signatures.get(cls); + } + if (cls.isArray()) { + return "[" + getSignature(cls.getComponentType()); + } + return "L" + cls.getName().replace('.', '/') + ";"; + } + + public static Class<?> getArrayType(Class<?> componentType, int dims) throws ClassNotFoundException { + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < dims; i++) { + buf.append('['); + } + buf.append(getSignature(componentType)); + return Class.forName(buf.toString(), false, componentType.getClassLoader()); + } + + public static Set<Method> getMethods(Class<?> clazz) { + Set<Method> methods = new HashSet<Method>(); + Method[] declaredMethods = clazz.getDeclaredMethods(); + for (final Method declaredMethod : declaredMethods) { + methods.add(declaredMethod); + } // end for + + return methods; + } // end method getMethods + + public static Set<Field> getPrivateFields(Class<?> clazz) { + Set<Field> fields = new HashSet<Field>(); + Field[] declaredFields = clazz.getDeclaredFields(); + for (final Field declaredField : declaredFields) { + int modifiers = declaredField.getModifiers(); + if(Modifier.isPrivate(modifiers)) { + fields.add(declaredField); + } + } + + return fields; + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaOperationImpl.java b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaOperationImpl.java new file mode 100644 index 0000000000..0aa0cfb3ee --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaOperationImpl.java @@ -0,0 +1,111 @@ +/* + * 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; + private boolean hasReturnTypeVoid = 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(); + } + + @Override + public boolean hasReturnTypeVoid() { + return hasReturnTypeVoid; + } + + @Override + public void setReturnTypeVoid(boolean flag) { + hasReturnTypeVoid = flag; + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/impl/PolicyJavaInterfaceVisitor.java b/sca-java-2.x/branches/2.0-Beta3/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/sca-java-2.x/branches/2.0-Beta3/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); + } + } + } + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/introspect/JavaInterfaceVisitor.java b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/introspect/JavaInterfaceVisitor.java new file mode 100644 index 0000000000..3bc03a528e --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/introspect/JavaInterfaceVisitor.java @@ -0,0 +1,39 @@ +/* + * 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.introspect; + +import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; + +/** + * Implementations introspect metadata on a Java interface, populating the + * corresponding {@link JavaInterface} + * + * @version $Rev$ $Date$ + */ +public interface JavaInterfaceVisitor { + + /** + * Visit a java interface + * @param javaInterface + * @throws InvalidInterfaceException + */ + void visitInterface(JavaInterface javaInterface) throws InvalidInterfaceException; + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/package.html b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/package.html new file mode 100644 index 0000000000..828c112479 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/package.html @@ -0,0 +1,30 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- + * 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. +--> +<html> +<head> +</head> +<body> + +The Tuscany Java Interface Extension + +@tuscany.spi.extension + +</body> +</html> diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/xml/JavaConstants.java b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/xml/JavaConstants.java new file mode 100644 index 0000000000..2db916e2d3 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/xml/JavaConstants.java @@ -0,0 +1,36 @@ +/* + * 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.xml; + +import javax.xml.namespace.QName; + +/** + * Interface Java XML Constants. + * + * @version $Rev$ $Date$ + */ +public interface JavaConstants { + String SCA11_NS = "http://docs.oasis-open.org/ns/opencsa/sca/200912"; + String INTERFACE_JAVA = "interface.java"; + QName INTERFACE_JAVA_QNAME = new QName(SCA11_NS, "interface.java"); + String INTERFACE = "interface"; + String CALLBACK_INTERFACE = "callbackInterface"; + String REMOTABLE = "remotable"; + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/xml/JavaInterfaceProcessor.java b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/xml/JavaInterfaceProcessor.java new file mode 100644 index 0000000000..87628d9901 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/java/org/apache/tuscany/sca/interfacedef/java/xml/JavaInterfaceProcessor.java @@ -0,0 +1,445 @@ +/* + * 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.xml; + +import static javax.xml.stream.XMLStreamConstants.END_ELEMENT; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.ws.WebServiceClient; + +import org.apache.tuscany.sca.assembly.xml.PolicySubjectProcessor; +import org.apache.tuscany.sca.contribution.processor.ContributionReadException; +import org.apache.tuscany.sca.contribution.processor.ContributionResolveException; +import org.apache.tuscany.sca.contribution.processor.ContributionWriteException; +import org.apache.tuscany.sca.contribution.processor.ProcessorContext; +import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor; +import org.apache.tuscany.sca.contribution.resolver.ClassReference; +import org.apache.tuscany.sca.contribution.resolver.ModelResolver; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.apache.tuscany.sca.interfacedef.Compatibility; +import org.apache.tuscany.sca.interfacedef.IncompatibleInterfaceContractException; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +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.wsdl.WSDLFactory; +import org.apache.tuscany.sca.interfacedef.wsdl.WSDLInterface; +import org.apache.tuscany.sca.interfacedef.wsdl.WSDLInterfaceContract; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.monitor.Problem; +import org.apache.tuscany.sca.monitor.Problem.Severity; +import org.apache.tuscany.sca.policy.PolicyFactory; +import org.oasisopen.sca.annotation.AllowsPassByReference; +import org.oasisopen.sca.annotation.Callback; +import org.oasisopen.sca.annotation.ComponentName; +import org.oasisopen.sca.annotation.Constructor; +import org.oasisopen.sca.annotation.Context; +import org.oasisopen.sca.annotation.Destroy; +import org.oasisopen.sca.annotation.EagerInit; +import org.oasisopen.sca.annotation.Init; +import org.oasisopen.sca.annotation.Intent; +import org.oasisopen.sca.annotation.Property; +import org.oasisopen.sca.annotation.Qualifier; +import org.oasisopen.sca.annotation.Reference; +import org.oasisopen.sca.annotation.Scope; +import org.oasisopen.sca.annotation.Service; + +/** + * + * @version $Rev$ $Date$ + */ +public class JavaInterfaceProcessor implements StAXArtifactProcessor<JavaInterfaceContract>, JavaConstants { + private static final String SCA11_NS = "http://docs.oasis-open.org/ns/opencsa/sca/200912"; + + private JavaInterfaceFactory javaFactory; + private ExtensionPointRegistry extensionPoints; + private PolicyFactory policyFactory; + private PolicySubjectProcessor policyProcessor; + private WSDLFactory wsdlFactory; + private StAXArtifactProcessor<Object> extensionProcessor; + private transient InterfaceContractMapper interfaceContractMapper; + + public JavaInterfaceProcessor(ExtensionPointRegistry extensionPoints, StAXArtifactProcessor<?> staxProcessor) { + this.extensionPoints = extensionPoints; + FactoryExtensionPoint modelFactories = extensionPoints.getExtensionPoint(FactoryExtensionPoint.class); + this.policyFactory = modelFactories.getFactory(PolicyFactory.class); + this.policyProcessor = new PolicySubjectProcessor(policyFactory); + this.javaFactory = modelFactories.getFactory(JavaInterfaceFactory.class); + this.wsdlFactory = modelFactories.getFactory(WSDLFactory.class); + this.extensionProcessor = (StAXArtifactProcessor<Object>)staxProcessor; + UtilityExtensionPoint utilities = extensionPoints.getExtensionPoint(UtilityExtensionPoint.class); + this.interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); + } + + /** + * Report a exception. + * + * @param problems + * @param message + * @param model + */ + private void error(Monitor monitor, String message, Object model, Exception ex) { + if (monitor != null) { + Problem problem = + monitor.createProblem(this.getClass().getName(), + "interface-javaxml-validation-messages", + Severity.ERROR, + model, + message, + ex); + monitor.problem(problem); + } + } + + /** + * Report a error. + * + * @param problems + * @param message + * @param model + */ + private void error(Monitor monitor, String message, Object model, Object... messageParameters) { + if (monitor != null) { + Problem problem = + monitor.createProblem(this.getClass().getName(), + "interface-javaxml-validation-messages", + Severity.ERROR, + model, + message, + (Object[])messageParameters); + monitor.problem(problem); + } + } + + private JavaInterface createJavaInterface(String interfaceName) { + JavaInterface javaInterface = javaFactory.createJavaInterface(); + javaInterface.setUnresolved(true); + javaInterface.setName(interfaceName); + return javaInterface; + } + + public JavaInterfaceContract read(XMLStreamReader reader, ProcessorContext context) throws ContributionReadException, XMLStreamException { + + // Read an <interface.java> + JavaInterfaceContract javaInterfaceContract = javaFactory.createJavaInterfaceContract(); + String interfaceName = reader.getAttributeValue(null, INTERFACE); + if (interfaceName != null) { + JavaInterface javaInterface = createJavaInterface(interfaceName); + javaInterfaceContract.setInterface(javaInterface); + } + + String callbackInterfaceName = reader.getAttributeValue(null, CALLBACK_INTERFACE); + if (callbackInterfaceName != null) { + JavaInterface javaCallbackInterface = createJavaInterface(callbackInterfaceName); + javaInterfaceContract.setCallbackInterface(javaCallbackInterface); + } + + String remotable = reader.getAttributeValue(null, REMOTABLE); + if (remotable != null) { + javaInterfaceContract.getInterface().setRemotable(Boolean.parseBoolean(remotable)); + } + + // Read intents and policy sets + policyProcessor.readPolicies(javaInterfaceContract.getInterface(), reader); + + // Skip to end element + while (reader.hasNext()) { + if (reader.next() == END_ELEMENT && INTERFACE_JAVA_QNAME.equals(reader.getName())) { + break; + } + } + return javaInterfaceContract; + } + + public void write(JavaInterfaceContract javaInterfaceContract, XMLStreamWriter writer, ProcessorContext context) throws ContributionWriteException, XMLStreamException { + + // Write an <interface.java> + writer.writeStartElement(SCA11_NS, INTERFACE_JAVA); + JavaInterface javaInterface = (JavaInterface)javaInterfaceContract.getInterface(); + + if (javaInterface != null && javaInterface.getName() != null) { + writer.writeAttribute(INTERFACE, javaInterface.getName()); + } + + if(javaInterface != null && javaInterface.isRemotableSet()) { + writer.writeAttribute(REMOTABLE, String.valueOf(javaInterface.isRemotable())); + } + + JavaInterface javaCallbackInterface = (JavaInterface)javaInterfaceContract.getCallbackInterface(); + if (javaCallbackInterface != null && javaCallbackInterface.getName() != null) { + writer.writeAttribute(CALLBACK_INTERFACE, javaCallbackInterface.getName()); + } + + policyProcessor.writePolicyAttributes(javaInterface, writer); + + writer.writeEndElement(); + } + + private JavaInterface resolveJavaInterface(JavaInterface javaInterface, ModelResolver resolver, ProcessorContext context) throws ContributionResolveException { + + if (javaInterface != null && javaInterface.isUnresolved()) { + Monitor monitor = context.getMonitor(); + // Resolve the Java interface + javaInterface = resolver.resolveModel(JavaInterface.class, javaInterface, context); + if (javaInterface.isUnresolved()) { + + // If the Java interface has never been resolved yet, do it now + ClassReference classReference = new ClassReference(javaInterface.getName()); + classReference = resolver.resolveModel(ClassReference.class, classReference, context); + Class<?> javaClass = classReference.getJavaClass(); + if (javaClass == null) { + error(monitor, "ClassNotFoundException", resolver, javaInterface.getName()); + return javaInterface; + //throw new ContributionResolveException(new ClassNotFoundException(javaInterface.getName())); + } + + try { + // Introspect the Java interface and populate the interface and + // operations + javaFactory.createJavaInterface(javaInterface, javaClass); + + // cache the contribution that was used to resolve the Java interface + // in case we need it to reolve a referenced WSDL file + javaInterface.setContributionContainingClass(classReference.getContributionContainingClass()); + + } catch (InvalidInterfaceException e) { + ContributionResolveException ce = new ContributionResolveException("Resolving Java interface " + javaInterface.getName(), e); + //error("ContributionResolveException", javaFactory, ce); + error(monitor, "InvalidInterfaceException", javaFactory, e); + return javaInterface; + //throw ce; + } catch ( Exception e ) { + throw new ContributionResolveException( "Resolving Java interface " + javaInterface.getName(), e ); + } // end try + + // Cache the resolved interface + javaInterface.setUnresolved(false); + resolver.addModel(javaInterface, context); + } + } + return javaInterface; + } + + public void resolve(JavaInterfaceContract javaInterfaceContract, ModelResolver resolver, ProcessorContext context) + throws ContributionResolveException { + try { + Monitor monitor = context.getMonitor(); + // Resolve the interface and callback interface + JavaInterface javaInterface = + resolveJavaInterface((JavaInterface)javaInterfaceContract.getInterface(), resolver, context); + javaInterfaceContract.setInterface(javaInterface); + + JavaInterface javaCallbackInterface = + resolveJavaInterface((JavaInterface)javaInterfaceContract.getCallbackInterface(), resolver, context); + javaInterfaceContract.setCallbackInterface(javaCallbackInterface); + + postJAXWSProcessorResolve(javaInterfaceContract, resolver, context); + + checkForbiddenAnnotations(monitor, javaInterfaceContract); + + } catch (Exception e) { + throw new ContributionResolveException("Resolving Java Interface " + javaInterfaceContract.getInterface() + .toString(), e); + } // end try + } + + private static List<Class<?>> JCA30006_ANNOTATIONS = + Arrays.asList(new Class<?>[] {AllowsPassByReference.class, ComponentName.class, Constructor.class, Context.class, + Destroy.class, EagerInit.class, Init.class, Intent.class, Property.class, Qualifier.class, + Reference.class, Scope.class, Service.class}); + private static List<Class<?>> JCA30007_ANNOTATIONS = + Arrays.asList(new Class<?>[] {AllowsPassByReference.class, Callback.class, ComponentName.class, Constructor.class, + Context.class, Destroy.class, EagerInit.class, Init.class, Intent.class, + Property.class, Qualifier.class, Reference.class, Scope.class, Service.class}); + private static List<Class<?>> JCA30008_ANNOTATIONS = Arrays.asList(new Class<?>[] {Intent.class, Qualifier.class}); + + private void checkForbiddenAnnotations(Monitor monitor, JavaInterfaceContract javaInterfaceContract) { + if (javaInterfaceContract.getInterface() == null) { + return; + } + Class<?> ifc = ((JavaInterface) javaInterfaceContract.getInterface()).getJavaClass(); + if (ifc == null) { + return; + } + for (Annotation a : ifc.getAnnotations()) { + if (ifc.isInterface()) { + if (JCA30006_ANNOTATIONS.contains(a.annotationType())) { + error(monitor, "ForbiddenAnnotationJCA30006", javaInterfaceContract, a.annotationType(), ifc.getName()); + } + } else { + if (JCA30008_ANNOTATIONS.contains(a.annotationType())) { + error(monitor, "ForbiddenAnnotationJCA30008", javaInterfaceContract, a.annotationType(), ifc.getName()); + } + } + + if ( a.annotationType().equals(WebServiceClient.class) ) { + error(monitor, "ForbiddenAnnotationJCA100018", javaInterfaceContract, a.annotationType(), ifc.getName()); + } + + } + for (Method m : ifc.getMethods()) { + for (Annotation a : m.getAnnotations()) { + if (ifc.isInterface()) { + if (JCA30006_ANNOTATIONS.contains(a.annotationType())) { + error(monitor, "ForbiddenAnnotationJCA30006", javaInterfaceContract, a.annotationType(), ifc.getName()); + } + } else { + if (JCA30008_ANNOTATIONS.contains(a.annotationType())) { + error(monitor, "ForbiddenAnnotationJCA30008", javaInterfaceContract, a.annotationType(), ifc.getName()); + } + } + } + } + for (Field f : ifc.getFields()) { + for (Annotation a : f.getAnnotations()) { + if (ifc.isInterface()) { + if (JCA30006_ANNOTATIONS.contains(a.annotationType())) { + error(monitor, "ForbiddenAnnotationJCA30006", javaInterfaceContract, a.annotationType(), ifc.getName()); + } + } else { + if (JCA30008_ANNOTATIONS.contains(a.annotationType())) { + error(monitor, "ForbiddenAnnotationJCA30008", javaInterfaceContract, a.annotationType(), ifc.getName()); + } + } + } + } + + if (javaInterfaceContract.getCallbackInterface() == null) { + return; + } + ifc = ((JavaInterface) javaInterfaceContract.getCallbackInterface()).getJavaClass(); + if (ifc == null) { + return; + } + + for (Annotation a : ifc.getAnnotations()) { + if (ifc.isInterface()) { + if (JCA30007_ANNOTATIONS.contains(a.annotationType())) { + error(monitor, "ForbiddenAnnotationJCA30007", javaInterfaceContract, a.annotationType(), ifc.getName()); + } + } else { + if (JCA30008_ANNOTATIONS.contains(a.annotationType())) { + error(monitor, "ForbiddenAnnotationJCA30008", javaInterfaceContract, a.annotationType(), ifc.getName()); + } + } + } + for (Method m : ifc.getMethods()) { + for (Annotation a : m.getAnnotations()) { + if (ifc.isInterface()) { + if (JCA30007_ANNOTATIONS.contains(a.annotationType())) { + error(monitor, "ForbiddenAnnotationJCA30007", javaInterfaceContract, a.annotationType(), ifc.getName()); + } + } else { + if (JCA30008_ANNOTATIONS.contains(a.annotationType())) { + error(monitor, "ForbiddenAnnotationJCA30008", javaInterfaceContract, a.annotationType(), ifc.getName()); + } + } + } + } + for (Field f : ifc.getFields()) { + for (Annotation a : f.getAnnotations()) { + if (ifc.isInterface()) { + if (JCA30007_ANNOTATIONS.contains(a.annotationType())) { + error(monitor, "ForbiddenAnnotationJCA30007", javaInterfaceContract, a.annotationType(), ifc.getName()); + } + } else { + if (JCA30008_ANNOTATIONS.contains(a.annotationType())) { + error(monitor, "ForbiddenAnnotationJCA30008", javaInterfaceContract, a.annotationType(), ifc.getName()); + } + } + } + } + } + + public QName getArtifactType() { + return INTERFACE_JAVA_QNAME; + } + + public Class<JavaInterfaceContract> getModelType() { + return JavaInterfaceContract.class; + } + + private void postJAXWSProcessorResolve(JavaInterfaceContract javaInterfaceContract, ModelResolver resolver, ProcessorContext context) + throws ContributionResolveException, IncompatibleInterfaceContractException { + + JavaInterface javaInterface = (JavaInterface)javaInterfaceContract.getInterface(); + + // the Java interface may now be marked as unresolved due to a new Java interface + // name retrieved from JAXWS annotations. Resolve it again if it is. + if (javaInterface != null && javaInterface.isUnresolved()){ + javaInterface = resolveJavaInterface(javaInterface, resolver, context); + javaInterfaceContract.setInterface(javaInterface); + } + + JavaInterface javaCallbackInterface = (JavaInterface)javaInterfaceContract.getCallbackInterface(); + // the Java callback interface may now be marked as unresolved due to a new Java interface + // name retrieved from JAXWS annotations. Resolve it again if it is. + if (javaCallbackInterface != null && javaCallbackInterface.isUnresolved()){ + javaCallbackInterface = resolveJavaInterface(javaCallbackInterface, resolver, context); + javaInterfaceContract.setCallbackInterface(javaCallbackInterface); + } + + // the Java interface may be replaced by a WSDL contract picked up from JAXWS annotation + // if so we need to fluff up a WSDL contract and set it to be the normalized contract + // for the Java interface so it's used during contract mapping + if (javaInterface != null && javaInterface.getJAXWSWSDLLocation() != null){ + WSDLInterface wsdlInterface = wsdlFactory.createWSDLInterface(); + wsdlInterface.setUnresolved(true); + wsdlInterface.setRemotable(true); + + WSDLInterfaceContract wsdlInterfaceContract = wsdlFactory.createWSDLInterfaceContract(); + wsdlInterfaceContract.setInterface(wsdlInterface); + wsdlInterfaceContract.setLocation(javaInterface.getJAXWSWSDLLocation()); + javaInterfaceContract.setNormalizedWSDLContract(wsdlInterfaceContract); + + ProcessorContext wsdlContext = new ProcessorContext(javaInterface.getContributionContainingClass(), + context.getMonitor()); + extensionProcessor.resolve(wsdlInterfaceContract, resolver, wsdlContext); + + // check that the Java and WSDL contracts are compatible + interfaceContractMapper.checkCompatibility(wsdlInterfaceContract, + javaInterfaceContract, + Compatibility.SUBSET, + false, + false); + + // copy policy from the WSDL interface to the Java interface + javaInterface.getPolicySets().addAll(wsdlInterface.getPolicySets()); + javaInterface.getRequiredIntents().addAll(wsdlInterface.getRequiredIntents()); + + // TODO - is there anything else to be copied from the user specified WSDL? + + } + + // TODO - how to handle callbacks as the location is stored at the contract level? + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor new file mode 100644 index 0000000000..2cbda24dd8 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor @@ -0,0 +1,20 @@ +# 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. + +# Implementation class for the artifact processor extension +org.apache.tuscany.sca.interfacedef.java.xml.JavaInterfaceProcessor;qname=http://docs.oasis-open.org/ns/opencsa/sca/200912#interface.java,model=org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract +
diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/resources/META-INF/services/org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/resources/META-INF/services/org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory new file mode 100644 index 0000000000..82972f856a --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/resources/META-INF/services/org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory @@ -0,0 +1,18 @@ +# 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. + +org.apache.tuscany.sca.interfacedef.java.DefaultJavaInterfaceFactory
diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/resources/META-INF/services/org.apache.tuscany.sca.interfacedef.java.introspect.JavaInterfaceVisitor b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/resources/META-INF/services/org.apache.tuscany.sca.interfacedef.java.introspect.JavaInterfaceVisitor new file mode 100644 index 0000000000..ef73adb3e6 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/resources/META-INF/services/org.apache.tuscany.sca.interfacedef.java.introspect.JavaInterfaceVisitor @@ -0,0 +1,18 @@ +# 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. +org.apache.tuscany.sca.interfacedef.java.impl.PolicyJavaInterfaceVisitor;ranking=1000 +
diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/resources/interface-javaxml-validation-messages.properties b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/resources/interface-javaxml-validation-messages.properties new file mode 100644 index 0000000000..329f55e0a7 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/main/resources/interface-javaxml-validation-messages.properties @@ -0,0 +1,28 @@ +# +# +# 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. +# +# +ClassNotFoundException = Class Not Found Exception: {0} +ContributionResolveException = ContributionResolveException occurred due to: {0} +InvalidInterfaceException = InvalidInterfaceException due to: {0} +ForbiddenAnnotationJCA30006 = [JCA30006] Forbidden annotation {0} found on service interface in class {1} +ForbiddenAnnotationJCA30007 = [JCA30007] Forbidden annotation {0} found on callback interface in class {1} +ForbiddenAnnotationJCA30008 = [JCA30008] Forbidden annotation {0} found in class {1} +ForbiddenAnnotationJCA100018 = [JCA100018] Forbidden annotation {0} found in class {1} + diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/test/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceUtilDuplicateRemotableTestCase.java b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/test/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceUtilDuplicateRemotableTestCase.java new file mode 100644 index 0000000000..c70bdcaf47 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/test/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceUtilDuplicateRemotableTestCase.java @@ -0,0 +1,317 @@ +/* + * 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 static org.junit.Assert.assertEquals; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import org.apache.tuscany.sca.core.DefaultExtensionPointRegistry; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.interfacedef.DataType; +import org.apache.tuscany.sca.interfacedef.Interface; +import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.interfacedef.OverloadedOperationException; +import org.apache.tuscany.sca.interfacedef.impl.DataTypeImpl; +import org.apache.tuscany.sca.interfacedef.impl.InterfaceImpl; +import org.apache.tuscany.sca.interfacedef.impl.OperationImpl; +import org.apache.tuscany.sca.interfacedef.java.DefaultJavaInterfaceFactory; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; +import org.junit.Assert; +import org.junit.Test; +import org.oasisopen.sca.annotation.Remotable; + +/** + * This test case will test that a Component that has multiple Remotable interfaces + * that contain methods with the same name will correctly select the right method. + * + * @version $Rev$ $Date$ + */ +public class JavaInterfaceUtilDuplicateRemotableTestCase { + + /** + * Test to get the getTime() method from the LocalTimeService + * + * @throws Exception Test failed + */ + @Test + public void testLocalTimeServiceGetTime() throws Exception { + doTestLocalTimeServiceGetTime(LocalTimeService.class); + } + + /** + * Test to get the getTime() method from the LocalTimeService interface from + * the specified class + * + * @param timeServiceClass The class that implements the LocalTimeService + * @throws Exception Test failed + */ + private void doTestLocalTimeServiceGetTime(Class<?> timeServiceClass) throws Exception { + // Add a getTime() method + Operation operation = newOperation("getTime", LocalTimeService.class); + + Method method = JavaInterfaceUtil.findMethod(timeServiceClass, operation); + assertEquals("getTime", method.getName()); + assertEquals(0, method.getParameterTypes().length); + } + + /** + * Test to get the getTime(String) method from the WorldTimeService + * + * @throws Exception Test failed + */ + @Test + public void testWorldTimeServiceGetTime() throws Exception { + doTestWorldTimeServiceGetTime(WorldTimeService.class); + } + + /** + * Test to get the getTime(String) method from the WorldTimeService interface from + * the specified class + * + * @param timeServiceClass The class that implements the WorldTimeService + * @throws Exception Test failed + */ + private void doTestWorldTimeServiceGetTime(Class<?> timeServiceClass) throws Exception { + // Add a getTime(String) method + Operation operation = newOperation("getTime", WorldTimeService.class, String.class); + + Method method = JavaInterfaceUtil.findMethod(timeServiceClass, operation); + assertEquals("getTime", method.getName()); + assertEquals(1, method.getParameterTypes().length); + assertEquals(String.class, method.getParameterTypes()[0]); + } + + /** + * Test to get the getTime(int) method from the GMTTimeService + * + * @throws Exception Test failed + */ + @Test + public void testGMTTimeServiceGetTime() throws Exception { + doTestGMTTimeServiceGetTime(GMTTimeService.class); + } + + /** + * Test to get the getTime(int) method from the GMTTimeService interface from + * the specified class + * + * @param timeServiceClass The class that implements the WorldTimeService + * @throws Exception Test failed + */ + private void doTestGMTTimeServiceGetTime(Class<?> timeServiceClass) throws Exception { + // Add a getTime(String) method + Operation operation = newOperation("getTime", GMTTimeService.class, Integer.TYPE); + + Method method = JavaInterfaceUtil.findMethod(timeServiceClass, operation); + assertEquals("getTime", method.getName()); + assertEquals(1, method.getParameterTypes().length); + assertEquals(Integer.TYPE, method.getParameterTypes()[0]); + } + + /** + * Test to get the getTime() method from the LocalTimeService on the + * TimeServiceImpl class + * + * @throws Exception Test failed + */ + @Test + public void testLocalTimeServiceGetTimeFromTimeServiceImpl() throws Exception { + doTestLocalTimeServiceGetTime(TimeServiceImpl.class); + } + + /** + * Test to get the getTime(String) method from the WorldTimeService on the + * TimeServiceImpl class + * + * @throws Exception Test failed + */ + @Test + public void testWorldTimeServiceGetTimeFromTimeServiceImpl() throws Exception { + doTestWorldTimeServiceGetTime(TimeServiceImpl.class); + } + + /** + * Test to get the getTime(int) method from the GMTTimeService + * + * @throws Exception Test failed + */ + @Test + public void testGMTTimeServiceGetTimeFromTimeServiceImpl() throws Exception { + doTestGMTTimeServiceGetTime(TimeServiceImpl.class); + } + + /** + * Test case that validates that a @Remotable interface with Overloaded operations + * is detected. + * + * This test case is for TUSCANY-2194 + */ + @Test + public void testDuplicateOpeartionOnRemotableInterface() + { + ExtensionPointRegistry registry = new DefaultExtensionPointRegistry(); + JavaInterfaceFactory javaFactory = new DefaultJavaInterfaceFactory(registry); + JavaInterfaceIntrospectorImpl introspector = new JavaInterfaceIntrospectorImpl(javaFactory); + JavaInterfaceImpl javaInterface = new JavaInterfaceImpl(); + + try { + introspector.introspectInterface(javaInterface, DuplicateMethodOnRemotableInterface.class); + Assert.fail("Should have thrown an exception as @Remotable interface has overloaded methods"); + } catch (OverloadedOperationException ex) { + // As expected + // Make sure that the class and method names are in the exception + String exMsg = ex.toString(); + Assert.assertTrue("Method name missing from exception", exMsg.indexOf("aDuplicateMethod") != -1); + Assert.assertTrue("Class name missing from exception", + exMsg.indexOf(DuplicateMethodOnRemotableInterface.class.getName()) != -1); + } catch (InvalidInterfaceException ex) { + // Should have thrown OverloadedOperationException + Assert.fail("Should have thrown an OverloadedOperationException but threw " + ex); + } + } + + /** + * Creates a new operation with the specified name and parameter types + * + * @param name The name of the operation + * @param operationInterface The interface to which the operation belongs + * @param parameterTypes The types of the parameters for this operation + * @return An operation with the specified name and parameter types + */ + private static Operation newOperation(String name, Class<?> operationInterface, Class<?>... parameterTypes) { + // Create and set the operation name + Operation operation = new OperationImpl(); + operation.setName(name); + + // Make the operation remotable + Interface iface = new InterfaceImpl(); + iface.setRemotable(true); + operation.setInterface(iface); + + // Construct the parameters + List<DataType> types = new ArrayList<DataType>(); + DataType<List<DataType>> inputType = new DataTypeImpl<List<DataType>>(Object[].class, types); + for (Class<?> parameterType : parameterTypes) { + DataType type = new DataTypeImpl<Class>(parameterType, Object.class); + types.add(type); + } + operation.setInputType(inputType); + + // Return the created operation + return operation; + } + + /** + * Sample @Remotable interface that has an overloaded operation which is not + * allowed according to the SCA Assembly Specification. + */ + @Remotable + private interface DuplicateMethodOnRemotableInterface { + void aNonDuplicateMethod(); + void aDuplicateMethod(); + void aDuplicateMethod(String aParam); + } + + + /** + * Sample interface needed for the unit tests + */ + @Remotable + private interface LocalTimeService { + + /** + * Gets the local time + * + * @return The Local Time + */ + String getTime(); + } + + /** + * Sample interface needed for the unit tests + */ + @Remotable + private interface WorldTimeService { + + /** + * Gets the time in the specified TimeZone + * + * @param timeZone A Time Zone + * + * @return The time in the specified TimeZone + */ + String getTime(String timeZone); + } + + /** + * Sample interface needed for the unit tests + */ + @Remotable + private interface GMTTimeService { + + /** + * Gets the time with the specified GMT offset + * + * @param gmtOffset A GMT offset in hours + * + * @return The time with the specified GMT offset + */ + String getTime(int gmtOffset); + } + + /** + * Sample implementation class that implements the three @Remotable interfaces + */ + private class TimeServiceImpl implements LocalTimeService, WorldTimeService, GMTTimeService { + /** + * Gets the local time + * + * @return The Local Time + */ + public String getTime() { + return "The current local time"; + } + + /** + * Gets the time in the specified TimeZone + * + * @param timeZone A Time Zone + * + * @return The time in the specified TimeZone + */ + public String getTime(String timeZone) { + return "The current time in TimeZone " + timeZone; + } + + /** + * Gets the time with the specified GMT offset + * + * @param gmtOffset A GMT offset in hours + * + * @return The time with the specified GMT offset + */ + public String getTime(int gmtOffset) { + return "The current time with GMT offset of " + gmtOffset; + } + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/test/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceUtilTestCase.java b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/test/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceUtilTestCase.java new file mode 100644 index 0000000000..86a38fa0c4 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/test/java/org/apache/tuscany/sca/interfacedef/java/impl/JavaInterfaceUtilTestCase.java @@ -0,0 +1,123 @@ +/* + * 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 static org.apache.tuscany.sca.interfacedef.java.impl.JavaInterfaceUtil.findOperation; +import static org.junit.Assert.assertEquals; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +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.OperationImpl; +import org.junit.Before; +import org.junit.Test; + +/** + * @version $Rev$ $Date$ + */ +public class JavaInterfaceUtilTestCase { + private List<Operation> operations; + + @Test + public void testNoParamsFindOperation() throws Exception { + Method method = Foo.class.getMethod("foo"); + Operation ret = findOperation(method, operations); + assertEquals("foo", ret.getName()); + assertEquals(0, method.getParameterTypes().length); + } + + @Test + public void testParamsFindOperation() throws Exception { + Method method = Foo.class.getMethod("foo", String.class); + Operation ret = findOperation(method, operations); + assertEquals("foo", ret.getName()); + assertEquals(String.class, method.getParameterTypes()[0]); + } + + @Test + public void testPrimitiveParamFindOperation() throws NoSuchMethodException { + Method method = Foo.class.getMethod("foo", Integer.TYPE); + Operation operation = findOperation(method, operations); + assertEquals(Integer.TYPE, operation.getInputType().getLogical().get(0).getPhysical()); + } + + @Before + public void setUp() throws Exception { + Operation operation = newOperation("foo"); + List<DataType> types = new ArrayList<DataType>(); + DataType<List<DataType>> inputType = new DataTypeImpl<List<DataType>>(Object[].class, types); + operation.setInputType(inputType); + + operations = new ArrayList<Operation>(); + operations.add(operation); + + types = new ArrayList<DataType>(); + inputType = new DataTypeImpl<List<DataType>>(Object[].class, types); + DataType type = new DataTypeImpl<Class>(String.class, Object.class); + types.add(type); + operation = newOperation("foo"); + operation.setInputType(inputType); + operations.add(operation); + + types = new ArrayList<DataType>(); + type = new DataTypeImpl<Class>(String.class, Object.class); + DataType type2 = new DataTypeImpl<Class>(String.class, Object.class); + types.add(type); + types.add(type2); + inputType = new DataTypeImpl<List<DataType>>(Object[].class, types); + operation = newOperation("foo"); + operation.setInputType(inputType); + operations.add(operation); + + types = new ArrayList<DataType>(); + type = new DataTypeImpl<Class>(Integer.class, Object.class); + types.add(type); + inputType = new DataTypeImpl<List<DataType>>(Object[].class, types); + operation = newOperation("foo"); + operation.setInputType(inputType); + operations.add(operation); + + types = new ArrayList<DataType>(); + type = new DataTypeImpl<Class>(Integer.TYPE, Object.class); + types.add(type); + inputType = new DataTypeImpl<List<DataType>>(Object[].class, types); + operation = newOperation("foo"); + operation.setInputType(inputType); + operations.add(operation); + + } + + private interface Foo { + void foo(); + + void foo(String foo); + + void foo(int b); + } + + private static Operation newOperation(String name) { + Operation operation = new OperationImpl(); + operation.setName(name); + return operation; + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/test/java/org/apache/tuscany/sca/interfacedef/java/introspection/impl/JavaInterfaceProcessorRegistryImplTestCase.java.fixme b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/test/java/org/apache/tuscany/sca/interfacedef/java/introspection/impl/JavaInterfaceProcessorRegistryImplTestCase.java.fixme new file mode 100644 index 0000000000..14ac8b0134 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/test/java/org/apache/tuscany/sca/interfacedef/java/introspection/impl/JavaInterfaceProcessorRegistryImplTestCase.java.fixme @@ -0,0 +1,107 @@ +/* + * 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.introspection.impl; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; + +import java.io.IOException; +import java.util.List; + +import javax.xml.namespace.QName; + +import junit.framework.TestCase; + +import org.apache.tuscany.sca.interfacedef.DataType; +import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.interfacedef.java.DefaultJavaInterfaceFactory; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; +import org.apache.tuscany.sca.interfacedef.java.introspect.JavaInterfaceVisitor; +import org.apache.tuscany.sca.interfacedef.util.XMLType; +import org.easymock.EasyMock; + +/** + * @version $Rev$ $Date$ + */ +public class JavaInterfaceProcessorRegistryImplTestCase extends TestCase { + private JavaInterfaceFactory factory; + + @SuppressWarnings("unchecked") + public void testSimpleInterface() throws InvalidInterfaceException { + JavaInterface intf = factory.createJavaInterface(Simple.class); + + assertEquals(Simple.class, intf.getJavaClass()); + List<Operation> operations = intf.getOperations(); + assertEquals(1, operations.size()); + Operation baseInt = operations.get(0); + assertEquals("baseInt", baseInt.getName()); + + QName element = new QName("http://impl.introspection.java.interfacedef.sca.tuscany.apache.org/", "return"); + + DataType<XMLType> returnType = baseInt.getOutputType(); + assertEquals(Integer.TYPE, returnType.getPhysical()); + assertEquals(element, returnType.getLogical().getElementName()); + + List<DataType> parameterTypes = baseInt.getInputType().getLogical(); + assertEquals(1, parameterTypes.size()); + DataType<XMLType> arg0 = parameterTypes.get(0); + assertEquals(Integer.TYPE, arg0.getPhysical()); + + element = new QName("http://impl.introspection.java.interfacedef.sca.tuscany.apache.org/", "arg0"); + assertEquals(element, arg0.getLogical().getElementName()); + + List<DataType> faultTypes = baseInt.getFaultTypes(); + assertEquals(1, faultTypes.size()); + DataType<DataType<XMLType>> fault0 = faultTypes.get(0); + assertEquals(IOException.class, fault0.getPhysical()); + element = new QName("http://impl.introspection.java.interfacedef.sca.tuscany.apache.org/", "IOException"); + assertEquals(element, fault0.getLogical().getLogical().getElementName()); + } + + public void testUnregister() throws Exception { + JavaInterfaceVisitor extension = createMock(JavaInterfaceVisitor.class); + extension.visitInterface(EasyMock.isA(JavaInterface.class)); + expectLastCall().once(); + replay(extension); + factory.addInterfaceVisitor(extension); + factory.createJavaInterface(Base.class); + factory.removeInterfaceVisitor(extension); + factory.createJavaInterface(Base.class); + verify(extension); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + factory = new DefaultJavaInterfaceFactory(); + + } + + private static interface Base { + int baseInt(int param) throws IllegalArgumentException, IOException; + } + + private static interface Simple extends Base { + + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/test/java/org/apache/tuscany/sca/interfacedef/java/introspection/impl/PolicyProcessorTestCase.java b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/test/java/org/apache/tuscany/sca/interfacedef/java/introspection/impl/PolicyProcessorTestCase.java new file mode 100644 index 0000000000..41facdb3e7 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/test/java/org/apache/tuscany/sca/interfacedef/java/introspection/impl/PolicyProcessorTestCase.java @@ -0,0 +1,119 @@ +/* + * 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.introspection.impl; + +import static org.junit.Assert.assertEquals; + +import org.apache.tuscany.sca.core.DefaultExtensionPointRegistry; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.interfacedef.java.DefaultJavaInterfaceFactory; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; +import org.junit.Before; +import org.junit.Test; +import org.oasisopen.sca.annotation.Authentication; +import org.oasisopen.sca.annotation.Confidentiality; +import org.oasisopen.sca.annotation.PolicySets; +import org.oasisopen.sca.annotation.Requires; + +/** + * @version $Rev$ $Date$ + */ +public class PolicyProcessorTestCase { + private JavaInterfaceFactory factory; + // private PolicyJavaInterfaceVisitor policyProcessor; + + @Test + public void testInterfaceLevel() throws Exception { + JavaInterface type = factory.createJavaInterface(Interface1.class); + // policyProcessor.visitInterface(type); + assertEquals(2, type.getRequiredIntents().size()); + assertEquals(1, type.getPolicySets().size()); + } + + @Test + public void testMethodLevel() throws Exception { + JavaInterface type = factory.createJavaInterface(Interface2.class); + // policyProcessor.visitInterface(type); + assertEquals(0, type.getRequiredIntents().size()); + assertEquals(3, type.getOperations().get(0).getRequiredIntents().size()); + assertEquals(1, type.getOperations().get(1).getRequiredIntents().size()); + assertEquals(0, type.getPolicySets().size()); + assertEquals(1, type.getOperations().get(0).getPolicySets().size()); + assertEquals(1, type.getOperations().get(1).getPolicySets().size()); + } + + @Test + public void testInterfaceAndMethodLevel() throws Exception { + JavaInterface type = factory.createJavaInterface(Interface3.class); + // policyProcessor.visitInterface(type); + assertEquals(2, type.getRequiredIntents().size()); + assertEquals(3, type.getOperations().get(0).getRequiredIntents().size()); + assertEquals(3, type.getOperations().get(1).getRequiredIntents().size()); + assertEquals(1, type.getPolicySets().size()); + assertEquals(2, type.getOperations().get(0).getPolicySets().size()); + assertEquals(2, type.getOperations().get(1).getPolicySets().size()); + } + + @Before + public void setUp() throws Exception { + ExtensionPointRegistry registry = new DefaultExtensionPointRegistry(); + factory = new DefaultJavaInterfaceFactory(registry); + // policyProcessor = new PolicyJavaInterfaceVisitor(registry); + } + + // @Remotable + @Requires( {"transaction.global"}) + @PolicySets( {"{http://ns1}PS1"}) + @Authentication + private interface Interface1 { + int method1(); + + int method2(); + + int method3(); + + int method4(); + } + + private interface Interface2 { + @Requires( {"transaction.global"}) + @Confidentiality({"message", "transport"}) + @PolicySets( {"{http://ns1}PS1"}) + int method1(); + + @Requires( {"transaction.local"}) + @PolicySets( {"{http://ns1}PS2"}) + int method2(); + } + + @Requires( {"transaction.global.Interface6"}) + @PolicySets( {"{http://ns1}PS1"}) + @Authentication + private interface Interface3 { + @Requires( {"transaction.global.Interface6.method1"}) + @PolicySets( {"{http://ns1}PS2"}) + int method1(); + + @Requires( {"transaction.local.Interface6.method2"}) + @PolicySets( {"{http://ns1}PS3"}) + int method2(); + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/test/java/org/apache/tuscany/sca/interfacedef/java/xml/ReadTestCase.java b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/test/java/org/apache/tuscany/sca/interfacedef/java/xml/ReadTestCase.java new file mode 100644 index 0000000000..7cacf06abd --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/test/java/org/apache/tuscany/sca/interfacedef/java/xml/ReadTestCase.java @@ -0,0 +1,81 @@ +/* + * 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.xml; + +import static org.junit.Assert.assertNotNull; + +import java.io.InputStream; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamReader; + +import org.apache.tuscany.sca.assembly.ComponentType; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.contribution.processor.DefaultStAXArtifactProcessorExtensionPoint; +import org.apache.tuscany.sca.contribution.processor.ExtensibleStAXArtifactProcessor; +import org.apache.tuscany.sca.contribution.processor.ProcessorContext; +import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor; +import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessorExtensionPoint; +import org.apache.tuscany.sca.core.DefaultExtensionPointRegistry; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +/** + * Test reading Java interfaces. + * + * @version $Rev$ $Date$ + */ +public class ReadTestCase { + + private static XMLInputFactory inputFactory; + private static XMLOutputFactory outputFactory; + private static StAXArtifactProcessor<Object> staxProcessor; + private static ProcessorContext context; + + @BeforeClass + public static void setUp() throws Exception { + DefaultExtensionPointRegistry extensionPoints = new DefaultExtensionPointRegistry(); + context = new ProcessorContext(extensionPoints); + inputFactory = XMLInputFactory.newInstance(); + outputFactory = XMLOutputFactory.newInstance(); + StAXArtifactProcessorExtensionPoint staxProcessors = new DefaultStAXArtifactProcessorExtensionPoint(extensionPoints); + staxProcessor = new ExtensibleStAXArtifactProcessor(staxProcessors, inputFactory, outputFactory); + } + + @Test + public void testReadComponentType() throws Exception { + InputStream is = getClass().getResourceAsStream("CalculatorImpl.componentType"); + XMLStreamReader reader = inputFactory.createXMLStreamReader(is); + ComponentType componentType = (ComponentType)staxProcessor.read(reader, context); + assertNotNull(componentType); + } + + @Test + @Ignore + public void testReadComposite() throws Exception { + InputStream is = getClass().getResourceAsStream("Calculator.composite"); + XMLStreamReader reader = inputFactory.createXMLStreamReader(is); + Composite composite = (Composite)staxProcessor.read(reader, context); + assertNotNull(composite); + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/test/java/org/apache/tuscany/sca/interfacedef/java/xml/WriteTestCase.java b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/test/java/org/apache/tuscany/sca/interfacedef/java/xml/WriteTestCase.java new file mode 100644 index 0000000000..615fb15fc6 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/test/java/org/apache/tuscany/sca/interfacedef/java/xml/WriteTestCase.java @@ -0,0 +1,80 @@ +/* + * 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.xml; + +import static org.junit.Assert.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; + +import org.apache.tuscany.sca.assembly.ComponentType; +import org.apache.tuscany.sca.assembly.Composite; +import org.apache.tuscany.sca.contribution.processor.DefaultStAXArtifactProcessorExtensionPoint; +import org.apache.tuscany.sca.contribution.processor.ExtensibleStAXArtifactProcessor; +import org.apache.tuscany.sca.contribution.processor.ProcessorContext; +import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor; +import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessorExtensionPoint; +import org.apache.tuscany.sca.core.DefaultExtensionPointRegistry; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Test writing Java interfaces. + * + * @version $Rev$ $Date$ + */ +public class WriteTestCase { + private static XMLInputFactory inputFactory; + private static XMLOutputFactory outputFactory; + private static StAXArtifactProcessor<Object> staxProcessor; + private static ProcessorContext context; + + @BeforeClass + public static void setUp() throws Exception { + DefaultExtensionPointRegistry extensionPoints = new DefaultExtensionPointRegistry(); + context = new ProcessorContext(extensionPoints); + inputFactory = XMLInputFactory.newInstance(); + outputFactory = XMLOutputFactory.newInstance(); + StAXArtifactProcessorExtensionPoint staxProcessors = new DefaultStAXArtifactProcessorExtensionPoint(extensionPoints); + staxProcessor = new ExtensibleStAXArtifactProcessor(staxProcessors, inputFactory, outputFactory); + } + + @Test + public void testReadWriteComponentType() throws Exception { + InputStream is = getClass().getResourceAsStream("CalculatorImpl.componentType"); + ComponentType componentType = (ComponentType)staxProcessor.read(inputFactory.createXMLStreamReader(is), context); + assertNotNull(componentType); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + staxProcessor.write(componentType, outputFactory.createXMLStreamWriter(bos), context); + } + + @Test + public void testReadWriteComposite() throws Exception { + InputStream is = getClass().getResourceAsStream("Calculator.composite"); + Composite composite = (Composite)staxProcessor.read(inputFactory.createXMLStreamReader(is), context); + assertNotNull(composite); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + staxProcessor.write(composite, outputFactory.createXMLStreamWriter(bos), context); + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/test/resources/org/apache/tuscany/sca/interfacedef/java/xml/Calculator.composite b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/test/resources/org/apache/tuscany/sca/interfacedef/java/xml/Calculator.composite new file mode 100644 index 0000000000..e5455dc970 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/test/resources/org/apache/tuscany/sca/interfacedef/java/xml/Calculator.composite @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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. +--> +<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" + xmlns:calc="http://sample.calculator" + targetNamespace="http://calc" + name="Calculator"> + + <service name="CalculatorService" promote="CalculatorServiceComponent"> + <interface.java interface="calculator.CalculatorService" requires="calc:intent1" policySets="calc:policySet1" /> + </service> + + <component name="CalculatorServiceComponent"> + <implementation.java class="calculator.CalculatorServiceImpl"/> + <reference name="addService" target="AddServiceComponent"/> + <reference name="subtractService" target="SubtractServiceComponent"/> + <reference name="multiplyService" target="MultiplyServiceComponent"/> + <reference name="divideService" target="DivideServiceComponent"/> + </component> + + <component name="AddServiceComponent"> + <implementation.java class="calculator.AddServiceImpl"/> + </component> + + <component name="SubtractServiceComponent"> + <implementation.java class="calculator.SubtractServiceImpl"/> + </component> + + <component name="MultiplyServiceComponent"> + <implementation.java class="calculator.MultiplyServiceImpl"/> + </component> + + <component name="DivideServiceComponent"> + <implementation.java class="calculator.DivideServiceImpl"/> + </component> + +</composite> diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/test/resources/org/apache/tuscany/sca/interfacedef/java/xml/CalculatorImpl.componentType b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/test/resources/org/apache/tuscany/sca/interfacedef/java/xml/CalculatorImpl.componentType new file mode 100644 index 0000000000..68793041e1 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/interface-java/src/test/resources/org/apache/tuscany/sca/interfacedef/java/xml/CalculatorImpl.componentType @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="ASCII"?> +<!-- + * 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. +--> +<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"> + + <service name="CalculatorService"> + <interface.java interface="calculator.CalculatorService" /> + </service> + + <reference name="divideService"> + <interface.java interface="calculator.DivideService" /> + </reference> + +</componentType> +
\ No newline at end of file |