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

com.microsoft.windowsazure.services.core.DefaultBuilder Maven / Gradle / Ivy

There is a newer version: 0.4.6
Show newest version
/**
 * Copyright Microsoft Corporation
 * 
 * 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 com.microsoft.windowsazure.services.core;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;

import javax.inject.Inject;
import javax.inject.Named;

public class DefaultBuilder implements Builder, Builder.Registry {
    Map, Factory> factories;
    Map, List>> alterations;

    public DefaultBuilder() {
        factories = new HashMap, Factory>();
        alterations = new HashMap, List>>();
    }

    public static DefaultBuilder create() {
        DefaultBuilder builder = new DefaultBuilder();

        for (Builder.Exports exports : ServiceLoader.load(Builder.Exports.class)) {
            exports.register(builder);
        }

        return builder;
    }

    void addFactory(Class service, Factory factory) {
        factories.put(service, factory);
    }

    public  Builder.Registry add(Class service) {
        return add(service, service);
    }

    Constructor findInjectConstructor(Class implementation) {

        Constructor withInject = null;
        Constructor withoutInject = null;
        int count = 0;

        for (Constructor ctor : implementation.getConstructors()) {
            if (ctor.getAnnotation(Inject.class) != null) {
                if (withInject != null) {
                    throw new RuntimeException("Class must not have multple @Inject annotations: "
                            + implementation.getName());
                }
                withInject = ctor;
            }
            else {
                ++count;
                withoutInject = ctor;
            }
        }
        if (withInject != null) {
            return withInject;
        }
        if (count != 1) {
            throw new RuntimeException("Class without @Inject annotation must have one constructor: "
                    + implementation.getName());
        }
        return withoutInject;
    }

    public  Builder.Registry add(Class service, final Class implementation) {
        final Constructor ctor = findInjectConstructor(implementation);
        final Class[] parameterTypes = ctor.getParameterTypes();
        final Annotation[][] parameterAnnotations = ctor.getParameterAnnotations();

        addFactory(service, new Builder.Factory() {
            @SuppressWarnings("unchecked")
            public T create(String profile, Builder builder, Map properties) {
                Object[] initargs = new Object[parameterTypes.length];
                for (int i = 0; i != parameterTypes.length; ++i) {

                    boolean located = false;

                    String named = findNamedAnnotation(parameterAnnotations[i]);
                    String fullName = dotCombine(profile, named);

                    boolean probeProperties = fullName != null && fullName != "";
                    int startingIndex = 0;
                    while (!located && probeProperties) {
                        String probeName = fullName.substring(startingIndex);
                        if (!located && named != null && properties.containsKey(probeName)) {
                            located = true;
                            initargs[i] = properties.get(probeName);
                        }
                        else {
                            startingIndex = fullName.indexOf('.', startingIndex) + 1;
                            if (startingIndex == 0) {
                                probeProperties = false;
                            }
                        }
                    }

                    if (!located) {
                        located = true;
                        initargs[i] = builder.build(fullName, parameterTypes[i], properties);
                    }
                }

                try {
                    return (T) ctor.newInstance(initargs);
                }
                catch (InstantiationException e) {
                    throw new ConfigurationException(e);
                }
                catch (IllegalAccessException e) {
                    throw new ConfigurationException(e);
                }
                catch (InvocationTargetException e) {
                    throw new ConfigurationException(e);
                }
            }
        });
        return this;
    }

    protected String dotCombine(String profile, String named) {
        boolean noProfile = profile == null || profile == "";
        boolean noName = named == null || named == "";
        if (noName)
            return profile;
        if (noProfile)
            return named;
        return profile + "." + named;
    }

    protected String findNamedAnnotation(Annotation[] annotations) {
        for (Annotation annotation : annotations) {
            if (Named.class.isAssignableFrom(annotation.getClass())) {
                return ((Named) annotation).value();
            }
        }
        return null;
    }

    public  Registry add(Factory factory) {
        for (Type genericInterface : factory.getClass().getGenericInterfaces()) {
            ParameterizedType parameterizedType = (ParameterizedType) genericInterface;
            if (parameterizedType.getRawType().equals(Builder.Factory.class)) {
                Type typeArgument = parameterizedType.getActualTypeArguments()[0];
                addFactory((Class) typeArgument, factory);
            }
        }
        return this;
    }

    @SuppressWarnings("unchecked")
    public  T build(String profile, Class service, Map properties) {
        Factory factory = (Factory) factories.get(service);
        if (factory == null) {
            throw new RuntimeException("Service or property not registered: " + profile + " " + service.getName());
        }
        T instance = factory.create(profile, this, properties);
        List> alterationList = alterations.get(service);
        if (alterationList != null) {
            for (Alteration alteration : alterationList) {
                instance = ((Alteration) alteration).alter(instance, this, properties);
            }
        }
        return instance;
    }

    public  void alter(Class service, Alteration alteration) {
        if (!this.alterations.containsKey(service)) {
            this.alterations.put(service, new ArrayList>());
        }
        this.alterations.get(service).add(alteration);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy