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

com.nikedlab.android.inject.processors.DirectApplicationContext Maven / Gradle / Ivy

The newest version!
package com.nikedlab.android.inject.processors;

import android.app.Activity;
import android.content.Context;
import com.nikedlab.android.inject.Bean;
import com.nikedlab.android.inject.annotations.Autowired;
import com.nikedlab.android.inject.annotations.Component;
import com.nikedlab.android.inject.exceptions.BeanInstantiationException;
import com.nikedlab.android.inject.exceptions.BeanNotFoundException;
import com.nikedlab.android.inject.exceptions.InjectException;
import com.nikedlab.android.inject.extenders.SimpleInjector;
import com.nikedlab.android.inject.interfaces.ApplicationContext;
import com.nikedlab.android.inject.interfaces.BindingFactory;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

@SuppressWarnings("TypeParameterExplicitlyExtendsObject")
public class DirectApplicationContext implements ApplicationContext {

	private Map, Class> binding;
	private Map> bindingByName;
	private Map, Object> singletons;
	private Map singletonByName;
	private Map, BindingFactory> factories;
    private List beans;

	public DirectApplicationContext() {
		binding = new WeakHashMap, Class>();
		bindingByName = new WeakHashMap>();
		singletons = new WeakHashMap, Object>();
		singletonByName = new WeakHashMap();
		factories = new WeakHashMap, BindingFactory>();
	}
	
	public void bind(Class interfaceClass, Class implementationClass) {
		binding.put(interfaceClass, implementationClass);
	}
	
	public void bind(Class implementationClass) {
		Component component = implementationClass.getAnnotation(Component.class);
		if (component != null) {
			if (component.value() != null) {
				bindingByName.put(component.value(), implementationClass);
			}
		}
		binding.put(implementationClass, implementationClass);
	}
	
	public void bindInstance(Class interfaceClass, Object singleton) {
		singletons.put(interfaceClass, singleton);
	}

	public void bindFactory(Class interfaceClass, BindingFactory factory) {
		factories.put(interfaceClass, factory);
	}

    @Override
    public void setConfig(List beans) {
        this.beans = beans;
    }

    public void inject(Object target) {
		Class targetClass = target.getClass();
		Method[] methods = targetClass.getMethods();
		for (Method method : methods) {
			if (method.getName().startsWith("set")) {
				Autowired inject = method.getAnnotation(Autowired.class);
				if (inject != null) {
					injectParameters(target, method);
				}
			}
		}
	}
	
	/**
	 * {@inheritDoc}
	 */
	@SuppressWarnings("unchecked")
    public  T getBean(Class interfaceClass) {
        return (T) getSingleton(interfaceClass);
	}
	
	/**
	 * {@inheritDoc}
	 */
	@SuppressWarnings("unchecked")
	public  T getBean(String name) {
        return (T) getSingleton(name);
	}

	/**
	 * {@inheritDoc}
	 */
	public  boolean containsType(Class interfaceClass) {
        return (singletons.containsKey(interfaceClass) || binding.containsKey(interfaceClass) || factories.containsKey(interfaceClass));
	}

	private void injectParameters(Object target, Method method) {
		Class[] parameterTypes = method.getParameterTypes();
		Object[] parameters = new Object[parameterTypes.length];
		int parameterIndex = 0;
		boolean allParametersInstantiated = true;
		for (Class parameterType : parameterTypes) {
			if (singletons.containsKey(parameterType) || binding.containsKey(parameterType) || factories.containsKey(parameterType)) {
				parameters[parameterIndex] = getSingleton(parameterType);
			} else {
				allParametersInstantiated = false;
			}
			parameterIndex++;
		}
		if (allParametersInstantiated) {
			try {
				method.invoke(target, parameters);
			} catch (IllegalArgumentException e) {
				throw new InjectException(e);
			} catch (IllegalAccessException e) {
				throw new InjectException(e);
			} catch (InvocationTargetException e) {
				throw new InjectException(e);
			}
		}
	}

