MentaContainer

Rev

Rev 2 | Rev 20 | 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.Container;
import org.mentacontainer.util.InjectionUtils;

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.getMethod(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.getDependencyClass().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
                           // injected

        } catch (Exception e) {

            throw new RuntimeException(e);
        }
    }

    public Container ioc(String key, Class<? extends Object> klass, boolean singleton) {

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

        Component c = new Component(klass, singleton);

        beans.put(key, c);

        return this;
    }

    public Container ioc(String key, Class<? extends Object> klass) {

        return ioc(key, klass, false);
    }

    public Container autowire(String property, Class<? extends Object> klass, String source) {

        Dependency d = new Dependency(property, klass, source);

        if (dependencies.contains(d)) throw new RuntimeException("Dependency is already set: " + property);
       
        if (!klass.isInterface()) throw new RuntimeException("Dependency must be an interface!");

        dependencies.add(d);

        return this;
    }

    public Container autowire(String property, Class<? extends Object> klass) {
        return autowire(property, klass, property);
    }

    public Container init(String key, Object value) {

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

        Component c = beans.get(key);

        c.addInitValue(value);

        return this;
    }

    public Container set(String key, String name, Object value) {

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

        Component c = beans.get(key);

        c.addProperty(name, value);

        return this;
    }

    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);
    }
}