Coverage report

  %line %branch
org.apache.turbine.services.factory.TurbineFactoryService
40% 
64% 

 1  
 package org.apache.turbine.services.factory;
 2  
 
 3  
 /*
 4  
  * Copyright 2001-2005 The Apache Software Foundation.
 5  
  *
 6  
  * Licensed under the Apache License, Version 2.0 (the "License")
 7  
  * you may not use this file except in compliance with the License.
 8  
  * You may obtain a copy of the License at
 9  
  *
 10  
  *     http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing, software
 13  
  * distributed under the License is distributed on an "AS IS" BASIS,
 14  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15  
  * See the License for the specific language governing permissions and
 16  
  * limitations under the License.
 17  
  */
 18  
 
 19  
 import java.io.ByteArrayInputStream;
 20  
 import java.io.ByteArrayOutputStream;
 21  
 import java.io.ObjectOutputStream;
 22  
 import java.util.ArrayList;
 23  
 import java.util.HashMap;
 24  
 import java.util.Iterator;
 25  
 import java.util.List;
 26  
 
 27  
 import org.apache.commons.configuration.Configuration;
 28  
 
 29  
 import org.apache.turbine.services.InitializationException;
 30  
 import org.apache.turbine.services.TurbineBaseService;
 31  
 import org.apache.turbine.util.TurbineException;
 32  
 import org.apache.turbine.util.pool.ObjectInputStreamForContext;
 33  
 
 34  
 /**
 35  
  * The Factory Service instantiates objects using specified
 36  
  * class loaders. If none is specified, the default one
 37  
  * will be used.
 38  
  *
 39  
  * @author <a href="mailto:ilkka.priha@simsoft.fi">Ilkka Priha</a>
 40  
  * @version $Id: TurbineFactoryService.java 264148 2005-08-29 14:21:04Z henning $
 41  
  */
 42  
 public class TurbineFactoryService
 43  
         extends TurbineBaseService
 44  
         implements FactoryService
 45  
 {
 46  
     /**
 47  
      * The property specifying a set of additional class loaders.
 48  
      */
 49  
     public static final String CLASS_LOADERS = "class.loaders";
 50  
 
 51  
     /**
 52  
      * The property prefix specifying additional object factories.
 53  
      */
 54  
     public static final String OBJECT_FACTORY = "factory.";
 55  
 
 56  
     /**
 57  
      * Primitive classes for reflection of constructors.
 58  
      */
 59  
     private static HashMap primitiveClasses;
 60  
 
 61  
     {
 62  48
         primitiveClasses = new HashMap(8);
 63  48
         primitiveClasses.put(Boolean.TYPE.toString(), Boolean.TYPE);
 64  48
         primitiveClasses.put(Character.TYPE.toString(), Character.TYPE);
 65  48
         primitiveClasses.put(Byte.TYPE.toString(), Byte.TYPE);
 66  48
         primitiveClasses.put(Short.TYPE.toString(), Short.TYPE);
 67  48
         primitiveClasses.put(Integer.TYPE.toString(), Integer.TYPE);
 68  48
         primitiveClasses.put(Long.TYPE.toString(), Long.TYPE);
 69  48
         primitiveClasses.put(Float.TYPE.toString(), Float.TYPE);
 70  48
         primitiveClasses.put(Double.TYPE.toString(), Double.TYPE);
 71  
     }
 72  
 
 73  
     /**
 74  
      * Additional class loaders.
 75  
      */
 76  48
     private ArrayList classLoaders = new ArrayList();
 77  
 
 78  
     /**
 79  
      * Customized object factories.
 80  
      */
 81  48
     private HashMap objectFactories = new HashMap();
 82  
 
 83  
     /**
 84  
      * Gets the class of a primitive type.
 85  
      *
 86  
      * @param type a primitive type.
 87  
      * @return the corresponding class, or null.
 88  
      */
 89  
     protected static Class getPrimitiveClass(String type)
 90  
     {
 91  40
         return (Class) primitiveClasses.get(type);
 92  
     }
 93  
 
 94  
     /**
 95  
      * Constructs a Factory Service.
 96  
      */
 97  
     public TurbineFactoryService()
 98  48
     {
 99  48
     }
 100  
 
 101  
     /**
 102  
      * Initializes the service by loading default class loaders
 103  
      * and customized object factories.
 104  
      *
 105  
      * @throws InitializationException if initialization fails.
 106  
      */
 107  
     public void init() throws InitializationException
 108  
     {
 109  50
         Configuration conf = getConfiguration();
 110  50
         if (conf != null)
 111  
         {
 112  50
             List loaders = conf.getList(CLASS_LOADERS);
 113  50
             if (loaders != null)
 114  
             {
 115  50
                 for (int i = 0; i < loaders.size(); i++)
 116  
                 {
 117  
                     try
 118  
                     {
 119  0
                         classLoaders.add(
 120  
                                 loadClass((String) loaders.get(i)).newInstance());
 121  
                     }
 122  0
                     catch (Exception x)
 123  
                     {
 124  0
                         throw new InitializationException(
 125  
                                 "No such class loader '" +
 126  
                                 (String) loaders.get(i) +
 127  
                                 "' for TurbineFactoryService", x);
 128  0
                     }
 129  
                 }
 130  
             }
 131  
 
 132  
             String key,factory;
 133  75
             for (Iterator i = conf.getKeys(OBJECT_FACTORY); i.hasNext();)
 134  
             {
 135  0
                 key = (String) i.next();
 136  0
                 factory = conf.getString(key);
 137  
 
 138  
                 /*
 139  
                  * Store the factory to the table as a string and
 140  
                  * instantiate it by using the service when needed.
 141  
                  */
 142  0
                 objectFactories.put(
 143  
                         key.substring(OBJECT_FACTORY.length()), factory);
 144  
             }
 145  
         }
 146  50
         setInit(true);
 147  50
     }
 148  
 
 149  
     /**
 150  
      * Gets an instance of a named class.
 151  
      *
 152  
      * @param className the name of the class.
 153  
      * @return the instance.
 154  
      * @throws TurbineException if instantiation fails.
 155  
      */
 156  
     public Object getInstance(String className)
 157  
             throws TurbineException
 158  
     {
 159  324
         if (className == null)
 160  
         {
 161  0
             throw new TurbineException(
 162  
                     new NullPointerException("String className"));
 163  
         }
 164  
 
 165  324
         Factory factory = getFactory(className);
 166  324
         if (factory == null)
 167  
         {
 168  
             Class clazz;
 169  
             try
 170  
             {
 171  324
                 clazz = loadClass(className);
 172  162
             }
 173  0
             catch (ClassNotFoundException x)
 174  
             {
 175  0
                 throw new TurbineException(
 176  
                         "Instantiation failed for class " + className, x);
 177  162
             }
 178  324
             return getInstance(clazz);
 179  
         }
 180  
         else
 181  
         {
 182  0
             return factory.getInstance();
 183  
         }
 184  
     }
 185  
 
 186  
     /**
 187  
      * Gets an instance of a named class using a specified class loader.
 188  
      *
 189  
      * <p>Class loaders are supported only if the isLoaderSupported
 190  
      * method returns true. Otherwise the loader parameter is ignored.
 191  
      *
 192  
      * @param className the name of the class.
 193  
      * @param loader the class loader.
 194  
      * @return the instance.
 195  
      * @throws TurbineException if instantiation fails.
 196  
      */
 197  
     public Object getInstance(String className,
 198  
             ClassLoader loader)
 199  
             throws TurbineException
 200  
     {
 201  0
         if (className == null)
 202  
         {
 203  0
             throw new TurbineException(
 204  
                     new NullPointerException("String className"));
 205  
         }
 206  
 
 207  0
         Factory factory = getFactory(className);
 208  0
         if (factory == null)
 209  
         {
 210  0
             if (loader != null)
 211  
             {
 212  
                 Class clazz;
 213  
                 try
 214  
                 {
 215  0
                     clazz = loadClass(className, loader);
 216  
                 }
 217  0
                 catch (ClassNotFoundException x)
 218  
                 {
 219  0
                     throw new TurbineException(
 220  
                             "Instantiation failed for class " + className, x);
 221  0
                 }
 222  0
                 return getInstance(clazz);
 223  
             }
 224  
             else
 225  
             {
 226  0
                 return getInstance(className);
 227  
             }
 228  
         }
 229  
         else
 230  
         {
 231  0
             return factory.getInstance(loader);
 232  
         }
 233  
     }
 234  
 
 235  
     /**
 236  
      * Gets an instance of a named class.
 237  
      * Parameters for its constructor are given as an array of objects,
 238  
      * primitive types must be wrapped with a corresponding class.
 239  
      *
 240  
      * @param className the name of the class.
 241  
      * @param params an array containing the parameters of the constructor.
 242  
      * @param signature an array containing the signature of the constructor.
 243  
      * @return the instance.
 244  
      * @throws TurbineException if instantiation fails.
 245  
      */
 246  
     public Object getInstance(String className,
 247  
             Object[] params,
 248  
             String[] signature)
 249  
             throws TurbineException
 250  
     {
 251  20
         if (className == null)
 252  
         {
 253  0
             throw new TurbineException(
 254  
                     new NullPointerException("String className"));
 255  
         }
 256  
 
 257  20
         Factory factory = getFactory(className);
 258  20
         if (factory == null)
 259  
         {
 260  
             Class clazz;
 261  
             try
 262  
             {
 263  20
                 clazz = loadClass(className);
 264  10
             }
 265  0
             catch (ClassNotFoundException x)
 266  
             {
 267  0
                 throw new TurbineException(
 268  
                         "Instantiation failed for class " + className, x);
 269  10
             }
 270  20
             return getInstance(clazz, params, signature);
 271  
         }
 272  
         else
 273  
         {
 274  0
             return factory.getInstance(params, signature);
 275  
         }
 276  
     }
 277  
 
 278  
     /**
 279  
      * Gets an instance of a named class using a specified class loader.
 280  
      * Parameters for its constructor are given as an array of objects,
 281  
      * primitive types must be wrapped with a corresponding class.
 282  
      *
 283  
      * <p>Class loaders are supported only if the isLoaderSupported
 284  
      * method returns true. Otherwise the loader parameter is ignored.
 285  
      *
 286  
      * @param className the name of the class.
 287  
      * @param loader the class loader.
 288  
      * @param params an array containing the parameters of the constructor.
 289  
      * @param signature an array containing the signature of the constructor.
 290  
      * @return the instance.
 291  
      * @throws TurbineException if instantiation fails.
 292  
      */
 293  
     public Object getInstance(String className,
 294  
             ClassLoader loader,
 295  
             Object[] params,
 296  
             String[] signature)
 297  
             throws TurbineException
 298  
     {
 299  0
         if (className == null)
 300  
         {
 301  0
             throw new TurbineException(
 302  
                     new NullPointerException("String className"));
 303  
         }
 304  
 
 305  0
         Factory factory = getFactory(className);
 306  0
         if (factory == null)
 307  
         {
 308  0
             if (loader != null)
 309  
             {
 310  
                 Class clazz;
 311  
                 try
 312  
                 {
 313  0
                     clazz = loadClass(className, loader);
 314  
                 }
 315  0
                 catch (ClassNotFoundException x)
 316  
                 {
 317  0
                     throw new TurbineException(
 318  
                             "Instantiation failed for class " + className, x);
 319  0
                 }
 320  0
                 return getInstance(clazz, params, signature);
 321  
             }
 322  
             else
 323  
             {
 324  0
                 return getInstance(className, params, signature);
 325  
             }
 326  
         }
 327  
         else
 328  
         {
 329  0
             return factory.getInstance(loader, params, signature);
 330  
         }
 331  
     }
 332  
 
 333  
     /**
 334  
      * Tests if specified class loaders are supported for a named class.
 335  
      *
 336  
      * @param className the name of the class.
 337  
      * @return true if class loaders are supported, false otherwise.
 338  
      * @throws TurbineException if test fails.
 339  
      */
 340  
     public boolean isLoaderSupported(String className)
 341  
             throws TurbineException
 342  
     {
 343  0
         Factory factory = getFactory(className);
 344  0
         return factory != null ?
 345  
                 factory.isLoaderSupported() : true;
 346  
     }
 347  
 
 348  
     /**
 349  
      * Gets an instance of a specified class.
 350  
      *
 351  
      * @param clazz the class.
 352  
      * @return the instance.
 353  
      * @throws TurbineException if instantiation fails.
 354  
      */
 355  
     protected Object getInstance(Class clazz)
 356  
             throws TurbineException
 357  
     {
 358  
         try
 359  
         {
 360  324
             return clazz.newInstance();
 361  
         }
 362  0
         catch (Exception x)
 363  
         {
 364  0
             throw new TurbineException(
 365  
                     "Instantiation failed for " + clazz.getName(), x);
 366  
         }
 367  
     }
 368  
 
 369  
     /**
 370  
      * Gets an instance of a specified class.
 371  
      * Parameters for its constructor are given as an array of objects,
 372  
      * primitive types must be wrapped with a corresponding class.
 373  
      *
 374  
      * @param clazz the class.
 375  
      * @param params an array containing the parameters of the constructor.
 376  
      * @param signature an array containing the signature of the constructor.
 377  
      * @return the instance.
 378  
      * @throws TurbineException if instantiation fails.
 379  
      */
 380  
     protected Object getInstance(Class clazz,
 381  
             Object params[],
 382  
             String signature[])
 383  
             throws TurbineException
 384  
     {
 385  
         /* Try to construct. */
 386  
         try
 387  
         {
 388  20
             Class[] sign = getSignature(clazz, params, signature);
 389  20
             return clazz.getConstructor(sign).newInstance(params);
 390  
         }
 391  0
         catch (Exception x)
 392  
         {
 393  0
             throw new TurbineException(
 394  
                     "Instantiation failed for " + clazz.getName(), x);
 395  
         }
 396  
     }
 397  
 
 398  
     /**
 399  
      * Gets the signature classes for parameters of a method of a class.
 400  
      *
 401  
      * @param clazz the class.
 402  
      * @param params an array containing the parameters of the method.
 403  
      * @param signature an array containing the signature of the method.
 404  
      * @return an array of signature classes. Note that in some cases
 405  
      * objects in the parameter array can be switched to the context
 406  
      * of a different class loader.
 407  
      * @throws ClassNotFoundException if any of the classes is not found.
 408  
      */
 409  
     public Class[] getSignature(Class clazz,
 410  
             Object params[],
 411  
             String signature[])
 412  
             throws ClassNotFoundException
 413  
     {
 414  20
         if (signature != null)
 415  
         {
 416  
             /* We have parameters. */
 417  
             ClassLoader tempLoader;
 418  20
             ClassLoader loader = clazz.getClassLoader();
 419  20
             Class[] sign = new Class[signature.length];
 420  60
             for (int i = 0; i < signature.length; i++)
 421  
             {
 422  
                 /* Check primitive types. */
 423  40
                 sign[i] = getPrimitiveClass(signature[i]);
 424  40
                 if (sign[i] == null)
 425  
                 {
 426  
                     /* Not a primitive one, continue building. */
 427  40
                     if (loader != null)
 428  
                     {
 429  
                         /* Use the class loader of the target object. */
 430  40
                         sign[i] = loader.loadClass(signature[i]);
 431  40
                         tempLoader = sign[i].getClassLoader();
 432  40
                         if ((params[i] != null) &&
 433  
                                 (tempLoader != null) &&
 434  
                                 !tempLoader.equals(params[i].getClass().getClassLoader()))
 435  
                         {
 436  
                             /*
 437  
                              * The class uses a different class loader,
 438  
                              * switch the parameter.
 439  
                              */
 440  0
                             params[i] = switchObjectContext(params[i], loader);
 441  
                         }
 442  
                     }
 443  
                     else
 444  
                     {
 445  
                         /* Use the default class loader. */
 446  0
                         sign[i] = loadClass(signature[i]);
 447  
                     }
 448  
                 }
 449  
             }
 450  20
             return sign;
 451  
         }
 452  
         else
 453  
         {
 454  0
             return null;
 455  
         }
 456  
     }
 457  
 
 458  
     /**
 459  
      * Switches an object into the context of a different class loader.
 460  
      *
 461  
      * @param object an object to switch.
 462  
      * @param loader the loader of the new context.
 463  
      */
 464  
     protected Object switchObjectContext(Object object,
 465  
             ClassLoader loader)
 466  
     {
 467  0
         ByteArrayOutputStream bout =
 468  
                 new ByteArrayOutputStream();
 469  
         try
 470  
         {
 471  0
             ObjectOutputStream out =
 472  
                     new ObjectOutputStream(bout);
 473  0
             out.writeObject(object);
 474  0
             out.flush();
 475  
         }
 476  0
         catch (Exception x)
 477  
         {
 478  0
             return object;
 479  0
         }
 480  
 
 481  
         try
 482  
         {
 483  0
             ByteArrayInputStream bin =
 484  
                     new ByteArrayInputStream(bout.toByteArray());
 485  0
             ObjectInputStreamForContext in =
 486  
                     new ObjectInputStreamForContext(bin, loader);
 487  
 
 488  0
             return in.readObject();
 489  
         }
 490  0
         catch (Exception x)
 491  
         {
 492  0
             return object;
 493  
         }
 494  
     }
 495  
 
 496  
     /**
 497  
      * Loads the named class using the default class loader.
 498  
      *
 499  
      * @param className the name of the class to load.
 500  
      * @return the loaded class.
 501  
      * @throws ClassNotFoundException if the class was not found.
 502  
      */
 503  
     protected Class loadClass(String className)
 504  
             throws ClassNotFoundException
 505  
     {
 506  344
         ClassLoader loader = this.getClass().getClassLoader();
 507  
         try
 508  
         {
 509  344
             return loader != null ?
 510  
                     loader.loadClass(className) : Class.forName(className);
 511  
         }
 512  0
         catch (ClassNotFoundException x)
 513  
         {
 514  
             /* Go through additional loaders. */
 515  0
             for (Iterator i = classLoaders.iterator(); i.hasNext();)
 516  
             {
 517  
                 try
 518  
                 {
 519  0
                     return ((ClassLoader) i.next()).loadClass(className);
 520  
                 }
 521  0
                 catch (ClassNotFoundException xx)
 522  
                 {
 523  0
                 }
 524  
             }
 525  
 
 526  
             /* Give up. */
 527  0
             throw x;
 528  
         }
 529  
     }
 530  
 
 531  
     /**
 532  
      * Loads the named class using a specified class loader.
 533  
      *
 534  
      * @param className the name of the class to load.
 535  
      * @param loader the loader to use.
 536  
      * @return the loaded class.
 537  
      * @throws ClassNotFoundException if the class was not found.
 538  
      */
 539  
     protected Class loadClass(String className,
 540  
             ClassLoader loader)
 541  
             throws ClassNotFoundException
 542  
     {
 543  0
         return loader != null ?
 544  
                 loader.loadClass(className) : loadClass(className);
 545  
     }
 546  
 
 547  
     /**
 548  
      * Gets a customized factory for a named class.
 549  
      *
 550  
      * @param className the name of the class to load.
 551  
      * @return the factory or null if not specified.
 552  
      * @throws TurbineException if instantiation of the factory fails.
 553  
      */
 554  
     protected Factory getFactory(String className)
 555  
             throws TurbineException
 556  
     {
 557  344
         HashMap factories = objectFactories;
 558  344
         Object factory = factories.get(className);
 559  344
         if (factory != null)
 560  
         {
 561  0
             if (factory instanceof String)
 562  
             {
 563  
                 /* Not yet instantiated... */
 564  
                 try
 565  
                 {
 566  0
                     factory = (Factory) getInstance((String) factory);
 567  0
                     ((Factory) factory).init(className);
 568  
                 }
 569  0
                 catch (TurbineException x)
 570  
                 {
 571  0
                     throw x;
 572  
                 }
 573  0
                 catch (ClassCastException x)
 574  
                 {
 575  0
                     throw new TurbineException(
 576  
                             "Incorrect factory " + (String) factory +
 577  
                             " for class " + className, x);
 578  0
                 }
 579  0
                 factories = (HashMap) factories.clone();
 580  0
                 factories.put(className, factory);
 581  0
                 objectFactories = factories;
 582  
             }
 583  0
             return (Factory) factory;
 584  
         }
 585  
         else
 586  
         {
 587  344
             return null;
 588  
         }
 589  
     }
 590  
 }

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.