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

Java tutorial

Introduction

Here is the source code for de.openknowledge.cdi.common.property.PropertiesLoader.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 java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Properties;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.inject.Inject;

import org.apache.commons.lang.ClassUtils;

import de.openknowledge.cdi.common.property.source.PropertyProvider;
import de.openknowledge.cdi.common.qualifier.Current;

/**
 * Our property source.
 *
 * @author Arne Limburg - open knowledge GmbH
 * @author Jens Schumann - open knowledge GmbH
 */
@ApplicationScoped
public class PropertiesLoader {

    @Inject
    @Current
    private ApplicationProperties currentValues = new ApplicationProperties();

    @Inject
    private PropertyProvider provider;

    @Produces
    @Property(name = "any")
    public Properties produceWildcardProperties(InjectionPoint injectionPoint) {
        return provider.getPropertyValues(injectionPoint);
    }

    /**
     * Creates an object, assuming the object has a constructor that takes a {@link String} argument.
     * The type of the object is determined from the type of the specified injection point.
     * The value for the constructor argument of type {@link String} is taken from the {@link Property}
     * specified at the injection point.
     * 
     * @param injectionPoint the injection point to get the type and the property from
     * @return the value which's type depends on the type of the injection point
     */
    @Produces
    @Property(name = "any")
    public Object produceProperty(InjectionPoint injectionPoint) {
        Class<?> type = toClass(injectionPoint.getType());
        return newInstance(injectionPoint, getPropertyValue(injectionPoint, type),
                ClassUtils.primitiveToWrapper(type));
    }

    /**
     * Creates a {@link Character} object from the specified injection point.
     * The character value is taken from the {@link Property} specified at the injection point.
     * This method is needed in addition to {@link #produceProperty(InjectionPoint)} since
     * {@link Character} has no constructor that takes a {@link String} argument.
     * 
     * @param injectionPoint the injection point to get the property from
     * @return the character value
     */
    @Produces
    @Property(name = "any")
    public Character produceCharacterProperty(InjectionPoint injectionPoint) {
        Class<?> type = toClass(injectionPoint.getType());
        String value = getPropertyValue(injectionPoint, type);
        if (value.length() != 1) {
            throw buildIllegalArgumentException(injectionPoint, value, type, null);
        }
        return value.charAt(0);
    }

    protected String getPropertyValue(InjectionPoint injectionPoint, Class<?> targetType) {
        String value = provider.getPropertyValue(injectionPoint);
        assertPrimitiveNotNull(injectionPoint, value, targetType);
        currentValues.registerPropertyValue(injectionPoint, value);
        return value;
    }

    static Class<?> toClass(Type type) {
        if (type instanceof Class<?>) {
            return (Class<?>) type;
        } else if (type instanceof ParameterizedType) {
            return toClass(((ParameterizedType) type).getRawType());
        } else {
            throw new IllegalArgumentException("unsupported type for property injection: " + type);
        }
    }

    private <T> T newInstance(InjectionPoint injectionPoint, String value, Class<T> type) {
        if (value == null) {
            return null;
        }
        try {
            return type.getConstructor(String.class).newInstance(value);
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException(type.getName() + " must have String-constructor to be injected");
        } catch (IllegalAccessException e) {
            throw new IllegalArgumentException("String-constructor must be public");
        } catch (InstantiationException e) {
            throw buildIllegalArgumentException(injectionPoint, value, type, e);
        } catch (InvocationTargetException e) {
            throw buildIllegalArgumentException(injectionPoint, value, type, e.getTargetException());
        }
    }

    private void assertPrimitiveNotNull(InjectionPoint injectionPoint, String value, Class<?> expectedType) {
        if (expectedType.isPrimitive() && value == null) {
            throw buildIllegalArgumentException(injectionPoint, value, expectedType, null);
        }
    }

    private RuntimeException buildIllegalArgumentException(InjectionPoint injectionPoint, String value,
            Class<?> expectedType, Throwable cause) {
        StringBuilder messageBuilder = new StringBuilder();
        messageBuilder.append("Unable to convert ");
        if (value == null) {
            messageBuilder.append("null value");
        } else {
            messageBuilder.append('"').append(value).append('"');
        }
        messageBuilder.append(" to ").append(expectedType.getName());
        messageBuilder.append(" for injection point ").append(injectionPoint);
        return new IllegalArgumentException(messageBuilder.toString(), cause);
    }
}