Coverage Report - org.simject.SimFactory
 
Classes in this File Line Coverage Branch Coverage Complexity
SimFactory
95%
70/74
90%
27/30
0
 
 1  
 /*
 2  
  * Copyright 2008 Simon Martinelli, Rebenweg 32, 3236 Gampelen, Switzerland
 3  
  *
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  *      http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.simject;
 17  
 
 18  
 import java.io.FileNotFoundException;
 19  
 import java.io.InputStream;
 20  
 import java.lang.annotation.Annotation;
 21  
 import java.lang.reflect.Field;
 22  
 import java.net.MalformedURLException;
 23  
 import java.util.HashMap;
 24  
 import java.util.Map;
 25  
 import java.util.logging.Level;
 26  
 import java.util.logging.Logger;
 27  
 
 28  
 import javax.persistence.EntityManager;
 29  
 import javax.persistence.EntityManagerFactory;
 30  
 import javax.persistence.Persistence;
 31  
 import javax.xml.bind.JAXBContext;
 32  
 import javax.xml.bind.Unmarshaller;
 33  
 
 34  
 import org.simject.exception.SimConfigException;
 35  
 import org.simject.exception.SimResourceNotFoundException;
 36  
 import org.simject.jaxb.Property;
 37  
 import org.simject.jaxb.Resource;
 38  
 import org.simject.jaxb.Resources;
 39  
 import org.simject.remoting.client.HttpClientProxy;
 40  
 import org.simject.util.SimConstants;
 41  
 
 42  
 /**
 43  
  * SimFactory represents the IOC container. It parses the XML configuration
 44  
  * files, does the dependency injection and provides methods for retrieving
 45  
  * resources.
 46  
  * 
 47  
  * @author Simon Martinelli
 48  
  */
 49  
 public class SimFactory {
 50  
 
 51  1
         private static final Logger logger = Logger.getLogger(SimFactory.class
 52  
                         .getName());
 53  
 
 54  
         /**
 55  
          * Container holding all configured resources
 56  
          */
 57  7
         final private Map<Class<?>, Object> resourceMap = new HashMap<Class<?>, Object>();
 58  
 
 59  
         /**
 60  
          * Constructor that takes 0-n configuration files
 61  
          * 
 62  
          * @param fileNames
 63  
          */
 64  7
         public SimFactory(final String... fileNames) {
 65  
 
 66  13
                 for (String fileName : fileNames) {
 67  7
                         this.loadXmlConfig(fileName);
 68  
                 }
 69  6
                 this.injectDependencies();
 70  6
         }
 71  
 
 72  
         /**
 73  
          * Generic method to retrieve a resource identified by <type> If <type> is
 74  
          * an interface, <target> must be present. If <type> is
 75  
          * javax.persistence.EntityManager a special treatment will occur
 76  
          * 
 77  
          * @param <T>
 78  
          *            type of resource
 79  
          * @param clazz
 80  
          *            must be the type configured in the config file
 81  
          * @return an instance of the desired type
 82  
          */
 83  
         @SuppressWarnings("unchecked")
 84  
         public <T> T getResource(final Class<T> clazz) {
 85  6
                 final Object obj = this.resourceMap.get(clazz);
 86  6
                 if (obj == null) {
 87  1
                         final String message = "Resource of type " + clazz.getName()
 88  
                                         + " not found";
 89  1
                         logger.severe(message);
 90  1
                         throw new SimResourceNotFoundException(message);
 91  
                 }
 92  5
                 return (T) obj;
 93  
         }
 94  
 
 95  
         /**
 96  
          * Uses JAXB to parse the config file
 97  
          * 
 98  
          * @param fileName
 99  
          */
 100  
         private void loadXmlConfig(final String fileName) {
 101  
                 try {
 102  7
                         logger.info("Loading configuration from <"
 103  
                                         + SimConstants.DEFAULT_DIRECTORY + fileName + ">");
 104  
 
 105  7
                         final JAXBContext jcontext = JAXBContext
 106  
                                         .newInstance("org.simject.jaxb");
 107  7
                         final Unmarshaller unmarshaller = jcontext.createUnmarshaller();
 108  
 
 109  7
                         final InputStream istream = Thread.currentThread()
 110  
                                         .getContextClassLoader().getResourceAsStream(
 111  
                                                         SimConstants.DEFAULT_DIRECTORY + fileName);
 112  
 
 113  7
                         if (istream == null) {
 114  1
                                 throw new FileNotFoundException(SimConstants.DEFAULT_DIRECTORY
 115  
                                                 + fileName + " not found");
 116  
                         } else {
 117  6
                                 final Resources resources = (Resources) unmarshaller
 118  
                                                 .unmarshal(istream);
 119  6
                                 for (Resource resource : resources.getResource()) {
 120  24
                                         this.createResource(resource);
 121  
                                 }
 122  
                         }
 123  1
                 } catch (Exception e) {
 124  1
                         logger.log(Level.SEVERE, e.getMessage(), e);
 125  1
                         throw new SimConfigException(e.getMessage(), e);
 126  6
                 }
 127  6
         }
 128  
 
 129  
         /**
 130  
          * Creates an new Resource and stores it in the resource container
 131  
          * 
 132  
          * @param resource
 133  
          *            the resource retrieved from config file
 134  
          * @throws ClassNotFoundException
 135  
          * @throws InstantiationException
 136  
          * @throws IllegalAccessException
 137  
          * @throws MalformedURLException
 138  
          */
 139  
         private void createResource(final Resource resource)
 140  
                         throws ClassNotFoundException, InstantiationException,
 141  
                         IllegalAccessException, MalformedURLException {
 142  
 
 143  24
                 final String className = resource.getType();
 144  24
                 final Class<?> clazz = Class.forName(className);
 145  
 
 146  24
                 Object obj = null;
 147  24
                 if (resource.getType().equals(EntityManager.class.getName())) {
 148  
                         // type is EntityManager
 149  6
                         obj = this.createEntityManager(resource);
 150  18
                 } else if (resource.getTarget() != null
 151  
                                 && resource.getTarget().contains("http://")) {
 152  
                         // target is URL
 153  6
                         obj = this.createHttpClientProxy(clazz, resource.getTarget());
 154  
                 } else {
 155  
                         // any other will create a POJO instance
 156  12
                         obj = this.createPojo(resource, clazz);
 157  
                 }
 158  24
                 this.resourceMap.put(clazz, obj);
 159  24
         }
 160  
 
 161  
         /**
 162  
          * Creates a HttpClientProxy
 163  
          * 
 164  
          * @param clazz
 165  
          * @param target
 166  
          * @return
 167  
          * @throws MalformedURLException
 168  
          */
 169  
         private Object createHttpClientProxy(final Class<?> clazz,
 170  
                         final String target) throws MalformedURLException {
 171  6
                 logger.info("Creating <" + clazz.getName() + "> for URL <" + target
 172  
                                 + ">");
 173  
 
 174  6
                 return HttpClientProxy.newInstance(Thread.currentThread()
 175  
                                 .getContextClassLoader(), new Class[] { clazz }, target);
 176  
         }
 177  
 
 178  
         /**
 179  
          * Creates a simple POJO instance
 180  
          * 
 181  
          * @param resource
 182  
          * @param clazz
 183  
          * @return
 184  
          * @throws InstantiationException
 185  
          * @throws IllegalAccessException
 186  
          * @throws ClassNotFoundException
 187  
          */
 188  
         private Object createPojo(final Resource resource, final Class<?> clazz)
 189  
                         throws InstantiationException, IllegalAccessException,
 190  
                         ClassNotFoundException {
 191  
 
 192  12
                 Object obj = null;
 193  12
                 if (resource.getTarget() == null || resource.getTarget().equals("")) {
 194  6
                         logger.info("Creating <" + resource.getType() + ">");
 195  6
                         obj = createInstance(clazz);
 196  
                 } else {
 197  6
                         logger.info("Creating <" + resource.getType() + "> as <"
 198  
                                         + resource.getTarget() + ">");
 199  6
                         final String realizedby = resource.getTarget();
 200  6
                         final Class<?> realizedbyClazz = Class.forName(realizedby);
 201  6
                         obj = createInstance(realizedbyClazz);
 202  
                 }
 203  12
                 return obj;
 204  
         }
 205  
 
 206  
         /**
 207  
          * Creates a JPA EntityManager
 208  
          * 
 209  
          * @param resource
 210  
          * @return
 211  
          */
 212  
         private Object createEntityManager(final Resource resource) {
 213  
 
 214  6
                 logger.info("Creating <" + resource.getType() + ">");
 215  
 
 216  6
                 final Map<String, String> props = new HashMap<String, String>();
 217  6
                 for (Property property : resource.getProperty()) {
 218  42
                         props.put(property.getName(), property.getValue());
 219  
                 }
 220  6
                 final EntityManagerFactory emf = Persistence
 221  
                                 .createEntityManagerFactory(resource.getName(), props);
 222  6
                 return emf.createEntityManager();
 223  
         }
 224  
 
 225  
         /**
 226  
          * Creates an instance of the provided Class. If Class is an Interface an
 227  
          * Exception is thrown.
 228  
          * 
 229  
          * @param clazz
 230  
          * @return
 231  
          * @throws InstantiationException
 232  
          * @throws IllegalAccessException
 233  
          */
 234  
         private Object createInstance(final Class<?> clazz)
 235  
                         throws InstantiationException, IllegalAccessException {
 236  
 
 237  12
                 if (clazz.isInterface()) {
 238  0
                         throw new InstantiationException(
 239  
                                         "Can not instantiate a interface. Please check configuration");
 240  
                 }
 241  12
                 return clazz.newInstance();
 242  
         }
 243  
 
 244  
         /**
 245  
          * Loops over the resource container and does the dependency injection
 246  
          */
 247  
         private void injectDependencies() {
 248  
                 try {
 249  6
                         for (Object obj : this.resourceMap.values()) {
 250  24
                                 final Field[] fields = obj.getClass().getDeclaredFields();
 251  90
                                 for (Field field : fields) {
 252  66
                                         final Annotation[] annotations = field
 253  
                                                         .getDeclaredAnnotations();
 254  72
                                         for (Annotation annotation : annotations) {
 255  6
                                                 if (annotation.annotationType().equals(
 256  
                                                                 javax.annotation.Resource.class)) {
 257  6
                                                         final Class<?> clazz = field.getType();
 258  6
                                                         final Object value = this.resourceMap.get(clazz);
 259  6
                                                         field.setAccessible(true);
 260  6
                                                         field.set(obj, value);
 261  6
                                                         logger.info("Injecting instance of <"
 262  
                                                                         + value.getClass().getName()
 263  
                                                                         + "> into field <" + field.getName()
 264  
                                                                         + "> in class <" + obj.getClass().getName()
 265  
                                                                         + ">");
 266  
                                                 }
 267  
                                         }
 268  
                                 }
 269  24
                         }
 270  0
                 } catch (Exception e) {
 271  0
                         logger.log(Level.SEVERE, e.getMessage(), e);
 272  0
                         throw new SimConfigException(
 273  
                                         "Unable to inject dependencies. Please check the configuration",
 274  
                                         e);
 275  6
                 }
 276  6
         }
 277  
 }