	private synchronized Object getSingleton(Class parameterType) {

		Object singleton;
		if (singletons.containsKey(parameterType)) {
			singleton = singletons.get(parameterType);
		} else {
			if (factories.containsKey(parameterType)) {
				BindingFactory factory = factories.get(parameterType);
				singleton = factory.getBinding();
			} else if (binding.containsKey(parameterType)) {
				Class implementationClass = binding.get(parameterType);
				if (implementationClass == null) {
					throw new BeanNotFoundException("no binding found for type: " + parameterType.toString());
				}
				singleton = createSingleton(implementationClass);
			} else {
				throw new InjectException("Failed to find binding for type: " + parameterType.getCanonicalName());
			}
			singletons.put(parameterType, singleton);
		}
		return singleton;
	}

    private synchronized Object getSingleton(String name) {

		Object singleton;
		if (singletonByName.containsKey(name)) {
			singleton = singletonByName.get(name);
		} else {
			Class implementationClass = bindingByName.get(name);
			if (implementationClass == null) {
				throw new BeanNotFoundException("no binding found for name: " + name);
			}
			singleton = createSingleton(implementationClass);
			singletonByName.put(name, singleton);
		}
		return singleton;
	}

	private Object createSingleton(Class implementationClass) {
        Object singleton = null;
		try {
            Bean bean = _getCurrentBean(implementationClass);
            if (bean.isSystemService()) {
                singleton = _getSystemService(bean.getClazz());
            } else if (bean.getArgs().size() > 0) {
                singleton = _composeInstanceWithConstructor(implementationClass, bean);
            } else if (bean.isSingleton()) {
                boolean isReallySingleton = bean.isSingleton();
                if (!isReallySingleton) {
                    singleton = implementationClass.newInstance();
                } else {
                    Method method = implementationClass.getMethod("getInstance", new Class[0]);
                    singleton = method.invoke(implementationClass);
                }
            } else if (SimpleInjector.class.isAssignableFrom(implementationClass)){
                singleton = implementationClass.newInstance();
            } else {
                singleton = implementationClass.newInstance();
            }

		    Component component = implementationClass.getAnnotation(Component.class);
		    if (component != null) {
		        inject(singleton);
		    }
		} catch (InstantiationException e) {
			throw new BeanInstantiationException(e);
		} catch (IllegalAccessException e) {
			throw new BeanInstantiationException(e);
		} catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return singleton;
	}

    private Object _getSystemService(String clazz) {
        Context context = getBean(Context.class);

        Object result = null;
        if ("android.app.admin.DevicePolicyManager".equals(clazz)) {
            result = context.getSystemService(Context.DEVICE_POLICY_SERVICE);
        } else  if ("android.telephony.TelephonyManager".equals(clazz)) {
            result = context.getSystemService(Context.TELEPHONY_SERVICE);
        } else if ("android.media.AudioManager".equals(clazz)) {
            result = context.getSystemService(Context.AUDIO_SERVICE);
        } else if ("android.os.PowerManager".equals(clazz)) {
            result = context.getSystemService(Context.POWER_SERVICE);
        } else if ("android.net.ConnectivityManager".equals(clazz)) {
            result = context.getSystemService(Context.CONNECTIVITY_SERVICE);
        } else if ("android.os.Vibrator".equals(clazz)) {
            result = context.getSystemService(Context.VIBRATOR_SERVICE);
        } else if ("android.net.wifi.WifiManager".equals(clazz)) {
            result = context.getSystemService(Context.WIFI_SERVICE);
        } else if ("android.location.LocationManager".equals(clazz)) {
            result = context.getSystemService(Context.LOCATION_SERVICE);
        } else if ("android.app.NotificationManager".equals(clazz)) {
            result = context.getSystemService(Context.NOTIFICATION_SERVICE);
        } else if ("android.app.ActivityManager".equals(clazz)) {
            result = context.getSystemService( Activity.ACTIVITY_SERVICE );
        } else if ("android.view.WindowManager".equals(clazz)) {
            result = context.getSystemService( Context.WINDOW_SERVICE );
        }

        return result;
    }

