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

org.fabric3.spi.introspection.java.AbstractBindingPostProcessor Maven / Gradle / Ivy

There is a newer version: 3.1.0
Show newest version
/*
 * Fabric3
 * Copyright (c) 2009-2015 Metaform Systems
 *
 * 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.fabric3.spi.introspection.java;

import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;

import org.fabric3.api.host.runtime.HostInfo;
import org.fabric3.api.model.type.ModelObject;
import org.fabric3.api.model.type.component.Binding;
import org.fabric3.api.model.type.component.BindingHandler;
import org.fabric3.api.model.type.component.ComponentType;
import org.fabric3.api.model.type.component.Reference;
import org.fabric3.api.model.type.component.Service;
import org.fabric3.api.model.type.contract.ServiceContract;
import org.fabric3.api.model.type.java.InjectingComponentType;
import org.fabric3.api.model.type.java.InjectionSite;
import org.fabric3.spi.introspection.IntrospectionContext;
import org.fabric3.spi.model.type.java.ConstructorInjectionSite;
import org.fabric3.spi.model.type.java.FieldInjectionSite;
import org.fabric3.spi.model.type.java.MethodInjectionSite;
import org.oasisopen.sca.annotation.EagerInit;

/**
 * Base class for introspecting binding information in a component implementation.
 */
@EagerInit
public abstract class AbstractBindingPostProcessor implements PostProcessor {
    private Class annotationType;
    private Method serviceAttribute;

    @org.oasisopen.sca.annotation.Reference
    protected HostInfo info;

    protected AbstractBindingPostProcessor(Class annotationType) {
        this.annotationType = annotationType;
        try {
            serviceAttribute = annotationType.getDeclaredMethod("service");
        } catch (NoSuchMethodException e) {
            throw new AssertionError("Binding annotation must have a service attribute");
        }
    }

    public void process(InjectingComponentType componentType, Class implClass, IntrospectionContext context) {
        processService(componentType, implClass, context);
        processReferences(componentType, implClass, context);
    }

    protected String getNullableValue(String value) {
        return value.isEmpty() ? null : value;
    }

    protected abstract Binding processService(A annotation,
                                              Service service,
                                              InjectingComponentType componentType,
                                              Class implClass,
                                              IntrospectionContext context);

    protected abstract Binding processServiceCallback(A annotation,
                                                      Service service,
                                                      InjectingComponentType componentType,
                                                      Class implClass,
                                                      IntrospectionContext context);

    /**
     * Processes the annotation for the reference.
     *
     * @param annotation the annotation
     * @param reference  the reference
     * @param implClass  the implementation class
     * @param context    the current introspection context
     * @return may return null if the annotation is not processed by the implementing class or is not applicable to the environment
     */
    protected abstract Binding processReference(A annotation, Reference reference, Class implClass, IntrospectionContext context);

    protected abstract Binding processReferenceCallback(A annotation, Reference reference, Class implClass, IntrospectionContext context);

    protected void processService(InjectingComponentType componentType, Class implClass, IntrospectionContext context) {
        A annotation = AnnotationHelper.findAnnotation(annotationType, implClass);
        if (annotation == null) {
            return;
        }
        Class serviceInterface = getService(annotation);
        if (serviceInterface.equals(Void.class)) {
            serviceInterface = null;
        }
        Service boundService = null;
        if (serviceInterface == null) {
            if (componentType.getServices().size() != 1) {
                InvalidAnnotation error = new InvalidAnnotation("Binding annotation must specify a service interface", implClass, annotation, implClass);
                context.addError(error);
                return;
            }
            boundService = componentType.getServices().values().iterator().next();
        } else {
            String name = serviceInterface.getName();
            for (Service service : componentType.getServices().values()) {
                String interfaceName = service.getServiceContract().getQualifiedInterfaceName();
                if (interfaceName.equals(name)) {
                    boundService = service;
                    break;
                }
            }
            if (boundService == null) {
                InvalidAnnotation error = new InvalidAnnotation("Service specified in binding annotation not found: " + name, implClass, annotation, implClass);
                context.addError(error);
                return;
            }
        }
        Binding binding = processService(annotation, boundService, componentType, implClass, context);
        if (binding == null) {
            return;
        }
        processHandlers(implClass, binding, implClass, context);
        boundService.addBinding(binding);

        ServiceContract contract = boundService.getServiceContract();
        if (contract.getCallbackContract() != null) {
            Binding callbackBinding = processServiceCallback(annotation, boundService, componentType, implClass, context);
            if (callbackBinding != null) {
                boundService.addCallbackBinding(callbackBinding);
            }
        }

    }

