diff options
Diffstat (limited to 'sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache')
61 files changed, 6660 insertions, 0 deletions
diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/BaseJavaImplementation.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/BaseJavaImplementation.java new file mode 100644 index 0000000000..a3b0343d51 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/BaseJavaImplementation.java @@ -0,0 +1,68 @@ +/* + * 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.implementation.java; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.Extensible; +import org.apache.tuscany.sca.assembly.Implementation; + +/** + * Represents a Java implementation. + * + * @version $Rev$ $Date$ + */ +public interface BaseJavaImplementation extends Implementation, Extensible { + + /** + * Returns the name of the Java implementation class. + * + * @return the name of the Java implementation class + */ + String getName(); + + /** + * Sets the name of the Java implementation class. + * + * @param className the name of the Java implementation class + */ + void setName(String className); + + /** + * Returns the Java implementation class. + * + * @return the Java implementation class + */ + Class<?> getJavaClass(); + + /** + * Sets the Java implementation class. + * + * @param javaClass the Java implementation class + */ + void setJavaClass(Class<?> javaClass); + + /** + * Customize the implementation type so that components are implemented using Java based framework such as + * implementation.spring or implementation.jaxrs can leverage the introspection + * @param type + */ + void setType(QName type); + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/DefaultJavaImplementationFactory.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/DefaultJavaImplementationFactory.java new file mode 100644 index 0000000000..f98a617925 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/DefaultJavaImplementationFactory.java @@ -0,0 +1,40 @@ +/* + * 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.implementation.java; + +/** + * A factory for the Java model. + * + * @version $Rev$ $Date$ + */ +import org.apache.tuscany.sca.core.DefaultExtensionPointRegistry; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.implementation.java.impl.JavaImplementationFactoryImpl; + +public class DefaultJavaImplementationFactory extends JavaImplementationFactoryImpl implements JavaImplementationFactory { + + public DefaultJavaImplementationFactory(ExtensionPointRegistry registry) { + super(registry); + } + + // For UNIT test only + public DefaultJavaImplementationFactory() { + super(new DefaultExtensionPointRegistry()); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/IntrospectionException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/IntrospectionException.java new file mode 100644 index 0000000000..2198a632c0 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/IntrospectionException.java @@ -0,0 +1,60 @@ +/* + * 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.implementation.java; + +import java.lang.reflect.Member; + +/** + * Denotes a problem processing annotations on a POJO implementation + * + * @version $Rev$ $Date$ + */ +public class IntrospectionException extends Exception { + private static final long serialVersionUID = -361025119035104470L; + private Member member; + + public IntrospectionException() { + } + + public IntrospectionException(String message) { + super(message); + } + + public IntrospectionException(String message, Member member) { + super(message); + this.member = member; + } + + public IntrospectionException(String message, Throwable cause) { + super(message, cause); + } + + public IntrospectionException(Throwable cause) { + super(cause); + } + + public Member getMember() { + return member; + } + + public void setMember(Member member) { + this.member = member; + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaConstructorImpl.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaConstructorImpl.java new file mode 100644 index 0000000000..df76d3ea4e --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaConstructorImpl.java @@ -0,0 +1,56 @@ +/* + * 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.implementation.java; + +import java.lang.reflect.Constructor; + + +/** + * Hold injection information for the constructor used to instantiate a + * component implementation instance + * + * @version $Rev$ $Date$ + */ +public class JavaConstructorImpl<T> { + private Constructor<T> constructor; + private JavaParameterImpl[] parameters; + + public JavaConstructorImpl(Constructor<T> constructor) { + this.constructor = constructor; + int size = constructor.getParameterTypes().length; + parameters = new JavaParameterImpl[size]; + for (int i = 0; i < size; i++) { + parameters[i] = new JavaParameterImpl(constructor, i); + } + } + + /** + * @return the constructor + */ + public Constructor<T> getConstructor() { + return constructor; + } + + /** + * @return the parameters + */ + public JavaParameterImpl[] getParameters() { + return parameters; + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaElementImpl.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaElementImpl.java new file mode 100644 index 0000000000..e748a5f6fa --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaElementImpl.java @@ -0,0 +1,222 @@ +/* + * 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.implementation.java; + +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Type; + +/** + * This class represents a java element such as a Package, Class, Constructor, + * Field, Method or Parameter. + * + * @version $Rev$ $Date$ + */ +public class JavaElementImpl { + private AnnotatedElement anchor; + private ElementType elementType; + private Class<?> type; + private Type genericType; + private int index = -1; + private String name; + private Class<? extends Annotation> classifer; + + public JavaElementImpl(Class<?> cls) { + this.anchor = cls; + this.elementType = ElementType.TYPE; + this.type = cls; + this.genericType = cls; + this.name = cls.getName(); + } + + public JavaElementImpl(Field field) { + this.anchor = field; + this.elementType = ElementType.FIELD; + this.type = field.getType(); + this.genericType = field.getGenericType(); + this.name = field.getName(); + } + + public JavaElementImpl(Constructor<?> constructor, int index) { + this.anchor = constructor; + this.elementType = ElementType.PARAMETER; + this.type = constructor.getParameterTypes()[index]; + this.genericType = constructor.getGenericParameterTypes()[index]; + this.index = index; + this.name = ""; + } + + public JavaElementImpl(Method method, int index) { + this.anchor = method; + this.elementType = ElementType.PARAMETER; + this.type = method.getParameterTypes()[index]; + this.genericType = method.getGenericParameterTypes()[index]; + this.index = index; + this.name = ""; + } + + /** + * For testing purpose + * + * @param name + * @param type + * @param classifer TODO + * @param elementType + */ + public JavaElementImpl(String name, Class<?> type, Class<? extends Annotation> classifer) { + super(); + this.type = type; + this.name = name; + this.classifer = classifer; + } + + /** + * @return the anchor + */ + public AnnotatedElement getAnchor() { + return anchor; + } + + /** + * @return the elementType + */ + public ElementType getElementType() { + return elementType; + } + + /** + * @return the genericType + */ + public Type getGenericType() { + return genericType; + } + + /** + * @return the index + */ + public int getIndex() { + return index; + } + + /** + * @return the type + */ + public Class<?> getType() { + return type; + } + + /** + * @return the annotations + */ + public Annotation[] getAnnotations() { + if (elementType == ElementType.PARAMETER) { + if (anchor instanceof Method) { + // We only care about the method-level annotations + return ((Method)anchor).getAnnotations(); + } + if (anchor instanceof Constructor) { + return ((Constructor<?>)anchor).getParameterAnnotations()[index]; + } + } + return anchor.getAnnotations(); + } + + public <T extends Annotation> T getAnnotation(Class<T> annotationType) { + for (Annotation a : getAnnotations()) { + if (a.annotationType() == annotationType) { + return annotationType.cast(a); + } + } + return null; + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return the classifier + */ + public Class<? extends Annotation> getClassifer() { + return classifer; + } + + /** + * @param classifer the classifier to set + */ + public void setClassifer(Class<? extends Annotation> classifer) { + this.classifer = classifer; + } + + + @Override + public String toString() { + return anchor.toString() + (elementType == ElementType.PARAMETER ? "[" + index + "]" : ""); + } + + @Override + public int hashCode() { + final int PRIME = 31; + int result = 1; + result = PRIME * result + ((anchor == null) ? 0 : anchor.hashCode()); + result = PRIME * result + index; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final JavaElementImpl other = (JavaElementImpl)obj; + if (anchor == null) { + if (other.anchor != null) { + return false; + } + } else if (!anchor.equals(other.anchor)) { + return false; + } + if (index != other.index) { + return false; + } + return true; + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaImplementation.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaImplementation.java new file mode 100644 index 0000000000..60649eb5d6 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaImplementation.java @@ -0,0 +1,164 @@ +/* + * 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.implementation.java; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import javax.xml.namespace.QName; + +/** + * Represents a Java implementation. + * + * @version $Rev$ $Date$ + */ +public interface JavaImplementation extends BaseJavaImplementation { + QName TYPE = new QName(SCA11_NS, "implementation.java"); + /** + * Returns the constructor used to instantiate implementation instances. + * + * @return the constructor used to instantiate implementation instances + */ + JavaConstructorImpl<?> getConstructor(); + + /** + * Sets the constructor used to instantiate implementation instances + * + * @param definition the constructor used to instantiate implementation instances + */ + void setConstructor(JavaConstructorImpl<?> definition); + + /** + * Returns the component initializer method. + * + * @return the component initializer method + */ + Method getInitMethod(); + + /** + * Sets the component initializer method. + * + * @param initMethod the component initializer method + */ + void setInitMethod(Method initMethod); + + /** + * Returns the component destructor method. + * + * @return the component destructor method + */ + Method getDestroyMethod(); + + /** + * Sets the component destructor method. + * + * @param destroyMethod the component destructor method + */ + void setDestroyMethod(Method destroyMethod); + + /** + * Returns the resources injected into this implementation. + * + * @return + */ + Map<String, JavaResourceImpl> getResources(); + + /** + * Returns the Java member used to inject a conversation ID. + * + * @return + */ + List<Member> getConversationIDMembers(); + + /** + * Sets the Java member used to inject a conversation ID. + * + * @param conversationIDMember + */ + void addConversationIDMember(Member conversationIDMember); + + /** + * Returns true if AllowsPassReference is set. + * + * @return true if AllowsPassByReference is set + */ + boolean isAllowsPassByReference(); + + /** + * @param allowsPassByReference the allowsPassByReference to set + */ + void setAllowsPassByReference(boolean allowsPassByReference); + + /** + * @return the allowsPassByReferenceMethods + */ + List<Method> getAllowsPassByReferenceMethods(); + + /** + * @param method + * @return + */ + boolean isAllowsPassByReference(Method method); + + /** + * @return the constructors + */ + Map<Constructor, JavaConstructorImpl> getConstructors(); + + /** + * @return the eagerInit + */ + boolean isEagerInit(); + + /** + * @param eagerInit the eagerInit to set + */ + void setEagerInit(boolean eagerInit); + + /** + * @return the callbacks + */ + Map<String, Collection<JavaElementImpl>> getCallbackMembers(); + + /** + * @return the properties + */ + Map<String, JavaElementImpl> getPropertyMembers(); + + /** + * @return the references + */ + Map<String, JavaElementImpl> getReferenceMembers(); + + /** + * @return the scope + */ + JavaScopeImpl getJavaScope(); + + /** + * @param scope the scope to set + */ + void setJavaScope(JavaScopeImpl scope); + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaImplementationFactory.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaImplementationFactory.java new file mode 100644 index 0000000000..8228c80372 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaImplementationFactory.java @@ -0,0 +1,75 @@ +/* + * 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.implementation.java; + +import java.util.List; + +import org.apache.tuscany.sca.implementation.java.introspect.JavaClassVisitor; + + +/** + * Factory for the Java model + * + * @version $Rev$ $Date$ + */ +public interface JavaImplementationFactory { + + /** + * Creates a new Java implementation model. + * + * @return + */ + JavaImplementation createJavaImplementation(); + + /** + * Creates a new Java implementation model from an implementation class. + * + * @param implementationClass The implementation class to introspect. + * @return + */ + JavaImplementation createJavaImplementation(Class<?> implementationClass) throws IntrospectionException; + + /** + * Creates the contents of a Java implementation model from an implementation class. + * + * @param implementationClass The implementation class to introspect. + * @return + */ + void createJavaImplementation(JavaImplementation javaImplementation, Class<?> implementationClass) throws IntrospectionException; + + /** + * Registers the given visitor. + * + * @param visitor + */ + void addClassVisitor(JavaClassVisitor visitor); + + /** + * Deregisters the given visitor. + */ + void removeClassVisitor(JavaClassVisitor visitor); + + /** + * Returns the list of visitors. + * + * @return + */ + List<JavaClassVisitor> getClassVisitors(); + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaParameterImpl.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaParameterImpl.java new file mode 100644 index 0000000000..80911a9552 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaParameterImpl.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.implementation.java; + +import java.lang.reflect.Constructor; + + +/** + * @version $Rev$ $Date$ + */ +public class JavaParameterImpl extends JavaElementImpl { + /** + * @param constructor + * @param index + */ + public JavaParameterImpl(Constructor<?> constructor, int index) { + super(constructor, index); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaResourceImpl.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaResourceImpl.java new file mode 100644 index 0000000000..19a9f38549 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaResourceImpl.java @@ -0,0 +1,86 @@ +/* + * 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.implementation.java; + + + +/** + * A resource dependency declared by a Java component implementation + * + * @version $Rev$ $Date$ + */ +public class JavaResourceImpl { + private JavaElementImpl element; + private String mappedName; + private boolean optional; + + public JavaResourceImpl(JavaElementImpl element) { + this.element = element; + } + + /** + * The name of the resource + * + * @return the name of the resource + */ + public String getName() { + return element.getName(); + } + + /** + * Returns the URI of the resource + * + * @return the URI of the resource + */ + public String getMappedName() { + return mappedName; + } + + /** + * Sets the resource URI + */ + public void setMappedName(String mappedName) { + this.mappedName = mappedName; + } + + /** + * If true, the resource is optional + * + * @return true if the resource is optional + */ + public boolean isOptional() { + return optional; + } + + /** + * Sets whether the resource is optional + */ + public void setOptional(boolean optional) { + this.optional = optional; + } + + /** + * @return the element + */ + public JavaElementImpl getElement() { + return element; + } + + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaScopeImpl.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaScopeImpl.java new file mode 100644 index 0000000000..c977736630 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/JavaScopeImpl.java @@ -0,0 +1,62 @@ +/* + * 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.implementation.java; + +/** + * The default implementation scopes supported by assemblies. + * + * @version $Rev$ $Date$ + */ +public class JavaScopeImpl { + public static final JavaScopeImpl STATELESS = new JavaScopeImpl("STATELESS"); + public static final JavaScopeImpl COMPOSITE = new JavaScopeImpl("COMPOSITE"); + public static final JavaScopeImpl INVALID = new JavaScopeImpl("INVALID"); + + private String scope; + + public JavaScopeImpl(String scope) { + this.scope = scope.toUpperCase().intern(); + } + + public String getScope() { + return scope; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final JavaScopeImpl scope1 = (JavaScopeImpl) o; + return !(scope != null ? scope != scope1.scope.intern() : scope1.scope != null); + } + + @Override + public int hashCode() { + return scope != null ? scope.hashCode() : 0; + } + + @Override + public String toString() { + return scope; + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/BaseJavaImplementationImpl.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/BaseJavaImplementationImpl.java new file mode 100644 index 0000000000..a5dd89f75a --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/BaseJavaImplementationImpl.java @@ -0,0 +1,102 @@ +/* + * 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.implementation.java.impl; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.impl.ImplementationImpl; +import org.apache.tuscany.sca.implementation.java.BaseJavaImplementation; + +/** + * Represents a Java implementation. + * + * @version $Rev$ $Date$ + */ +abstract class BaseJavaImplementationImpl extends ImplementationImpl implements BaseJavaImplementation { + + private String className; + private Class<?> javaClass; + + protected BaseJavaImplementationImpl(QName type) { + super(type); + } + + public String getName() { + if (isUnresolved()) { + return className; + } else if (javaClass != null) { + return javaClass.getName(); + } else { + return null; + } + } + + public void setName(String className) { + if (!isUnresolved()) { + throw new IllegalStateException(); + } + this.className = className; + } + + public Class<?> getJavaClass() { + return javaClass; + } + + public void setJavaClass(Class<?> javaClass) { + this.javaClass = javaClass; + if (this.className == null) { + this.className = javaClass.getName(); + } + } + + @Override + public String toString() { + return getType() + " (class=" + getName() + ")"; + } + +/* TUSCANY-3876 - disable implementation model sharing so that + * we can get implementation policy modelled on an + * impementation by implementation basis rather than + * storing it on the component + @Override + public int hashCode() { + return String.valueOf(getName()).hashCode(); + } +*/ + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } else if (obj instanceof BaseJavaImplementation) { + if (getName() != null) { + return getName().equals(((BaseJavaImplementation)obj).getName()); + } else { + return ((BaseJavaImplementation)obj).getName() == null; + } + } else { + return false; + } + } + + @Override + public void setType(QName type) { + this.type = type; + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaClassIntrospectorImpl.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaClassIntrospectorImpl.java new file mode 100644 index 0000000000..491408098e --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaClassIntrospectorImpl.java @@ -0,0 +1,125 @@ +/* + * 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.implementation.java.impl; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Set; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaConstructorImpl; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaParameterImpl; +import org.apache.tuscany.sca.implementation.java.introspect.JavaClassVisitor; +import org.apache.tuscany.sca.implementation.java.introspect.JavaIntrospectionHelper; + +/** + * An extensible Java class introspector implementation. + * + * @version $Rev$ $Date$ + */ +public class JavaClassIntrospectorImpl { + + private List<JavaClassVisitor> visitors; + + public JavaClassIntrospectorImpl(List<JavaClassVisitor> visitors) { + this.visitors = visitors; + } + + /** + * JSR-250 PFD recommends the following guidelines for how annotations + * interact with inheritance in order to keep the resulting complexity in + * control: + * <ol> + * <li>Class-level annotations only affect the class they annotate and + * their members, that is, its methods and fields. They never affect a + * member declared by a superclass, even if it is not hidden or overridden + * by the class in question. + * <li>In addition to affecting the annotated class, class-level + * annotations may act as a shorthand for member-level annotations. If a + * member carries a specific member-level annotation, any annotations of the + * same type implied by a class-level annotation are ignored. In other + * words, explicit member-level annotations have priority over member-level + * annotations implied by a class-level annotation. + * <li>The interfaces implemented by a class never contribute annotations + * to the class itself or any of its members. + * <li>Members inherited from a superclass and which are not hidden or + * overridden maintain the annotations they had in the class that declared + * them, including member-level annotations implied by class-level ones. + * <li>Member-level annotations on a hidden or overridden member are always + * ignored. + * </ol> + */ + public void introspectClass(JavaImplementation type, Class<?> clazz) + throws IntrospectionException { + for (JavaClassVisitor visitor : visitors) { + visitor.visitClass(clazz, type); + for (Constructor<?> constructor : clazz.getConstructors()) { + visitor.visitConstructor(constructor, type); + // Assuming the visitClass or visitConstructor will populate the + // type.getConstructors + JavaConstructorImpl<?> definition = type.getConstructors().get(constructor); + if (definition != null) { + for (JavaParameterImpl p : definition.getParameters()) { + visitor.visitConstructorParameter(p, type); + } + } + } + + Set<Field> fields = JavaIntrospectionHelper.getInjectableFields(clazz, true); + for (Field field : fields) { + visitor.visitField(field, type); + } + + Set<Method> methods = JavaIntrospectionHelper.getAllUniquePublicProtectedMethods(clazz, true); + for (Method method : methods) { + visitor.visitMethod(method, type); + } + + // Check if any private methods have illegal annotations that should be raised as errors + Set<Method> privateMethods = JavaIntrospectionHelper.getPrivateMethods(clazz); + for (Method method : privateMethods) { + visitor.visitMethod(method, type); + } + + Class<?> superClass = clazz.getSuperclass(); + if (superClass != null) { + visitSuperClass(superClass, type, visitor); + } + + visitor.visitEnd(clazz, type); + + } + + } + + private void visitSuperClass(Class<?> clazz, JavaImplementation type, JavaClassVisitor visitor) + throws IntrospectionException { + if (!Object.class.equals(clazz)) { + visitor.visitSuperClass(clazz, type); + clazz = clazz.getSuperclass(); + if (clazz != null) { + visitSuperClass(clazz, type, visitor); + } + } + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaImplementationFactoryImpl.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaImplementationFactoryImpl.java new file mode 100644 index 0000000000..a579a6719c --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaImplementationFactoryImpl.java @@ -0,0 +1,135 @@ +/* + * 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.implementation.java.impl; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.extensibility.ServiceDeclaration; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.introspect.JavaClassVisitor; + + +/** + * A factory for the Java model. + * + * @version $Rev$ $Date$ + */ +public abstract class JavaImplementationFactoryImpl implements JavaImplementationFactory { + + private List<JavaClassVisitor> visitors = new ArrayList<JavaClassVisitor>(); + private JavaClassIntrospectorImpl introspector; + private boolean loaded; + protected ExtensionPointRegistry registry; + + public JavaImplementationFactoryImpl(ExtensionPointRegistry registry) { + this.registry = registry; + } + + public JavaImplementation createJavaImplementation() { + JavaImplementation javaImplementation = new JavaImplementationImpl(); + return javaImplementation; + } + + public JavaImplementation createJavaImplementation(Class<?> implementationClass) throws IntrospectionException { + JavaImplementation javaImplementation = createJavaImplementation(); + getIntrospector().introspectClass(javaImplementation, implementationClass); + return javaImplementation; + } + + public void createJavaImplementation(JavaImplementation javaImplementation, Class<?> implementationClass) throws IntrospectionException { + getIntrospector().introspectClass(javaImplementation, implementationClass); + } + + public void addClassVisitor(JavaClassVisitor visitor) { + for (JavaClassVisitor tmpVisitor : visitors){ + if (tmpVisitor.getClass() == visitor.getClass()){ + // trying to add a duplicate visitor so + // ignore it + return; + } + } + visitors.add(visitor); + } + + public void removeClassVisitor(JavaClassVisitor visitor) { + visitors.remove(visitor); + } + + public List<JavaClassVisitor> getClassVisitors() { + loadVisitors(); + return visitors; + } + + /** + * Load visitors declared under META-INF/services + */ + @SuppressWarnings("unchecked") + private synchronized void loadVisitors() { + if (loaded) + return; + + // Get the databinding service declarations + Collection<ServiceDeclaration> visitorDeclarations; + try { + visitorDeclarations = registry.getServiceDiscovery().getServiceDeclarations(JavaClassVisitor.class, true); + } catch (IOException e) { + throw new IllegalStateException(e); + } + + // Load data bindings + for (ServiceDeclaration visitorDeclaration: visitorDeclarations) { + JavaClassVisitor visitor = null; + try { + Class<JavaClassVisitor> visitorClass = (Class<JavaClassVisitor>)visitorDeclaration.loadClass(); + + try { + Constructor<JavaClassVisitor> 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; + } + + addClassVisitor(visitor); + } + + loaded = true; + } + + private synchronized JavaClassIntrospectorImpl getIntrospector() { + if (introspector != null) { + return introspector; + } + introspector = new JavaClassIntrospectorImpl(getClassVisitors()); + return introspector; + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaImplementationImpl.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaImplementationImpl.java new file mode 100644 index 0000000000..5f7885ed5d --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/impl/JavaImplementationImpl.java @@ -0,0 +1,144 @@ +/* + * 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.implementation.java.impl; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.tuscany.sca.implementation.java.JavaConstructorImpl; +import org.apache.tuscany.sca.implementation.java.JavaElementImpl; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaResourceImpl; +import org.apache.tuscany.sca.implementation.java.JavaScopeImpl; + +/** + * A component type specialization for POJO implementations + * + * @version $Rev$ $Date$ + */ +public class JavaImplementationImpl extends BaseJavaImplementationImpl implements JavaImplementation { + private JavaConstructorImpl<?> constructorDefinition; + private Map<Constructor, JavaConstructorImpl> constructors = new HashMap<Constructor, JavaConstructorImpl>(); + private Method initMethod; + private Method destroyMethod; + private final Map<String, JavaResourceImpl> resources = new HashMap<String, JavaResourceImpl>(); + private final Map<String, JavaElementImpl> propertyMembers = new HashMap<String, JavaElementImpl>(); + private final Map<String, JavaElementImpl> referenceMembers = new HashMap<String, JavaElementImpl>(); + private final Map<String, Collection<JavaElementImpl>> callbackMembers = new HashMap<String, Collection<JavaElementImpl>>(); + private List<Member> conversationIDMember = new ArrayList<Member>(); + private boolean eagerInit; + private boolean allowsPassByReference; + private List<Method> allowsPassByReferenceMethods = new ArrayList<Method>(); + private JavaScopeImpl scope = JavaScopeImpl.STATELESS; + + protected JavaImplementationImpl() { + super(TYPE); + } + + public JavaConstructorImpl<?> getConstructor() { + return constructorDefinition; + } + + public void setConstructor(JavaConstructorImpl<?> definition) { + this.constructorDefinition = definition; + } + + public Method getInitMethod() { + return initMethod; + } + + public void setInitMethod(Method initMethod) { + this.initMethod = initMethod; + } + + public Method getDestroyMethod() { + return destroyMethod; + } + + public void setDestroyMethod(Method destroyMethod) { + this.destroyMethod = destroyMethod; + } + + public Map<String, JavaResourceImpl> getResources() { + return resources; + } + + public List<Member> getConversationIDMembers() { + return this.conversationIDMember; + } + + public void addConversationIDMember(Member conversationIDMember) { + this.conversationIDMember.add(conversationIDMember); + } + + public boolean isAllowsPassByReference() { + return allowsPassByReference; + } + + public void setAllowsPassByReference(boolean allowsPassByReference) { + this.allowsPassByReference = allowsPassByReference; + } + + public List<Method> getAllowsPassByReferenceMethods() { + return allowsPassByReferenceMethods; + } + + public boolean isAllowsPassByReference(Method method) { + return allowsPassByReference || allowsPassByReferenceMethods.contains(method); + } + + public Map<Constructor, JavaConstructorImpl> getConstructors() { + return constructors; + } + + public boolean isEagerInit() { + return eagerInit; + } + + public void setEagerInit(boolean eagerInit) { + this.eagerInit = eagerInit; + } + + public Map<String, Collection<JavaElementImpl>> getCallbackMembers() { + return callbackMembers; + } + + public Map<String, JavaElementImpl> getPropertyMembers() { + return propertyMembers; + } + + public Map<String, JavaElementImpl> getReferenceMembers() { + return referenceMembers; + } + + public JavaScopeImpl getJavaScope() { + return scope; + } + + public void setJavaScope(JavaScopeImpl scope) { + this.scope = scope; + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/BaseJavaClassVisitor.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/BaseJavaClassVisitor.java new file mode 100644 index 0000000000..26ca54df88 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/BaseJavaClassVisitor.java @@ -0,0 +1,74 @@ +/* + * 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.implementation.java.introspect; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaParameterImpl; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; + +/** + * A convenience class for annotation processors which alleviates the need to + * implement unused callbacks + * + * @version $Rev$ $Date$ + */ +public abstract class BaseJavaClassVisitor implements JavaClassVisitor { + protected AssemblyFactory assemblyFactory; + protected JavaInterfaceFactory javaInterfaceFactory; + + protected BaseJavaClassVisitor(AssemblyFactory factory) { + this.assemblyFactory = factory; + } + + protected BaseJavaClassVisitor(ExtensionPointRegistry registry) { + super(); + FactoryExtensionPoint factories = registry.getExtensionPoint(FactoryExtensionPoint.class); + this.assemblyFactory = factories.getFactory(AssemblyFactory.class); + this.javaInterfaceFactory = factories.getFactory(JavaInterfaceFactory.class); + } + + public <T> void visitClass(Class<T> clazz, JavaImplementation type) throws IntrospectionException { + } + + public <T> void visitSuperClass(Class<T> clazz, JavaImplementation type) throws IntrospectionException { + } + + public void visitMethod(Method method, JavaImplementation type) throws IntrospectionException { + } + + public <T> void visitConstructor(Constructor<T> constructor, JavaImplementation type) throws IntrospectionException { + } + + public void visitField(Field field, JavaImplementation type) throws IntrospectionException { + } + + public <T> void visitEnd(Class<T> clazz, JavaImplementation type) throws IntrospectionException { + } + + public void visitConstructorParameter(JavaParameterImpl parameter, JavaImplementation type) throws IntrospectionException { + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/JavaClassVisitor.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/JavaClassVisitor.java new file mode 100644 index 0000000000..4b0f5bea55 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/JavaClassVisitor.java @@ -0,0 +1,126 @@ +/* + * 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.implementation.java.introspect; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaParameterImpl; + +/** + * Implementations process class-level metadata, typically parsing annotations + * and updating the corresponding <code>ComponentType</code>. A processor + * may, for example, create a Property which is responsible for injecting a + * complex type on a component implementation instance when it is instantiated. + * <p/> Processors will receive callbacks as the implementation class is walked + * while evaluating an assembly. It is the responsibility of the parser to + * determine whether to perform an action during the callback. + * + * @version $Rev$ $Date$ + */ +public interface JavaClassVisitor { + + /** + * A callback received when the component implementation class is first + * loaded + * + * @param clazz the component implementation class + * @param type the incomplete component type associated with the + * implementation class + * @throws IntrospectionException if an error is encountered while processing + * metadata + */ + <T> void visitClass(Class<T> clazz, JavaImplementation type) throws IntrospectionException; + + /** + * A callback received as the component implementation class hierarchy is + * evaluated + * + * @param clazz the superclass in the component implmentation's class + * hierarchy + * @param type the incomplete component type associated with the + * implementation class + * @throws IntrospectionException if an error is encountered while processing + * metadata + */ + <T> void visitSuperClass(Class<T> clazz, JavaImplementation type) throws IntrospectionException; + + /** + * A callback received as the component implementation's public and + * protected methods are evaluated + * + * @param method the current public or protected method being evaluated + * @param type the incomplete component type associated with the + * implementation class + * @throws IntrospectionException if an error is encountered while processing + * metadata + */ + void visitMethod(Method method, JavaImplementation type) throws IntrospectionException; + + /** + * A callback received as the component implementation's constructor used + * for instantiation by the runtime is evaluated. If an implementation + * contains more than one constructor, the constructor passed to the + * callback will be chosen according to the algorithm described in the SCA + * Java Client and Implementation Model Specification. + * + * @param constructor the constructor used for instantiating component + * implementation instances + * @param type the incomplete component type associated with the + * implementation class + * @throws IntrospectionException if an error is encountered while processing + * metadata + */ + <T> void visitConstructor(Constructor<T> constructor, JavaImplementation type) throws IntrospectionException; + + /** + * @param parameter + * @param type + * @throws IntrospectionException + */ + void visitConstructorParameter(JavaParameterImpl parameter, JavaImplementation type) throws IntrospectionException; + + /** + * A callback received as the component implementation's public and + * protected fields are evaluated + * + * @param field the current public or protected field being evaluated + * @param type the incomplete component type associated with the + * implementation class + * @throws IntrospectionException if an error is encountered while processing + * metadata + */ + void visitField(Field field, JavaImplementation type) throws IntrospectionException; + + /** + * The final callback received when all other callbacks during evaluation of + * the component implementation have been issued + * + * @param clazz the component implementation class + * @param type the incomplete component type associated with the + * implementation class + * @throws IntrospectionException if an error is encountered while processing + * metadata + */ + <T> void visitEnd(Class<T> clazz, JavaImplementation type) throws IntrospectionException; + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/JavaIntrospectionHelper.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/JavaIntrospectionHelper.java new file mode 100644 index 0000000000..a04ad3721a --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/JavaIntrospectionHelper.java @@ -0,0 +1,648 @@ +/* + * 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.implementation.java.introspect; + +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; + } + + public static <T> Constructor<T> getDefaultConstructor(Class<T> clazz) throws NoSuchMethodException { + return clazz.getConstructor((Class[])null); + } + + /** + * 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> getPrivateMethods(Class<?> clazz) { + Set<Method> methods = new HashSet<Method>(); + Method[] declaredMethods = clazz.getDeclaredMethods(); + for (final Method declaredMethod : declaredMethods) { + int modifiers = declaredMethod.getModifiers(); + if(Modifier.isPrivate(modifiers)) { + methods.add(declaredMethod); + } + } + + return methods; + } + + 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/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AbstractPropertyProcessor.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AbstractPropertyProcessor.java new file mode 100644 index 0000000000..ff70fb89eb --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AbstractPropertyProcessor.java @@ -0,0 +1,257 @@ +/* + * 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.implementation.java.introspect.impl; + +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +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.util.Collection; +import java.util.List; +import java.util.Map; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Property; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaElementImpl; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaParameterImpl; +import org.apache.tuscany.sca.implementation.java.introspect.BaseJavaClassVisitor; +import org.apache.tuscany.sca.implementation.java.introspect.JavaIntrospectionHelper; +import org.apache.tuscany.sca.interfacedef.DataType; +import org.apache.tuscany.sca.interfacedef.impl.DataTypeImpl; +import org.apache.tuscany.sca.interfacedef.util.XMLType; + +/** + * Base class for ImplementationProcessors that handle annotations that add + * Properties. + * + * @version $Rev$ $Date$ + */ +public abstract class AbstractPropertyProcessor<A extends Annotation> extends BaseJavaClassVisitor { + private final Class<A> annotationClass; + + protected AbstractPropertyProcessor(ExtensionPointRegistry registry, Class<A> annotationClass) { + super(registry); + this.annotationClass = annotationClass; + } + + private static boolean removeProperty(JavaElementImpl prop, JavaImplementation type) { + if(prop==null) { + return false; + } + List<Property> props = type.getProperties(); + for(int i=0;i<props.size();i++) { + if(props.get(i).getName().equals(prop.getName())) { + props.remove(i); + return true; + } + } + return false; + } + + @Override + public void visitMethod(Method method, JavaImplementation type) throws IntrospectionException { + A annotation = method.getAnnotation(annotationClass); + if (annotation != null) { + + if (!JavaIntrospectionHelper.isSetter(method)) { + throw new IllegalPropertyException("Annotated method is not a setter: " + method, method); + } + + if(Modifier.isStatic(method.getModifiers())) { + throw new IllegalPropertyException("Static method " + method.getName() +" in class " + method.getDeclaringClass().getName() + " can not be annotated as a Property"); + } + + String name = getName(annotation); + if (name == null || "".equals(name)) { + name = method.getName(); + if (name.startsWith("set")) { + name = JavaIntrospectionHelper.toPropertyName(method.getName()); + } + } + + Map<String, JavaElementImpl> properties = type.getPropertyMembers(); + JavaElementImpl prop = properties.get(name); + // Setter override field + if (prop != null && prop.getElementType() != ElementType.FIELD) { + throw new DuplicatePropertyException(name); + } + + removeProperty(prop, type); + + JavaElementImpl element = new JavaElementImpl(method, 0); + Property property = createProperty(name, element); + + // add databinding available as annotations, as extensions + + initProperty(property, annotation); + type.getProperties().add(property); + properties.put(name, element); + } + + // enforce the constraint that an ordinary method's argument can not be a Property + Annotation paramsAnnotations[][] = method.getParameterAnnotations(); + for (int i = 0; i < paramsAnnotations.length; i++) { + Annotation argAnnotations[] = paramsAnnotations[i]; + for (int j = 0; j < argAnnotations.length; j++) { + if(argAnnotations[j].annotationType() == org.oasisopen.sca.annotation.Property.class) { + throw new IllegalPropertyException("[JCA90001] Argument " + (i+1) + " of method " + method.getName() + " in class " + method.getDeclaringClass() + " can not be a Property"); + } + } + } + } + + + @Override + public void visitField(Field field, JavaImplementation type) throws IntrospectionException { + + A annotation = field.getAnnotation(annotationClass); + if (annotation == null) { + return; + } + + if(Modifier.isStatic(field.getModifiers())) { + throw new IllegalPropertyException("Static field " + field.getName() +" in class " + field.getDeclaringClass().getName() + " can not be annotated as a Property"); + } + + if(Modifier.isFinal(field.getModifiers())) { + throw new IllegalPropertyException("[JCA90011] Final field " + field.getName() +" in class " + field.getDeclaringClass().getName() + " can not be annotated as a Property"); + } + + String name = getName(annotation); + if (name == null) { + name = ""; + } + if ("".equals(name) || name.equals(field.getType().getName())) { + name = field.getName(); + } + + Map<String, JavaElementImpl> properties = type.getPropertyMembers(); + JavaElementImpl prop = properties.get(name); + // Setter override field + if (prop != null && prop.getElementType() == ElementType.FIELD) { + throw new DuplicatePropertyException(name); + } + + if (prop == null) { + JavaElementImpl element = new JavaElementImpl(field); + Property property = createProperty(name, element); + initProperty(property, annotation); + type.getProperties().add(property); + properties.put(name, element); + } + } + + @Override + public void visitConstructorParameter(JavaParameterImpl parameter, JavaImplementation type) + throws IntrospectionException { + + Map<String, JavaElementImpl> properties = type.getPropertyMembers(); + A annotation = parameter.getAnnotation(annotationClass); + if (annotation != null) { + String name = getName(annotation); + if (name == null) { + name = parameter.getType().getName(); + } + if (!"".equals(name) && !"".equals(parameter.getName()) && !name.equals(parameter.getName())) { + throw new InvalidConstructorException("Mismatched property name: " + parameter); + } + if ("".equals(name) && "".equals(parameter.getName())) { + throw new InvalidPropertyException("[JCA90013] Missing property name: " + parameter); + } + if ("".equals(name)) { + name = parameter.getName(); + } + + if (!getRequired(annotation)) { + throw new InvalidPropertyException("[JCA90014] Constructor property must not have required=false: " + type.getName()); + } + + JavaElementImpl prop = properties.get(name); + // Setter override field + if (prop != null && prop.getElementType() != ElementType.FIELD) { + throw new DuplicatePropertyException(name); + } + removeProperty(prop, type); + + parameter.setName(name); + parameter.setClassifer(annotationClass); + Property property = createProperty(name, parameter); + initProperty(property, annotation); + type.getProperties().add(property); + properties.put(name, parameter); + } + } + + protected Property createProperty(String name, JavaElementImpl element) throws IntrospectionException { + + Type type = element.getGenericType(); + Class<?> javaType = element.getType(); + + return createProperty(assemblyFactory, name, javaType, type); + + } + + public static Property createProperty(AssemblyFactory assemblyFactory, String name, Class<?> javaClass, Type genericType) { + Property property = assemblyFactory.createProperty(); + property.setName(name); + + if (javaClass.isArray() || Collection.class.isAssignableFrom(javaClass)) { + property.setMany(true); + if (javaClass.isArray()) { + Class<?> propType = javaClass.getComponentType(); + Type genericPropType = propType; + if (genericType instanceof GenericArrayType) { + genericPropType = ((GenericArrayType)genericType).getGenericComponentType(); + } + DataType dt = new DataTypeImpl(null, propType, genericPropType, XMLType.UNKNOWN); + property.setDataType(dt); + } else { + if (genericType instanceof ParameterizedType) { + // Collection<BaseType> property; + Type genericPropType = ((ParameterizedType)genericType).getActualTypeArguments()[0]; + Class<?> propType = JavaIntrospectionHelper.getErasure(genericPropType); + DataType dt = new DataTypeImpl(null, propType, genericPropType, XMLType.UNKNOWN); + property.setDataType(dt); + } else { + // Collection property; + DataType dt = new DataTypeImpl(null, Object.class, Object.class, XMLType.UNKNOWN); + property.setDataType(dt); + } + } + } else { + DataType dt = new DataTypeImpl(null, javaClass, genericType, XMLType.UNKNOWN); + property.setDataType(dt); + } + return property; + } + + protected abstract String getName(A annotation); + protected abstract boolean getRequired(A annotation); + + protected abstract void initProperty(Property property, A annotation) throws IntrospectionException; + + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AllowsPassByReferenceProcessor.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AllowsPassByReferenceProcessor.java new file mode 100644 index 0000000000..4aa29d3b91 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AllowsPassByReferenceProcessor.java @@ -0,0 +1,57 @@ +/* + * 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.implementation.java.introspect.impl; + +import java.lang.reflect.Method; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.introspect.BaseJavaClassVisitor; +import org.oasisopen.sca.annotation.AllowsPassByReference; + +/** + * Processes {@link AllowsPassByReference} on an implementation + * + * @version $Rev$ $Date$ + */ +public class AllowsPassByReferenceProcessor extends BaseJavaClassVisitor { + + public AllowsPassByReferenceProcessor(AssemblyFactory factory) { + super(factory); + } + + public AllowsPassByReferenceProcessor(ExtensionPointRegistry registry) { + super(registry); + } + + @Override + public <T> void visitClass(Class<T> clazz, JavaImplementation type) throws IntrospectionException { + type.setAllowsPassByReference(clazz.isAnnotationPresent(AllowsPassByReference.class)); + } + + @Override + public void visitMethod(Method method, JavaImplementation type) throws IntrospectionException { + boolean pbr = method.isAnnotationPresent(AllowsPassByReference.class); + if (pbr) { + type.getAllowsPassByReferenceMethods().add(method); + } + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AmbiguousConstructorException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AmbiguousConstructorException.java new file mode 100644 index 0000000000..c6e6b6e4d6 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/AmbiguousConstructorException.java @@ -0,0 +1,40 @@ +/* + * 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.implementation.java.introspect.impl; + +import java.lang.reflect.Member; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Thrown when constructor parameters cannot be unambiguously resolved to a property or reference + * + * @version $Rev$ $Date$ + */ +public class AmbiguousConstructorException extends IntrospectionException { + private static final long serialVersionUID = 3662860753837091880L; + + public AmbiguousConstructorException(String message) { + super(message); + } + + public AmbiguousConstructorException(String message, Member member) { + super(message, member); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ComponentNameProcessor.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ComponentNameProcessor.java new file mode 100644 index 0000000000..1813a177b4 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ComponentNameProcessor.java @@ -0,0 +1,87 @@ +/* + * 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.implementation.java.introspect.impl; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaElementImpl; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaResourceImpl; +import org.apache.tuscany.sca.implementation.java.introspect.BaseJavaClassVisitor; +import org.apache.tuscany.sca.implementation.java.introspect.JavaIntrospectionHelper; +import org.oasisopen.sca.annotation.ComponentName; + +/** + * Processes {@link @ComponentName} annotations on a component implementation and adds + * a {@link JavaMappedProperty} to the component type which will be used to + * inject the appropriate component name. + * + * @version $Rev$ $Date$ + */ +public class ComponentNameProcessor extends BaseJavaClassVisitor { + + public ComponentNameProcessor(AssemblyFactory factory) { + super(factory); + } + + public ComponentNameProcessor(ExtensionPointRegistry registry) { + super(registry); + } + + @Override + public void visitMethod(Method method, JavaImplementation type) throws IntrospectionException { + if (method.getAnnotation(ComponentName.class) == null) { + return; + } + if (method.getParameterTypes().length != 1) { + throw new IllegalContextException("ComponentName setter must have one parameter", method); + } + Class<?> paramType = method.getParameterTypes()[0]; + String name = JavaIntrospectionHelper.toPropertyName(method.getName()); + if (String.class.equals(paramType)) { + JavaElementImpl element = new JavaElementImpl(method, 0); + element.setName(name); + element.setClassifer(org.apache.tuscany.sca.implementation.java.introspect.impl.Resource.class); + JavaResourceImpl resource = new JavaResourceImpl(element); + type.getResources().put(resource.getName(), resource); + } else { + throw new IllegalContextException(paramType.getName()); + } + } + + @Override + public void visitField(Field field, JavaImplementation type) throws IntrospectionException { + if (field.getAnnotation(ComponentName.class) == null) { + return; + } + Class<?> paramType = field.getType(); + if (String.class.equals(paramType)) { + JavaElementImpl element = new JavaElementImpl(field); + element.setClassifer(Resource.class); + JavaResourceImpl resource = new JavaResourceImpl(element); + type.getResources().put(resource.getName(), resource); + } else { + throw new IllegalContextException(paramType.getName()); + } + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConstructorProcessor.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConstructorProcessor.java new file mode 100644 index 0000000000..52a3fbd89a --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ConstructorProcessor.java @@ -0,0 +1,110 @@ +/* + * 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.implementation.java.introspect.impl; + +import java.lang.reflect.Constructor; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaConstructorImpl; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaParameterImpl; +import org.apache.tuscany.sca.implementation.java.introspect.BaseJavaClassVisitor; + +/** + * Handles processing of a constructor decorated with + * {@link org.oasisopen.sca.annotation.Constructor} + * + * @version $Rev$ $Date$ + */ +@SuppressWarnings("unchecked") +public class ConstructorProcessor extends BaseJavaClassVisitor { + + public ConstructorProcessor(AssemblyFactory factory) { + super(factory); + } + + public ConstructorProcessor(ExtensionPointRegistry registry) { + super(registry); + } + + @Override + public <T> void visitClass(Class<T> clazz, JavaImplementation type) throws IntrospectionException { + Constructor[] ctors = clazz.getConstructors(); + boolean found = false; + for (Constructor constructor : ctors) { + JavaConstructorImpl<?> definition = new JavaConstructorImpl(constructor); + type.getConstructors().put(constructor, definition); + if (constructor.getAnnotation(org.oasisopen.sca.annotation.Constructor.class) != null) { + if (found) { + throw new DuplicateConstructorException("[JCI50002] Multiple constructors marked with @Constructor", constructor); + } + found = true; + type.setConstructor(definition); + } + } + } + + @Override + public <T> void visitConstructor(Constructor<T> constructor, JavaImplementation type) + throws IntrospectionException { + org.oasisopen.sca.annotation.Constructor annotation = constructor + .getAnnotation(org.oasisopen.sca.annotation.Constructor.class); + if (annotation == null) { + return; + } + JavaConstructorImpl<?> definition = type.getConstructor(); + if (definition == null) { + definition = new JavaConstructorImpl(constructor); + type.setConstructor(definition); + } + JavaParameterImpl[] parameters = definition.getParameters(); + String[] value = annotation.value(); + boolean isDefault = value.length == 0 || (value.length == 1 && "".equals(value[0])); + if (!isDefault && value.length != parameters.length) { + throw new InvalidConstructorException("Invalid Number of names in @Constructor"); + } + + for (JavaParameterImpl p : parameters) { + if (!hasAnnotation(p)) { + throw new InvalidConstructorException("JCA90003 constructor parameters for class " + type.getName() + " must have @Property or @Reference annotation"); + } + } + + for (int i = 0; i < parameters.length; i++) { + parameters[i].setName(i < value.length ? value[i] : ""); + } + type.setConstructor(definition); + } + + private boolean hasAnnotation(JavaParameterImpl p) { + if (p.getAnnotations() != null && p.getAnnotations().length > 0) { + return true; + } +// TODO: need to verify JCA90003 as it seems like any annotation should be ok not just SCA ref or prop +// if (p.getAnnotation(Reference.class) != null) { +// return true; +// } +// if (p.getAnnotation(Property.class) != null) { +// return true; +// } + return false; + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ContextProcessor.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ContextProcessor.java new file mode 100644 index 0000000000..651ecdbd7e --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ContextProcessor.java @@ -0,0 +1,89 @@ +/* + * 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.implementation.java.introspect.impl; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaElementImpl; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaResourceImpl; +import org.apache.tuscany.sca.implementation.java.introspect.BaseJavaClassVisitor; +import org.apache.tuscany.sca.implementation.java.introspect.JavaIntrospectionHelper; +import org.oasisopen.sca.ComponentContext; +import org.oasisopen.sca.RequestContext; +import org.oasisopen.sca.annotation.Context; + +/** + * Processes {@link @Context} annotations on a component implementation and adds + * a {@link JavaMappedProperty} to the component type which will be used to + * inject the appropriate context + * + * @version $Rev$ $Date$ + */ +public class ContextProcessor extends BaseJavaClassVisitor { + + public ContextProcessor(AssemblyFactory factory) { + super(factory); + } + + public ContextProcessor(ExtensionPointRegistry registry) { + super(registry); + } + + @Override + public void visitMethod(Method method, JavaImplementation type) throws IntrospectionException { + if (method.getAnnotation(Context.class) == null) { + return; + } + if (method.getParameterTypes().length != 1) { + throw new IllegalContextException("Context setter must have one parameter", method); + } + Class<?> paramType = method.getParameterTypes()[0]; + String name = JavaIntrospectionHelper.toPropertyName(method.getName()); + if (ComponentContext.class.equals(paramType) || RequestContext.class.equals(paramType)) { + JavaElementImpl element = new JavaElementImpl(method, 0); + element.setName(name); + element.setClassifer(org.apache.tuscany.sca.implementation.java.introspect.impl.Resource.class); + JavaResourceImpl resource = new JavaResourceImpl(element); + type.getResources().put(resource.getName(), resource); + } else { + throw new UnknownContextTypeException(paramType.getName()); + } + } + + @Override + public void visitField(Field field, JavaImplementation type) throws IntrospectionException { + if (field.getAnnotation(Context.class) == null) { + return; + } + Class<?> paramType = field.getType(); + if (ComponentContext.class.equals(paramType) || RequestContext.class.equals(paramType)) { + JavaElementImpl element = new JavaElementImpl(field); + element.setClassifer(Resource.class); + JavaResourceImpl resource = new JavaResourceImpl(element); + type.getResources().put(resource.getName(), resource); + } else { + throw new UnknownContextTypeException(paramType.getName()); + } + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DestroyProcessor.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DestroyProcessor.java new file mode 100644 index 0000000000..a4b760760c --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DestroyProcessor.java @@ -0,0 +1,63 @@ +/* + * 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.implementation.java.introspect.impl; + +import java.lang.reflect.Method; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.introspect.BaseJavaClassVisitor; +import org.oasisopen.sca.annotation.Destroy; + +/** + * Processes the {@link @Destroy} annotation on a component implementation and + * updates the component type with the decorated destructor method + * + * @version $Rev$ $Date$ + */ +public class DestroyProcessor extends BaseJavaClassVisitor { + + public DestroyProcessor(AssemblyFactory factory) { + super(factory); + } + + public DestroyProcessor(ExtensionPointRegistry registry) { + super(registry); + } + + @Override + public void visitMethod(Method method, JavaImplementation type) throws IntrospectionException { + Destroy annotation = method.getAnnotation(Destroy.class); + if (annotation == null) { + return; + } + if (method.getParameterTypes().length != 0) { + throw new IllegalDestructorException("[JCA90004] Destructor must not have arguments", method); + } + if(!method.getReturnType().equals(void.class)) { + throw new IllegalDestructorException("Destructor must return void.", method); + } + if (type.getDestroyMethod() != null) { + throw new DuplicateDestructorException("More than one destructor found on implementation"); + } + type.setDestroyMethod(method); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateConstructorException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateConstructorException.java new file mode 100644 index 0000000000..d6494e3845 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateConstructorException.java @@ -0,0 +1,41 @@ +/* + * 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.implementation.java.introspect.impl; + +import java.lang.reflect.Member; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Thrown when more than one component implementation constructor is annotated with {@link + * org.oasisopen.sca.annotation.Constructor} + * + * @version $Rev$ $Date$ + */ +public class DuplicateConstructorException extends IntrospectionException { + private static final long serialVersionUID = -5926763756570552986L; + + public DuplicateConstructorException(String message) { + super(message); + } + + public DuplicateConstructorException(String message, Member member) { + super(message, member); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateDestructorException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateDestructorException.java new file mode 100644 index 0000000000..8bfae89162 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateDestructorException.java @@ -0,0 +1,35 @@ +/* + * 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.implementation.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Thrown when an implementation is annotated multiple times with {@link org.oasisopen.sca.annotation.Destroy} + * + * @version $Rev$ $Date$ + */ +public class DuplicateDestructorException extends IntrospectionException { + private static final long serialVersionUID = -7474912510114895203L; + + public DuplicateDestructorException(String message) { + super(message); + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateInitException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateInitException.java new file mode 100644 index 0000000000..38f6478531 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateInitException.java @@ -0,0 +1,35 @@ +/* + * 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.implementation.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Thrown when an implementation is annotated multiple times with {@link @org.oasisopen.sca.annotation.Init} + * + * @version $Rev$ $Date$ + */ +public class DuplicateInitException extends IntrospectionException { + private static final long serialVersionUID = -6282935288115512057L; + + public DuplicateInitException(String message) { + super(message); + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicatePropertyException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicatePropertyException.java new file mode 100644 index 0000000000..b9e1923e73 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicatePropertyException.java @@ -0,0 +1,34 @@ +/* + * 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.implementation.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Thrown when an implementation has more than one property injection site with the same name + * + * @version $Rev$ $Date$ + */ +public class DuplicatePropertyException extends IntrospectionException { + private static final long serialVersionUID = 5536415875694904037L; + + public DuplicatePropertyException(String message) { + super(message); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateReferenceException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateReferenceException.java new file mode 100644 index 0000000000..300ad6817e --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateReferenceException.java @@ -0,0 +1,35 @@ +/* + * 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.implementation.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Thrown when an implementation has more than one reference injection site with the same name + * + * @version $Rev$ $Date$ + */ +public class DuplicateReferenceException extends IntrospectionException { + private static final long serialVersionUID = 907910648213477158L; + + public DuplicateReferenceException(String message) { + super(message); + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateResourceException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateResourceException.java new file mode 100644 index 0000000000..2d177b3f76 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/DuplicateResourceException.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.implementation.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Thrown when an implementation has more than one resource injection site with the same name + * + * @version $Rev$ $Date$ + */ +public class DuplicateResourceException extends IntrospectionException { + + private static final long serialVersionUID = 1619276459330463299L; + + public DuplicateResourceException(String message) { + super(message); + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/EagerInitProcessor.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/EagerInitProcessor.java new file mode 100644 index 0000000000..5c0e2c1397 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/EagerInitProcessor.java @@ -0,0 +1,63 @@ +/* + * 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.implementation.java.introspect.impl; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.introspect.BaseJavaClassVisitor; +import org.oasisopen.sca.annotation.EagerInit; + +/** + * Handles processing of {@link org.oasisopen.sca.annotation.EagerInit} + * + * @version $Rev$ $Date$ + */ +public class EagerInitProcessor extends BaseJavaClassVisitor { + + public EagerInitProcessor(AssemblyFactory factory) { + super(factory); + } + + public EagerInitProcessor(ExtensionPointRegistry registry) { + super(registry); + } + + @Override + public <T> void visitClass(Class<T> clazz, + JavaImplementation type) throws IntrospectionException { + super.visitClass(clazz, type); + EagerInit annotation = clazz.getAnnotation(EagerInit.class); + if (annotation == null) { + Class<?> superClass = clazz.getSuperclass(); + while (superClass != null && !Object.class.equals(superClass)) { + annotation = superClass.getAnnotation(EagerInit.class); + if (annotation != null) { + break; + } + superClass = superClass.getSuperclass(); + } + if (annotation == null) { + return; + } + } + type.setEagerInit(true); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/HeuristicPojoProcessor.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/HeuristicPojoProcessor.java new file mode 100644 index 0000000000..19d3992781 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/HeuristicPojoProcessor.java @@ -0,0 +1,758 @@ +/* + * 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.implementation.java.introspect.impl; + +import static org.apache.tuscany.sca.implementation.java.introspect.JavaIntrospectionHelper.getAllInterfaces; +import static org.apache.tuscany.sca.implementation.java.introspect.JavaIntrospectionHelper.getAllPublicAndProtectedFields; +import static org.apache.tuscany.sca.implementation.java.introspect.JavaIntrospectionHelper.getAllUniquePublicProtectedMethods; +import static org.apache.tuscany.sca.implementation.java.introspect.JavaIntrospectionHelper.getBaseType; +import static org.apache.tuscany.sca.implementation.java.introspect.JavaIntrospectionHelper.toPropertyName; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.jws.WebService; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Contract; +import org.apache.tuscany.sca.assembly.Multiplicity; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaConstructorImpl; +import org.apache.tuscany.sca.implementation.java.JavaElementImpl; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaParameterImpl; +import org.apache.tuscany.sca.implementation.java.introspect.BaseJavaClassVisitor; +import org.apache.tuscany.sca.implementation.java.introspect.JavaIntrospectionHelper; +import org.apache.tuscany.sca.interfacedef.Interface; +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.oasisopen.sca.ServiceReference; +import org.oasisopen.sca.annotation.Callback; +import org.oasisopen.sca.annotation.ComponentName; +import org.oasisopen.sca.annotation.Context; +import org.oasisopen.sca.annotation.Property; +import org.oasisopen.sca.annotation.Reference; +import org.oasisopen.sca.annotation.Remotable; + +/** + * Heuristically evaluates an un-annotated Java implementation type to determine + * services, references, and properties according to the algorithm described in + * the SCA Java Client and Implementation Model Specification <p/> TODO + * Implement: <p/> When no service interface is annotated, need to calculate a + * single service comprising all public methods that are not reference or + * property injection sites. If that service can be exactly mapped to an + * interface implemented by the class then the service interface will be defined + * in terms of that interface. + * + * @version $Rev$ $Date$ + */ +public class HeuristicPojoProcessor extends BaseJavaClassVisitor { + + public HeuristicPojoProcessor(AssemblyFactory assemblyFactory, JavaInterfaceFactory javaFactory) { + super(assemblyFactory); + this.javaInterfaceFactory = javaFactory; + } + + public HeuristicPojoProcessor(ExtensionPointRegistry registry) { + super(registry); + } + + @Override + public <T> void visitEnd(Class<T> clazz, JavaImplementation type) throws IntrospectionException { + List<org.apache.tuscany.sca.assembly.Service> services = type.getServices(); + if (services.isEmpty()) { + // heuristically determine the service + /** + * The following is quoted from Java Specification 1.2.1.3. Introspecting services offered by a Java implementation + * In the cases described below, the services offered by a Java implementation class may be determined + * through introspection, eliding the need to specify them using @Service. The following algorithm is used + * to determine how services are introspected from an implementation class: + * + * If the interfaces of the SCA services are not specified with the @Service annotation on the + * implementation class, it is assumed that all implemented interfaces that have been annotated + * as @Remotable are the service interfaces provided by the component. If none of the implemented + * interfaces is remotable, then by default the implementation offers a single service whose type + * is the implementation class. + */ + Set<Class<?>> interfaces = getAllInterfaces(clazz); + for (Class<?> i : interfaces) { + if (i.isAnnotationPresent(Remotable.class) || i.isAnnotationPresent(WebService.class)) { + addService(type, i); + } + } + if (services.isEmpty()) { + // class is the interface + addService(type, clazz); + } + } + if (!(type.getReferenceMembers().isEmpty() && type.getPropertyMembers().isEmpty())) { + // references and properties have been explicitly defined + // if (type.getServices().isEmpty()) { + // calculateServiceInterface(clazz, type, methods); + // if (type.getServices().isEmpty()) { + // throw new ServiceTypeNotFoundException(clazz.getName()); + // } + // } + evaluateConstructor(type, clazz); + return; + } + Set<Method> methods = getAllUniquePublicProtectedMethods(clazz, false); + + calcPropRefs(methods, services, type, clazz); + evaluateConstructor(type, clazz); + } + + // Check if the implementation is implementation.java + private boolean isImplementationJava(JavaImplementation type) { + return JavaImplementation.TYPE.equals(type.getType()); + } + + private void addService(JavaImplementation type, Class<?> clazz) throws IntrospectionException { + try { + org.apache.tuscany.sca.assembly.Service service = createService(clazz); + type.getServices().add(service); + } catch (InvalidInterfaceException e) { + throw new IntrospectionException(e); + } + } + + private static boolean isAnnotatedWithSCA(AnnotatedElement element) { + for (Annotation a : element.getAnnotations()) { + // JCI_8023 + // policy annotations can be added to reference fields that + // don't have @Reference annotations so we need to allow + // for the fields to be detected as references + if (isSCAPolicyAnnotation(a)){ + continue; + } else if (isSCAAnnotation(a)) { + return true; + } + } + return false; + } + + private static boolean isSCAAnnotation(Annotation a) { + return a.annotationType().getName().startsWith("org.oasisopen.sca.annotation."); + } + + private static boolean isSCAPolicyAnnotation(Annotation a) { + if (a.annotationType().getName().startsWith("org.oasisopen.sca.annotation.PolicySets") ){ + return true; + } else if (a.annotationType().getName().startsWith("org.oasisopen.sca.annotation.Intent") ){ + return true; + } else { + return false; + } + } + + private <T> void calcPropRefs(Set<Method> methods, + List<org.apache.tuscany.sca.assembly.Service> services, + JavaImplementation type, + Class<T> clazz) throws IntrospectionException { + // heuristically determine the properties references + // make a first pass through all public methods with one param + Set<String> setters = new HashSet<String>(); + Set<String> others = new HashSet<String>(); + for (Method method : methods) { + if (!isPublicSetter(method)) { + continue; + } + if (isAnnotatedWithSCA(method)) { + // Add the property name as others + others.add(toPropertyName(method.getName())); + continue; + } + if (!isInServiceInterface(method, services)) { + // Not part of the service interface + String name = toPropertyName(method.getName()); + setters.add(name); + // avoid duplicate property or ref names + if (!type.getPropertyMembers().containsKey(name) && !type.getReferenceMembers().containsKey(name)) { + Class<?> param = method.getParameterTypes()[0]; + Type genericType = method.getGenericParameterTypes()[0]; + if (isReferenceType(param, genericType)) { + type.getReferences().add(createReference(name, param, genericType)); + type.getReferenceMembers().put(name, new JavaElementImpl(method, 0)); + } else { + type.getProperties().add(createProperty(name, param, genericType)); + type.getPropertyMembers().put(name, new JavaElementImpl(method, 0)); + } + } + } + } + // second pass for protected methods with one param + for (Method method : methods) { + if (!isProtectedSetter(method)) { + continue; + } + if (isAnnotatedWithSCA(method)) { + // Add the property name as others + others.add(toPropertyName(method.getName())); + continue; + } + Class<?> param = method.getParameterTypes()[0]; + Type paramType = method.getGenericParameterTypes()[0]; + + String name = toPropertyName(method.getName()); + setters.add(name); + // avoid duplicate property or ref names + if (isReferenceType(param, method.getGenericParameterTypes()[0])) { + if (!type.getReferenceMembers().containsKey(name)) { + type.getReferences().add(createReference(name, param, paramType)); + type.getReferenceMembers().put(name, new JavaElementImpl(method, 0)); + } + } else { + if (!type.getPropertyMembers().containsKey(name)) { + type.getProperties().add(createProperty(name, param, paramType)); + type.getPropertyMembers().put(name, new JavaElementImpl(method, 0)); + } + } + } + + // Public or protected fields unless there is a public or protected + // setter method + // for the same name + Set<Field> fields = getAllPublicAndProtectedFields(clazz, false); + for (Field field : fields) { + if (isAnnotatedWithSCA(field)) { + continue; + } + if (setters.contains(field.getName()) || others.contains(field.getName())) { + continue; + } + String name = field.getName(); + Class<?> paramType = field.getType(); + Type genericType = field.getGenericType(); + if (isReferenceType(paramType, field.getGenericType())) { + if (!type.getReferenceMembers().containsKey(name)) { + type.getReferences().add(createReference(name, paramType, genericType)); + type.getReferenceMembers().put(name, new JavaElementImpl(field)); + } + } else { + if (!type.getPropertyMembers().containsKey(name)) { + type.getProperties().add(createProperty(name, paramType, genericType)); + type.getPropertyMembers().put(name, new JavaElementImpl(field)); + } + } + } + } + + /** + * Determines the constructor to use based on the component type's + * references and properties + * + * @param type the component type + * @param clazz the implementation class corresponding to the component type + * @throws NoConstructorException if no suitable constructor is found + * @throws AmbiguousConstructorException if the parameters of a constructor + * cannot be unambiguously mapped to references and properties + */ + @SuppressWarnings("unchecked") + private <T> void evaluateConstructor(JavaImplementation type, Class<T> clazz) throws IntrospectionException { + // determine constructor if one is not annotated + JavaConstructorImpl<?> definition = type.getConstructor(); + Constructor constructor; + boolean explict = false; + if (definition != null && definition.getConstructor() + .isAnnotationPresent(org.oasisopen.sca.annotation.Constructor.class)) { + // the constructor was already defined explicitly + return; + } else if (definition != null) { + explict = true; + constructor = definition.getConstructor(); + } else { + if (!isImplementationJava(type)) { + // FIXME: [rfeng] Don't process the constructors for non implementation.java types + return; + } + // no definition, heuristically determine constructor + Constructor[] constructors = clazz.getConstructors(); + if (constructors.length == 0) { + throw new NoConstructorException("[JCI50001] No public constructor for class :" + type.getName()); + } else if (constructors.length == 1) { + // Only one constructor, take it + constructor = constructors[0]; + } else { + Constructor<T> selected = null; + for (Constructor<T> ctor : constructors) { + if (allArgsAnnotated(ctor)) { + selected = ctor; + for (Constructor<T> ctor2 : constructors) { + if (selected != ctor2 && allArgsAnnotated(ctor2)) { + throw new InvalidConstructorException("[JCI50005] Multiple annotated constructors for class :" + type.getName()); + } + } + } + } + if (selected == null) { + for (Constructor<T> ctor : constructors) { + if (ctor.getParameterTypes().length == 0) { + selected = ctor; + break; + } + } + } + if (selected == null) { + throw new NoConstructorException(); + } + constructor = selected; + definition = type.getConstructors().get(selected); + type.setConstructor(definition); + } + definition = type.getConstructors().get(constructor); + type.setConstructor(definition); + } + JavaParameterImpl[] parameters = definition.getParameters(); + if (parameters.length == 0) { + return; + } + Map<String, JavaElementImpl> props = type.getPropertyMembers(); + Map<String, JavaElementImpl> refs = type.getReferenceMembers(); + Annotation[][] annotations = constructor.getParameterAnnotations(); + if (!explict) { + // the constructor wasn't defined by an annotation, so check to see + // if any of the params have an annotation + // which we can impute as explicitly defining the constructor, e.g. + // @Property, @Reference, or @Autowire + explict = injectionAnnotationsPresent(annotations); + } + if (explict) { + for (int i = 0; i < parameters.length; i++) { + if (isAnnotated(parameters[i])) { + continue; + } else if (!findReferenceOrProperty(parameters[i], props, refs)) { + throw new AmbiguousConstructorException(parameters[i].toString()); + } + } + } else { + if (!areUnique(parameters)) { + throw new AmbiguousConstructorException("Cannot resolve non-unique parameter types, use @Constructor"); + } + if (!calcPropRefUniqueness(props.values(), refs.values())) { + throw new AmbiguousConstructorException("Cannot resolve non-unique parameter types, use @Constructor"); + } + if (!(props.isEmpty() && refs.isEmpty())) { + calcParamNames(parameters, props, refs); + } else { + heuristicParamNames(type, parameters); + + } + } + } + + private boolean allArgsAnnotated(Constructor<?> ctor) { + if (ctor.getParameterTypes().length < 1) { + return false; + } + for (Annotation[] as : ctor.getParameterAnnotations()) { + if (as.length < 1) { + return false; + } + } + return true; + } + + private void calcParamNames(JavaParameterImpl[] parameters, + Map<String, JavaElementImpl> props, + Map<String, JavaElementImpl> refs) throws AmbiguousConstructorException { + // the constructor param types must unambiguously match defined + // reference or property types + for (JavaParameterImpl param : parameters) { + if (!findReferenceOrProperty(param, props, refs)) { + throw new AmbiguousConstructorException(param.getName()); + } + } + } + + private void heuristicParamNames(JavaImplementation type, JavaParameterImpl[] parameters) + throws IntrospectionException { + // heuristically determine refs and props from the parameter types + for (JavaParameterImpl p : parameters) { + String name = p.getType().getSimpleName().toLowerCase(); + if (isReferenceType(p.getType(), p.getGenericType())) { + type.getReferences().add(createReference(name, p.getType(), p.getGenericType())); + p.setClassifer(Reference.class); + type.getReferenceMembers().put(name, p); + } else { + type.getProperties().add(createProperty(name, p.getType(), p.getGenericType())); + p.setClassifer(Property.class); + type.getPropertyMembers().put(name, p); + } + p.setName(name); + } + } + + + + /** + * Returns true if the union of the given collections of properties and + * references have unique Java types + */ + private boolean calcPropRefUniqueness(Collection<JavaElementImpl> props, Collection<JavaElementImpl> refs) { + + Class<?>[] classes = new Class[props.size() + refs.size()]; + int i = 0; + for (JavaElementImpl property : props) { + classes[i] = property.getType(); + i++; + } + for (JavaElementImpl reference : refs) { + classes[i] = reference.getType(); + i++; + } + return areUnique(classes); + } + + /** + * Unambiguously finds the reference or property associated with the given + * type + * + * @return the name of the reference or property if found, null if not + * @throws AmbiguousConstructorException if the constructor parameter cannot + * be resolved to a property or reference + */ + private boolean findReferenceOrProperty(JavaParameterImpl parameter, + Map<String, JavaElementImpl> props, + Map<String, JavaElementImpl> refs) throws AmbiguousConstructorException { + + boolean found = false; + if (!"".equals(parameter.getName())) { + // Match by name + JavaElementImpl prop = props.get(parameter.getName()); + if (prop != null && prop.getType() == parameter.getType()) { + parameter.setClassifer(Property.class); + return true; + } + JavaElementImpl ref = refs.get(parameter.getName()); + if (ref != null && ref.getType() == parameter.getType()) { + parameter.setClassifer(Reference.class); + return true; + } + } + for (JavaElementImpl property : props.values()) { + if (property.getType() == parameter.getType()) { + if (found) { + throw new AmbiguousConstructorException("Ambiguous property or reference for constructor type", + (Member)parameter.getAnchor()); + } + parameter.setClassifer(Property.class); + parameter.setName(property.getName()); + found = true; + // do not break since ambiguities must be checked, i.e. more + // than one prop or ref of the same type + } + } + for (JavaElementImpl reference : refs.values()) { + if (reference.getType() == parameter.getType()) { + if (found) { + throw new AmbiguousConstructorException("Ambiguous property or reference for constructor type", + (Member)parameter.getAnchor()); + } + parameter.setClassifer(Reference.class); + parameter.setName(reference.getName()); + found = true; + // do not break since ambiguities must be checked, i.e. more + // than one prop or ref of the same type + } + } + return found; + } + + /** + * Creates a mapped property. + * + * @param name the property name + * @param paramType the property type + */ + private org.apache.tuscany.sca.assembly.Property createProperty(String name, Class<?> javaClass, Type genericType) { + return AbstractPropertyProcessor.createProperty(assemblyFactory, name, javaClass, genericType); + } + + private org.apache.tuscany.sca.assembly.Reference createReference(String name, Class<?> paramType, + Type genericType ) + throws IntrospectionException { + org.apache.tuscany.sca.assembly.Reference reference = assemblyFactory.createReference(); + reference.setName(name); + JavaInterfaceContract interfaceContract = javaInterfaceFactory.createJavaInterfaceContract(); + reference.setInterfaceContract(interfaceContract); + // Compute the interface type dealing with array/Collection types and with Generic types + Class<?> baseType = getBaseType(paramType, genericType); + if (ServiceReference.class.isAssignableFrom(baseType)) { + if (Collection.class.isAssignableFrom(paramType)) { + genericType = JavaIntrospectionHelper.getParameterType(genericType); + } + baseType = JavaIntrospectionHelper.getBusinessInterface(baseType, genericType); + } // end if + try { + JavaInterface callInterface = javaInterfaceFactory.createJavaInterface(baseType); + + reference.getInterfaceContract().setInterface(callInterface); + if (callInterface.getCallbackClass() != null) { + JavaInterface callbackInterface = javaInterfaceFactory.createJavaInterface(callInterface.getCallbackClass()); + reference.getInterfaceContract().setCallbackInterface(callbackInterface); + } + // Multiplicity of an implicit reference is 1..1 for a simple interface type + // and 1..n for an array of interface or Collection of interface type + // as defined in the OASIS SCA Java POJO specification, section 8.1 : TUSCANY-3636 + if( isCollectionType( paramType ) || isArrayType( paramType )) { + reference.setMultiplicity(Multiplicity.ONE_N); + } else { + reference.setMultiplicity(Multiplicity.ONE_ONE); + } // end if + } catch (InvalidInterfaceException e1) { + throw new IntrospectionException(e1); + } // end try + + // FIXME: This part seems to have already been taken care above!! + try { + processCallback(paramType, reference); + } catch (InvalidServiceTypeException e) { + throw new IntrospectionException(e); + } + return reference; + } + + /** + * Reports if a parameter type is a form of java.util.Collection + * @param paramType + * @return true if paramType is a form of java.util.Collection, false otherwise + */ + private boolean isCollectionType( Class<?> paramType ) { + if( Collection.class.isAssignableFrom(paramType) ) return true; + return false; + } + + /** + * Reports if a parameter type is an array + * @param paramType + * @return true if paramType is an array + */ + private boolean isArrayType( Class<?> paramType ) { + if( paramType.isArray() ) return true; + return false; + } + + private org.apache.tuscany.sca.assembly.Service createService(Class<?> interfaze) throws InvalidInterfaceException { + org.apache.tuscany.sca.assembly.Service service = assemblyFactory.createService(); + service.setName(interfaze.getSimpleName()); + + JavaInterfaceContract interfaceContract = javaInterfaceFactory.createJavaInterfaceContract(); + service.setInterfaceContract(interfaceContract); + + JavaInterface callInterface = javaInterfaceFactory.createJavaInterface(interfaze); + service.getInterfaceContract().setInterface(callInterface); + if (callInterface.getCallbackClass() != null) { + JavaInterface callbackInterface = javaInterfaceFactory.createJavaInterface(callInterface.getCallbackClass()); + service.getInterfaceContract().setCallbackInterface(callbackInterface); + } + + Interface javaInterface = service.getInterfaceContract().getInterface(); + javaInterface.setRemotable(interfaze.getAnnotation(Remotable.class) != null); + service.getInterfaceContract().setInterface(javaInterface); + return service; + } + + private void processCallback(Class<?> interfaze, Contract contract) throws InvalidServiceTypeException { + Callback callback = interfaze.getAnnotation(Callback.class); + if (callback != null && !Void.class.equals(callback.value())) { + Class<?> callbackClass = callback.value(); + JavaInterface javaInterface; + try { + javaInterface = javaInterfaceFactory.createJavaInterface(callbackClass); + contract.getInterfaceContract().setCallbackInterface(javaInterface); + } catch (InvalidInterfaceException e) { + throw new InvalidServiceTypeException("Invalid callback interface "+callbackClass, interfaze); + } + } else if (callback != null && Void.class.equals(callback.value())) { + throw new InvalidServiceTypeException("No callback interface specified on annotation", interfaze); + } + } + + + /** + * Utility methods + */ + + + /** + * Verify if the method is a public setter + * @param method + * @return + */ + private static boolean isPublicSetter(Method method) { + return method.getParameterTypes().length == 1 && Modifier.isPublic(method.getModifiers()) + && method.getName().startsWith("set") + && method.getReturnType() == void.class; + } + + /** + * Verify if the method is a protected setter + * @param method + * @return + */ + private static boolean isProtectedSetter(Method method) { + return method.getParameterTypes().length == 1 && Modifier.isProtected(method.getModifiers()) + && method.getName().startsWith("set") + && method.getReturnType() == void.class; + } + + /** + * @param collection + * @return + */ + private static boolean areUnique(Class<?>[] collection) { + Set<Class<?>> set = new HashSet<Class<?>>(Arrays.asList(collection)); + return set.size() == collection.length; + } + + /** + * Returns true if a given type is reference according to the SCA + * specification rules for determining reference types The following rules + * are used to determine whether an unannotated field or setter method is a + * property or reference: + * <ol> + * <li>If its type is simple, then it is a property. + * <li>If its type is complex, then if the type is an interface marked by + * + * @Remotable, then it is a reference; otherwise, it is a property. + * <li>Otherwise, if the type associated with the member is an + * array or a java.util.Collection, the basetype is the element + * type of the array or the parameterized type of the + * Collection; otherwise the basetype is the member type. If the + * basetype is an interface with an + * @Remotable or + * @Service annotation then the member is defined as a reference. Otherwise, + * it is defined as a property. + * </ol> + * <p> + * The name of the reference or of the property is derived from the + * name found on the setter method or on the field. + */ + // FIXME: [rfeng] What if it's a collection of references? + private static boolean isReferenceType(Class<?> cls, Type genericType) { + Class<?> baseType = JavaIntrospectionHelper.getBaseType(cls, genericType); + return baseType.isInterface() && baseType.isAnnotationPresent(Remotable.class); + } + + /** + * Returns true if the given operation is defined in the collection of + * service interfaces + * @param operation + * @param services + * @return + */ + private static boolean isInServiceInterface(Method operation, List<org.apache.tuscany.sca.assembly.Service> services) { + for (org.apache.tuscany.sca.assembly.Service service : services) { + Interface interface1 = service.getInterfaceContract().getInterface(); + if (interface1 instanceof JavaInterface) { + Class<?> clazz = ((JavaInterface)interface1).getJavaClass(); + if (isMethodMatched(clazz, operation)) { + return true; + } + } + } + return false; + } + + /** + * Test if the class declares a method which matches the signature of the + * given method + * + * @param clazz + * @param method + * @return + */ + private static boolean isMethodMatched(Class<?> clazz, Method method) { + if (method.getDeclaringClass() == clazz) { + return true; + } + Method[] methods = clazz.getMethods(); + for (Method m : methods) { + if (JavaIntrospectionHelper.exactMethodMatch(method, m)) { + return true; + } + } + return false; + } + + /** + * Verify if there is any SCA annotation on the parameter + * @param parameter + * @return + */ + private static boolean isAnnotated(JavaParameterImpl parameter) { + for (Annotation annotation : parameter.getAnnotations()) { + if (isSCAAnnotation(annotation)) { + return true; + } + } + return false; + } + + /** + * Verify if the parameters are unique + * @param parameters + * @return + */ + private static boolean areUnique(JavaParameterImpl[] parameters) { + Set<Class<?>> set = new HashSet<Class<?>>(parameters.length); + for (JavaParameterImpl p : parameters) { + if (!set.add(p.getType())) { + return false; + } + } + return true; + } + + /** + * Verify if the annotations are SCA annotation + * @param annots + * @return + */ + private static boolean injectionAnnotationsPresent(Annotation[][] annots) { + for (Annotation[] annotations : annots) { + for (Annotation annotation : annotations) { + Class<? extends Annotation> annotType = annotation.annotationType(); + if (annotType == Property.class || annotType == Reference.class + || annotType == Resource.class + || annotType == ComponentName.class + || annotType == Context.class + || annotType == Callback.class) { + return true; + } + } + } + return false; + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalCallbackReferenceException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalCallbackReferenceException.java new file mode 100644 index 0000000000..badd41fbb9 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalCallbackReferenceException.java @@ -0,0 +1,40 @@ +/* + * 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.implementation.java.introspect.impl; + +import java.lang.reflect.Member; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Denotes an illegal use of {@link org.oasisopen.sca.annotation.Callback} on a reference + * + * @version $Rev$ $Date$ + */ +public class IllegalCallbackReferenceException extends IntrospectionException { + private static final long serialVersionUID = -8932525723147700591L; + + public IllegalCallbackReferenceException(String message) { + super(message); + } + + public IllegalCallbackReferenceException(String message, Member member) { + super(message, member); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalContextException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalContextException.java new file mode 100644 index 0000000000..fa1e67a336 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalContextException.java @@ -0,0 +1,40 @@ +/* + * 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.implementation.java.introspect.impl; + +import java.lang.reflect.Member; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Denotes an illegal signature for a method decorated with {@link org.oasisopen.sca.annotation.Context} + * + * @version $Rev$ $Date$ + */ +public class IllegalContextException extends IntrospectionException { + private static final long serialVersionUID = -6946383136750117008L; + + public IllegalContextException(String message) { + super(message); + } + + public IllegalContextException(String message, Member member) { + super(message, member); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalDestructorException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalDestructorException.java new file mode 100644 index 0000000000..0c4c3d5646 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalDestructorException.java @@ -0,0 +1,40 @@ +/* + * 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.implementation.java.introspect.impl; + +import java.lang.reflect.Member; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Denotes an illegal signature for a method decorated with {@link org.oasisopen.sca.annotation.Destroy} + * + * @version $Rev$ $Date$ + */ +public class IllegalDestructorException extends IntrospectionException { + private static final long serialVersionUID = 365719353107446326L; + + public IllegalDestructorException(String message) { + super(message); + } + + public IllegalDestructorException(String message, Member member) { + super(message, member); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalInitException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalInitException.java new file mode 100644 index 0000000000..2956b60b65 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalInitException.java @@ -0,0 +1,40 @@ +/* + * 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.implementation.java.introspect.impl; + +import java.lang.reflect.Member; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Denotes an illegal signature for a method decorated with {@link @org.oasisopen.sca.annotation.Init} + * + * @version $Rev$ $Date$ + */ +public class IllegalInitException extends IntrospectionException { + private static final long serialVersionUID = -3690763271986854701L; + + public IllegalInitException(String message) { + super(message); + } + + public IllegalInitException(String message, Member member) { + super(message, member); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalPropertyException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalPropertyException.java new file mode 100644 index 0000000000..54f7dfad1e --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalPropertyException.java @@ -0,0 +1,40 @@ +/* + * 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.implementation.java.introspect.impl; + +import java.lang.reflect.Member; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Denotes an illegal property definition in a component type + * + * @version $Rev$ $Date$ + */ +public class IllegalPropertyException extends IntrospectionException { + private static final long serialVersionUID = -2836849110706758494L; + + public IllegalPropertyException(String message) { + super(message); + } + + public IllegalPropertyException(String message, Member member) { + super(message, member); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalReferenceException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalReferenceException.java new file mode 100644 index 0000000000..25196c56e5 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalReferenceException.java @@ -0,0 +1,40 @@ +/* + * 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.implementation.java.introspect.impl; + +import java.lang.reflect.Member; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Denotes an illegal reference definition in a component type + * + * @version $Rev$ $Date$ + */ +public class IllegalReferenceException extends IntrospectionException { + private static final long serialVersionUID = 4612984122225271395L; + + public IllegalReferenceException(String message) { + super(message); + } + + public IllegalReferenceException(String message, Member member) { + super(message, member); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalResourceException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalResourceException.java new file mode 100644 index 0000000000..ccfbaf0043 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalResourceException.java @@ -0,0 +1,40 @@ +/* + * 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.implementation.java.introspect.impl; + +import java.lang.reflect.Member; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Denotes an illegal resource definition in a component type + * + * @version $Rev$ $Date$ + */ +public class IllegalResourceException extends IntrospectionException { + private static final long serialVersionUID = -1100936539412435579L; + + public IllegalResourceException(String message) { + super(message); + } + + public IllegalResourceException(String message, Member member) { + super(message, member); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalServiceDefinitionException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalServiceDefinitionException.java new file mode 100644 index 0000000000..e0f90779a1 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/IllegalServiceDefinitionException.java @@ -0,0 +1,35 @@ +/* + * 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.implementation.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Denotes an illegal use of the {@link @org.oasisopen.sca.annotation.Service} annotation + * + * @version $Rev$ $Date$ + */ +public class IllegalServiceDefinitionException extends IntrospectionException { + private static final long serialVersionUID = -7151534258405092548L; + + public IllegalServiceDefinitionException(String message) { + super(message); + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InitProcessor.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InitProcessor.java new file mode 100644 index 0000000000..a5227fc4f5 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InitProcessor.java @@ -0,0 +1,67 @@ +/* + * 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.implementation.java.introspect.impl; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.introspect.BaseJavaClassVisitor; +import org.oasisopen.sca.annotation.Init; + +/** + * Processes the {@link @Init} annotation on a component implementation and + * updates the component type with the decorated initializer method + * + * @version $Rev$ $Date$ + */ +public class InitProcessor extends BaseJavaClassVisitor { + + public InitProcessor(AssemblyFactory factory) { + super(factory); + } + + public InitProcessor(ExtensionPointRegistry registry) { + super(registry); + } + + @Override + public void visitMethod(Method method, JavaImplementation type) throws IntrospectionException { + Init annotation = method.getAnnotation(Init.class); + if (annotation == null) { + return; + } + if (method.getParameterTypes().length != 0) { + throw new IllegalInitException("[JCA90008] Initializer must not have argments", method); + } + if(!method.getReturnType().equals(void.class)) { + throw new IllegalInitException("Initializer must return void.", method); + } + if (type.getInitMethod() != null) { + throw new DuplicateInitException("More than one initializer found on implementaton"); + } + if (!Modifier.isPublic(method.getModifiers())) { + throw new IllegalInitException("Initializer must be a public method. Invalid annotation @Init found on "+method); + } + type.setInitMethod(method); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidConstructorException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidConstructorException.java new file mode 100644 index 0000000000..c75dfdaf46 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidConstructorException.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.implementation.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Denotes an invalid constructor definition, e.g. when the number of injection names specified in {@link + * org.oasisopen.sca.annotation.Constructor} do not match the number of actual constructor parameters + * + * @version $Rev$ $Date$ + */ +public class InvalidConstructorException extends IntrospectionException { + private static final long serialVersionUID = 1411492435210741512L; + + public InvalidConstructorException(String message) { + super(message); + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidConversationalImplementationException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidConversationalImplementationException.java new file mode 100644 index 0000000000..079495e4db --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidConversationalImplementationException.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.implementation.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Raised when an implementation specifies improper conversational metadata + * + * @version $Rev$ $Date$ + */ +public class InvalidConversationalImplementationException extends IntrospectionException { + private static final long serialVersionUID = -5487291552769408149L; + + public InvalidConversationalImplementationException(String message) { + super(message); + } + + public InvalidConversationalImplementationException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidPropertyException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidPropertyException.java new file mode 100644 index 0000000000..429b88aa1f --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidPropertyException.java @@ -0,0 +1,35 @@ +/* + * 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.implementation.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Denotes an invalid usage of {@link org.oasisopen.sca.annotation.Property} + * + * @version $Rev$ $Date$ + */ +public class InvalidPropertyException extends IntrospectionException { + private static final long serialVersionUID = -2682862652069727948L; + + public InvalidPropertyException(String message) { + super(message); + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidReferenceException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidReferenceException.java new file mode 100644 index 0000000000..fbf3fc9ed3 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidReferenceException.java @@ -0,0 +1,42 @@ +/* + * 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.implementation.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Denotes an invalid usage of {@link org.oasisopen.sca.annotation.Reference} + * + * @version $Rev$ $Date$ + */ +public class InvalidReferenceException extends IntrospectionException { + private static final long serialVersionUID = -3285246635989254165L; + + public InvalidReferenceException(String message) { + super(message); + } + + public InvalidReferenceException(String message, Throwable cause) { + super(message, cause); + } + + public InvalidReferenceException(Throwable cause) { + super(cause); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidResourceException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidResourceException.java new file mode 100644 index 0000000000..debb5cbacc --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidResourceException.java @@ -0,0 +1,40 @@ +/* + * 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.implementation.java.introspect.impl; + +import java.lang.reflect.Member; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Denotes an invalid usage of {@link @org.apache.tuscany.api.annotation.Resource} + * + * @version $Rev$ $Date$ + */ +public class InvalidResourceException extends IntrospectionException { + private static final long serialVersionUID = 511728001735534934L; + + public InvalidResourceException(String message) { + super(message); + } + + public InvalidResourceException(String message, Member member) { + super(message, member); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidServiceTypeException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidServiceTypeException.java new file mode 100644 index 0000000000..230c8c6fdd --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/InvalidServiceTypeException.java @@ -0,0 +1,48 @@ +/* + * 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.implementation.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Thrown when a service type specified by an {@link org.oasisopen.sca.annotation.Service} annotation is invalid, e.g. it is + * not an interface + * + * @version $Rev$ $Date$ + */ +public class InvalidServiceTypeException extends IntrospectionException { + private static final long serialVersionUID = -1076466639416644386L; + private Class<?> serviceType; + + public InvalidServiceTypeException(String message) { + super(message); + } + + public InvalidServiceTypeException(String message, Class<?> clazz) { + super(message); + this.serviceType = clazz; + } + + /** + * @return the serviceType + */ + public Class<?> getServiceType() { + return serviceType; + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/JAXWSProcessor.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/JAXWSProcessor.java new file mode 100644 index 0000000000..50bb5f86d3 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/JAXWSProcessor.java @@ -0,0 +1,337 @@ +/*
+ * 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.implementation.java.introspect.impl;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+
+import javax.jws.WebParam;
+import javax.jws.WebResult;
+import javax.jws.WebService;
+import javax.jws.soap.SOAPBinding;
+import javax.xml.ws.BindingType;
+import javax.xml.ws.ServiceMode;
+import javax.xml.ws.WebServiceProvider;
+
+import org.apache.tuscany.sca.assembly.AssemblyFactory;
+import org.apache.tuscany.sca.assembly.Service;
+import org.apache.tuscany.sca.assembly.xml.Constants;
+import org.apache.tuscany.sca.binding.ws.WebServiceBinding;
+import org.apache.tuscany.sca.binding.ws.WebServiceBindingFactory;
+import org.apache.tuscany.sca.binding.ws.xml.WebServiceConstants;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.FactoryExtensionPoint;
+import org.apache.tuscany.sca.implementation.java.IntrospectionException;
+import org.apache.tuscany.sca.implementation.java.JavaImplementation;
+import org.apache.tuscany.sca.implementation.java.introspect.BaseJavaClassVisitor;
+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.policy.ExtensionType;
+import org.apache.tuscany.sca.policy.Intent;
+import org.apache.tuscany.sca.policy.PolicyFactory;
+import org.apache.tuscany.sca.policy.PolicySubject;
+
+/**
+ * Process JAXWS annotations and updates the component type accordingly
+ *
+ */
+public class JAXWSProcessor extends BaseJavaClassVisitor {
+
+ private PolicyFactory policyFactory;
+ private WSDLFactory wsdlFactory;
+ private WebServiceBindingFactory wsBindingFactory;
+
+ public JAXWSProcessor(ExtensionPointRegistry registry) {
+ super(registry);
+ FactoryExtensionPoint factories = registry.getExtensionPoint(FactoryExtensionPoint.class);
+ this.wsdlFactory = factories.getFactory(WSDLFactory.class);
+ this.assemblyFactory = factories.getFactory(AssemblyFactory.class);
+ this.policyFactory = factories.getFactory(PolicyFactory.class);
+ this.javaInterfaceFactory = factories.getFactory(JavaInterfaceFactory.class);
+ this.wsBindingFactory = factories.getFactory(WebServiceBindingFactory.class);
+ }
+
+ @Override
+ public <T> void visitClass(Class<T> clazz, JavaImplementation type) throws IntrospectionException {
+
+ boolean hasJaxwsAnnotation = false;
+
+ // Process @ServiceMode annotation - JCA 11013
+ if ( clazz.getAnnotation(ServiceMode.class) != null ) {
+ addSOAPIntent(type);
+ hasJaxwsAnnotation = true;
+ }
+
+ // Process @WebService annotation - POJO_8029, POJO_8030
+ WebService webServiceAnnotation = clazz.getAnnotation(WebService.class);
+ org.oasisopen.sca.annotation.Service serviceAnnotation = clazz.getAnnotation(org.oasisopen.sca.annotation.Service.class);
+
+ if (webServiceAnnotation != null &&
+ serviceAnnotation == null) {
+ String serviceName = clazz.getSimpleName();
+ serviceName = getValue(webServiceAnnotation.name(), serviceName);
+
+ String serviceInterfaceClassName = webServiceAnnotation.endpointInterface();
+
+ String wsdlLocation = webServiceAnnotation.wsdlLocation();
+
+ try {
+ createService(type, clazz, serviceName, serviceInterfaceClassName, wsdlLocation, false);
+ } catch (InvalidInterfaceException e) {
+ throw new IntrospectionException(e);
+ }
+ hasJaxwsAnnotation = true;
+ }
+
+ // Process @WebServiceProvider annotation - JCA_11015, POJO_8034
+ WebServiceProvider webServiceProviderAnnotation = clazz.getAnnotation(WebServiceProvider.class);
+ if (webServiceProviderAnnotation != null) {
+ // if the implmentation already has a service set, use it's name
+ // and the new service, which uses the implementation as an interface,
+ // will be replaced
+ String serviceName = clazz.getSimpleName();
+
+ if (type.getServices().size() > 0){
+ serviceName = ((Service)type.getServices().get(0)).getName();
+ }
+
+ // the annotation may specify a service name
+ serviceName = getValue(webServiceProviderAnnotation.serviceName(), serviceName);
+
+ String wsdlLocation = webServiceProviderAnnotation.wsdlLocation();
+
+ // Make sure that there is a service with an interface
+ // based on the implementation class and have it replace
+ // any service with the same name
+ try {
+ createService(type, clazz, serviceName, null, wsdlLocation, true);
+ } catch (InvalidInterfaceException e) {
+ throw new IntrospectionException(e);
+ }
+
+ // Make sure all service references are remotable
+ for ( Service service : type.getServices() ) {
+ service.getInterfaceContract().getInterface().setRemotable(true);
+ }
+
+ hasJaxwsAnnotation = true;
+ }
+
+ // Process @WebParam and @WebResult annotations - POJO_8031, POJO_8032
+ Class<?> interfaze = clazz;
+ Method[] implMethods = interfaze.getDeclaredMethods();
+ for ( Service service : type.getServices() ) {
+ JavaInterface javaInterface = (JavaInterface)service.getInterfaceContract().getInterface();
+ interfaze = javaInterface.getJavaClass();
+
+ if (interfaze == null){
+ // this interface has come from an @WebService enpointInterface annotation
+ // so hasn't been resolved. Use the implementation class as the interface
+ interfaze = clazz;
+ }
+
+ boolean hasHeaderParam = false;
+ for (Method method : interfaze.getDeclaredMethods()){
+ // find the impl method for this service method
+ for (int i = 0; i < implMethods.length; i++){
+ Method implMethod = implMethods[i];
+ if (implMethod.getName().equals(method.getName())){
+ for (int j = 0; j < implMethod.getParameterTypes().length; j++) {
+ WebParam webParamAnnotation = getParameterAnnotation(implMethod, j, WebParam.class);
+ if (webParamAnnotation != null &&
+ webParamAnnotation.header()) {
+ hasHeaderParam = true;
+ break;
+ }
+ }
+
+ WebResult webResultAnnotation = implMethod.getAnnotation(WebResult.class);
+ if (webResultAnnotation != null &&
+ webResultAnnotation.header()){
+ hasHeaderParam = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (hasHeaderParam){
+ // Add a SOAP intent to the service
+ addSOAPIntent(service);
+ hasJaxwsAnnotation = true;
+ }
+ }
+
+ // Process @SOAPBinding annotation - POJO_8033
+ if ( clazz.getAnnotation(SOAPBinding.class) != null ) {
+ // If the implementation is annotated with @SOAPBinding,
+ // give all services a SOAP intent
+ for ( Service service : type.getServices() ) {
+ addSOAPIntent(service);
+ }
+ hasJaxwsAnnotation = true;
+ }
+
+
+ // Process @BindingType annotation - POJO_8037
+ BindingType bindingType = clazz.getAnnotation(BindingType.class);
+
+ if ( bindingType != null ) {
+ String bindingTypeValue = bindingType.value();
+ for ( Service service : type.getServices() ) {
+ addBindingTypeIntent(service, bindingTypeValue);
+ }
+ hasJaxwsAnnotation = true;
+ }
+
+ if (hasJaxwsAnnotation == true){
+ // Note that services are based on JAXWS annotations in case
+ // we need to know later. Add a ws binding and a JAXWS annotation
+ // implies a WS binding
+ for ( Service service : type.getServices() ) {
+ service.setJAXWSService(true);
+ createWSBinding(type, service);
+ }
+ }
+
+
+
+ }
+
+ private void addBindingTypeIntent(PolicySubject subject,
+ String bindingTypeValue) {
+
+ Intent soapIntent = policyFactory.createIntent();
+ if ( javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_BINDING.equals(bindingTypeValue)) {
+ soapIntent.setName(Constants.SOAP11_INTENT);
+ } else if ( javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING.equals(bindingTypeValue)) {
+ soapIntent.setName(Constants.SOAP12_INTENT);
+ } else {
+ soapIntent.setName(Constants.SOAP11_INTENT);
+ }
+
+ subject.getRequiredIntents().add(soapIntent);
+
+ }
+
+ /**
+ * Utility methods
+ */
+
+ private static String getValue(String value, String defaultValue) {
+ return "".equals(value) ? defaultValue : value;
+ }
+
+ private Service createService(JavaImplementation type, Class<?> clazz, String serviceName, String javaInterfaceName, String wsdlFileName, boolean replace) throws InvalidInterfaceException, IntrospectionException {
+ Service service = assemblyFactory.createService();
+
+ if (serviceName != null) {
+ service.setName(serviceName);
+ } else if (javaInterfaceName != null){
+ service.setName(javaInterfaceName.substring(javaInterfaceName.lastIndexOf('.')));
+ }
+
+ // create the physical Java interface contract
+ JavaInterfaceContract javaInterfaceContract = javaInterfaceFactory.createJavaInterfaceContract();;
+ service.setInterfaceContract(javaInterfaceContract);
+
+ if (javaInterfaceName != null &&
+ javaInterfaceName.length() > 0){
+ JavaInterface callInterface = javaInterfaceFactory.createJavaInterface();
+ callInterface.setName(javaInterfaceName);
+ callInterface.setRemotable(true);
+ callInterface.setUnresolved(true);
+ javaInterfaceContract.setInterface(callInterface);
+ } else {
+ // we use the bean class as the service interface
+ JavaInterface callInterface = javaInterfaceFactory.createJavaInterface(clazz);
+ callInterface.setRemotable(true);
+ callInterface.setUnresolved(false); // this will already be false but this makes it easy to follow the logic
+ javaInterfaceContract.setInterface(callInterface);
+ }
+
+ // create the logical WSDL interface if it's specified in
+ // the @WebService annotation
+ if (wsdlFileName != null &&
+ wsdlFileName.length() > 0){
+ WSDLInterface callInterface = wsdlFactory.createWSDLInterface();
+ callInterface.setUnresolved(true);
+ callInterface.setRemotable(true);
+
+ WSDLInterfaceContract wsdlInterfaceContract = wsdlFactory.createWSDLInterfaceContract();
+ wsdlInterfaceContract.setInterface(callInterface);
+ wsdlInterfaceContract.setLocation(wsdlFileName);
+ javaInterfaceContract.setNormailizedWSDLContract(wsdlInterfaceContract);
+ }
+
+ // add the service model into the implementation type
+ Service serviceAlreadyPresent = null;
+ for (Service typeService : type.getServices()){
+ if (typeService.getName().equals(service.getName())){
+ serviceAlreadyPresent = typeService;
+ break;
+ }
+ }
+
+ if (replace == true){
+ type.getServices().remove(serviceAlreadyPresent);
+ type.getServices().add(service);
+ } else {
+ if (serviceAlreadyPresent == null){
+ type.getServices().add(service);
+ }
+ }
+
+ return service;
+ }
+
+ private <T extends Annotation> T getParameterAnnotation(Method method, int index, Class<T> annotationType) {
+ Annotation[] annotations = method.getParameterAnnotations()[index];
+ for (Annotation annotation : annotations) {
+ if (annotation.annotationType() == annotationType) {
+ return annotationType.cast(annotation);
+ }
+ }
+ return null;
+ }
+
+ private void addSOAPIntent(PolicySubject policySubject){
+ Intent soapIntent = policyFactory.createIntent();
+ soapIntent.setName(Constants.SOAP_INTENT);
+ policySubject.getRequiredIntents().add(soapIntent);
+ }
+
+ private void createWSBinding(JavaImplementation javaImplementation, Service service){
+ if(service.getBindings().size() == 0){
+ WebServiceBinding wsBinding = wsBindingFactory.createWebServiceBinding();
+ wsBinding.setName(service.getName());
+ ExtensionType bindingType = policyFactory.createBindingType();
+ bindingType.setType(WebServiceConstants.BINDING_WS_QNAME);
+ bindingType.setUnresolved(true);
+ ((PolicySubject)wsBinding).setExtensionType(bindingType);
+ service.getBindings().add(wsBinding);
+ }
+ }
+
+}
diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/NoConstructorException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/NoConstructorException.java new file mode 100644 index 0000000000..453cfa35fe --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/NoConstructorException.java @@ -0,0 +1,37 @@ +/* + * 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.implementation.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Thrown when a suitable constructor for a component implementation cannot be found + * + * @version $Rev$ $Date$ + */ +public class NoConstructorException extends IntrospectionException { + private static final long serialVersionUID = 3086706387280694424L; + + public NoConstructorException() { + } + + public NoConstructorException(String message) { + super(message); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/PolicyProcessor.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/PolicyProcessor.java new file mode 100644 index 0000000000..15d31a5ad9 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/PolicyProcessor.java @@ -0,0 +1,303 @@ +/* + * 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.implementation.java.introspect.impl; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaElementImpl; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaParameterImpl; +import org.apache.tuscany.sca.implementation.java.introspect.BaseJavaClassVisitor; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceFactory; +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.ServiceRuntimeException; +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 PolicyProcessor extends BaseJavaClassVisitor { + + private PolicyFactory policyFactory; + + public PolicyProcessor(AssemblyFactory assemblyFactory, + PolicyFactory policyFactory, + JavaInterfaceFactory javaInterfaceFactory) { + super(assemblyFactory); + this.policyFactory = policyFactory; + this.javaInterfaceFactory = javaInterfaceFactory; + } + + public PolicyProcessor(ExtensionPointRegistry registry) { + super(registry); + FactoryExtensionPoint factories = registry.getExtensionPoint(FactoryExtensionPoint.class); + this.policyFactory = factories.getFactory(PolicyFactory.class); + } + + @Override + public <T> void visitClass(Class<T> clazz, JavaImplementation type) throws IntrospectionException { + + // Read intents on the Java implementation class + readPolicySetAndIntents((PolicySubject)type, clazz); + + /* + // FIXME: [rfeng] We might want to refactor this out + // Find the business methods in the implementation class for all services + Set<Method> methods = new HashSet<Method>(); + for (Service service : type.getServices()) { + for (Operation op : service.getInterfaceContract().getInterface().getOperations()) { + Method method; + try { + method = JavaInterfaceUtil.findMethod(clazz, op); + } catch (NoSuchMethodException e1) { + throw new IntrospectionException(e1); + } + if (method != null) { + methods.add(method); + } + } + } + for (Method method : methods) { + JavaOperation op = javaInterfaceFactory.createJavaOperation(method); + type.getOperations().add(op); + } + + // Read the operation-level policy settings for the implementation + for (Operation op : type.getOperations()) { + JavaOperation operation = (JavaOperation)op; + PolicySubject subject = op; + Method method = operation.getJavaMethod(); + if (subject != null) { + readPolicySetAndIntents(subject, method); + } + } + */ + + // Start to process annotations on the reference members + Map<String, Reference> referenceMap = new HashMap<String, Reference>(); + for (Reference ref : type.getReferences()) { + referenceMap.put(ref.getName(), ref); + } + Map<String, JavaElementImpl> members = type.getReferenceMembers(); + for (Map.Entry<String, JavaElementImpl> e : members.entrySet()) { + Reference reference = referenceMap.get(e.getKey()); + readPolicySetAndIntents(reference, e.getValue().getAnchor()); + } + + } + + private void readPolicySetAndIntents(PolicySubject subject, AnnotatedElement element) { + readIntents(element.getAnnotation(Requires.class), subject.getRequiredIntents()); + readSpecificIntents(element.getAnnotations(), subject.getRequiredIntents()); + readPolicySets(element.getAnnotation(PolicySets.class), subject.getPolicySets()); + } + + private void readPolicySetAndIntents(PolicySubject subject, JavaElementImpl element) { + readIntents(element.getAnnotation(Requires.class), subject.getRequiredIntents()); + readSpecificIntents(element.getAnnotations(), subject.getRequiredIntents()); + readPolicySets(element.getAnnotation(PolicySets.class), subject.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); + } + } + } + } + + /** + * Read intent annotations on the given interface or class + * @param intentAnnotation + * @param requiredIntents + */ + 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); + } + } + } + } + + /** + * Read policy set annotations on a given interface or class + * @param policySetAnnotation + * @param policySets + */ + 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); + } + } + } + } + + /** + * Utility methods + */ + + /** + * + * @param intentName + * @return + */ + private static 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; + } + + @Override + public void visitField(Field field, JavaImplementation type) throws IntrospectionException { + // Check if a field that is not an SCA reference has any policySet/intent annotations + JavaElementImpl element = new JavaElementImpl(field); + if (!type.getReferenceMembers().values().contains(element)) { + PolicySubject subject = assemblyFactory.createComponent(); + readPolicySetAndIntents(subject, field); + if (subject.getPolicySets().isEmpty() && subject.getRequiredIntents().isEmpty()) { + return; + } + throw new ServiceRuntimeException( + "[JCA70002,JCA70005] Field that is not an SCA reference cannot have policySet/intent annotations: " + field); + } + } + + @Override + public void visitConstructorParameter(JavaParameterImpl parameter, JavaImplementation type) { + if (!type.getReferenceMembers().values().contains(parameter)) { + PolicySubject subject = assemblyFactory.createComponent(); + readPolicySetAndIntents(subject, parameter); + if (subject.getPolicySets().isEmpty() && subject.getRequiredIntents().isEmpty()) { + return; + } + throw new ServiceRuntimeException( + "[JCA70002,JCA70005] Constructor parameter that is not an SCA reference cannot have policySet/intent annotations: " + parameter); + } + } + + @Override + public void visitMethod(Method method, JavaImplementation type) throws IntrospectionException { + Set<AnnotatedElement> annotatedElements = new HashSet<AnnotatedElement>(); + for (JavaElementImpl element : type.getReferenceMembers().values()) { + annotatedElements.add(element.getAnchor()); + } + // Check if a field that is not an SCA reference has any policySet/intent annotations + if (!annotatedElements.contains(method)) { + PolicySubject subject = assemblyFactory.createComponent(); + readPolicySetAndIntents(subject, method); + if (subject.getPolicySets().isEmpty() && subject.getRequiredIntents().isEmpty()) { + return; + } + throw new ServiceRuntimeException( + "[JCA70002,JCA70005] Method that is not an SCA reference cannot have policySet/intent annotations: " + method); + } + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/PropertyProcessor.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/PropertyProcessor.java new file mode 100644 index 0000000000..ed68be20b4 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/PropertyProcessor.java @@ -0,0 +1,50 @@ +/* + * 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.implementation.java.introspect.impl; + +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.oasisopen.sca.annotation.Property; + +/** + * Processes an {@link @Property} annotation, updating the component type with + * corresponding {@link JavaMappedProperty} + * + * @version $Rev$ $Date$ + */ +public class PropertyProcessor extends AbstractPropertyProcessor<Property> { + + public PropertyProcessor(ExtensionPointRegistry registry) { + super(registry, Property.class); + } + + @Override + protected String getName(Property annotation) { + return annotation.name(); + } + + @Override + protected void initProperty(org.apache.tuscany.sca.assembly.Property property, Property annotation) { + property.setMustSupply(annotation.required()); + } + + @Override + protected boolean getRequired(Property annotation) { + return annotation.required(); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ReferenceProcessor.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ReferenceProcessor.java new file mode 100644 index 0000000000..225099758d --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ReferenceProcessor.java @@ -0,0 +1,283 @@ +/* + * 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.implementation.java.introspect.impl; + +import static org.apache.tuscany.sca.implementation.java.introspect.JavaIntrospectionHelper.getBaseType; + +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.util.Collection; +import java.util.List; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Multiplicity; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaElementImpl; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaParameterImpl; +import org.apache.tuscany.sca.implementation.java.introspect.BaseJavaClassVisitor; +import org.apache.tuscany.sca.implementation.java.introspect.JavaIntrospectionHelper; +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.oasisopen.sca.ServiceReference; +import org.oasisopen.sca.annotation.AllowsPassByReference; +import org.oasisopen.sca.annotation.Reference; + +/** + * Processes an {@link @Reference} annotation, updating the component type with + * corresponding {@link + * org.apache.tuscany.spi.implementation.java.JavaMappedReference} + * + * @version $Rev$ $Date$ + */ +public class ReferenceProcessor extends BaseJavaClassVisitor { + + public ReferenceProcessor(AssemblyFactory assemblyFactory, JavaInterfaceFactory javaFactory) { + super(assemblyFactory); + this.javaInterfaceFactory = javaFactory; + } + + public ReferenceProcessor(ExtensionPointRegistry registry) { + super(registry); + } + + @Override + public void visitMethod(Method method, JavaImplementation type) throws IntrospectionException { + Reference annotation = method.getAnnotation(Reference.class); + if (annotation != null) { + + if (!JavaIntrospectionHelper.isSetter(method)) { + throw new IllegalReferenceException("Annotated method is not a setter: " + method, method); + } + + if(Modifier.isStatic(method.getModifiers())) { + throw new IllegalPropertyException("Static method " + method.getName() +" in class " + method.getDeclaringClass().getName() + " can not be annotated as a Reference"); + } + + String name = annotation.name(); + if ("".equals(name)) { + name = JavaIntrospectionHelper.toPropertyName(method.getName()); + } + JavaElementImpl ref = type.getReferenceMembers().get(name); + // Setter override field + if (ref != null && ref.getElementType() != ElementType.FIELD) { + throw new DuplicateReferenceException(name); + } + removeReference(ref, type); + + JavaElementImpl element = new JavaElementImpl(method, 0); + org.apache.tuscany.sca.assembly.Reference reference = createReference(type, element, name); + type.getReferences().add(reference); + type.getReferenceMembers().put(name, element); + } + + // enforce the constraint that an ordinary method's argument can not be a reference + Annotation paramsAnnotations[][] = method.getParameterAnnotations(); + for (int i = 0; i < paramsAnnotations.length; i++) { + Annotation argAnnotations[] = paramsAnnotations[i]; + for (int j = 0; j < argAnnotations.length; j++) { + if(argAnnotations[j].annotationType() == Reference.class) { + throw new IllegalReferenceException("Argument " + (i+1) + " of method " + method.getName() + " in class " + method.getDeclaringClass() + " can not be a Reference"); + } + } + } + } + + + @Override + public void visitField(Field field, JavaImplementation type) throws IntrospectionException { + Reference annotation = field.getAnnotation(Reference.class); + if (annotation == null) { + return; + } + + if(Modifier.isStatic(field.getModifiers())) { + throw new IllegalReferenceException("Static field " + field.getName() +" in class " + field.getDeclaringClass().getName() + " can not be annotated as Reference"); + } + String name = annotation.name(); + if ("".equals(name)) { + name = field.getName(); + } + JavaElementImpl ref = type.getReferenceMembers().get(name); + if (ref != null && ref.getElementType() == ElementType.FIELD) { + throw new DuplicateReferenceException(name); + } + + // Setter method override field + if (ref == null) { + JavaElementImpl element = new JavaElementImpl(field); + org.apache.tuscany.sca.assembly.Reference reference = createReference(type, element, name); + type.getReferences().add(reference); + type.getReferenceMembers().put(name, element); + } + } + + @Override + public void visitConstructorParameter(JavaParameterImpl parameter, JavaImplementation type) + throws IntrospectionException { + Reference refAnnotation = parameter.getAnnotation(Reference.class); + if (refAnnotation == null) { + return; + } + + if (!refAnnotation.required()) { + throw new InvalidReferenceException("[JCA90016] Constructor has @Reference with required=false: " + type.getName()); + } + + if (refAnnotation.name() == null || refAnnotation.name().length() < 1) { + throw new InvalidReferenceException("[JCA90018] @Reference in a Constructor must have a name attribute" + type.getName()); + } + + String paramName = parameter.getName(); + String name = getReferenceName(paramName, parameter.getIndex(), refAnnotation.name()); + JavaElementImpl ref = type.getReferenceMembers().get(name); + + // Setter override field + if (ref != null && ref.getElementType() != ElementType.FIELD) { + throw new DuplicateReferenceException(name); + } + + removeReference(ref, type); + org.apache.tuscany.sca.assembly.Reference reference = createReference(type, parameter, name); + type.getReferences().add(reference); + type.getReferenceMembers().put(name, parameter); + parameter.setClassifer(Reference.class); + parameter.setName(name); + } + + /** + * Create a SCA reference for a java Element + * @param implementation TODO + * @param element + * @param name + * @return + * @throws IntrospectionException + */ + private org.apache.tuscany.sca.assembly.Reference createReference(JavaImplementation implementation, JavaElementImpl element, String name) + throws IntrospectionException { + org.apache.tuscany.sca.assembly.Reference reference = assemblyFactory.createReference(); + JavaInterfaceContract interfaceContract = javaInterfaceFactory.createJavaInterfaceContract(); + reference.setInterfaceContract(interfaceContract); + + AllowsPassByReference pbr = element.getAnnotation(AllowsPassByReference.class); + if (pbr != null) { + reference.setAllowsPassByReference(true); + } else { + reference.setAllowsPassByReference(implementation.isAllowsPassByReference()); + } + + // reference.setMember((Member)element.getAnchor()); + boolean required = true; + Reference ref = element.getAnnotation(Reference.class); + if (ref != null) { + required = ref.required(); + } + // reference.setRequired(required); + reference.setName(name); + Class<?> rawType = element.getType(); + if (rawType.isArray() || Collection.class.isAssignableFrom(rawType)) { + if (required) { + reference.setMultiplicity(Multiplicity.ONE_N); + } else { + reference.setMultiplicity(Multiplicity.ZERO_N); + } + } else { + if (required) { + reference.setMultiplicity(Multiplicity.ONE_ONE); + } else { + reference.setMultiplicity(Multiplicity.ZERO_ONE); + } + } + Type genericType = element.getGenericType(); + Class<?> baseType = getBaseType(rawType, genericType); + if (ServiceReference.class.isAssignableFrom(baseType)) { + if (Collection.class.isAssignableFrom(rawType)) { + genericType = JavaIntrospectionHelper.getParameterType(genericType); + } + baseType = JavaIntrospectionHelper.getBusinessInterface(baseType, genericType); + } + try { + JavaInterface callInterface = javaInterfaceFactory.createJavaInterface(baseType); + reference.getInterfaceContract().setInterface(callInterface); + if (callInterface.getCallbackClass() != null) { + JavaInterface callbackInterface = javaInterfaceFactory.createJavaInterface(callInterface.getCallbackClass()); + reference.getInterfaceContract().setCallbackInterface(callbackInterface); + } + } catch (InvalidInterfaceException e) { + throw new IntrospectionException(e); + } + return reference; + } + + + /** + * Utility methods + */ + + /** + * + * @param paramName + * @param pos + * @param name + * @return + * @throws InvalidConstructorException + */ + private static String getReferenceName(String paramName, int pos, String name) throws InvalidConstructorException { + if ("".equals(name)) { + name = paramName; + } + if ("".equals(name)) { + return "_ref" + pos; + } + if (!"".equals(paramName) && !name.equals(paramName)) { + throw new InvalidConstructorException("Mismatching names specified for reference parameter " + pos); + } else { + return name; + } + } + + /** + * + * @param ref + * @param type + * @return + */ + private static boolean removeReference(JavaElementImpl ref, JavaImplementation type) { + if (ref == null) { + return false; + } + List<org.apache.tuscany.sca.assembly.Reference> refs = type.getReferences(); + for (int i = 0; i < refs.size(); i++) { + if (refs.get(i).getName().equals(ref.getName())) { + refs.remove(i); + return true; + } + } + return false; + } + + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/Resource.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/Resource.java new file mode 100644 index 0000000000..3d43e39ce8 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/Resource.java @@ -0,0 +1,49 @@ +/* + * 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.implementation.java.introspect.impl; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation used to indicate a resource should be provided to an implementation by the runtime. + * + * @version $Rev$ $Date$ + */ +@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Resource { + + /** + * Denotes the name of the resource declared by the implementation. + */ + String name() default ""; + + /** + * Denotes if the resource is optional + */ + boolean optional() default false; + + /** + * Denotes the default name of the resource provided by the runtime environment. + */ + String mappedName() default ""; +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ResourceProcessor.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ResourceProcessor.java new file mode 100644 index 0000000000..3abe832cb9 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ResourceProcessor.java @@ -0,0 +1,153 @@ +/* + * 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.implementation.java.introspect.impl; + +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaElementImpl; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaParameterImpl; +import org.apache.tuscany.sca.implementation.java.JavaResourceImpl; +import org.apache.tuscany.sca.implementation.java.introspect.BaseJavaClassVisitor; +import org.apache.tuscany.sca.implementation.java.introspect.JavaIntrospectionHelper; + +/** + * Processes an {@link @Resource} annotation, updating the component type with + * corresponding {@link org.apache.tuscany.spi.implementation.java.JavaResourceImpl} + * + * @version $Rev$ $Date$ + */ +public class ResourceProcessor extends BaseJavaClassVisitor { + + public ResourceProcessor(AssemblyFactory factory) { + super(factory); + } + + public ResourceProcessor(ExtensionPointRegistry registry) { + super(registry); + } + + @Override + public void visitMethod(Method method, JavaImplementation type) throws IntrospectionException { + org.apache.tuscany.sca.implementation.java.introspect.impl.Resource annotation = method + .getAnnotation(org.apache.tuscany.sca.implementation.java.introspect.impl.Resource.class); + if (annotation == null) { + return; + } + if (method.getParameterTypes().length != 1) { + throw new IllegalResourceException("Resource setter must have one parameter", method); + } + String name = annotation.name(); + if (name.length() < 1) { + name = JavaIntrospectionHelper.toPropertyName(method.getName()); + } + if (type.getResources().get(name) != null) { + throw new DuplicateResourceException(name); + } + + String mappedName = annotation.mappedName(); + JavaResourceImpl resource = createResource(name, new JavaElementImpl(method, 0)); + resource.setOptional(annotation.optional()); + if (mappedName.length() > 0) { + resource.setMappedName(mappedName); + } + type.getResources().put(resource.getName(), resource); + } + + @Override + public void visitField(Field field, JavaImplementation type) throws IntrospectionException { + + org.apache.tuscany.sca.implementation.java.introspect.impl.Resource annotation = field + .getAnnotation(org.apache.tuscany.sca.implementation.java.introspect.impl.Resource.class); + if (annotation == null) { + return; + } + String name = annotation.name(); + if (name.length() < 1) { + name = field.getName(); + } + if (type.getResources().get(name) != null) { + throw new DuplicateResourceException(name); + } + + String mappedName = annotation.mappedName(); + + JavaResourceImpl resource = createResource(name, new JavaElementImpl(field)); + resource.setOptional(annotation.optional()); + if (mappedName.length() > 0) { + resource.setMappedName(mappedName); + } + type.getResources().put(resource.getName(), resource); + } + + @Override + public void visitConstructorParameter(JavaParameterImpl parameter, JavaImplementation type) + throws IntrospectionException { + org.apache.tuscany.sca.implementation.java.introspect.impl.Resource resourceAnnotation = parameter + .getAnnotation(org.apache.tuscany.sca.implementation.java.introspect.impl.Resource.class); + if (resourceAnnotation != null) { + String name = resourceAnnotation.name(); + if ("".equals(name)) { + name = parameter.getName(); + } + if ("".equals(name)) { + throw new InvalidResourceException("Missing resource name", (Member)parameter.getAnchor()); + } + + if (!"".equals(parameter.getName()) && !name.equals(parameter.getName())) { + throw new InvalidConstructorException("Mismatched resource name: " + parameter); + } + + if (type.getResources().get(name) != null) { + throw new DuplicateResourceException(name); + } + + String mappedName = resourceAnnotation.mappedName(); + + JavaResourceImpl resource = createResource(name, parameter); + resource.setOptional(resourceAnnotation.optional()); + if (mappedName.length() > 0) { + resource.setMappedName(mappedName); + } + type.getResources().put(resource.getName(), resource); + } + } + + + /** + * Utility methods + */ + + /** + * + * @param name + * @param element + * @return + */ + private static JavaResourceImpl createResource(String name, JavaElementImpl element) { + element.setClassifer(org.apache.tuscany.sca.implementation.java.introspect.impl.Resource.class); + element.setName(name); + return new JavaResourceImpl(element); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ScopeProcessor.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ScopeProcessor.java new file mode 100644 index 0000000000..dfc122c715 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ScopeProcessor.java @@ -0,0 +1,68 @@ +/* + * 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.implementation.java.introspect.impl; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaScopeImpl; +import org.apache.tuscany.sca.implementation.java.introspect.BaseJavaClassVisitor; + +/** + * Processes the {@link JavaScopeImpl} annotation and updates the component type with the corresponding implmentation scope + * + * @version $Rev$ $Date$ + */ +public class ScopeProcessor extends BaseJavaClassVisitor { + + public ScopeProcessor(AssemblyFactory factory) { + super(factory); + } + + public ScopeProcessor(ExtensionPointRegistry registry) { + super(registry); + } + + @Override + public <T> void visitClass(Class<T> clazz, + JavaImplementation type) + throws IntrospectionException { + org.oasisopen.sca.annotation.Scope annotation = clazz.getAnnotation(org.oasisopen.sca.annotation.Scope.class); + if (annotation == null) { + type.setJavaScope(JavaScopeImpl.STATELESS); + return; + } + + String name = annotation.value(); + JavaScopeImpl scope; + if ("COMPOSITE".equals(name)) { + scope = JavaScopeImpl.COMPOSITE; + } else if ("STATELESS".equals(name)) { + scope = JavaScopeImpl.STATELESS; + } else { + scope = JavaScopeImpl.INVALID; + } + type.setJavaScope(scope); + + if (type.getJavaScope().equals(JavaScopeImpl.INVALID)) { + throw new IntrospectionException("Invalid scope :" + name + " for " + type.getName()); + } + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ServiceProcessor.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ServiceProcessor.java new file mode 100644 index 0000000000..6ad2140304 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ServiceProcessor.java @@ -0,0 +1,268 @@ +/* + * 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.implementation.java.introspect.impl; + +import static org.apache.tuscany.sca.implementation.java.introspect.JavaIntrospectionHelper.getAllInterfaces; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import javax.jws.WebService; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.Service; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaElementImpl; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaScopeImpl; +import org.apache.tuscany.sca.implementation.java.introspect.BaseJavaClassVisitor; +import org.apache.tuscany.sca.implementation.java.introspect.JavaIntrospectionHelper; +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.oasisopen.sca.ServiceReference; +import org.oasisopen.sca.annotation.Callback; +import org.oasisopen.sca.annotation.Remotable; + +/** + * Processes an {@link org.oasisopen.sca.annotation.Service} annotation and updates + * the component type with corresponding {@link Service}s. Also processes + * related {@link org.oasisopen.sca.annotation.Callback} annotations. + * + * This Visitor MUST follow the ScopeProcessor in the sequence of visitors, since processing of + * the Callback annotations depends on knowing the Scope of the implementation + * + * @version $Rev$ $Date$ + */ +public class ServiceProcessor extends BaseJavaClassVisitor { + + public ServiceProcessor(AssemblyFactory assemblyFactory, JavaInterfaceFactory javaFactory) { + super(assemblyFactory); + this.javaInterfaceFactory = javaFactory; + } + + public ServiceProcessor(ExtensionPointRegistry registry) { + super(registry); + } + + @Override + public <T> void visitClass(Class<T> clazz, JavaImplementation type) throws IntrospectionException { + org.oasisopen.sca.annotation.Service annotation = clazz.getAnnotation(org.oasisopen.sca.annotation.Service.class); + if (annotation == null) { + // scan interfaces for remotable + Set<Class<?>> interfaces = getAllInterfaces(clazz); + for (Class<?> interfaze : interfaces) { + if (interfaze.isAnnotationPresent(Remotable.class) + || interfaze.isAnnotationPresent(WebService.class) + || interfaze.isAnnotationPresent(Callback.class) + ) { + Service service; + try { + service = createService(clazz, interfaze, null); + } catch (InvalidInterfaceException e) { + throw new IntrospectionException(e); + } + type.getServices().add(service); + } + } + return; + } + + if (annotation.value().length == 0) { + throw new IntrospectionException("[JCA90059] The array of interfaces or classes specified by the value attribute of the @Service annotation MUST contain at least one element"); + } + Class<?>[] interfaces = annotation.value(); + if (annotation.names().length > 0) { + if (annotation.names().length != interfaces.length) { + throw new IntrospectionException("[JCA90050] The number of Strings in the names attribute array of the @Service annotation MUST match the number of elements in the value attribute array"); + } + Set<String> names = new HashSet<String>(); + names.addAll(Arrays.asList(annotation.names())); + if (names.size() != annotation.names().length) { + throw new IntrospectionException("[JCA90060] The value of each element in the @Service names array MUST be unique amongst all the other element values in the array"); + } + } + + //validate no scope on servce interface + for (Class<?> iface : interfaces) { + if (iface.getAnnotation(org.oasisopen.sca.annotation.Scope.class) != null) { + throw new IntrospectionException("[JCA90041] @Scope annotation not allowed on service interface " + iface + .getName()); + } + } + + //validate service methods implemented + Method[] ms = clazz.getMethods(); + for (Class<?> iface : interfaces) { + for (Method m : iface.getMethods()) { + if (!hasMethod(m, ms)) { + throw new IntrospectionException("[JCA90042,JCI20002] Implementation missing service method " + m.getName() + " service interface " + iface.getName()); + } + } + } + + for (int i=0; i < interfaces.length; i++) { + try { + String name = (annotation.names().length > 0) ? annotation.names()[i] : null; + Service service = createService(clazz, interfaces[i], name); + type.getServices().add(service); + } catch (InvalidInterfaceException e) { + throw new IntrospectionException(e); + } + } + + } + + protected boolean hasMethod(Method m1, Method[] ms) { + for (Method m2 : ms) { + if (JavaIntrospectionHelper.exactMethodMatch(m1, m2)) { + return true; + } + } + return false; + } + + @Override + public void visitMethod(Method method, JavaImplementation type) throws IntrospectionException { + + Callback annotation = method.getAnnotation(Callback.class); + if (annotation == null) { + return; + } + if( type.getJavaScope() == JavaScopeImpl.COMPOSITE ) { + throw new IllegalCallbackReferenceException("[JCA90057] @Callback on field or method cannot be used for a class with @Scope(COMPOSITE): " + type.getName() + "." + method.getName()); + } + + if (!(annotation.value() == null || annotation.value() == Void.class)) { + throw new IllegalCallbackReferenceException("[JCA90046] @Callback on field of method must not have any parameters: " + type.getName() + "." + method.getName()); + } + + if(Modifier.isPrivate(method.getModifiers())) { + throw new IllegalCallbackReferenceException("Illegal annotation @Callback found on "+method, method); + } + if (method.getParameterTypes().length != 1) { + throw new IllegalCallbackReferenceException("Setter must have one parameter", method); + } + JavaElementImpl element = new JavaElementImpl(method, 0); + createCallback(type, element); + } + + @Override + public void visitField(Field field, JavaImplementation type) throws IntrospectionException { + + Callback annotation = field.getAnnotation(Callback.class); + if (annotation == null) { + return; + } + if( type.getJavaScope() == JavaScopeImpl.COMPOSITE ) { + throw new IllegalCallbackReferenceException("[JCA90057] @Callback on field or method cannot be used for a class with @Scope(COMPOSITE): " + type.getName() + "." + field.getName()); + } + if (!(annotation.value() == null || annotation.value() == Void.class)) { + throw new IllegalCallbackReferenceException("[JCA90046] @Callback on field of method must not have any parameters: " + type.getName() + "." + field.getName()); + } + if(Modifier.isPrivate(field.getModifiers())) { + throw new IllegalCallbackReferenceException("Illegal annotation @Callback found on "+field, field); + } + JavaElementImpl element = new JavaElementImpl(field); + createCallback(type, element); + } + + public Service createService(Class<?> clazz, Class<?> interfaze, String name) throws InvalidInterfaceException { + Service service = assemblyFactory.createService(); + JavaInterfaceContract interfaceContract = javaInterfaceFactory.createJavaInterfaceContract(); + service.setInterfaceContract(interfaceContract); + + JavaInterface callInterface = javaInterfaceFactory.createJavaInterface(interfaze); + + if (name == null) { + String serviceName = interfaze.getSimpleName(); + // If the interface has @WebService annotation then take the + // service name from the @name attribute if present + if (interfaze.isAnnotationPresent(WebService.class)){ + if (callInterface.getQName() != null){ + serviceName = callInterface.getQName().getLocalPart(); + } + } + + service.setName(serviceName); + } else { + service.setName(name); + } + + + boolean remotable = clazz.getAnnotation(Remotable.class) != null; + if (remotable){ + callInterface.setRemotable(true); + } + service.getInterfaceContract().setInterface(callInterface); + + if (callInterface.getCallbackClass() != null) { + JavaInterface callbackInterface = javaInterfaceFactory.createJavaInterface(callInterface.getCallbackClass()); + if (remotable){ + callbackInterface.setRemotable(true); + } + service.getInterfaceContract().setCallbackInterface(callbackInterface); + } + return service; + } + + /** + * Utility methods + */ + + + /** + * @param type + * @param element + * @throws IllegalCallbackReferenceException + */ + private static void createCallback(JavaImplementation type, JavaElementImpl element) + throws IllegalCallbackReferenceException { + Service callbackService = null; + Class<?> callbackClass = element.getType(); + Type genericType = element.getGenericType(); + Class<?> baseType = callbackClass; + if(ServiceReference.class.isAssignableFrom(baseType)) { + // @Callback protected CallableReference<MyCallback> callback; + // The base type will be MyCallback + baseType = JavaIntrospectionHelper.getBusinessInterface(baseType, genericType); + } + for (Service service : type.getServices()) { + JavaInterface javaInterface = (JavaInterface)service.getInterfaceContract().getCallbackInterface(); + if (javaInterface != null && baseType == javaInterface.getJavaClass()) { + callbackService = service; + } + } + if (callbackService == null) { + throw new IllegalCallbackReferenceException("Callback type does not match a service callback interface: " + type.getName() ); + } + if(type.getCallbackMembers().get(baseType.getName()) == null) { + type.getCallbackMembers().put(baseType.getName(), new ArrayList<JavaElementImpl>()); + } + type.getCallbackMembers().get(baseType.getName()).add(element); + } +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ServiceTypeNotFoundException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ServiceTypeNotFoundException.java new file mode 100644 index 0000000000..e1ca3ea565 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/ServiceTypeNotFoundException.java @@ -0,0 +1,35 @@ +/* + * 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.implementation.java.introspect.impl; + +import org.apache.tuscany.sca.implementation.java.IntrospectionException; + +/** + * Thrown when a service interface cannot be determined based on a heuristic evaluation of an implementation + * + * @version $Rev$ $Date$ + */ +public class ServiceTypeNotFoundException extends IntrospectionException { + private static final long serialVersionUID = -5124437274726947007L; + + public ServiceTypeNotFoundException(String message) { + super(message); + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/UnknownContextTypeException.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/UnknownContextTypeException.java new file mode 100644 index 0000000000..bfaa759cd2 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/introspect/impl/UnknownContextTypeException.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.implementation.java.introspect.impl; + +/** + * Thrown when a method or field marked with {@link org.oasisopen.sca.annotation.Context} takes an unknown type + * + * @version $Rev$ $Date$ + */ +public class UnknownContextTypeException extends IllegalContextException { + private static final long serialVersionUID = 8125863714365422419L; + + public UnknownContextTypeException(String message) { + super(message); + } + +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/package.html b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/package.html new file mode 100644 index 0000000000..53614a627b --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/package.html @@ -0,0 +1,29 @@ +<!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> +Base Package for the implementation.java extension. + +Whilst this package and its subpackages are not currently deemed to represent extension developers SPI, this extension has a special relationship with implementation.spring. Implementation.spring can be viewed as an extension of implementation.java. + +</body> +</html> diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/xml/JavaImplementationConstants.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/xml/JavaImplementationConstants.java new file mode 100644 index 0000000000..c23f5e4d39 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/xml/JavaImplementationConstants.java @@ -0,0 +1,35 @@ +/* + * 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.implementation.java.xml; + +import javax.xml.namespace.QName; + +/** + * Constants for the Java Implementation. + * + * @version $Rev$ $Date$ + */ +public interface JavaImplementationConstants { + String SCA11_NS = "http://docs.oasis-open.org/ns/opencsa/sca/200912"; + String IMPLEMENTATION_JAVA = "implementation.java"; + QName IMPLEMENTATION_JAVA_QNAME = new QName(SCA11_NS, "implementation.java"); + String CLASS = "class"; + String OPERATION = "operation"; + QName OPERATION_QNAME = new QName(SCA11_NS, OPERATION); +} diff --git a/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/xml/JavaImplementationProcessor.java b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/xml/JavaImplementationProcessor.java new file mode 100644 index 0000000000..ebf905ec44 --- /dev/null +++ b/sca-java-2.x/branches/2.0-Beta3/modules/implementation-java/src/main/java/org/apache/tuscany/sca/implementation/java/xml/JavaImplementationProcessor.java @@ -0,0 +1,395 @@ +/* + * 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.implementation.java.xml; + +import static javax.xml.stream.XMLStreamConstants.END_ELEMENT; +import static org.apache.tuscany.sca.implementation.java.xml.JavaImplementationConstants.CLASS; +import static org.apache.tuscany.sca.implementation.java.xml.JavaImplementationConstants.IMPLEMENTATION_JAVA; +import static org.apache.tuscany.sca.implementation.java.xml.JavaImplementationConstants.IMPLEMENTATION_JAVA_QNAME; +import static org.apache.tuscany.sca.implementation.java.xml.JavaImplementationConstants.SCA11_NS; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Map; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; + +import org.apache.tuscany.sca.assembly.AssemblyFactory; +import org.apache.tuscany.sca.assembly.ComponentType; +import org.apache.tuscany.sca.assembly.Property; +import org.apache.tuscany.sca.assembly.Reference; +import org.apache.tuscany.sca.assembly.Service; +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.implementation.java.IntrospectionException; +import org.apache.tuscany.sca.implementation.java.JavaElementImpl; +import org.apache.tuscany.sca.implementation.java.JavaImplementation; +import org.apache.tuscany.sca.implementation.java.JavaImplementationFactory; +import org.apache.tuscany.sca.implementation.java.introspect.JavaIntrospectionHelper; +import org.apache.tuscany.sca.interfacedef.Compatibility; +import org.apache.tuscany.sca.interfacedef.IncompatibleInterfaceContractException; +import org.apache.tuscany.sca.interfacedef.Interface; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract; +import org.apache.tuscany.sca.interfacedef.wsdl.WSDLDefinition; +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.ExtensionType; +import org.apache.tuscany.sca.policy.PolicyFactory; + +/** + * + * @version $Rev$ $Date$ + */ +public class JavaImplementationProcessor implements StAXArtifactProcessor<JavaImplementation> { + + private JavaImplementationFactory javaFactory; + private AssemblyFactory assemblyFactory; + private PolicyFactory policyFactory; + private PolicySubjectProcessor policyProcessor; + private StAXArtifactProcessor<Object> extensionProcessor; + private transient InterfaceContractMapper interfaceContractMapper; + + public JavaImplementationProcessor(ExtensionPointRegistry registry, StAXArtifactProcessor<?> staxProcessor) { + FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class); + this.assemblyFactory = modelFactories.getFactory(AssemblyFactory.class); + this.policyFactory = modelFactories.getFactory(PolicyFactory.class); + this.javaFactory = modelFactories.getFactory(JavaImplementationFactory.class); + this.policyProcessor = new PolicySubjectProcessor(policyFactory); + this.extensionProcessor = (StAXArtifactProcessor<Object>)staxProcessor; + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + this.interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class); + } + + /** + * 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(), + "impl-javaxml-validation-messages", + Severity.ERROR, + model, + message, + (Object[])messageParameters); + monitor.problem(problem); + } + } + + /** + * 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(), + "impl-javaxml-validation-messages", + Severity.ERROR, + model, + message, + ex); + monitor.problem(problem); + } + } + + public JavaImplementation read(XMLStreamReader reader, ProcessorContext context) throws ContributionReadException, XMLStreamException { + + // Read an <implementation.java> + JavaImplementation javaImplementation = javaFactory.createJavaImplementation(); + + ExtensionType implType = policyFactory.createImplementationType(); + implType.setType(getArtifactType()); + implType.setUnresolved(true); + javaImplementation.setExtensionType(implType); + + javaImplementation.setUnresolved(true); + javaImplementation.setName(reader.getAttributeValue(null, CLASS)); + + // Read policies + policyProcessor.readPolicies(javaImplementation, reader); + + // read operation elements if exists or skip unto end element + int event; + while (reader.hasNext()) { + event = reader.next(); + if (event == END_ELEMENT && IMPLEMENTATION_JAVA_QNAME.equals(reader.getName())) { + break; + } + } + return javaImplementation; + } + + public void write(JavaImplementation javaImplementation, XMLStreamWriter writer, ProcessorContext context) throws ContributionWriteException, + XMLStreamException { + + // Write an <implementation.java> + writer.writeStartElement(SCA11_NS, IMPLEMENTATION_JAVA); + policyProcessor.writePolicyAttributes(javaImplementation, writer); + + if (javaImplementation.getName() != null) { + writer.writeAttribute(CLASS, javaImplementation.getName()); + } + + writer.writeEndElement(); + } + + public void resolve(JavaImplementation javaImplementation, ModelResolver resolver, ProcessorContext context) + throws ContributionResolveException { + Monitor monitor = context.getMonitor(); + try { + ClassReference classReference = new ClassReference(javaImplementation.getName()); + classReference = resolver.resolveModel(ClassReference.class, classReference, context); + Class<?> javaClass = classReference.getJavaClass(); + if (javaClass == null) { + error(monitor, "ClassNotFoundException", resolver, javaImplementation.getName()); + //throw new ContributionResolveException(new ClassNotFoundException(javaImplementation.getName())); + return; + } + + javaImplementation.setJavaClass(javaClass); + + try { + javaFactory.createJavaImplementation(javaImplementation, javaImplementation.getJavaClass()); + } catch (IntrospectionException e) { + ContributionResolveException ce = new ContributionResolveException(e); + error(monitor, "ContributionResolveException", javaFactory, ce); + //throw ce; + return; + } + + checkNoStaticAnnotations(monitor, javaImplementation); + + postJAXWSProcessorResolve(resolver, javaImplementation, context); + + javaImplementation.setUnresolved(false); + + mergeComponentType(resolver, javaImplementation, context); + + // FIXME the introspector should always create at least one service + if (javaImplementation.getServices().isEmpty()) { + javaImplementation.getServices().add(assemblyFactory.createService()); + } + } catch (Throwable e) { + throw new ContributionResolveException("Resolving Java implementation: " + javaImplementation.getName() + + ", " + + e.getMessage(), e); + } // end try + } // end method + + private void checkNoStaticAnnotations(Monitor monitor, JavaImplementation javaImplementation) { + if (javaImplementation.getJavaClass() != null) { + Class<?> clazz = javaImplementation.getJavaClass(); + for (Method m : clazz.getMethods()) { + if (Modifier.isStatic(m.getModifiers())) { + for (Annotation a : m.getAnnotations()) { + if (a.annotationType().getName().startsWith("org.oasisopen.sca.annotation")) { + error(monitor, "IllegalSCAAnnotation", javaFactory, javaImplementation.getName(), m.getName()); + } + } + } + } + for (Field f : clazz.getFields()) { + if (Modifier.isStatic(f.getModifiers())) { + for (Annotation a : f.getAnnotations()) { + if (a.annotationType().getName().startsWith("org.oasisopen.sca.annotation")) { + error(monitor, "IllegalSCAAnnotation", javaFactory, javaImplementation.getName(), f.getName()); + } + } + } + } + } + } + + private JavaElementImpl getMemeber(JavaImplementation impl, String name, Class<?> type) { + String setter = JavaIntrospectionHelper.toSetter(name); + try { + Method method = impl.getJavaClass().getDeclaredMethod(setter, type); + int mod = method.getModifiers(); + if ((Modifier.isPublic(mod) || Modifier.isProtected(mod)) && (!Modifier.isStatic(mod))) { + return new JavaElementImpl(method, 0); + } + } catch (NoSuchMethodException e) { + Field field; + try { + field = impl.getJavaClass().getDeclaredField(name); + int mod = field.getModifiers(); + if ((Modifier.isPublic(mod) || Modifier.isProtected(mod)) && (!Modifier.isStatic(mod))) { + return new JavaElementImpl(field); + } + } catch (NoSuchFieldException e1) { + // Ignore + } + } + return null; + } + + /** + * Merge the componentType from introspection and external file + * @param resolver + * @param impl + */ + private void mergeComponentType(ModelResolver resolver, JavaImplementation impl, ProcessorContext context) { + // FIXME: Need to clarify how to merge + ComponentType componentType = getComponentType(resolver, impl, context); + if (componentType != null && !componentType.isUnresolved()) { + Map<String, Reference> refMap = new HashMap<String, Reference>(); + for (Reference ref : impl.getReferences()) { + refMap.put(ref.getName(), ref); + } + for (Reference reference : componentType.getReferences()) { + refMap.put(reference.getName(), reference); + } + impl.getReferences().clear(); + impl.getReferences().addAll(refMap.values()); + + // Try to match references by type + Map<String, JavaElementImpl> refMembers = impl.getReferenceMembers(); + for (Reference ref : impl.getReferences()) { + if (ref.getInterfaceContract() != null) { + Interface i = ref.getInterfaceContract().getInterface(); + if (i instanceof JavaInterface) { + Class<?> type = ((JavaInterface)i).getJavaClass(); + if (!refMembers.containsKey(ref.getName())) { + JavaElementImpl e = getMemeber(impl, ref.getName(), type); + if (e != null) { + refMembers.put(ref.getName(), e); + } + } + } + } + } + + Map<String, Service> serviceMap = new HashMap<String, Service>(); + for (Service svc : impl.getServices()) { + serviceMap.put(svc.getName(), svc); + } + for (Service service : componentType.getServices()) { + serviceMap.put(service.getName(), service); + } + impl.getServices().clear(); + impl.getServices().addAll(serviceMap.values()); + + Map<String, Property> propMap = new HashMap<String, Property>(); + for (Property prop : impl.getProperties()) { + propMap.put(prop.getName(), prop); + } + for (Property property : componentType.getProperties()) { + propMap.put(property.getName(), property); + } + impl.getProperties().clear(); + impl.getProperties().addAll(propMap.values()); + + } + } + + private void postJAXWSProcessorResolve(ModelResolver resolver, JavaImplementation impl, ProcessorContext context) + throws ContributionResolveException, IncompatibleInterfaceContractException { + for(Service service : impl.getServices()){ + JavaInterfaceContract javaInterfaceContract = (JavaInterfaceContract)service.getInterfaceContract(); + + JavaInterface javaInterface = (JavaInterface)javaInterfaceContract.getInterface(); + if (javaInterface.isUnresolved()){ + extensionProcessor.resolve(javaInterfaceContract, resolver, context); + } + + WSDLInterfaceContract wsdlInterfaceContract = (WSDLInterfaceContract)javaInterfaceContract.getNormalizedWSDLContract(); + if(wsdlInterfaceContract != null){ + // The user has explicitly associated a WSDL with the Java implementation + // using a @WebService(wsdlLocation="...") annotation + WSDLInterface wsdlInterface = (WSDLInterface)wsdlInterfaceContract.getInterface(); + if (wsdlInterface.isUnresolved()){ + //WSDLDefinition resolved = resolver.resolveModel(WSDLDefinition.class, wsdlInterface.getWsdlDefinition(), context); + extensionProcessor.resolve(wsdlInterfaceContract, resolver, context); + + // check that the Java and WSDL contracts are compatible + interfaceContractMapper.checkCompatibility(wsdlInterfaceContract, + javaInterfaceContract, + Compatibility.SUBSET, + false, + false); + + // retrieve the resolved WSDL interface + wsdlInterface = (WSDLInterface)wsdlInterfaceContract.getInterface(); + + // copy policy from the WSDL interface to the Java interface + javaInterface.getPolicySets().addAll(wsdlInterface.getPolicySets()); + javaInterface.getRequiredIntents().addAll(wsdlInterface.getRequiredIntents()); + + // copy policy from the WSDL interface to the component type service + service.getPolicySets().addAll(wsdlInterface.getPolicySets()); + service.getRequiredIntents().addAll(wsdlInterface.getRequiredIntents()); + + // TODO - is there anything else to be copied from the user specified WSDL? + } + } + } + } + + private ComponentType getComponentType(ModelResolver resolver, JavaImplementation impl, ProcessorContext context) { + String className = impl.getJavaClass().getName(); + String componentTypeURI = className.replace('.', '/') + ".componentType"; + ComponentType componentType = assemblyFactory.createComponentType(); + componentType.setUnresolved(true); + componentType.setURI(componentTypeURI); + componentType = resolver.resolveModel(ComponentType.class, componentType, context); + if (!componentType.isUnresolved()) { + return componentType; + } + return null; + } + + public QName getArtifactType() { + return IMPLEMENTATION_JAVA_QNAME; + } + + public Class<JavaImplementation> getModelType() { + return JavaImplementation.class; + } + +} |