package com.horstmann.violet.framework.injection.resources; import java.awt.Image; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.Locale; import java.util.ResourceBundle; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; import javax.swing.JMenu; import javax.swing.JMenuItem; import com.horstmann.violet.framework.injection.resources.annotation.ResourceBundleBean; /** * This class can inject external values into object attributes. To do that, it uses the {@link ResourceBundleBean} * annotation. Injected objects are created using the {@link ResourceFactory} * * * @author Alexandre de Pellegrin * */ public class ResourceBundleInjector { /** * Unique instance */ private static ResourceBundleInjector instance; /** * Singleton constructor */ private ResourceBundleInjector() { // Singleton pattern } /** * @return injector instance */ public static ResourceBundleInjector getInjector() { if (ResourceBundleInjector.instance == null) { ResourceBundleInjector.instance = new ResourceBundleInjector(); } return ResourceBundleInjector.instance; } /** * Injects values into object attributes if they are correctly annoted * * @param o which need injection */ public void inject(Object o) { ResourceBundle classResourceBundle = getPropertyFile(o); Class<?> referencedClass = getReferencedClass(o); ResourceFactory classResourceFactory = new ResourceFactory(classResourceBundle, referencedClass); // Injects on constructors for (Constructor<?> aConstructor : o.getClass().getDeclaredConstructors()) { for (Annotation annotation : aConstructor.getAnnotations()) { Class<? extends Annotation> annotationType = annotation.annotationType(); if (annotationType.equals(ResourceBundleBean.class)) { ResourceBundleBean constructorAnnotation = (ResourceBundleBean) annotation; injectState(o, constructorAnnotation, classResourceFactory); } } } // Injects on fields for (Field aField : o.getClass().getDeclaredFields()) { for (Annotation annotation : aField.getAnnotations()) { Class<? extends Annotation> annotationType = annotation.annotationType(); if (annotationType.equals(ResourceBundleBean.class)) { ResourceBundleBean propertyAnnotation = (ResourceBundleBean) annotation; try { aField.setAccessible(true); if (!propertyAnnotation.resourceReference().equals(Object.class)) { ResourceBundle fieldResourceBundle = ResourceBundle.getBundle(propertyAnnotation.resourceReference() .getName(), Locale.getDefault()); ResourceFactory fieldResourceFactory = new ResourceFactory(fieldResourceBundle, o.getClass()); injectValue(o, aField, propertyAnnotation, fieldResourceFactory); } else { injectValue(o, aField, propertyAnnotation, classResourceFactory); } } catch (IllegalAccessException e) { throw new RuntimeException("Error while injecting external property values", e); } } } } } /** * Gets the correct property file. * * @param o object which need injection * @return resource bundle found */ private ResourceBundle getPropertyFile(Object o) { Class<?> referencedClass = getReferencedClass(o); return ResourceBundle.getBundle(referencedClass.getName(), Locale.getDefault()); } /** * Gets the referenced class * * @param o object which need injection * @return the corresponding class or the class declared in ResourceBundleBean.resourceReference() */ private Class<?> getReferencedClass(Object o) { for (Annotation annotation : o.getClass().getAnnotations()) { Class<? extends Annotation> annotationType = annotation.annotationType(); if (annotationType.equals(ResourceBundleBean.class)) { ResourceBundleBean propertyAnnotation = (ResourceBundleBean) annotation; Class ref = propertyAnnotation.resourceReference(); if (!Object.class.equals(ref)) { return ref; } } } return o.getClass(); } /** * Injects values * * @param concernedObject = object which need injection * @param field = field to inject * @param annotation = current field annotation * @param resourceFactory = resource factory belonging to the concernedObject * @throws IllegalAccessException if field is not accessible */ private void injectValue(Object concernedObject, Field field, ResourceBundleBean annotation, ResourceFactory resourceFactory) throws IllegalAccessException { String propertyPrefix = (!"".equals(annotation.key()) ? annotation.key() : field.getName()); Class<?> fieldType = field.getType(); if (fieldType.equals(String.class)) { String value = resourceFactory.createString(propertyPrefix); field.set(concernedObject, value); } if (fieldType.equals(ImageIcon.class)) { ImageIcon value = resourceFactory.createIcon(propertyPrefix); field.set(concernedObject, value); } if (fieldType.equals(Image.class)) { Image value = resourceFactory.createImage(propertyPrefix); field.set(concernedObject, value); } if (fieldType.equals(JButton.class)) { JButton value = resourceFactory.createButton(propertyPrefix); field.set(concernedObject, value); } if (fieldType.equals(JMenu.class)) { JMenu value = resourceFactory.createMenu(propertyPrefix); field.set(concernedObject, value); } if (fieldType.equals(JMenuItem.class)) { JMenuItem value = resourceFactory.createMenuItem(propertyPrefix); field.set(concernedObject, value); } if (fieldType.equals(JCheckBoxMenuItem.class)) { JMenuItem value = resourceFactory.createCheckBoxMenuItem(propertyPrefix); field.set(concernedObject, value); } } /** * Configures an object * * @param concernedObject * @param annotation * @param resourceFactory */ private void injectState(Object concernedObject, ResourceBundleBean annotation, ResourceFactory resourceFactory) { Class<?> clazz = concernedObject.getClass(); String propertyPrefix = annotation.key(); if ("".equals(propertyPrefix)) { return; } if (JMenu.class.isAssignableFrom(clazz)) { resourceFactory.configureMenu((JMenu) concernedObject, propertyPrefix); } } }