    protected void processReferences(InjectingComponentType componentType, Class implClass, IntrospectionContext context) {
        for (Map.Entry entry : componentType.getInjectionSiteMappings().entrySet()) {
            if (!(entry.getKey() instanceof Reference)) {
                continue;
            }
            Reference reference = (Reference) entry.getKey();
            InjectionSite site = entry.getValue();
            if (site instanceof FieldInjectionSite) {
                FieldInjectionSite fieldSite = (FieldInjectionSite) site;
                Field field = fieldSite.getField();
                processBindingAnnotations(field, reference, implClass, context);
            } else if (site instanceof MethodInjectionSite) {
                MethodInjectionSite methodSite = (MethodInjectionSite) site;
                Method method = methodSite.getMethod();
                processBindingAnnotations(method, reference, implClass, context);
            } else if (site instanceof ConstructorInjectionSite) {
                ConstructorInjectionSite constructorSite = (ConstructorInjectionSite) site;
                Constructor constructor = constructorSite.getConstructor();
                Annotation[] annotations = constructor.getParameterAnnotations()[constructorSite.getParam()];
                for (Annotation annotation : annotations) {
                    if (annotationType.equals(annotation.annotationType())) {
                        A castAnnotation = annotationType.cast(annotation);
                        Binding binding = processReference(castAnnotation, reference, implClass, context);
                        if (binding == null) {
                            continue;
                        }
                        reference.addBinding(binding);
                        ServiceContract contract = reference.getServiceContract();
                        if (contract.getCallbackContract() != null) {
                            Binding callbackBinding = processReferenceCallback(castAnnotation, reference, implClass, context);
                            if (callbackBinding != null) {
                                reference.addCallbackBinding(callbackBinding);
                            }
                        }
                    }
                }
            }
        }

    }

    protected void processBindingAnnotations(AccessibleObject object, Reference reference, Class implClass, IntrospectionContext context) {
        A annotations[] = object.getAnnotationsByType(annotationType);
        if (annotations.length == 0) {
            // check meta-annotations
            for (Annotation annotation : object.getAnnotations()) {
                annotations = annotation.annotationType().getAnnotationsByType(annotationType);
                if (annotations.length > 0) {
                    break;
                }
            }
            if (annotations.length == 0) {
                return;
            }
        }

        for (A annotation : annotations) {
            Binding binding = processReference(annotation, reference, implClass, context);
            if (binding == null) {
                continue;
            }
            reference.addBinding(binding);
            ServiceContract contract = reference.getServiceContract();
            if (contract.getCallbackContract() != null) {
                Binding callbackBinding = processReferenceCallback(annotationType.cast(annotation), reference, implClass, context);
                if (callbackBinding != null) {
                    reference.addCallbackBinding(callbackBinding);
                }
            }
        }

    }

    protected boolean isActiveForEnvironment(String[] environments) {
        if (environments.length == 0) {
            return true;
        }
        String activeEnvironment = info.getEnvironment();
        for (String environment : environments) {
            if (environment.equals(activeEnvironment)) {
                return true;
            }
        }
        return false;
    }

    private void processHandlers(AnnotatedElement element, Binding binding, Class implClass, IntrospectionContext context) {
        org.fabric3.api.annotation.model.BindingHandler annotation = element.getAnnotation(org.fabric3.api.annotation.model.BindingHandler.class);
        if (annotation == null) {
            return;
        }
        if (annotation.value().isEmpty()) {
            String[] values = annotation.handlers();
            for (String value : values) {
                parseHandlerUri(value, element, binding, implClass, context, annotation);
            }
        } else {
            parseHandlerUri(annotation.value(), element, binding, implClass, context, annotation);
        }
    }

    private void parseHandlerUri(String value,
                                 AnnotatedElement element,
                                 Binding binding,
                                 Class implClass,
                                 IntrospectionContext context,
                                 org.fabric3.api.annotation.model.BindingHandler annotation) {
        try {
            BindingHandler definition = new BindingHandler(new URI(value));
            binding.addHandler(definition);
        } catch (URISyntaxException e) {
            InvalidAnnotation error = new InvalidAnnotation("Invalid binding handler URI", element, annotation, implClass, e);
            context.addError(error);
        }
    }

    private Class getService(A annotation) {
        try {
            return (Class) serviceAttribute.invoke(annotation);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new AssertionError(e);
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy