summaryrefslogtreecommitdiffstats
path: root/sca-java-1.x/tags/java-stable-20060304/sca/core/src/main/java/org/apache/tuscany/core/config/impl/Java5ComponentTypeIntrospector.java
diff options
context:
space:
mode:
Diffstat (limited to 'sca-java-1.x/tags/java-stable-20060304/sca/core/src/main/java/org/apache/tuscany/core/config/impl/Java5ComponentTypeIntrospector.java')
-rw-r--r--sca-java-1.x/tags/java-stable-20060304/sca/core/src/main/java/org/apache/tuscany/core/config/impl/Java5ComponentTypeIntrospector.java423
1 files changed, 423 insertions, 0 deletions
diff --git a/sca-java-1.x/tags/java-stable-20060304/sca/core/src/main/java/org/apache/tuscany/core/config/impl/Java5ComponentTypeIntrospector.java b/sca-java-1.x/tags/java-stable-20060304/sca/core/src/main/java/org/apache/tuscany/core/config/impl/Java5ComponentTypeIntrospector.java
new file mode 100644
index 0000000000..8799969028
--- /dev/null
+++ b/sca-java-1.x/tags/java-stable-20060304/sca/core/src/main/java/org/apache/tuscany/core/config/impl/Java5ComponentTypeIntrospector.java
@@ -0,0 +1,423 @@
+/**
+ *
+ * Copyright 2005 The Apache Software Foundation or its licensors, as applicable.
+ *
+ * Licensed 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.core.config.impl;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.osoa.sca.annotations.Callback;
+import org.osoa.sca.annotations.Remotable;
+
+import org.apache.tuscany.core.config.ComponentTypeIntrospector;
+import org.apache.tuscany.core.config.ConfigurationException;
+import org.apache.tuscany.core.config.JavaIntrospectionHelper;
+import org.apache.tuscany.model.assembly.AssemblyFactory;
+import org.apache.tuscany.model.assembly.ComponentType;
+import org.apache.tuscany.model.assembly.Multiplicity;
+import org.apache.tuscany.model.assembly.Property;
+import org.apache.tuscany.model.assembly.Reference;
+import org.apache.tuscany.model.assembly.Scope;
+import org.apache.tuscany.model.assembly.Service;
+import org.apache.tuscany.model.assembly.ServiceContract;
+import org.apache.tuscany.model.types.java.JavaServiceContract;
+
+/**
+ * Introspects Java annotation-based metata data
+ *
+ * @version $Rev$ $Date$
+ */
+public class Java5ComponentTypeIntrospector implements ComponentTypeIntrospector {
+ private final AssemblyFactory factory;
+
+ public Java5ComponentTypeIntrospector(AssemblyFactory factory) {
+ this.factory = factory;
+ }
+
+ /**
+ * Returns a component type for the given class
+ *
+ * @throws ConfigurationException
+ */
+ public ComponentType introspect(Class<?> implClass) throws ConfigurationException {
+ ComponentType compType = factory.createComponentType();
+ introspectServices(compType, implClass);
+ introspectAnnotatedMembers(compType, implClass);
+
+ // if implementation is not annotated and no annotated members were found, add public fields and setters
+ if (!implClass.isAnnotationPresent(org.osoa.sca.annotations.Service.class) && compType.getProperties().isEmpty()
+ && compType.getReferences().isEmpty()) {
+ introspectMembers(compType, implClass);
+ }
+
+ // FIXME scopes should be handled at the interface level
+ if (compType != null) {
+ Scope scope = getScope(implClass);
+ for (Iterator<Service> i = compType.getServices().iterator(); i.hasNext();) {
+ ServiceContract intf = i.next().getServiceContract();
+ if (intf != null)
+ intf.setScope(scope);
+ }
+ }
+
+ return compType;
+ }
+
+ /**
+ * Returns the scope for a given class
+ *
+ */
+ private static Scope getScope(Class<?> implClass) {
+ org.osoa.sca.annotations.Scope scope = implClass.getAnnotation(org.osoa.sca.annotations.Scope.class);
+ if (scope == null) {
+ // scope was not defined on the implementation class, look for annotated interfaces
+ Class<?>[] interfaces = implClass.getInterfaces();
+ for (int i = 0; i < interfaces.length; i++) {
+ scope = interfaces[i].getAnnotation(org.osoa.sca.annotations.Scope.class);
+ }
+ }
+ if (scope == null) {
+ return Scope.INSTANCE;
+ }
+
+ if ("MODULE".equalsIgnoreCase(scope.value())) {
+ return (Scope.MODULE);
+ } else if ("SESSION".equalsIgnoreCase(scope.value())) {
+ return (Scope.SESSION);
+ } else if ("REQUEST".equalsIgnoreCase(scope.value())) {
+ return (Scope.REQUEST);
+ } else {
+ return (Scope.INSTANCE);
+ }
+ }
+
+ /**
+ * Adds the supported services for a component implementation type to its component type
+ *
+ * @param compType the component type being generated
+ * @param implClass the component implementation type class
+ * @throws ConfigurationException
+ */
+ protected void introspectServices(ComponentType compType, Class<?> implClass) throws ConfigurationException {
+ List<Service> services = compType.getServices();
+ assert services.isEmpty() : "componentType already has services defined";
+
+ // add services defined in an @Service annotation
+ org.osoa.sca.annotations.Service serviceAnnotation = implClass.getAnnotation(org.osoa.sca.annotations.Service.class);
+ if (serviceAnnotation != null) {
+ Class<?>[] interfaces = serviceAnnotation.interfaces();
+ Class<?> value = serviceAnnotation.value();
+ if (interfaces.length > 0) {
+ if (!Void.class.equals(value)) {
+ throw new IllegalArgumentException("Both interfaces and value specified in @Service on "
+ + implClass.getName());
+ }
+ for (int i = 0; i < interfaces.length; i++) {
+ Class<?> intf = interfaces[i];
+ addService(services, intf);
+ }
+ return;
+ } else if (!Void.class.equals(value)) {
+ addService(services, value);
+ return;
+ }
+ }
+
+ // no @Service annotation, add all implemented interfaces with an @Remotable annotation
+ Class[] interfaces = implClass.getInterfaces();
+ for (int i = 0; i < interfaces.length; i++) {
+ Class<?> intf = interfaces[i];
+ if (intf.isAnnotationPresent(Remotable.class)) {
+ addService(services, intf);
+ }
+ }
+
+ // if no Remotable interfaces were specified, the class itself is the service
+ if (services.isEmpty()) {
+ addService(services, implClass);
+ }
+ }
+
+ /**
+ * Recursively adds supported services to a component type by walking the class hierarchy
+ *
+ * @throws ConfigurationException
+ */
+ protected void addService(List<Service> services, Class<?> serviceClass) throws ConfigurationException {
+ JavaServiceContract javaInterface = factory.createJavaServiceContract();
+ javaInterface.setInterface(serviceClass);
+ Callback callback = serviceClass.getAnnotation(Callback.class);
+ if (callback != null && !Void.class.equals(callback.value())) {
+ javaInterface.setCallbackInterface(callback.value());
+ }
+
+ String name = JavaIntrospectionHelper.getBaseName(serviceClass);
+ Service service = factory.createService();
+ service.setName(name);
+ service.setServiceContract(javaInterface);
+ services.add(service);
+ }
+
+ /**
+ * Root method for determining public field and method metadata
+ *
+ * @throws ConfigurationException
+ */
+ protected void introspectAnnotatedMembers(ComponentType compType, Class<?> implClass) throws ConfigurationException {
+
+ introspectPublicFields(compType, implClass);
+ introspectPrivateFields(compType, implClass);
+
+ introspectPublicMethods(compType, implClass);
+ introspectPrivateMethods(compType, implClass);
+ }
+
+ /**
+ * Introspects metdata for all public fields and methods for a class hierarchy
+ *
+ * @throws ConfigurationException
+ */
+ protected void introspectMembers(ComponentType compType, Class<?> implClass) throws ConfigurationException {
+ List<Property> properties = compType.getProperties();
+ List<Reference> references = compType.getReferences();
+
+ // inspect public fields from class and all superclasses
+ Field[] fields = implClass.getFields();
+ for (int i = 0; i < fields.length; i++) {
+ Field field = fields[i];
+ if (field.getType().isAnnotationPresent(Remotable.class)) {
+ addReference(references, field);
+ } else {
+ addProperty(properties, field);
+ }
+ }
+
+ // add public methods from class and all superclasses
+ Method[] methods = implClass.getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+ if (Void.class.equals(method.getReturnType()) && method.getName().startsWith("set")
+ && method.getParameterTypes().length == 1
+ && !method.getParameterTypes()[0].isAnnotationPresent(Remotable.class)) {
+ String name = method.getName();
+ name = Character.toLowerCase(name.charAt(3)) + name.substring(4);
+ Class<?> type = method.getParameterTypes()[0];
+ if (type.isAnnotationPresent(Remotable.class)) {
+ addReference(references, name, type, false);
+ } else {
+ addProperty(properties, name, type, false);
+ }
+ }
+ }
+ }
+
+ private void introspectPublicFields(ComponentType compType, Class<?> implClass) throws ConfigurationException {
+ List<Property> properties = compType.getProperties();
+ List<Reference> references = compType.getReferences();
+
+ // inspect public fields from class and all superclasses
+ Field[] fields = implClass.getFields();
+ for (int i = 0; i < fields.length; i++) {
+ Field field = fields[i];
+ if (field.isAnnotationPresent(org.osoa.sca.annotations.Property.class)) {
+ addProperty(properties, field);
+ } else if (field.isAnnotationPresent(org.osoa.sca.annotations.Reference.class)) {
+ addReference(references, field);
+ }
+ }
+ }
+
+ private void introspectPrivateFields(ComponentType compType, Class<?> implClass) throws ConfigurationException {
+ List<Property> properties = compType.getProperties();
+ List<Reference> references = compType.getReferences();
+
+ // inspect private fields declared in class
+ Field[] fields = implClass.getDeclaredFields();
+ for (int i = 0; i < fields.length; i++) {
+ Field field = fields[i];
+ if (!Modifier.isPrivate(field.getModifiers())) {
+ continue;
+ }
+ if (field.isAnnotationPresent(org.osoa.sca.annotations.Property.class)) {
+ addProperty(properties, field);
+ } else if (field.isAnnotationPresent(org.osoa.sca.annotations.Reference.class)) {
+ addReference(references, field);
+ }
+ }
+ }
+
+ private void introspectPublicMethods(ComponentType compType, Class<?> implClass) throws ConfigurationException {
+ List<Property> properties = compType.getProperties();
+ List<Reference> references = compType.getReferences();
+
+ // add public methods from class and all superclasses
+ Method[] methods = implClass.getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+ if (method.isAnnotationPresent(org.osoa.sca.annotations.Property.class)) {
+ addProperty(properties, method);
+ } else if (method.isAnnotationPresent(org.osoa.sca.annotations.Reference.class)) {
+ addReference(references, method);
+ }
+ }
+ }
+
+ private void introspectPrivateMethods(ComponentType compType, Class<?> implClass) throws ConfigurationException {
+ List<Property> properties = compType.getProperties();
+ List<Reference> references = compType.getReferences();
+
+ // add private methods declared on class
+ Method[] methods = implClass.getDeclaredMethods();
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+ if (!Modifier.isPrivate(method.getModifiers())) {
+ continue;
+ }
+ if (method.isAnnotationPresent(org.osoa.sca.annotations.Property.class)) {
+ addProperty(properties, method);
+ } else if (method.isAnnotationPresent(org.osoa.sca.annotations.Reference.class)) {
+ addReference(references, method);
+ }
+ }
+ }
+
+ protected void addProperty(List<Property> properties, Field field) throws ConfigurationException {
+ String name;
+ boolean required;
+ org.osoa.sca.annotations.Property annotation = field.getAnnotation(org.osoa.sca.annotations.Property.class);
+ if (annotation != null) {
+ name = annotation.name();
+ if (name.length() == 0) {
+ name = field.getName();
+ }
+ required = annotation.required();
+ } else {
+ name = field.getName();
+ required = false;
+ }
+ addProperty(properties, name, field.getType(), required);
+ }
+
+ protected void addProperty(List<Property> properties, Method method) throws ConfigurationException {
+ if (!Void.class.equals(method.getReturnType())) {
+ throw new ConfigurationException("Property setter method does not return void: " + method.toString());
+ }
+ Class<?>[] params = method.getParameterTypes();
+ if (params.length != 1) {
+ throw new ConfigurationException("Property setter method does not have 1 parameter: " + method.toString());
+ }
+
+ String name;
+ boolean required;
+ org.osoa.sca.annotations.Property annotation = method.getAnnotation(org.osoa.sca.annotations.Property.class);
+ if (annotation != null) {
+ name = annotation.name();
+ required = annotation.required();
+ } else {
+ name = "";
+ required = false;
+ }
+ if (name.length() == 0) {
+ name = method.getName();
+ if (name.length() > 3 && name.startsWith("set")) {
+ name = Character.toLowerCase(name.charAt(3)) + name.substring(4);
+ }
+ }
+ addProperty(properties, name, params[0], required);
+ }
+
+ protected void addProperty(List<Property> properties, String name, Class<?> type, boolean required)
+ throws ConfigurationException {
+ Property prop = factory.createProperty();
+ prop.setName(name);
+ prop.setType(type);
+ prop.setRequired(required);
+
+ // a java.util.Map is not a "many"
+ prop.setMany(type.isArray() || Collection.class.isAssignableFrom(type));
+
+ // todo how is the default specified using annotations?
+ prop.setDefaultValue(null);
+
+ properties.add(prop);
+ }
+
+ protected void addReference(List<Reference> references, Field field) throws ConfigurationException {
+ String name;
+ boolean required;
+ org.osoa.sca.annotations.Reference annotation = field.getAnnotation(org.osoa.sca.annotations.Reference.class);
+ if (annotation != null) {
+ name = annotation.name();
+ if (name.length() == 0) {
+ name = field.getName();
+ }
+ required = annotation.required();
+ } else {
+ name = field.getName();
+ required = false;
+ }
+ addReference(references, name, field.getType(), required);
+ }
+
+ protected void addReference(List<Reference> references, Method method) throws ConfigurationException {
+ if (!Void.TYPE.equals(method.getReturnType())) {
+ throw new ConfigurationException("Reference setter method does not return void: " + method.toString());
+ }
+ Class<?>[] params = method.getParameterTypes();
+ if (params.length != 1) {
+ throw new ConfigurationException("Reference setter method does not have 1 parameter: " + method.toString());
+ }
+
+ String name;
+ boolean required;
+ org.osoa.sca.annotations.Reference annotation = method.getAnnotation(org.osoa.sca.annotations.Reference.class);
+ if (annotation != null) {
+ name = annotation.name();
+ required = annotation.required();
+ } else {
+ name = "";
+ required = false;
+ }
+ if (name.length() == 0) {
+ name = method.getName();
+ if (name.length() > 3 && name.startsWith("set")) {
+ name = Character.toLowerCase(name.charAt(3)) + name.substring(4);
+ }
+ }
+ addReference(references, name, params[0], required);
+ }
+
+ protected void addReference(List<Reference> references, String name, Class<?> type, boolean required)
+ throws ConfigurationException {
+ Reference ref = factory.createReference();
+ ref.setName(name);
+ boolean many = type.isArray() || Collection.class.isAssignableFrom(type);
+ Multiplicity multiplicity;
+ if (required)
+ multiplicity = many ? Multiplicity.ONE_N : Multiplicity.ONE_ONE;
+ else
+ multiplicity = many ? Multiplicity.ZERO_N : Multiplicity.ZERO_ONE;
+ ref.setMultiplicity(multiplicity);
+ ServiceContract javaInterface = factory.createJavaServiceContract();
+ javaInterface.setInterface(type);
+ ref.setServiceContract(javaInterface);
+ references.add(ref);
+ }
+}