Package ca.pgon.st.light

Source Code of ca.pgon.st.light.SmallBeansContainer$Bean

/*
    Small Tools - Some basic libraries for developing and testing http://www.pgon.ca/st
    Copyright (C) 2013 Small Tools (info@pgon.ca)

    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 ca.pgon.st.light;

import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;

import ca.pgon.st.light.exception.StLightException;

/**
* If you need some beans available in all your application, you do not want to have hard references and you do not want to use Spring, this class can provide you the basics features. You should use
* this class only if you have not too many beans to keep since it will use quite a lot of memories due to its indexing for faster retrieval.
*
* Here is the usage:
*
* <pre>
* SmallBeansContainer.addBean(new MyGlobalBean());
*
* SmallBeansContainer.getOnly(MyGlobalBean.class);
* </pre>
*
* @author Simon Levesque
*
*/
public final class SmallBeansContainer {

    public static class Bean {

        private String scope;
        private Object bean;
        private Class<?> type;
        private String name;

        public Bean(String scope, Object bean, Class<?> type, String name) {
            this.scope = scope;
            this.bean = bean;
            this.type = type;
            this.name = name;
        }

        public Object getBean() {
            return bean;
        }

        public String getName() {
            return name;
        }

        public String getScope() {
            return scope;
        }

        public Class<?> getType() {
            return type;
        }

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();

            if (scope != null) {
                sb.append("String: ").append(scope);
            }
            if (name != null) {
                sb.append(" Name: ").append(name);
            }
            if (type != null) {
                sb.append(" Type: ").append(type.getName());
            }

            return sb.toString();
        }

    }

    private static final String ERROR_NO_BEANS_OF_TYPE = "There are no beans of type ";

    private static final String ERROR_TOO_MANY_BEANS_OF_TYPE = "There are too many beans of type ";

    private static final Logger logger = Logger.getLogger(SmallBeansContainer.class.getName());

    // The main list
    private static Deque<Bean> beans = new ConcurrentLinkedDeque<Bean>();

    // Cached indexes
    private static Map<String, Deque<Bean>> beansByName = new ConcurrentHashMap<String, Deque<Bean>>();
    private static Map<Class<?>, Deque<Bean>> beansByType = new ConcurrentHashMap<Class<?>, Deque<Bean>>();
    private static AtomicInteger beansAmountCache = new AtomicInteger();

    /**
     * Add a bean in the bucket.
     *
     * @param bean
     *            the bean
     */
    public static void addBean(Object bean) {
        addBean(null, bean, null);
    }

    /**
     * Add a bean in the bucket.
     *
     * @param scope
     *            the scope of the bean
     * @param bean
     *            the bean
     */
    public static void addBean(String scope, Object bean) {
        addBean(scope, bean, null);
    }

    /**
     * Add a bean in the bucket.
     *
     * @param scope
     *            (optional) the scope of the bean
     * @param bean
     *            the bean
     * @param name
     *            (optional) the name
     */
    public static void addBean(String scope, Object bean, String name) {

        Assert.assertNotNull(bean, "The bean cannot be null");

        // Create the entry
        Class<?> type = bean.getClass();
        Bean beanEntry = new Bean(scope, bean, type, name);
        logger.log(Level.FINE, "Adding bean [{0}]. Now has [{1}] beans", new Object[] { beanEntry, beansAmountCache.incrementAndGet() });

        // Add in the list and maps
        beans.add(beanEntry);
        if (name != null) {
            putInMap(beansByName, beanEntry, name);
        }
        putInMap(beansByType, beanEntry, type);
    }

    /**
     * To remove all the registered beans.
     */
    public static void clearAllBeans() {
        beans.clear();
        beansByType.clear();
        beansByName.clear();
        beansAmountCache.set(0);
    }

    /**
     * Retrieve beans by their type or a subclass of this type.
     *
     * @param type
     *            the type
     * @return the beans
     */
    @SuppressWarnings("unchecked")
    public static <T> List<T> getAll(Class<T> type) {

        logger.log(Level.FINE, "Retrieving all beans of type [{0}]", type.getName());

        List<T> responses = new ArrayList<T>();
        // Check all the types
        for (Entry<Class<?>, Deque<Bean>> entry : beansByType.entrySet()) {
            if (type.isAssignableFrom(entry.getKey())) {
                Deque<Bean> beans = entry.getValue();
                for (Bean bean : beans) {
                    responses.add((T) bean.getBean());
                }
            }
        }

        return responses;
    }

    /**
     * Retrieve one and only one bean by its type or a subclass of this type. Throws an exception if there is 0 or more than 1 available.
     *
     * @param type
     *            the type
     * @return the bean
     */
    @SuppressWarnings("unchecked")
    public static <T> T getOnly(Class<T> type) {

        logger.log(Level.FINE, "Retrieving one bean of type [{0}]", type.getName());

        T response = null;
        // Check all the types
        for (Entry<Class<?>, Deque<Bean>> entry : beansByType.entrySet()) {
            if (type.isAssignableFrom(entry.getKey())) {
                Deque<Bean> beans = entry.getValue();
                if (beans.isEmpty()) {
                    continue;
                }
                if (beans.size() > 1) {
                    throw new StLightException(ERROR_TOO_MANY_BEANS_OF_TYPE + type.getName());
                }
                if (response != null) {
                    throw new StLightException(ERROR_TOO_MANY_BEANS_OF_TYPE + type.getName());
                }
                response = (T) beans.getFirst().getBean();
            }
        }

        // Check there is one
        if (response == null) {
            throw new StLightException(ERROR_NO_BEANS_OF_TYPE + type.getName());
        }

        return response;
    }

    /**
     * Retrieve one and only one bean by its type or a subclass of this type in the designed scope. Throws an exception if there is 0 or more than 1 available.
     *
     * @param type
     *            the type
     * @return the bean
     */
    @SuppressWarnings("unchecked")
    public static <T> T getOnlyByScope(Class<T> type, String scope) {

        logger.log(Level.FINE, "Retrieving one bean of type [{0}] in scope [{1}]", new Object[] { type.getName(), scope });

        T response = null;
        // Check all the types
        for (Entry<Class<?>, Deque<Bean>> entry : beansByType.entrySet()) {
            if (type.isAssignableFrom(entry.getKey())) {
                Deque<Bean> beans = entry.getValue();
                for (Bean bean : beans) {

                    if (!scope.equals(bean.getScope())) {
                        continue;
                    }
                    if (response != null) {
                        throw new StLightException(ERROR_TOO_MANY_BEANS_OF_TYPE + type.getName());
                    }
                    response = (T) bean.getBean();
                }
            }
        }

        // Check there is one
        if (response == null) {
            throw new StLightException(ERROR_NO_BEANS_OF_TYPE + type.getName());
        }

        return response;
    }

    /**
     * Add the bean to the map by using the specified key. It creates the list if is a new one.
     *
     * @param map
     * @param beanEntry
     * @param key
     */
    private static <T> void putInMap(Map<T, Deque<Bean>> map, Bean beanEntry, T key) {
        Deque<Bean> list = map.get(key);
        if (list == null) {
            list = new ConcurrentLinkedDeque<Bean>();
            map.put(key, list);
        }

        list.add(beanEntry);
    }

    private SmallBeansContainer() {
    }

}
TOP

Related Classes of ca.pgon.st.light.SmallBeansContainer$Bean

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.