    private Object _composeInstanceWithConstructor(Class implementationClass, Bean bean) {

        List args = bean.getArgs();

        Constructor[] constructors = implementationClass.getDeclaredConstructors();
        for (Constructor item : constructors) {
            if (item.getParameterTypes().length == args.size()) {
                boolean coincidence = true;
                for (int i = 0; i < item.getParameterTypes().length; i++) {
                    Class[] parameters = item.getParameterTypes();
                    String name = _substituteKotlinTypes(parameters[i].getName());
                    if (!name.equals(args.get(i).getType())
                            && !name.equals(args.get(i).getReferral())
                            ) {
                        coincidence = false;
                        break;
                    }
                }

                boolean isSingleton = bean.isSingleton();
                if (coincidence) {
                    Object[] objParams = new Object[args.size()];
                    int i = 0;
                    for (Bean.Args arg : args) {

                        if (arg.getType().equals("int") || arg.getType().equals("java.lang.Integer")) {
                            objParams[i] = Integer.parseInt(arg.getValue());
                        } else if (arg.getType().equals("long") || arg.getType().equals("java.lang.Long")) {
                            objParams[i] = Long.parseLong(arg.getValue());
                        } else if (arg.getType().equals("java.lang.String")) {
                            objParams[i] = arg.getValue();
                        } else if (arg.getReferral() != null) {
                            try {
                                objParams[i] = getBean(Class.forName(arg.getReferral()));
                            } catch (ClassNotFoundException e) {
                                e.printStackTrace();
                            }
                        } else if (bean.isSingleton()) {
                            break;
                        } else if (arg.getType().equals("android.content.Context")) {
                            objParams[i] = getBean(Context.class);
                        }


                        i++;
                    }
                    try {
                        if (!isSingleton) {
                            return item.newInstance(objParams);
                        } else {

                            Class[] classes = new Class[args.size()];
                            Object[] objects = new Object[args.size()];
                            int j = 0;
                            for (Bean.Args arg : args) {
                                Class aClass = Class.forName(arg.getType());
                                classes[j] = aClass;
                                if ("".equals(arg.getValue()) && null == arg.getReferral()) {
                                    objects[j] = getBean(aClass);
                                } else if ("".equals(arg.getValue()) && null != arg.getReferral()) {
                                    objects[j] = getBean(aClass);
                                } else if (!"".equals(arg.getValue())) {
                                    if (arg.getType().equals("int") || arg.getType().equals("java.lang.Integer")) {
                                        objects[j] = Integer.parseInt(arg.getValue());
                                    } else if (arg.getType().equals("long") || arg.getType().equals("java.lang.Long")) {
                                        objects[j] = Long.parseLong(arg.getValue());
                                    } else if (arg.getType().equals("java.lang.String")) {
                                        objects[j] = arg.getValue();
                                    }
                                }
                                j++;
                            }
                            Method method = implementationClass.getMethod("getInstance", classes);
                            return method.invoke(implementationClass, objects);
                        }
                    } catch (InstantiationException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        return null;
    }

    private String _substituteKotlinTypes(String name) {
        String newName = name;
        if (name.equals("Int") || name.equals("int")) {
            newName = "java.lang.Integer";
        }
        return newName;
    }

    /**
     * Getter for current handled bean
     * @param implementationClass Class for injecting
     * @return Bean object {@link Bean}
     */
    private Bean _getCurrentBean(Class implementationClass) {
        for (Bean item : beans) {
            if (item.getClazz().equals(implementationClass.getName())) {
                return item;
            }
        }
        return null;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy