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

com.tacitknowledge.flip.FeatureServiceReflectionFactory Maven / Gradle / Ivy

The newest version!
/* Copyright 2012 Tacit Knowledge
*
* 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.tacitknowledge.flip;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Properties;

import org.apache.commons.lang3.ArrayUtils;

import com.google.common.collect.Lists;
import com.tacitknowledge.flip.context.FlipContext;
import com.tacitknowledge.flip.properties.FlipProperty;
import com.tacitknowledge.flip.properties.PropertyReader;
import com.tacitknowledge.flip.spi.ServiceProvider;

/**
 * Feature Service factory that creates {@link FeatureService} leveraging
 * reflection capabilities. This factory should be used when there is no DI
 * that is used within the system, and we want to leave responsibility 
 * of finding and instantiating {@link PropertyReader}s and Context Providers
 * to the reflection engine.
 * 
 * @author Serghei Soloviov 
 * @author Petric Coroli 
 */
public class FeatureServiceReflectionFactory extends AbstractFeatureServiceFactory
{
    private static final FeatureServiceReflectionFactory instance = new FeatureServiceReflectionFactory();

    /**
     * Instance method for {@link FeatureServiceReflectionFactory}
     * @return instance of {@link FeatureServiceReflectionFactory}
     */
    public static FeatureServiceReflectionFactory getInstance()
    {
        return instance;
    }

    /**
     * Factory method that creates a {@link FeatureService} entity
     * based on the internal {@link Environment} data.
     * 
     * @return initialized entity of {@link FeatureService}
     */
    public FeatureService createFeatureService()
    {
        return createFeatureService(null, (String[]) null);
    }

    /**
     * Factory method that creates a {@link FeatureService} entity
     * with provided properties.
    
     * @param properties environment specific {@link Properties}
     * @return initialized entity of {@link FeatureService}
     */
    public FeatureService createFeatureService(final Properties properties)
    {
        return createFeatureService(properties, (String[]) null);
    }

    /**
     * Factory method that creates a {@link FeatureService} entity
     * and performs its internal initialization based on the provided list
     * of the packages, that are used for reflection lookup process.
     * 
     * @param packagesToSearch list of package names to take part in the 
     *      {@link ServiceProvider} search process with the purpose of
     *      initialization of the classes declared as {@link PropertyReader}s and
     *      Context Providers
     * @return
     */
    public FeatureService createFeatureService(final String... packagesToSearch)
    {
        return createFeatureService(null, packagesToSearch);
    }

    /**
     * 
     * @param properties environment specific {@link Properties} 
     * @param packagesToSearch list of package names to take part in the 
     *      {@link ServiceProvider} search process with the purpose of
     *      initialization of the classes declared as {@link PropertyReader}s and
     *      Context Providers
     * @return
     */
    public FeatureService createFeatureService(final Properties properties, final String... packagesToSearch)
    {
        final Environment environment = getEnvironment(properties, packagesToSearch);

        initializeEnvironment(environment);

        return new FeatureServiceImpl(environment);
    }

    /**
     * This method is used to create and initialize {@link Environment}
     * entity based on the configuration provided by properties
     * and packagesToSearch.
     * Note that "com.tacitknowledge.flip" is included by default into the
     * list of packages to perform reflection lookup operation.
     * 
     * @param properties environment specific {@link Properties}
     * @param packagesToSearch list of package names to take part in the 
     *      {@link ServiceProvider} search process with the purpose of
     *      initialization of the classes declared as {@link PropertyReader}s and
     *      Context Providers
     * @return an initialized {@link Environment} entity based on the provided
     *  properties and packagesToSearch
     */
    protected Environment getEnvironment(final Properties properties, String... packagesToSearch)
    {
        final Environment environment = new Environment();

        if (properties != null)
        {
            environment.setProperties(properties);
        }

        packagesToSearch = ArrayUtils.add(packagesToSearch, getClass().getPackage().getName());
        final ServiceProvider serviceProvider = new ServiceProvider(packagesToSearch);

        final List propertyReaders = Lists.newArrayList(serviceProvider.find(FlipProperty.class,
                PropertyReader.class));
        Collections.sort(propertyReaders, new FlipPriorityComparator());
        environment.setPropertyReaders(propertyReaders);

        final List contextProviders = Lists.newArrayList(serviceProvider.find(FlipContext.class));
        Collections.sort(contextProviders, new FlipPriorityComparator());
        environment.setContextProviders(contextProviders);

        return environment;
    }

    /**
     * Comparator for entities that are annotated with {@link FlipProperty}.
     * Comparison is made based on the  {@link FlipProperty#priority()} value of
     * {@link FlipProperty} annotation. Higher priority value means precedence. 
     */
    private static class FlipPriorityComparator implements Comparator
    {

        @Override
        public int compare(final Object o1, final Object o2)
        {
            if (!o1.getClass().isAnnotationPresent(FlipContext.class)
                    || !o2.getClass().isAnnotationPresent(FlipContext.class))
            {
                return -1;
            }

            final int priority1 = o1.getClass().getAnnotation(FlipContext.class).priority();
            final int priority2 = o2.getClass().getAnnotation(FlipContext.class).priority();
            return priority2 - priority1;
        }

    }
}