MentaContainer

Rev

Rev 4 | Rev 22 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

package org.mentacontainer.impl;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.mentacontainer.Component;
import org.mentacontainer.Container;
import org.mentacontainer.Dependency;
import org.mentacontainer.util.InjectionUtils;

/**
 * The implementation of the IoC container.
 *
 * @author sergio.oliveira.jr@gmail.com
 */

public class MentaContainer implements Container {

        private Map<String, Component> beans = new HashMap<String, Component>();

        private Map<String, Object> singletons = new HashMap<String, Object>();

        private Set<Dependency> dependencies = new HashSet<Dependency>();

        public Object get(String key) {

                if (!beans.containsKey(key)) throw new RuntimeException("Container does not have this bean set: " + key);

                Component c = beans.get(key);

                Object target = null;

                try {

                        if (c.isSingleton()) {

                                if (singletons.containsKey(key)) {

                                        target = singletons.get(key);

                                        return target;

                                } else {

                                        target = c.getInstance();

                                        singletons.put(key, target);
                                }

                        } else {

                                target = c.getInstance();

                        }

                        if (target != null) {

                                for (Dependency d : dependencies) {

                                        // has dependency ?
                                        Method m = d.check(target.getClass());

                                        if (m != null) {

                                                String sourceKey = d.getSource();

                                                if (sourceKey.equals(key)) {

                                                        // cannot depend on itself... also avoid recursive StackOverflow...

                                                        continue;

                                                }

                                                Object source = get(sourceKey);

                                                boolean isAssignable = source != null && d.getType().isAssignableFrom(source.getClass());

                                                // check if we can find the dependency and if it is
                                                // assignable to the target dependency
                                                if (isAssignable) {

                                                        try {

                                                                // inject
                                                                m.invoke(target, source);

                                                        } catch (Exception e) {

                                                                throw new RuntimeException("Cannot inject dependency: method = " + (m != null ? m.getName() : "NULL") + " / source = "
                                                                        + (source != null ? source : "NULL") + " / target = " + target, e);

                                                        }

                                                }
                                        }
                                }
                        }

                        return target; // return target nicely with all the dependencies

                } catch (Exception e) {

                        throw new RuntimeException(e);
                }
        }

        public Component ioc(Component component) {
               
                String key = component.getName();

                if (beans.containsKey(key)) throw new RuntimeException("Container already set for the bean key: " + key);

                beans.put(key, component);

                return component;
        }
       
        public Component ioc(String key, Class<? extends Object> klass) {
               
                return ioc(new MentaComponent(key, klass));
        }
       
        public Component ioc(String key, Class<? extends Object> klass, boolean singleton) {
               
                return ioc(new MentaComponent(key, klass, singleton));
        }

        public Dependency autowire(Dependency d) {

                if (dependencies.contains(d)) throw new RuntimeException("Dependency is already set: " + d.getTarget());

                dependencies.add(d);

                return d;
        }

        public Dependency autowire(String property, Class<? extends Object> klass) {
               
                return autowire(property, klass, property);
        }
       
        public Dependency autowire(String property, Class<? extends Object> klass, String source) {
               
                return autowire(new MentaDependency(property, klass, source));
        }

        public Container populate(Object bean) throws Exception {

                InjectionUtils.getObject(bean, this, false, null, true, false, true);

                return this;
        }

        public boolean contains(String key) {

                return beans.containsKey(key);
        }
}