diff options
Diffstat (limited to 'branches/pre-spec-changes/kernel/core/src/main/java/org/apache/tuscany/core/implementation/processor/HeuristicPojoProcessor.java')
-rw-r--r-- | branches/pre-spec-changes/kernel/core/src/main/java/org/apache/tuscany/core/implementation/processor/HeuristicPojoProcessor.java | 546 |
1 files changed, 0 insertions, 546 deletions
diff --git a/branches/pre-spec-changes/kernel/core/src/main/java/org/apache/tuscany/core/implementation/processor/HeuristicPojoProcessor.java b/branches/pre-spec-changes/kernel/core/src/main/java/org/apache/tuscany/core/implementation/processor/HeuristicPojoProcessor.java deleted file mode 100644 index bdf5d23ea8..0000000000 --- a/branches/pre-spec-changes/kernel/core/src/main/java/org/apache/tuscany/core/implementation/processor/HeuristicPojoProcessor.java +++ /dev/null @@ -1,546 +0,0 @@ -/* - * 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.core.implementation.processor; - -import java.lang.annotation.Annotation; -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.ParameterizedType; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.osoa.sca.annotations.Remotable; -import org.osoa.sca.annotations.Service; - -import org.apache.tuscany.spi.annotation.Autowire; -import org.apache.tuscany.spi.component.CompositeComponent; -import org.apache.tuscany.spi.databinding.extension.SimpleTypeMapperExtension; -import org.apache.tuscany.spi.deployer.DeploymentContext; -import org.apache.tuscany.spi.idl.InvalidServiceContractException; -import org.apache.tuscany.spi.idl.TypeInfo; -import org.apache.tuscany.spi.implementation.java.ConstructorDefinition; -import org.apache.tuscany.spi.implementation.java.ImplementationProcessorExtension; -import org.apache.tuscany.spi.implementation.java.ImplementationProcessorService; -import org.apache.tuscany.spi.implementation.java.JavaMappedProperty; -import org.apache.tuscany.spi.implementation.java.JavaMappedReference; -import org.apache.tuscany.spi.implementation.java.JavaMappedService; -import org.apache.tuscany.spi.implementation.java.PojoComponentType; -import org.apache.tuscany.spi.implementation.java.ProcessingException; -import org.apache.tuscany.spi.model.OverrideOptions; - -import static org.apache.tuscany.core.util.JavaIntrospectionHelper.getAllInterfaces; -import static org.apache.tuscany.core.util.JavaIntrospectionHelper.getAllPublicAndProtectedFields; -import static org.apache.tuscany.core.util.JavaIntrospectionHelper.getAllUniquePublicProtectedMethods; -import static org.apache.tuscany.core.util.JavaIntrospectionHelper.getBaseName; -import static org.apache.tuscany.core.util.JavaIntrospectionHelper.toPropertyName; - -/** - * 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 inteface 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 ImplementationProcessorExtension { - private SimpleTypeMapperExtension typeMapper = new SimpleTypeMapperExtension(); - private ImplementationProcessorService implService; - - public HeuristicPojoProcessor(@Autowire ImplementationProcessorService service) { - this.implService = service; - } - - public <T> void visitEnd( - CompositeComponent parent, - Class<T> clazz, - PojoComponentType<JavaMappedService, JavaMappedReference, JavaMappedProperty<?>> type, - DeploymentContext context) throws ProcessingException { - Map<String, JavaMappedService> services = type.getServices(); - if (services.isEmpty()) { - // heuristically determine the service - // TODO finish algorithm - Set<Class> interfaces = getAllInterfaces(clazz); - if (interfaces.size() == 0) { - // class is the interface - JavaMappedService service; - try { - service = implService.createService(clazz); - } catch (InvalidServiceContractException e) { - throw new ProcessingException(e); - } - type.getServices().put(service.getName(), service); - } else if (interfaces.size() == 1) { - JavaMappedService service; - try { - service = implService.createService(interfaces.iterator().next()); - } catch (InvalidServiceContractException e) { - throw new ProcessingException(e); - } - type.getServices().put(service.getName(), service); - } - } - Set<Method> methods = getAllUniquePublicProtectedMethods(clazz); - if (!type.getReferences().isEmpty() || !type.getProperties().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; - } - calcPropRefs(methods, services, type, clazz); - evaluateConstructor(type, clazz); - } - - private <T> void calcPropRefs(Set<Method> methods, - Map<String, JavaMappedService> services, - PojoComponentType<JavaMappedService, JavaMappedReference, JavaMappedProperty<?>> type, - Class<T> clazz) throws ProcessingException { - // heuristically determine the properties references - // make a first pass through all public methods with one param - for (Method method : methods) { - if (method.getParameterTypes().length != 1 || !Modifier.isPublic(method.getModifiers()) - || !method.getName().startsWith("set") - || method.getReturnType() != void.class) { - continue; - } - if (!isInServiceInterface(method, services)) { - String name = toPropertyName(method.getName()); - // avoid duplicate property or ref names - if (!type.getProperties().containsKey(name) && !type.getReferences().containsKey(name)) { - Class<?> param = method.getParameterTypes()[0]; - Type genericType = method.getGenericParameterTypes()[0]; - if (isReferenceType(genericType)) { - type.add(createReference(name, method, param)); - } else { - type.add(createProperty(name, method, param)); - } - } - } - } - // second pass for protected methods with one param - for (Method method : methods) { - if (method.getParameterTypes().length != 1 || !Modifier.isProtected(method.getModifiers()) - || !method.getName().startsWith("set") - || method.getReturnType() != void.class) { - continue; - } - Class<?> param = method.getParameterTypes()[0]; - String name = toPropertyName(method.getName()); - // avoid duplicate property or ref names - if (!type.getProperties().containsKey(name) && !type.getReferences().containsKey(name)) { - if (isReferenceType(param)) { - type.add(createReference(name, method, param)); - } else { - type.add(createProperty(name, method, param)); - } - } - } - Set<Field> fields = getAllPublicAndProtectedFields(clazz); - for (Field field : fields) { - Class<?> paramType = field.getType(); - if (isReferenceType(paramType)) { - type.add(createReference(field.getName(), field, paramType)); - } else { - type.add(createProperty(field.getName(), field, paramType)); - } - } - } - - /** - * 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( - PojoComponentType<JavaMappedService, JavaMappedReference, JavaMappedProperty<?>> type, - Class<T> clazz) throws ProcessingException { - // determine constructor if one is not annotated - ConstructorDefinition<?> definition = type.getConstructorDefinition(); - Constructor constructor; - boolean explict = false; - if (definition != null - && definition.getConstructor().getAnnotation(org.osoa.sca.annotations.Constructor.class) != null) { - // the constructor was already defined explicitly - return; - } else if (definition != null) { - explict = true; - constructor = definition.getConstructor(); - } else { - // no definition, heuristically determine constructor - Constructor[] constructors = clazz.getConstructors(); - if (constructors.length == 0) { - throw new NoConstructorException("No public constructor for class", clazz.getName()); - } else if (constructors.length == 1) { - constructor = constructors[0]; - } else { - // FIXME multiple constructors, none yet done - Constructor<T> selected = null; - int sites = type.getProperties().size() + type.getReferences().size(); - for (Constructor<T> ctor : constructors) { - if (ctor.getParameterTypes().length == 0) { - selected = ctor; - } - if (ctor.getParameterTypes().length == sites) { - // TODO finish - // selected = constructor; - // select constructor - // break; - } - } - if (selected == null) { - throw new NoConstructorException(); - } - constructor = selected; - definition = new ConstructorDefinition<T>(selected); - type.setConstructorDefinition(definition); - // return; - } - definition = new ConstructorDefinition<T>(constructor); - type.setConstructorDefinition(definition); - } - Class[] params = constructor.getParameterTypes(); - if (params.length == 0) { - return; - } - List<String> paramNames = definition.getInjectionNames(); - Map<String, JavaMappedProperty<?>> props = type.getProperties(); - Map<String, JavaMappedReference> refs = type.getReferences(); - 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 = implService.injectionAnnotationsPresent(annotations); - } - if (explict) { - for (int i = 0; i < params.length; i++) { - Class param = params[i]; - implService.processParam(param, annotations[i], new String[0], i, type, paramNames); - } - } else { - if (!implService.areUnique(params)) { - 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"); - } - boolean empty = props.size() + refs.size() == 0; - if (!empty) { - calcParamNames(params, props, refs, paramNames); - } else { - heuristicParamNames(params, refs, props, paramNames); - - } - } - } - - private void calcParamNames(Class[] params, - Map<String, JavaMappedProperty<?>> props, - Map<String, JavaMappedReference> refs, - List<String> paramNames) - throws AmbiguousConstructorException { - // the constructor param types must unambiguously match defined reference or property types - for (Class param : params) { - String name = findReferenceOrProperty(param, props, refs); - if (name == null) { - throw new AmbiguousConstructorException(param.getName()); - } - paramNames.add(name); - } - } - - private void heuristicParamNames(Class[] params, - Map<String, JavaMappedReference> refs, - Map<String, JavaMappedProperty<?>> props, - List<String> paramNames) - throws ProcessingException { - // heuristically determine refs and props from the parameter types - for (Class<?> param : params) { - String name = getBaseName(param).toLowerCase(); - if (isReferenceType(param)) { - refs.put(name, createReference(name, null, param)); - } else { - props.put(name, createProperty(name, null, param)); - } - paramNames.add(name); - } - } - - /** - * Returns true if the union of the given collections of properties and references have unique Java types - */ - private boolean calcPropRefUniqueness( - Collection<JavaMappedProperty<?>> props, - Collection<JavaMappedReference> refs) { - - Class[] classes = new Class[props.size() + refs.size()]; - int i = 0; - for (JavaMappedProperty<?> property : props) { - classes[i] = property.getJavaType(); - i++; - } - for (JavaMappedReference reference : refs) { - classes[i] = reference.getServiceContract().getInterfaceClass(); - i++; - } - return implService.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 String findReferenceOrProperty( - Class<?> type, - Map<String, JavaMappedProperty<?>> props, - Map<String, JavaMappedReference> refs) throws AmbiguousConstructorException { - - String name = null; - for (JavaMappedProperty<?> property : props.values()) { - if (property.getJavaType().equals(type)) { - if (name != null) { - throw new AmbiguousConstructorException("Ambiguous property or reference for constructor type", - type.getName()); - } - name = property.getName(); - // do not break since ambiguities must be checked, i.e. more than one prop or ref of the same type - } - } - for (JavaMappedReference reference : refs.values()) { - if (reference.getServiceContract().getInterfaceClass().equals(type)) { - if (name != null) { - throw new AmbiguousConstructorException("Ambiguous property or reference for constructor type", - type.getName()); - } - name = reference.getName(); - // do not break since ambiguities must be checked, i.e. more than one prop or ref of the same type - } - } - return name; - } - - /** - * Returns true if a given type is reference according to the SCA specification rules for determining reference - * types - */ - private boolean isReferenceType(Type operationType) { - Class<?> rawType; - Class<?> referenceType = null; - if (operationType instanceof ParameterizedType) { - ParameterizedType parameterizedType = (ParameterizedType) operationType; - rawType = (Class<?>) parameterizedType.getRawType(); - Type[] typeArgs = parameterizedType.getActualTypeArguments(); - if (typeArgs.length == 1) { - referenceType = (Class<?>) typeArgs[0]; - } - } else { - rawType = (Class<?>) operationType; - } - if (rawType.isArray()) { - referenceType = rawType.getComponentType(); - } else if (Collection.class.isAssignableFrom(rawType) && referenceType == null) { - return true; - } - if (referenceType != null) { - return referenceType.getAnnotation(Remotable.class) != null - || referenceType.getAnnotation(Service.class) != null; - } else { - return rawType.getAnnotation(Remotable.class) != null || rawType.getAnnotation(Service.class) != null; - } - } - - /** - * Returns true if the given operation is defined in the collection of service interfaces - */ - private boolean isInServiceInterface(Method operation, Map<String, JavaMappedService> services) { - for (JavaMappedService service : services.values()) { - Class<?> clazz = service.getServiceContract().getInterfaceClass(); - if (operation.getDeclaringClass().equals(clazz)) { - return true; - } - Method[] methods = service.getServiceContract().getInterfaceClass().getMethods(); - for (Method method : methods) { - if (operation.getName().equals(method.getName()) - && operation.getParameterTypes().length == method.getParameterTypes().length) { - Class<?>[] methodTypes = method.getParameterTypes(); - for (int i = 0; i < operation.getParameterTypes().length; i++) { - Class<?> paramType = operation.getParameterTypes()[i]; - if (!paramType.equals(methodTypes[i])) { - break; - } else if (i == operation.getParameterTypes().length - 1) { - return true; - } - } - } - } - } - return false; - } - - /** - * Creates a mapped reference - * - * @param name the reference name - * @param member the injection site the reference maps to - * @param paramType the service interface of the reference - */ - private JavaMappedReference createReference(String name, Member member, Class<?> paramType) - throws ProcessingException { - return implService.createReference(name, member, paramType); - } - - /** - * Creates a mapped property - * - * @param name the property name - * @param member the injection site the reference maps to - * @param paramType the property type - */ - private <T> JavaMappedProperty<T> createProperty(String name, Member member, Class<T> paramType) { - JavaMappedProperty<T> property = new JavaMappedProperty<T>(); - property.setName(name); - property.setMember(member); - property.setOverride(OverrideOptions.MAY); - property.setJavaType(paramType); - TypeInfo xmlType = typeMapper.getXMLType(paramType); - if (xmlType != null) { - property.setXmlType(xmlType.getQName()); - } - - return property; - } - - /** - * Populates a component type with a service whose interface type is determined by examining all implemented - * interfaces of the given class and chosing one whose operations match all of the class's non-property and - * non-reference methods - * - * @param clazz the class to examine - * @param type the component type - * @param methods all methods in the class to examine - */ - private void calculateServiceInterface( - Class<?> clazz, - PojoComponentType<JavaMappedService, JavaMappedReference, JavaMappedProperty<?>> type, - Set<Method> methods) throws ProcessingException { - List<Method> nonPropRefMethods = new ArrayList<Method>(); - // Map<String, JavaMappedService> services = type.getServices(); - Map<String, JavaMappedReference> references = type.getReferences(); - Map<String, JavaMappedProperty<?>> properties = type.getProperties(); - // calculate methods that are not properties or references - for (Method method : methods) { - String name = toPropertyName(method.getName()); - if (!references.containsKey(name) && !properties.containsKey(name)) { - nonPropRefMethods.add(method); - } - } - // determine if an implemented interface matches all of the non-property and non-reference methods - Class[] interfaces = clazz.getInterfaces(); - if (interfaces.length == 0) { - return; - } - for (Class interfaze : interfaces) { - if (analyzeInterface(interfaze, nonPropRefMethods)) { - JavaMappedService service; - try { - service = implService.createService(interfaze); - } catch (InvalidServiceContractException e) { - throw new ProcessingException(e); - } - type.getServices().put(service.getName(), service); - } - } - } - - /** - * Determines if the methods of a given interface match the given list of methods - * - * @param interfaze the interface to examine - * @param nonPropRefMethods the list of methods to match against - * @return true if the interface matches - */ - private boolean analyzeInterface(Class<?> interfaze, List<Method> nonPropRefMethods) { - Method[] interfaceMethods = interfaze.getMethods(); - if (nonPropRefMethods.size() != interfaceMethods.length) { - return false; - } - for (Method method : nonPropRefMethods) { - boolean found = false; - for (Method interfaceMethod : interfaceMethods) { - if (interfaceMethod.getName().equals(method.getName())) { - Class<?>[] interfaceParamTypes = interfaceMethod.getParameterTypes(); - Class<?>[] methodParamTypes = method.getParameterTypes(); - if (interfaceParamTypes.length == methodParamTypes.length) { - if (interfaceParamTypes.length == 0) { - found = true; - } else { - for (int i = 0; i < methodParamTypes.length; i++) { - Class<?> param = methodParamTypes[i]; - if (!param.equals(interfaceParamTypes[i])) { - break; - } - if (i == methodParamTypes.length - 1) { - found = true; - } - } - } - } - if (found) { - break; - } - } - } - if (!found) { - return false; - } - } - return true; - } - -} - -/* - * 1) public setter methods that are not included in any service interface 2) protected setter methods 3) public or - * protected fields unless there is a setter method for the same name If the type associated with the member is an array - * or a java.util.Collection, then the basetype will be the element type of the array or the parameterized type of the - * Collection, otherwise the basetype will be the member type. If the basetype is an interface with an @Remotable or - * @Service annotation then the member will be defined as a reference, otherwise it will be defined as a property. - * - * - */ |