/* * Copyright (C) 2011 Peransin Nicolas. * Use is subject to license terms. */ package org.mypsycho.beans; import java.beans.ExceptionListener; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import org.apache.commons.collections.FastHashMap; import org.mypsycho.beans.converter.ConverterContainer; import org.mypsycho.beans.converter.TypeConverter; import org.mypsycho.util.PropertiesLoader; /** * Class for ... * <p>Details</p> * * @author Peransin Nicolas * */ public class Injector extends PropertyUtilsBean { public static final String LOCALE_PROPERTY = "locale"; public static final String DEFAULT_DEPRECATED_TAG = "@deprecated"; public static final String DEFAULT_NULL_TAG = "@null"; private static String createKey(Locale locale, Class<?> since) { String className = since.getCanonicalName(); if (className == null) { // anonymous or inner className = since.getName(); } return locale + "@" + className; } @SuppressWarnings("unchecked") Map<String, InjectDescriptor> descriptors = new FastHashMap(); // ThreadSafe Locale locale = Locale.getDefault(); ConverterContainer converter = new ConverterContainer(); InjectionTemplate template = new InjectionTemplate(); ExceptionListener exceptionHandler = null; // Cannot use a Set as property descriptor has a unextensive equals // Cannot use a Set as preemptive order is not defined. List<DescriptorExtension> extensions = new ArrayList<DescriptorExtension>(); private final static PropertiesLoader DEFAULT_LOADER = new PropertiesLoader() { @Override protected Class<?> until(Class<?> type) { Inject inject = type.getAnnotation(Inject.class); if ((inject == null) || (inject.until() == null) || inject.until().isInterface() || !inject.until().isAssignableFrom(type)) { return null; } return inject.until(); } }; private PropertiesLoader valuesLoader = DEFAULT_LOADER; private String deprecated = DEFAULT_DEPRECATED_TAG; private String nullTag = DEFAULT_NULL_TAG; public Injector() { ((FastHashMap) descriptors).setFast(true); setInvoker(new ExtensionInvoker()); } public void addGlobals(Map<?, ?> globals) { valuesLoader.addGlobals(globals); } public void addGlobals(String prefix, Map<?, ?> globals) { valuesLoader.addGlobals(prefix, globals); } public void addGlobal(String key, String value) { valuesLoader.addGlobal(key, value); } @Override protected void notify(Object event, String detail, Throwable t) { if (listener == null) { return; } super.notify(event, detail, t); } public <T> T inject(T value) { return (value != null) ? inject(value, getLocale(value)) : null; } public <T> T inject(Object value, String path, T element) { return (value != null) ? inject(value, getLocale(value), path, element) : null; } public <T> T inject(T value, Locale locale) { return inject(value, locale, null, value); } public <T> T inject(Object parent, Locale locale, String path, T element) { if ((parent == null) || (element == null)) { return null; } String key = createKey(locale, parent.getClass()); InjectDescriptor descr = descriptors.get(key); if (descr == null) { descr = createDescriptor(locale, parent.getClass()); if (!descr.hasChildren()) { descr = InjectDescriptor.EMPTY; } descriptors.put(key, descr); } descr.inject(parent, path, element); return element; } /** * Do something TODO. * <p> * Details of the function. * </p> * * @param locale2 * @param class1 * @return */ protected InjectDescriptor createDescriptor(Locale locale, Class<? extends Object> clazz) { return new InjectDescriptor(this, clazz, locale); } public Locale getLocale(Object bean) { try { PropertyDescriptor prop = getPropertyDescriptor(bean, LOCALE_PROPERTY); if ((prop != null) && Locale.class.equals(getInvoker().getPropertyType(prop, false))) { Locale locale = (Locale) getSimpleProperty(bean, LOCALE_PROPERTY); if (locale != null) { return locale; } } } catch (Exception e) { } return getLocale(); } @Override public PropertyDescriptor[] createDescriptorsCache(Class<?> beanClass) throws IntrospectionException { PropertyDescriptor[] cache = super.createDescriptorsCache(beanClass); List<PropertyDescriptor> extendeds = new ArrayList<PropertyDescriptor>(); Set<String> names = new HashSet<String>(); for (DescriptorExtension extension : extensions) { if (extension.getType().isAssignableFrom(beanClass)) { extendeds.add(extension); names.add(extension.getName()); } } if (extendeds.isEmpty()) { return cache; } for (PropertyDescriptor buildIn : cache) { if (!names.contains(buildIn.getName())) { extendeds.add(buildIn); } } return extendeds.toArray(new PropertyDescriptor[extendeds.size()]); } /** * Do something TODO. * <p> * Details of the function. * </p> * * @param type * @return */ public Map<String, String> getValue(Class<?> type, Locale locale) { return valuesLoader.getProperties(type, locale); } /** * Returns the locale. * * @return the locale */ public Locale getLocale() { return locale; } /** * Sets the locale. * * @param locale the locale to set */ public void setLocale(Locale locale) { if (locale == null) { throw new NullPointerException(); } this.locale = locale; } /** * Returns the converter. * * @return the converter */ public TypeConverter getConverter() { return converter; } /** * Sets the converter. * * @param converter the converter to set */ public void register(TypeConverter extension) { converter.register(extension); } public void register(DescriptorExtension extension) { extensions.add(0, extension); } public void register(CollectionExtension extension) { ((ExtensionInvoker) getInvoker()).register(extension); } /** * Returns the deprecated. * * @return the deprecated */ public String getDeprecated() { return deprecated; } /** * Sets the deprecated. * * @param deprecated the deprecated to set */ public void setDeprecated(String deprecated) { if (deprecated == null) { throw new NullPointerException(); } this.deprecated = deprecated; clearDescriptors(); } /** * Returns the nullTag. * * @return the nullTag */ public String getNullTag() { return nullTag; } /** * Sets the nullTag. * * @param nullTag the nullTag to set */ public void setNullTag(String nullTag) { if (nullTag == null) { throw new NullPointerException(); } this.nullTag = nullTag; clearDescriptors(); } /** * Returns the template. * * @return the template */ public InjectionTemplate getTemplate() { return template; } /** * Sets the template. * * @param template the template to set */ public void setTemplate(InjectionTemplate template) { if (template == null) { throw new NullPointerException(); } this.template = template; clearDescriptors(); } }