Coverage Report - org.apache.commons.clazz.Clazz
 
Classes in this File Line Coverage Branch Coverage Complexity
Clazz
0%
0/113
0%
0/52
1.844
Clazz$1
0%
0/3
N/A
1.844
Clazz$2
0%
0/3
N/A
1.844
Clazz$3
0%
0/3
N/A
1.844
Clazz$4
0%
0/3
N/A
1.844
Clazz$5
0%
0/3
N/A
1.844
Clazz$6
0%
0/3
N/A
1.844
Clazz$Notifier
0%
0/6
0%
0/6
1.844
 
 1  
 /*
 2  
  * Copyright 2002-2004 The Apache Software Foundation
 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.apache.commons.clazz;
 17  
 
 18  
 import java.lang.ref.WeakReference;
 19  
 import java.util.ArrayList;
 20  
 import java.util.HashMap;
 21  
 import java.util.Iterator;
 22  
 import java.util.List;
 23  
 import java.util.Map;
 24  
 
 25  
 import org.apache.commons.clazz.common.ClazzElementSupport;
 26  
 import org.apache.commons.clazz.common.ExtendedClazzLoaderFactory;
 27  
 import org.apache.commons.clazz.common.StandardClazzLoaderFactory;
 28  
 
 29  
 /**
 30  
  * 
 31  
  * 
 32  
  * @author <a href="mailto:scolebourne@apache.org">Stephen Colebourne</a>
 33  
  * @author <a href="mailto:dmitri@apache.org">Dmitri Plotnikov</a>
 34  
  * @version $Id: Clazz.java 155436 2005-02-26 13:17:48Z dirkv $
 35  
  */
 36  0
 public abstract class Clazz extends ClazzElementSupport
 37  
         implements ClazzElement
 38  
 {
 39  
     private ClazzLoader loader;
 40  
     private String name;
 41  
     private List listeners;
 42  
 
 43  
     /**
 44  
      * The name of the standard clazz model. The value of the constant is
 45  
      * "Standard".
 46  
      */
 47  
     public static final String STANDARD_CLAZZ_MODEL =
 48  
         StandardClazzLoaderFactory.MODEL;
 49  
 
 50  
     /**
 51  
      * The name of the extended clazz model. The value of the constant is
 52  
      * "Extended".
 53  
      */
 54  
     public static final String EXTENDED_CLAZZ_MODEL =
 55  
         ExtendedClazzLoaderFactory.MODEL;
 56  
         
 57  0
     private static String defaultClazzModel = EXTENDED_CLAZZ_MODEL;
 58  
     private static ClazzLoader defaultClazzLoader;
 59  0
     private static Map clazzLoaderFactories = new HashMap();
 60  
     
 61  
     static {
 62  0
         addClazzLoaderFactory(StandardClazzLoaderFactory.FACTORY);
 63  0
         addClazzLoaderFactory(ExtendedClazzLoaderFactory.FACTORY);
 64  
     }
 65  
         
 66  
     /**
 67  
      * Register a clazz loader factory, which manages ClazzLoaders, which manage
 68  
      * Clazzes.
 69  
      * 
 70  
      * @param clazzLoaderFactory
 71  
      */
 72  
     public static void addClazzLoaderFactory(ClazzLoaderFactory factory) {
 73  0
         clazzLoaderFactories.put(factory.getClazzModel(), factory);
 74  0
     }
 75  
     
 76  
     /**
 77  
      * Returns a ClazzLoaderFactory registered for the supplied model. We can
 78  
      * have multiple clazz loader factories implementing different models (e.g.
 79  
      * Standard JavaBeans, Extended JavaBeans etc).
 80  
      * 
 81  
      * @param model is the type of the model we need
 82  
      * @return ClazzLoaderFactory
 83  
      */
 84  
     public static ClazzLoaderFactory getClazzLoaderFactory(String model) {
 85  0
         return (ClazzLoaderFactory) clazzLoaderFactories.get(model);
 86  
     }
 87  
     
 88  
     /**
 89  
      * Select the default clazz model.
 90  
      * 
 91  
      * @param defaultClazzModel
 92  
      */
 93  
     public static void setDefaultClazzModel(String defaultClazzModel) {
 94  0
         Clazz.defaultClazzModel = defaultClazzModel;
 95  0
     }
 96  
 
 97  
     /**
 98  
      * Returns the name of the default clazz model.
 99  
      */
 100  
     public static String getDefaultClazzModel() {
 101  0
         return defaultClazzModel;
 102  
     }
 103  
 
 104  
     /**
 105  
      * Returns a clazz loader for the specified model.  The provided ClassLoader
 106  
      * can be used by the ClazzLoader for reflection.
 107  
      * 
 108  
      * @param model
 109  
      * @param classLoader
 110  
      * @return ClazzLoader
 111  
      */
 112  
     public static ClazzLoader getClazzLoader(
 113  
         String model,
 114  
         ClassLoader classLoader) 
 115  
     {
 116  0
         if (classLoader == null) {
 117  0
             classLoader = Clazz.class.getClassLoader();
 118  
         }
 119  0
         return getClazzLoaderFactory(model).getClazzLoader(classLoader);
 120  
     }
 121  
 
 122  
     /**
 123  
      * Returns the ClazzLoader for the default clazz model.
 124  
      */    
 125  
     public static ClazzLoader getDefaultClazzLoader(ClassLoader classLoader) {
 126  0
         return getClazzLoader(getDefaultClazzModel(), classLoader);
 127  
     }
 128  
     
 129  
     /**
 130  
      * Uses the clazz loader for the specified model to obtain the Clazz for the
 131  
      * supplied object.
 132  
      */
 133  
     public static Clazz getClazz(Object instance, String model) {
 134  0
         if (instance == null) {
 135  0
             throw new NullPointerException();
 136  
         }
 137  
 
 138  0
         ClassLoader classLoader = instance.getClass().getClassLoader();
 139  0
         Clazz clazz = getClazzLoader(model, classLoader).getClazz(instance);
 140  0
         if (clazz == null) {
 141  0
             throw new ClazzNotFoundException(instance.getClass().getName());
 142  
         }
 143  0
         return clazz;
 144  
     }
 145  
     
 146  
     /**
 147  
      * Uses the default clazz loader to obtain the Clazz for the supplied
 148  
      * object.
 149  
      */
 150  
     public static Clazz getClazz(Object instance) {
 151  0
         return getClazz(instance, getDefaultClazzModel());
 152  
     }    
 153  
         
 154  
     /**
 155  
      * Keep the constructor protected or private, we want Clazzes to 
 156  
      * be created by the ClazzLoaders only.
 157  
      *  
 158  
      * @param loader is the owning model clazz loader
 159  
      * @param name must be unique within the model
 160  
      */
 161  0
     protected Clazz(ClazzLoader modelClazzLoader, String name) {
 162  0
         this.loader = modelClazzLoader;
 163  0
         this.name = name;
 164  0
     }
 165  
     
 166  
     /**
 167  
      * Every Clazz belongs to one and only one ClazzLoader. Its name is unique
 168  
      * within that loader.
 169  
      */
 170  
     public ClazzLoader getClazzLoader() {
 171  0
         return loader;
 172  
     }
 173  
     
 174  
     /**
 175  
      * Returns the name of the Clazz. It is ok for the same name to be present
 176  
      * in different ClazzLoaders, except CachingClazzLoaders.
 177  
      */
 178  
     public String getName() {
 179  0
         return name;
 180  
     }
 181  
     
 182  
     /**
 183  
      * Gets the package name.
 184  
      * 
 185  
      * @return the package name
 186  
      */
 187  
     public String getPackageName() {
 188  0
         if (name == null) {
 189  0
             return null;
 190  
         }
 191  0
         int index = name.lastIndexOf('.');
 192  0
         if (index == -1) {
 193  0
             return "";
 194  
         }
 195  
         
 196  0
         return name.substring(0, index);
 197  
     }
 198  
 
 199  
     /**
 200  
      * Gets the class name (without the package).
 201  
      * 
 202  
      * @return the class name (without the package)
 203  
      */
 204  
     public String getShortClassName() {
 205  0
         if (name == null) {
 206  0
             return null;
 207  
         }
 208  0
         int index = name.lastIndexOf('.');
 209  0
         if (index == -1) {
 210  0
             return name;
 211  
         }
 212  
         
 213  0
         return name.substring(index + 1);
 214  
     }
 215  
 
 216  
     /**
 217  
      * Returns the class of instances created by the <code>newInstance()</code>
 218  
      * method.
 219  
      */    
 220  
     public abstract Class getInstanceClass();
 221  
     
 222  
     /**
 223  
      * Returns the superclazz for this Clazz, or null if there is none.
 224  
      */
 225  
     public abstract Clazz getSuperclazz();
 226  
     
 227  
     /**
 228  
      * Returns true if the supplied clazz is either the same or a subclazz of
 229  
      * this clazz.
 230  
      */
 231  
     public boolean isAssignableFrom(Clazz clazz) {
 232  0
         if (clazz == this) {
 233  0
             return true;
 234  
         }
 235  0
         Clazz superclazz = clazz.getSuperclazz();
 236  0
         if (superclazz != null) {
 237  0
             return isAssignableFrom(superclazz);
 238  
         }
 239  0
         return false;
 240  
     }
 241  
     
 242  
     /**
 243  
      * Returns properties declared by this Clazz, not its superclazzes
 244  
      */
 245  
     public abstract List getDeclaredProperties();
 246  
 
 247  
     /**
 248  
      * Returns all properties for this clazz, including those declared
 249  
      * by superclazzes.
 250  
      */
 251  
     public abstract List getProperties();
 252  
 
 253  
     /**
 254  
      * Returns the properties that match the Predicate.
 255  
      */
 256  
 //    public abstract List getProperties(Predicate predicate);
 257  
 
 258  
     /**
 259  
      * Returns a ClazzProperty for the given name
 260  
      */
 261  
     public abstract ClazzProperty getProperty(String name);
 262  
 
 263  
     /**
 264  
      * Returns all Operations for this clazz.
 265  
      */
 266  
     public abstract List getOperations();
 267  
 
 268  
     /**
 269  
      * Returns all Operations declared by this clazz, not its superclazzes.
 270  
      */
 271  
     public abstract List getDeclaredOperations();
 272  
 
 273  
     /**
 274  
      * Returns the Operations that match the Predicate.
 275  
      */
 276  
 //    public abstract List getOperations(Predicate predicate);
 277  
 
 278  
     /**
 279  
      * Returns the Operation for the given signature. The signature should be
 280  
      * formatted as follows: <code>"name(paramClazzName1,...)"</code>
 281  
      */
 282  
     public abstract ClazzOperation getOperation(String signature);
 283  
 
 284  
     /**
 285  
      * Returns all InstanceFactories for this clazz.
 286  
      */
 287  
     public abstract List getInstanceFactories();
 288  
 
 289  
     /**
 290  
      * Returns the InstanceFactories that match the Predicate.
 291  
      */
 292  
 //    public abstract List getInstanceFactories(Predicate predicate);
 293  
 
 294  
     /**
 295  
      * Returns ClazzInstanceFactory for the given signature. The signature
 296  
      * should be formatted as follows: <code>"(paramClazzName1,...)"</code>. You
 297  
      * can pass <code>null</code> in place of <code>"()"</code>. 
 298  
      */
 299  
     public abstract ClazzInstanceFactory getInstanceFactory(String signature);
 300  
     
 301  
     /**
 302  
      * Creates a new instance of this Clazz using the InstanceFactory that takes
 303  
      * no parameters.
 304  
      */
 305  
     public Object newInstance() {
 306  0
         ClazzInstanceFactory factory = getInstanceFactory("()");
 307  0
         if (factory == null) {
 308  
             // @todo: define exception
 309  0
             throw new RuntimeException(
 310  
                 "No such instance factory " + getName() + " ()");
 311  
         }
 312  0
         return factory.newInstance(null);
 313  
     }
 314  
 
 315  
     /**
 316  
      * Creates a new instance of this Clazz using the InstanceFactory
 317  
      * with the specified signature.
 318  
      */
 319  
     public Object newInstance(String signature, Object[] parameters) {
 320  0
         ClazzInstanceFactory factory = getInstanceFactory(signature);
 321  0
         if (factory == null) {
 322  
             // @todo: define exception
 323  0
             throw new RuntimeException(
 324  
                 "No such instance factory "
 325  
                     + getName()
 326  
                     + (signature == null ? "" : " " + signature));
 327  
         }
 328  0
         return factory.newInstance(parameters);
 329  
     }
 330  
     
 331  
     
 332  
     //--- Notification mechanism - verbose, but what are you gonna do?
 333  
     
 334  
     public void addClazzChangeListener(ClazzChangeListener listener) {
 335  0
         if (listeners == null) {
 336  0
             listeners = new ArrayList();
 337  
         }
 338  
         
 339  
         // We don't want to prevent the subclasses from being garbage
 340  
         // collection just because they are listening to their superclasses. 
 341  0
         WeakReference reference = new WeakReference(listener);
 342  0
         listeners.add(reference);
 343  0
     }
 344  
     
 345  
     public void removeClazzChangeListener(ClazzChangeListener listener) {
 346  0
         if (listeners == null) {
 347  0
             return;
 348  
         }
 349  0
         for (Iterator iter = listeners.iterator(); iter.hasNext();) {
 350  0
             WeakReference reference = (WeakReference) iter.next();
 351  0
             if (reference.get() == listener) {
 352  0
                 iter.remove();
 353  0
                 break;
 354  
             }
 355  0
         }
 356  0
     }
 357  
         
 358  0
     private static final WeakReference[] CLAZZ_CHANGE_LISTENER_ARRAY =
 359  
             new WeakReference[0];
 360  
 
 361  0
     private abstract static class Notifier {
 362  
         void fire(Clazz clazz, Object parameter) {
 363  0
             if (clazz.listeners != null && clazz.listeners.size() != 0) {
 364  0
                 WeakReference listenerArray[] =
 365  
                     (WeakReference[]) clazz.listeners.toArray(
 366  
                         CLAZZ_CHANGE_LISTENER_ARRAY);
 367  0
                 for (int i = 0; i < listenerArray.length; i++) {
 368  0
                     fire(
 369  
                         clazz,
 370  
                         (ClazzChangeListener) listenerArray[i].get(),
 371  
                         parameter);
 372  
                 }
 373  
             }
 374  0
         }
 375  
         
 376  
         abstract void fire(
 377  
             Clazz clazz, ClazzChangeListener listener, Object parameter);
 378  
     }
 379  
     
 380  0
     private static final Notifier PROPERTY_ADDED_NOTIFIER = new Notifier() {
 381  
         void fire(Clazz clazz, ClazzChangeListener listener, Object parameter) {
 382  0
             listener.propertyAdded(clazz, (ClazzProperty) parameter);
 383  0
         }
 384  
     };
 385  
                     
 386  
     protected void firePropertyAdded(ClazzProperty property) {
 387  0
         PROPERTY_ADDED_NOTIFIER.fire(this, property);
 388  0
     }
 389  
 
 390  0
     private static final Notifier PROPERTY_REMOVED_NOTIFIER = new Notifier() {
 391  
         void fire(Clazz clazz, ClazzChangeListener listener, Object parameter) {
 392  0
             listener.propertyRemoved(clazz, (ClazzProperty) parameter);
 393  0
         }
 394  
     };
 395  
 
 396  
     protected void firePropertyRemoved(ClazzProperty property) {
 397  0
         PROPERTY_REMOVED_NOTIFIER.fire(this, property);
 398  0
     }
 399  
 
 400  0
     private static final Notifier OPERATION_ADDED_NOTIFIER = new Notifier() {
 401  
         void fire(Clazz clazz, ClazzChangeListener listener, Object parameter) {
 402  0
             listener.operationAdded(clazz, (ClazzOperation) parameter);
 403  0
         }
 404  
     };
 405  
 
 406  
     protected void fireOperationAdded(ClazzOperation operation) {
 407  0
         OPERATION_ADDED_NOTIFIER.fire(this, operation);
 408  0
     }
 409  
 
 410  0
     private static final Notifier OPERATION_REMOVED_NOTIFIER = new Notifier() {
 411  
         void fire(Clazz clazz, ClazzChangeListener listener, Object parameter) {
 412  0
             listener.operationRemoved(clazz, (ClazzOperation) parameter);
 413  0
         }
 414  
     };
 415  
 
 416  
     protected void fireOperationRemoved(ClazzOperation operation) {
 417  0
         OPERATION_REMOVED_NOTIFIER.fire(this, operation);
 418  0
     }
 419  
 
 420  
 
 421  0
     private static final Notifier FACTORY_ADDED_NOTIFIER = new Notifier() {
 422  
         void fire(Clazz clazz, ClazzChangeListener listener, Object parameter) {
 423  0
             listener.instanceFactoryAdded(
 424  
                 clazz,
 425  
                 (ClazzInstanceFactory) parameter);
 426  0
         }
 427  
     };
 428  
 
 429  
     protected void fireInstanceFactoryAdded(ClazzInstanceFactory factory) {
 430  0
         FACTORY_ADDED_NOTIFIER.fire(this, factory);
 431  0
     }
 432  
 
 433  0
     private static final Notifier FACTORY_REMOVED_NOTIFIER = new Notifier() {
 434  
         void fire(Clazz clazz, ClazzChangeListener listener, Object parameter) {
 435  0
             listener.instanceFactoryRemoved(
 436  
                 clazz,
 437  
                 (ClazzInstanceFactory) parameter);
 438  0
         }
 439  
     };
 440  
 
 441  
     protected void fireInstanceFactoryRemoved(ClazzInstanceFactory factory) {
 442  0
         FACTORY_REMOVED_NOTIFIER.fire(this, factory);
 443  0
     }
 444  
 
 445  
     //--- End notification mechanism
 446  
     
 447  
     
 448  
     /**
 449  
      * Creates a signature string out of an operation or instance factory name
 450  
      * and parameter types.
 451  
      */
 452  
     public static String constructSignature(String name, Class[] arguments) {
 453  0
         StringBuffer buffer = new StringBuffer();
 454  0
         if (name != null) {
 455  0
             buffer.append(name);
 456  
         }
 457  0
         buffer.append('(');
 458  0
         if (arguments != null) {
 459  0
             for (int i = 0; i < arguments.length; i++) {
 460  0
                 if (i != 0) {
 461  0
                     buffer.append(',');
 462  
                 }
 463  0
                 buffer.append(getCanonicalClassName(arguments[i]));
 464  
             }
 465  
         }
 466  0
         buffer.append(')');
 467  0
         return buffer.toString();
 468  
     }
 469  
 
 470  
     /**
 471  
      * Creates a signature string out of an operation or instance factory name
 472  
      * and parameter types.
 473  
      */
 474  
     public static String constructSignature(String name, Clazz[] arguments) {
 475  0
         StringBuffer buffer = new StringBuffer();
 476  0
         if (name != null) {
 477  0
             buffer.append(name);
 478  
         }
 479  0
         buffer.append('(');
 480  0
         if (arguments != null) {
 481  0
             for (int i = 0; i < arguments.length; i++) {
 482  0
                 if (i != 0) {
 483  0
                     buffer.append(',');
 484  
                 }
 485  0
                 buffer.append(arguments[i].getName());
 486  
             }
 487  
         }
 488  0
         buffer.append(')');
 489  0
         return buffer.toString();
 490  
     }
 491  
     
 492  
     /**
 493  
      * Produces a nice type name for a classes representing an array, e.g. "[I"
 494  
      * is shown as "int[]". For non-array types returns the regular type name.
 495  
      */
 496  
     public static String getCanonicalClassName(Class javaClass) {
 497  
         /*
 498  
          * This is basically a remake of java.lang.reflect.Field.getTypeName
 499  
          * (Class), which cannot be used directly as it is declared with the
 500  
          * default scope.
 501  
          */
 502  0
         if (javaClass.isArray()) {
 503  0
             return getCanonicalClassName(javaClass.getComponentType()) + "[]";
 504  
         }
 505  0
         return javaClass.getName();
 506  
     }
 507  
 }