de.openknowledge.cdi.common.property.PropertiesLoaderExtension.java Source code

Java tutorial

Introduction

Here is the source code for de.openknowledge.cdi.common.property.PropertiesLoaderExtension.java

Source

/*
 * Copyright open knowledge GmbH
 *
 * 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 de.openknowledge.cdi.common.property;

import static de.openknowledge.cdi.common.property.PropertiesLoader.toClass;
import static org.apache.commons.lang.ClassUtils.primitiveToWrapper;
import static org.apache.commons.lang.ClassUtils.wrapperToPrimitive;
import static org.apache.commons.lang.Validate.notNull;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.AfterBeanDiscovery;
import javax.enterprise.inject.spi.Annotated;
import javax.enterprise.inject.spi.AnnotatedConstructor;
import javax.enterprise.inject.spi.AnnotatedField;
import javax.enterprise.inject.spi.AnnotatedMethod;
import javax.enterprise.inject.spi.AnnotatedParameter;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.ProcessAnnotatedType;
import javax.enterprise.inject.spi.ProcessBean;

import de.openknowledge.cdi.common.spi.DelegatingBean;

/**
 * This extension enables the injection of any object that has a constructor
 * with a single {@link String} parameter into injection points annotated with {@link Property}.
 * 
 * @author Arne Limburg
 */
public class PropertiesLoaderExtension implements Extension {

    private Set<Class<?>> customTypes = new HashSet<Class<?>>();
    private Bean<?> producePropertyBean;

    public <T> void registerCustomTypes(@Observes ProcessAnnotatedType<T> annotatedTypeEvent) {
        AnnotatedType<T> annotatedType = annotatedTypeEvent.getAnnotatedType();
        registerCustomType(annotatedType);
    }

    public void registerProducePropertyBean(@Observes ProcessBean<?> processBeanEvent) {
        Bean<?> bean = processBeanEvent.getBean();
        if (isProducePropertyBean(bean)) {
            producePropertyBean = bean;
        }
    }

    public void addBeans(@Observes AfterBeanDiscovery afterBeanDiscoveryEvent) {
        for (Class<?> customType : customTypes) {
            afterBeanDiscoveryEvent.addBean(createProducePropertyBean(producePropertyBean, customType));
        }
    }

    private void registerCustomType(AnnotatedType<?> annotatedType) {
        for (AnnotatedField<?> field : annotatedType.getFields()) {
            if (isPropertyInjectionPoint(field)) {
                customTypes.add(primitiveToWrapper(toClass(field.getBaseType())));
            }
        }
        for (AnnotatedMethod<?> method : annotatedType.getMethods()) {
            for (AnnotatedParameter<?> parameter : method.getParameters()) {
                if (isPropertyInjectionPoint(parameter)) {
                    customTypes.add(primitiveToWrapper(toClass(parameter.getBaseType())));
                }
            }
        }
        for (AnnotatedConstructor<?> constructor : annotatedType.getConstructors()) {
            for (AnnotatedParameter<?> parameter : constructor.getParameters()) {
                if (isPropertyInjectionPoint(parameter)) {
                    customTypes.add(primitiveToWrapper(toClass(parameter.getBaseType())));
                }
            }
        }
    }

    private static boolean isPropertyInjectionPoint(Annotated annotated) {
        return annotated.isAnnotationPresent(Property.class) && isStringConstructorPresent(annotated.getBaseType());
    }

    private static boolean isStringConstructorPresent(Type type) {
        for (Constructor<?> constructor : primitiveToWrapper(toClass(type)).getConstructors()) {
            Class<?>[] parameterTypes = constructor.getParameterTypes();
            if (parameterTypes.length == 1 && String.class.equals(parameterTypes[0])) {
                return true;
            }
        }
        return false;
    }

    private boolean isProducePropertyBean(Bean<?> bean) {
        if (bean.getTypes().size() > 1) {
            return false;
        }
        if (!bean.getTypes().contains(Object.class)) {
            return false;
        }
        for (Annotation annotation : bean.getQualifiers()) {
            if (annotation.annotationType().equals(Property.class)) {
                return true;
            }
        }
        return false;
    }

    private <T> Bean<T> createProducePropertyBean(Bean<T> bean, Class<?> type) {
        return new ProducePropertyBean<T>(bean, type);
    }

    private class ProducePropertyBean<T> extends DelegatingBean<T> {

        private Class<?> type;

        public ProducePropertyBean(Bean<T> delegateBean, Class<?> type) {
            super(delegateBean);
            notNull(type);
            this.type = type;
        }

        @Override
        public Set<Type> getTypes() {
            return Collections.<Type>singleton(type);
        }

        @Override
        public boolean isNullable() {
            if (isWrapperType()) {
                return false;
            }
            return super.isNullable();
        }

        private boolean isWrapperType() {
            return wrapperToPrimitive(type) != null;
        }
    }
}