All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.fabric3.introspection.impl.DefaultIntrospectionHelper Maven / Gradle / Ivy

There is a newer version: 1.1
Show newest version
/*
 * See the NOTICE file distributed with this work for information
 * regarding copyright ownership.  This file is licensed
 * 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.fabric3.introspection.impl;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.SortedSet;
import java.util.ArrayList;

import org.osoa.sca.ComponentContext;
import org.osoa.sca.RequestContext;
import org.osoa.sca.ServiceReference;
import org.osoa.sca.annotations.Remotable;
import org.osoa.sca.annotations.Service;
import org.osoa.sca.annotations.Callback;

import org.fabric3.introspection.IntrospectionException;
import org.fabric3.introspection.IntrospectionHelper;
import org.fabric3.introspection.TypeMapping;
import org.fabric3.introspection.java.ImplementationNotFoundException;
import org.fabric3.scdl.InjectableAttributeType;
import org.fabric3.scdl.ServiceDefinition;
import org.fabric3.scdl.Signature;
import org.fabric3.scdl.Operation;
import org.fabric3.scdl.DataType;

/**
 * @version $Rev: 3105 $ $Date: 2008-03-15 16:47:31 +0000 (Sat, 15 Mar 2008) $
 */
public class DefaultIntrospectionHelper implements IntrospectionHelper {
    // the wrapper classes we understand and which all have a single type parameter
    private static final Set> WRAPPERS;
    static {
        WRAPPERS = new HashSet>();
        WRAPPERS.add(Collection.class);
        WRAPPERS.add(List.class);
        WRAPPERS.add(Queue.class);
        WRAPPERS.add(Set.class);
        WRAPPERS.add(SortedSet.class);
        WRAPPERS.add(ServiceReference.class);
    }

    public Class loadClass(String name, ClassLoader cl) throws ImplementationNotFoundException {
        final Thread thread = Thread.currentThread();
        final ClassLoader oldCL = thread.getContextClassLoader();
        try {
            thread.setContextClassLoader(cl);
            return Class.forName(name, true, cl);
        } catch (ClassNotFoundException e) {
            throw new ImplementationNotFoundException(name, e);
        } catch (NoClassDefFoundError e) {
            // we trap this error as the most likely cause is a missing dependency on the classpath
            throw new ImplementationNotFoundException(name, e);
        } finally {
            thread.setContextClassLoader(oldCL);
        }
    }

    public String getSiteName(Field field, String override) throws IntrospectionException {
        if (override != null && override.length() != 0) {
            return override;
        }
        return field.getName();
    }

    public String getSiteName(Method setter, String override) throws IntrospectionException {
        if (override != null && override.length() != 0) {
            return override;
        }

        String name = setter.getName();
        if (name.length() > 3 && name.startsWith("set")) {
            return Character.toLowerCase(name.charAt(3)) + name.substring(4);
        } else {
            return name;
        }
    }

    public String getSiteName(Constructor constructor, int index, String override) throws IntrospectionException {
        if (override != null && override.length() != 0) {
            return override;
        }

        org.osoa.sca.annotations.Constructor annotation = constructor.getAnnotation(org.osoa.sca.annotations.Constructor.class);
        if (annotation != null) {
            String[] names = annotation.value();
            if (names.length != 1 || names[0].length() != 0) {
                return names[index];
            }
        }
        return constructor.getDeclaringClass().getSimpleName() + "[" + index + ']';
    }

    public Type getGenericType(Method setter) throws IntrospectionException {
        return getGenericType(setter, 0);
    }

    public Type getGenericType(Method method, int index) throws IntrospectionException {
        return method.getGenericParameterTypes()[index];
    }

    public Type getGenericType(Constructor constructor, int index) throws IntrospectionException {
        return constructor.getGenericParameterTypes()[index];
    }

    public Type getBaseType(Type type, TypeMapping typeMapping) {
        if (type instanceof Class) {
            Class clazz = (Class) type;
            if (clazz.isArray()) {
                return clazz.getComponentType();
            } else if (WRAPPERS.contains(clazz) || Map.class.equals(clazz)) {
                return Object.class;
            } else {
                return clazz;
            }
        } else if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            Class clazz = (Class) parameterizedType.getRawType();
            Type[] typeArguments = parameterizedType.getActualTypeArguments();
            if (WRAPPERS.contains(clazz)) {
                return typeMapping.getRawType(typeArguments[0]);
            } else if (Map.class.equals(clazz)) {
                return typeMapping.getRawType(typeArguments[1]);
            } else {
                return clazz;
            }

        } else if (type instanceof GenericArrayType) {
            GenericArrayType arrayType = (GenericArrayType) type;
            return typeMapping.getRawType(arrayType.getGenericComponentType());
        } else {
            throw new AssertionError("Unknown Type: " + type);
        }
    }

    public boolean isManyValued(TypeMapping typeMapping, Type type) {
        if (type instanceof GenericArrayType) {
            return true;
        } else {
            Class clazz = typeMapping.getRawType(type);
            return clazz.isArray() || WRAPPERS.contains(clazz) || Map.class.equals(clazz);
        }
    }

    public InjectableAttributeType inferType(Type type, TypeMapping typeMapping) {
        Type baseType = getBaseType(type, typeMapping);
        Class rawType = typeMapping.getRawType(baseType);

        // if it's not an interface, it must be a property
        if (!rawType.isInterface()) {
            return InjectableAttributeType.PROPERTY;
        }

        // it it's a context interfaces, it must be a context
        if (ComponentContext.class.isAssignableFrom(rawType) || RequestContext.class.isAssignableFrom(rawType)) {
            return InjectableAttributeType.CONTEXT;
        }

        // if it's Remotable or a local Service, it must be a reference
        if (isAnnotationPresent(rawType, Remotable.class) || isAnnotationPresent(rawType, Service.class)) {
            return InjectableAttributeType.REFERENCE;
        }

        // if it has a Callback anotation, it's a calback
        if (isAnnotationPresent(rawType, Callback.class)) {
            return InjectableAttributeType.CALLBACK;
        }

        // otherwise it's a property
        return InjectableAttributeType.PROPERTY;
    }

    public boolean isAnnotationPresent(Class type, Class annotationType) {
        if (type.isAnnotationPresent(annotationType)) {
            return true;
        }
        Class[] interfaces = type.getInterfaces();
        for (Class superInterface : interfaces) {
            if (isAnnotationPresent(superInterface, annotationType)) {
                return true;
            }
        }
        return false;
    }

    public Set> getImplementedInterfaces(Class type) {
        Set> interfaces = new HashSet>();
        while (type != null) {
            nextInterface: for (Class current : (Class[]) type.getInterfaces()) {
                for (Class foundAlready : interfaces) {
                    if (current.isAssignableFrom(foundAlready)) {
                        continue nextInterface;
                    }
                }
                interfaces.add(current);
            }
            type = type.getSuperclass();
        }
        return interfaces;
    }

    public Set getInjectionMethods(Class type, Collection services) {
        Set exclude = getOperations(services);
        Set methods = new HashSet();
        while (type != null) {
            for (Method method : type.getDeclaredMethods()) {
                // check method accessibility
                int modifiers = method.getModifiers();
                if (Modifier.isStatic(modifiers) || Modifier.isAbstract(modifiers)) {
                    continue;
                }
                if (!(Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers))) {
                    continue;
                }
                if (!isSetter(method)) {
                    continue;
                }

                // exclude methods we have seen already (i.e. in a contract or overriden in a subclass)
                // we check using the signature as the method itself will have been declared on a different class
                Signature signature = new Signature(method);
                if (exclude.contains(signature)) {
                    continue;
                }

                exclude.add(signature);
                methods.add(method);
            }
            type = type.getSuperclass();
        }
        return methods;
    }

    boolean isSetter(Method method) {
        // it must return void
        if (!Void.TYPE.equals(method.getReturnType())) {
            return false;
        }

        // it must have a single parameter
        if (method.getParameterTypes().length != 1) {
            return false;
        }

        // it's name must begin with "set" but not be "set"
        String name = method.getName();
        if (name.length() < 4 || !name.startsWith("set")) {
            return false;
        }

        return true;
    }

    private Set getOperations(Collection services) {
        Set operations = new HashSet();
        for (ServiceDefinition definition : services) {
            List> ops = definition.getServiceContract().getOperations();
            for (Operation operation : ops) {
                String name = operation.getName();
                List> inputTypes = operation.getInputType().getLogical();
                List paramTypes = new ArrayList(inputTypes.size());
                for (DataType inputType : inputTypes) {
                    paramTypes.add(((Class) inputType.getPhysical()).getName());
                }
                operations.add(new Signature(name, paramTypes));
            }
        }
        return operations;
    }

    public Set getInjectionFields(Class type) {
        Set fields = new HashSet();
        Set exclude = new HashSet();
        while (type != null) {
            for (Field field : type.getDeclaredFields()) {
                // check field accessibility
                int modifiers = field.getModifiers();
                if (Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers)) {
                    continue;
                }
                if (!(Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers))) {
                    continue;
                }

                // exclude fields already defined in a subclass
                String name = field.getName();
                if (exclude.contains(name)) {
                    continue;
                }
                exclude.add(name);
                fields.add(field);
            }
            
            type = type.getSuperclass();
        }
        return fields;
    }

    public TypeMapping mapTypeParameters(Class type) {
        TypeMapping mapping = new TypeMapping();
        while (type != null) {
            addTypeBindings(mapping, type.getGenericSuperclass());
            for (Type interfaceType : type.getGenericInterfaces()) {
                addTypeBindings(mapping, interfaceType);
            }
            type = type.getSuperclass();
        }
        return mapping;
    }

    private void addTypeBindings(TypeMapping mapping, Type type1) {
        if (type1 instanceof ParameterizedType) {
            ParameterizedType type = (ParameterizedType) type1;
            Class boundType = (Class) type.getRawType();
            TypeVariable>[] typeVariables = boundType.getTypeParameters();
            Type[] arguments = type.getActualTypeArguments();
            for (int i = 0; i < typeVariables.length; i++) {
                mapping.addMapping(typeVariables[i], arguments[i]);
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy