Coverage Report - org.codehaus.plexus.classworlds.realm.ClassRealm
 
Classes in this File Line Coverage Branch Coverage Complexity
ClassRealm
64 %
98/152
58 %
40/68
2,564
 
 1  
 package org.codehaus.plexus.classworlds.realm;
 2  
 
 3  
 /*
 4  
  * Copyright 2001-2006 Codehaus 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 org.codehaus.plexus.classworlds.ClassWorld;
 20  
 import org.codehaus.plexus.classworlds.strategy.Strategy;
 21  
 import org.codehaus.plexus.classworlds.strategy.StrategyFactory;
 22  
 
 23  
 import java.io.Closeable;
 24  
 import java.io.IOException;
 25  
 import java.io.PrintStream;
 26  
 import java.net.MalformedURLException;
 27  
 import java.net.URL;
 28  
 import java.net.URLClassLoader;
 29  
 import java.util.Collection;
 30  
 import java.util.Collections;
 31  
 import java.util.Enumeration;
 32  
 import java.util.HashSet;
 33  
 import java.util.LinkedHashSet;
 34  
 import java.util.SortedSet;
 35  
 import java.util.TreeSet;
 36  
 import java.util.concurrent.ConcurrentMap;
 37  
 import java.util.concurrent.ConcurrentHashMap;
 38  
 
 39  
 /**
 40  
  * The class loading gateway. Each class realm has access to a base class loader, imports form zero or more other class
 41  
  * loaders, an optional parent class loader and of course its own class path. When queried for a class/resource, a class
 42  
  * realm will always query its base class loader first before it delegates to a pluggable strategy. The strategy in turn
 43  
  * controls the order in which imported class loaders, the parent class loader and the realm itself are searched. The
 44  
  * base class loader is assumed to be capable of loading of the bootstrap classes.
 45  
  *
 46  
  * @author <a href="mailto:bob@eng.werken.com">bob mcwhirter</a>
 47  
  * @author Jason van Zyl
 48  
  */
 49  
 public class ClassRealm
 50  
     extends URLClassLoader
 51  
 {
 52  
 
 53  
     private ClassWorld world;
 54  
 
 55  
     private String id;
 56  
 
 57  
     private SortedSet<Entry> foreignImports;
 58  
 
 59  
     private SortedSet<Entry> parentImports;
 60  
 
 61  
     private Strategy strategy;
 62  
 
 63  
     private ClassLoader parentClassLoader;
 64  
 
 65  1
     private static final boolean isParallelCapable = Closeable.class.isAssignableFrom( URLClassLoader.class );
 66  
 
 67  
     private final ConcurrentMap<String, Object> lockMap;
 68  
 
 69  
     /**
 70  
      * Creates a new class realm.
 71  
      *
 72  
      * @param world           The class world this realm belongs to, must not be <code>null</code>.
 73  
      * @param id              The identifier for this realm, must not be <code>null</code>.
 74  
      * @param baseClassLoader The base class loader for this realm, may be <code>null</code> to use the bootstrap class
 75  
      *                        loader.
 76  
      */
 77  
     public ClassRealm( ClassWorld world, String id, ClassLoader baseClassLoader )
 78  
     {
 79  303
         super( new URL[0], baseClassLoader );
 80  
 
 81  303
         this.world = world;
 82  
 
 83  303
         this.id = id;
 84  
 
 85  303
         foreignImports = new TreeSet<Entry>();
 86  
 
 87  303
         strategy = StrategyFactory.getStrategy( this );
 88  
 
 89  303
         lockMap = isParallelCapable ? new ConcurrentHashMap<String, Object>() : null;
 90  
 
 91  303
         if ( isParallelCapable ) {
 92  
                 // We must call super.getClassLoadingLock at least once
 93  
                 // to avoid NPE in super.loadClass.
 94  303
                 super.getClassLoadingLock(getClass().getName());
 95  
         }
 96  303
     }
 97  
 
 98  
     public String getId()
 99  
     {
 100  2
         return this.id;
 101  
     }
 102  
 
 103  
     public ClassWorld getWorld()
 104  
     {
 105  26
         return this.world;
 106  
     }
 107  
 
 108  
     public void importFromParent( String packageName )
 109  
     {
 110  2
         if ( parentImports == null )
 111  
         {
 112  1
             parentImports = new TreeSet<Entry>();
 113  
         }
 114  
 
 115  2
         parentImports.add( new Entry( null, packageName ) );
 116  2
     }
 117  
 
 118  
     boolean isImportedFromParent( String name )
 119  
     {
 120  15
         if ( parentImports != null && !parentImports.isEmpty() )
 121  
         {
 122  3
             for ( Entry entry : parentImports )
 123  
             {
 124  3
                 if ( entry.matches( name ) )
 125  
                 {
 126  2
                     return true;
 127  
                 }
 128  1
             }
 129  
 
 130  1
             return false;
 131  
         }
 132  
 
 133  12
         return true;
 134  
     }
 135  
 
 136  
     public void importFrom( String realmId, String packageName )
 137  
         throws NoSuchRealmException
 138  
     {
 139  18
         importFrom( getWorld().getRealm( realmId ), packageName );
 140  18
     }
 141  
 
 142  
     public void importFrom( ClassLoader classLoader, String packageName )
 143  
     {
 144  18
         foreignImports.add( new Entry( classLoader, packageName ) );
 145  18
     }
 146  
 
 147  
     public ClassLoader getImportClassLoader( String name )
 148  
     {
 149  501
         for ( Entry entry : foreignImports )
 150  
         {
 151  70
             if ( entry.matches( name ) )
 152  
             {
 153  29
                 return entry.getClassLoader();
 154  
             }
 155  41
         }
 156  
 
 157  472
         return null;
 158  
     }
 159  
 
 160  
     public Collection<ClassRealm> getImportRealms()
 161  
     {
 162  0
         Collection<ClassRealm> importRealms = new HashSet<ClassRealm>();
 163  
 
 164  0
         for ( Entry entry : foreignImports )
 165  
         {
 166  0
             if ( entry.getClassLoader() instanceof ClassRealm )
 167  
             {
 168  0
                 importRealms.add( (ClassRealm) entry.getClassLoader() );
 169  
             }
 170  0
         }
 171  
 
 172  0
         return importRealms;
 173  
     }
 174  
 
 175  
     public Strategy getStrategy()
 176  
     {
 177  7
         return strategy;
 178  
     }
 179  
 
 180  
     public void setParentClassLoader( ClassLoader parentClassLoader )
 181  
     {
 182  0
         this.parentClassLoader = parentClassLoader;
 183  0
     }
 184  
 
 185  
     public ClassLoader getParentClassLoader()
 186  
     {
 187  37
         return parentClassLoader;
 188  
     }
 189  
 
 190  
     public void setParentRealm( ClassRealm realm )
 191  
     {
 192  108
         this.parentClassLoader = realm;
 193  108
     }
 194  
 
 195  
     public ClassRealm getParentRealm()
 196  
     {
 197  0
         return ( parentClassLoader instanceof ClassRealm ) ? (ClassRealm) parentClassLoader : null;
 198  
     }
 199  
 
 200  
     public ClassRealm createChildRealm( String id )
 201  
         throws DuplicateRealmException
 202  
     {
 203  7
         ClassRealm childRealm = getWorld().newRealm( id, null );
 204  
 
 205  7
         childRealm.setParentRealm( this );
 206  
 
 207  7
         return childRealm;
 208  
     }
 209  
 
 210  
     public void addURL( URL url )
 211  
     {
 212  266
         String urlStr = url.toExternalForm();
 213  
 
 214  266
         if ( urlStr.startsWith( "jar:" ) && urlStr.endsWith( "!/" ) )
 215  
         {
 216  0
             urlStr = urlStr.substring( 4, urlStr.length() - 2 );
 217  
 
 218  
             try
 219  
             {
 220  0
                 url = new URL( urlStr );
 221  
             }
 222  0
             catch ( MalformedURLException e )
 223  
             {
 224  0
                 e.printStackTrace();
 225  0
             }
 226  
         }
 227  
 
 228  266
         super.addURL( url );
 229  266
     }
 230  
 
 231  
     // ----------------------------------------------------------------------
 232  
     // We delegate to the Strategy here so that we can change the behavior
 233  
     // of any existing ClassRealm.
 234  
     // ----------------------------------------------------------------------
 235  
 
 236  
     public Class<?> loadClass( String name )
 237  
         throws ClassNotFoundException
 238  
     {
 239  793
         return loadClass( name, false );
 240  
     }
 241  
 
 242  
     protected Class<?> loadClass( String name, boolean resolve )
 243  
         throws ClassNotFoundException
 244  
     {
 245  805
         if ( isParallelCapable )
 246  
         {
 247  806
             return unsynchronizedLoadClass( name, resolve );
 248  
 
 249  
         }
 250  
         else
 251  
         {
 252  0
             synchronized ( this )
 253  
             {
 254  0
                 return unsynchronizedLoadClass( name, resolve );
 255  0
             }
 256  
 
 257  
         }
 258  
     }
 259  
 
 260  
     private Class<?> unsynchronizedLoadClass( String name, boolean resolve )
 261  
         throws ClassNotFoundException
 262  
     {
 263  
         try
 264  
         {
 265  
             // first, try loading bootstrap classes
 266  805
             return super.loadClass( name, resolve );
 267  
         }
 268  447
         catch ( ClassNotFoundException e )
 269  
         {
 270  
             // next, try loading via imports, self and parent as controlled by strategy
 271  447
             return strategy.loadClass( name );
 272  
         }
 273  
     }
 274  
 
 275  
     protected Class<?> findClass( String name )
 276  
         throws ClassNotFoundException
 277  
     {
 278  
         /*
 279  
          * NOTE: This gets only called from ClassLoader.loadClass(Class, boolean) while we try to check for bootstrap
 280  
          * stuff. Don't scan our class path yet, loadClassFromSelf() will do this later when called by the strategy.
 281  
          */
 282  447
         throw new ClassNotFoundException( name );
 283  
     }
 284  
 
 285  
     public URL getResource( String name )
 286  
     {
 287  16
         URL resource = super.getResource( name );
 288  16
         return resource != null ? resource : strategy.getResource( name );
 289  
     }
 290  
 
 291  
     public URL findResource( String name )
 292  
     {
 293  16
         return super.findResource( name );
 294  
     }
 295  
 
 296  
     public Enumeration<URL> getResources( String name )
 297  
         throws IOException
 298  
     {
 299  12
         Collection<URL> resources = new LinkedHashSet<URL>( Collections.list( super.getResources( name ) ) );
 300  12
         resources.addAll( Collections.list( strategy.getResources( name ) ) );
 301  12
         return Collections.enumeration( resources );
 302  
     }
 303  
 
 304  
     public Enumeration<URL> findResources( String name )
 305  
         throws IOException
 306  
     {
 307  15
         return super.findResources( name );
 308  
     }
 309  
 
 310  
     // ----------------------------------------------------------------------------
 311  
     // Display methods
 312  
     // ----------------------------------------------------------------------------
 313  
 
 314  
     public void display()
 315  
     {
 316  0
         display( System.out );
 317  0
     }
 318  
 
 319  
     public void display( PrintStream out )
 320  
     {
 321  0
         out.println( "-----------------------------------------------------" );
 322  
 
 323  0
         for ( ClassRealm cr = this; cr != null; cr = cr.getParentRealm() )
 324  
         {
 325  0
             out.println( "realm =    " + cr.getId() );
 326  0
             out.println( "strategy = " + cr.getStrategy().getClass().getName() );
 327  
 
 328  0
             showUrls( cr, out );
 329  
 
 330  0
             out.println();
 331  
         }
 332  
 
 333  0
         out.println( "-----------------------------------------------------" );
 334  0
     }
 335  
 
 336  
     private static void showUrls( ClassRealm classRealm, PrintStream out )
 337  
     {
 338  0
         URL[] urls = classRealm.getURLs();
 339  
 
 340  0
         for ( int i = 0; i < urls.length; i++ )
 341  
         {
 342  0
             out.println( "urls[" + i + "] = " + urls[i] );
 343  
         }
 344  
 
 345  0
         out.println( "Number of foreign imports: " + classRealm.foreignImports.size() );
 346  
 
 347  0
         for ( Entry entry : classRealm.foreignImports )
 348  
         {
 349  0
             out.println( "import: " + entry );
 350  0
         }
 351  
 
 352  0
         if ( classRealm.parentImports != null )
 353  
         {
 354  0
             out.println( "Number of parent imports: " + classRealm.parentImports.size() );
 355  
 
 356  0
             for ( Entry entry : classRealm.parentImports )
 357  
             {
 358  0
                 out.println( "import: " + entry );
 359  0
             }
 360  
         }
 361  0
     }
 362  
 
 363  
     public String toString()
 364  
     {
 365  0
         return "ClassRealm[" + getId() + ", parent: " + getParentClassLoader() + "]";
 366  
     }
 367  
 
 368  
     //---------------------------------------------------------------------------------------------
 369  
     // Search methods that can be ordered by strategies to load a class
 370  
     //---------------------------------------------------------------------------------------------
 371  
 
 372  
     public Class<?> loadClassFromImport( String name )
 373  
     {
 374  451
         ClassLoader importClassLoader = getImportClassLoader( name );
 375  
 
 376  451
         if ( importClassLoader != null )
 377  
         {
 378  
             try
 379  
             {
 380  7
                 return importClassLoader.loadClass( name );
 381  
             }
 382  0
             catch ( ClassNotFoundException e )
 383  
             {
 384  0
                 return null;
 385  
             }
 386  
         }
 387  
 
 388  444
         return null;
 389  
     }
 390  
 
 391  
     public Class<?> loadClassFromSelf( String name )
 392  
     {
 393  444
         synchronized ( getClassRealmLoadingLock( name ) )
 394  
         {
 395  
             try
 396  
             {
 397  444
                 Class<?> clazz = findLoadedClass( name );
 398  
 
 399  443
                 if ( clazz == null )
 400  
                 {
 401  442
                     clazz = super.findClass( name );
 402  
                 }
 403  
 
 404  422
                 return clazz;
 405  
             }
 406  22
             catch ( ClassNotFoundException e )
 407  
             {
 408  22
                 return null;
 409  
             }
 410  0
         }
 411  
     }
 412  
 
 413  
     private Object getClassRealmLoadingLock( String name )
 414  
     {
 415  444
         if ( isParallelCapable )
 416  
         {
 417  444
             return getClassLoadingLock( name );
 418  
         }
 419  
         else
 420  
         {
 421  0
             return this;
 422  
         }
 423  
     }
 424  
 
 425  
     @Override
 426  
     protected Object getClassLoadingLock( String name )
 427  
     {
 428  1251
         if ( isParallelCapable )
 429  
         {
 430  1253
             Object newLock = new Object();
 431  1251
             Object lock = lockMap.putIfAbsent( name, newLock );
 432  1253
             return ( lock == null ) ? newLock : lock;
 433  
         }
 434  0
         return this;
 435  
     }
 436  
 
 437  
     public Class<?> loadClassFromParent( String name )
 438  
     {
 439  22
         ClassLoader parent = getParentClassLoader();
 440  
 
 441  22
         if ( parent != null && isImportedFromParent( name ) )
 442  
         {
 443  
             try
 444  
             {
 445  10
                 return parent.loadClass( name );
 446  
             }
 447  0
             catch ( ClassNotFoundException e )
 448  
             {
 449  0
                 return null;
 450  
             }
 451  
         }
 452  
 
 453  12
         return null;
 454  
     }
 455  
 
 456  
     //---------------------------------------------------------------------------------------------
 457  
     // Search methods that can be ordered by strategies to get a resource
 458  
     //---------------------------------------------------------------------------------------------
 459  
 
 460  
     public URL loadResourceFromImport( String name )
 461  
     {
 462  3
         ClassLoader importClassLoader = getImportClassLoader( name );
 463  
 
 464  3
         if ( importClassLoader != null )
 465  
         {
 466  0
             return importClassLoader.getResource( name );
 467  
         }
 468  
 
 469  3
         return null;
 470  
     }
 471  
 
 472  
     public URL loadResourceFromSelf( String name )
 473  
     {
 474  3
         return super.findResource( name );
 475  
     }
 476  
 
 477  
     public URL loadResourceFromParent( String name )
 478  
     {
 479  2
         ClassLoader parent = getParentClassLoader();
 480  
 
 481  2
         if ( parent != null && isImportedFromParent( name ) )
 482  
         {
 483  1
             return parent.getResource( name );
 484  
         }
 485  
         else
 486  
         {
 487  1
             return null;
 488  
         }
 489  
     }
 490  
 
 491  
     //---------------------------------------------------------------------------------------------
 492  
     // Search methods that can be ordered by strategies to get resources
 493  
     //---------------------------------------------------------------------------------------------
 494  
 
 495  
     public Enumeration<URL> loadResourcesFromImport( String name )
 496  
     {
 497  13
         ClassLoader importClassLoader = getImportClassLoader( name );
 498  
 
 499  13
         if ( importClassLoader != null )
 500  
         {
 501  
             try
 502  
             {
 503  1
                 return importClassLoader.getResources( name );
 504  
             }
 505  0
             catch ( IOException e )
 506  
             {
 507  0
                 return null;
 508  
             }
 509  
         }
 510  
 
 511  12
         return null;
 512  
     }
 513  
 
 514  
     public Enumeration<URL> loadResourcesFromSelf( String name )
 515  
     {
 516  
         try
 517  
         {
 518  13
             return super.findResources( name );
 519  
         }
 520  0
         catch ( IOException e )
 521  
         {
 522  0
             return null;
 523  
         }
 524  
     }
 525  
 
 526  
     public Enumeration<URL> loadResourcesFromParent( String name )
 527  
     {
 528  13
         ClassLoader parent = getParentClassLoader();
 529  
 
 530  13
         if ( parent != null && isImportedFromParent( name ) )
 531  
         {
 532  
             try
 533  
             {
 534  3
                 return parent.getResources( name );
 535  
             }
 536  0
             catch ( IOException e )
 537  
             {
 538  
                 // eat it
 539  
             }
 540  
         }
 541  
 
 542  10
         return null;
 543  
     }
 544  
 
 545  
     static
 546  
     {
 547  1
         if  (isParallelCapable) // Avoid running this method on older jdks
 548  
         {
 549  1
             registerAsParallelCapable();
 550  
         }
 551  1
     }
 552  
 
 553  
 }