Coverage Report - org.apache.commons.classscan.builtin.UrlMetaClassLoader
 
Classes in this File Line Coverage Branch Coverage Complexity
UrlMetaClassLoader
0%
0/89
0%
0/43
2.762
UrlMetaClassLoader$1
0%
0/18
0%
0/10
2.762
 
 1  
 /*
 2  
  * Licensed under the Apache License, Version 2.0 (the "License");
 3  
  * you may not use this file except in compliance with the License.
 4  
  * You may obtain a copy of the License at
 5  
  *
 6  
  *      http://www.apache.org/licenses/LICENSE-2.0
 7  
  *
 8  
  * Unless required by applicable law or agreed to in writing, software
 9  
  * distributed under the License is distributed on an "AS IS" BASIS,
 10  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 11  
  * See the License for the specific language governing permissions and
 12  
  * limitations under the License.
 13  
  */
 14  
 package org.apache.commons.classscan.builtin;
 15  
 
 16  
 import java.util.ArrayList;
 17  
 import java.util.Collection;
 18  
 import java.util.Collections;
 19  
 import java.util.Iterator;
 20  
 import java.util.LinkedHashMap;
 21  
 import java.util.List;
 22  
 import java.util.Map;
 23  
 import java.util.MissingResourceException;
 24  
 import java.util.NoSuchElementException;
 25  
 
 26  
 import org.apache.commons.classscan.ClassPath;
 27  
 import org.apache.commons.classscan.ClassPathElement;
 28  
 import org.apache.commons.classscan.MetaClassLoader;
 29  
 import org.apache.commons.classscan.MetaClassPathElement;
 30  
 import org.apache.commons.classscan.model.MetaArray;
 31  
 import org.apache.commons.classscan.model.MetaClass;
 32  
 import org.apache.commons.classscan.model.MetaType;
 33  
 import org.apache.commons.classscan.spi.model.SpiClassPathElement;
 34  
 import org.apache.commons.classscan.spi.model.SpiMetaClassLoader;
 35  
 import org.apache.commons.classscan.spi.model.SpiMetaClassPathElement;
 36  
 import org.apache.commons.classscan.spi.model.SpiMetaRegistry;
 37  
 import org.slf4j.Logger;
 38  
 import org.slf4j.LoggerFactory;
 39  
 
 40  
 public class UrlMetaClassLoader implements SpiMetaClassLoader {
 41  
 
 42  0
     private static final Logger logger = LoggerFactory.getLogger(UrlMetaClassLoader.class);
 43  
 
 44  
     private final SpiMetaClassLoader parent;
 45  
     private Map<String, SpiMetaClassPathElement> locations;
 46  
     
 47  0
         public UrlMetaClassLoader(SpiMetaRegistry registry, ClassLoader classLoader) {
 48  0
                 parent= classLoader!= null ?(SpiMetaClassLoader)registry.getMetaClassLoader(classLoader.getParent()) :null;
 49  
                 // use LinkedHashMap to keep iteration over path elements in same order as definition
 50  0
                 locations = new LinkedHashMap<String, SpiMetaClassPathElement>();
 51  0
                 addLocations(registry, classLoader);
 52  0
                 resolve();
 53  0
                 locations = Collections.unmodifiableMap(locations);
 54  0
     }
 55  
 
 56  
         void addLocations(SpiMetaRegistry registry, ClassLoader classLoader) {
 57  0
             ClassPath classPath = registry.getClassPath(classLoader);
 58  0
                 for(ClassPathElement pathElement : classPath.getClassPathElements()) {
 59  0
                     addLocation(registry, pathElement);
 60  
             }
 61  0
     }
 62  
 
 63  
     /**
 64  
      * Add a location
 65  
      * 
 66  
      * @param pathElement
 67  
      *            The URI of a jar or folder
 68  
      */
 69  
         private void addLocation(SpiMetaRegistry registry, ClassPathElement pathElement) {
 70  0
             String baseLocation= pathElement.getLocation();
 71  0
         if (!locations.containsKey(baseLocation)) {
 72  0
             SpiMetaClassPathElement mcl = registry.createMetaClassPathElement(pathElement);
 73  0
             if (mcl != null) {
 74  0
                     locations.put(baseLocation, mcl);            
 75  
             }
 76  0
                 Collection<SpiClassPathElement> additionalUrls= ((SpiClassPathElement)pathElement).getAdditionalLocations(registry);
 77  0
                 if(additionalUrls!=null) {
 78  0
                         for(SpiClassPathElement additionalUrl : additionalUrls) {
 79  0
                                 addLocation(registry, additionalUrl);
 80  
                         }
 81  
                 }
 82  
         }
 83  0
     }
 84  
         
 85  
     protected void addLocation(SpiMetaClassPathElement cpe) {
 86  0
             locations.put(cpe.getName(), cpe);
 87  0
         }
 88  
 
 89  
     // resolve string names into model entities instead of using resolution upon demand
 90  
     // memory used by multiple string copies weighs more heavily than time spent resolving meta-class
 91  
     // demand resolution would require clients to filter out classes which have un-resolvable dependencies
 92  
     private void resolve() {
 93  0
             Iterator<SpiMetaClassPathElement> metaClassPathElements= locations.values().iterator();
 94  0
             while(metaClassPathElements.hasNext()) {
 95  0
                     SpiMetaClassPathElement metaClassPathElement= metaClassPathElements.next();
 96  0
                     if(!metaClassPathElement.resolve(this)) {
 97  0
                             metaClassPathElements.remove();
 98  
                     }
 99  0
             }
 100  0
         }
 101  
 
 102  
     @Override
 103  
     public MetaClassLoader getParent() {
 104  0
         return parent;
 105  
     }
 106  
 
 107  
     @Override
 108  
     public Collection<? extends MetaClassPathElement> getClassLocations() {
 109  0
         return locations.values();
 110  
     }
 111  
 
 112  
     @Override
 113  
     public MetaClassPathElement getClassLocation(String location) {
 114  0
         return locations.get(location);
 115  
     }
 116  
 
 117  
     @Override
 118  
     public Iterator<? extends MetaClass> getMetaClasses() {             
 119  0
             Collection<? extends MetaClassPathElement> classLocations = getClassLocations();
 120  0
             if(classLocations.isEmpty()) {
 121  0
                     List<? extends MetaClass> empty= Collections.emptyList();
 122  0
                     return empty.iterator();
 123  
             }
 124  
             
 125  0
                 final Iterator<? extends MetaClassPathElement> locations= classLocations.iterator();
 126  
             
 127  0
             return new Iterator<MetaClass>() {
 128  
                 {
 129  0
                         nextInnerIterator();
 130  0
                 }
 131  
                 Iterator<? extends MetaClass> metaClasses;
 132  
 
 133  
                 private boolean nextInnerIterator() {
 134  0
                         if(!locations.hasNext()) {
 135  0
                                 return false;
 136  
                         }
 137  0
                                 MetaClassPathElement mcpe= locations.next();
 138  0
                                 metaClasses= mcpe.getMetaClasses().iterator();
 139  0
                                 return true;
 140  
                         }
 141  
                 
 142  
                         @Override
 143  
                         public boolean hasNext() {
 144  0
                             while(!metaClasses.hasNext()) {                                        
 145  0
                                 if(!nextInnerIterator()) {
 146  0
                                         return false;
 147  
                                 }
 148  
                             }
 149  0
                             return true;
 150  
                         }
 151  
 
 152  
                         @Override
 153  
                         public MetaClass next() {
 154  0
                             while(!metaClasses.hasNext()) {                                        
 155  0
                                 if(!locations.hasNext()) {
 156  0
                                         throw new NoSuchElementException();
 157  
                                 }
 158  0
                                     nextInnerIterator();
 159  
                             }
 160  0
                             return metaClasses.next();
 161  
                         }
 162  
 
 163  
                         @Override
 164  
                         public void remove() {
 165  0
                                 throw new UnsupportedOperationException();
 166  
                         }
 167  
             };
 168  
     }
 169  
 
 170  
     @Override
 171  
     public MetaClass getMetaClass(String className) {
 172  0
             for(MetaClassPathElement location : locations.values()) {
 173  0
                     MetaClass mc = location.getMetaClass(className);
 174  0
                     if(mc != null) {
 175  0
                             return mc;
 176  
                     }
 177  0
             }
 178  0
         return null;
 179  
     }
 180  
 
 181  
     @Override
 182  
     public MetaClass findMetaClass(String className) {
 183  0
         MetaClass mc = parent.findMetaClass(className);
 184  0
         if (mc != null) {
 185  0
             return mc;
 186  
         }
 187  0
         return getMetaClass(className);
 188  
     }
 189  
 
 190  
     @Override
 191  
     public MetaClass resolveMetaClass(String className) {
 192  0
         MetaClass mc = parent.resolveMetaClass(className);
 193  0
         if (mc != null) {
 194  0
             return mc;
 195  
         }
 196  0
             return resolveInPath(className);
 197  
     }
 198  
 
 199  
         MetaClass resolveInPath(String className) {
 200  0
                 for(SpiMetaClassPathElement location : locations.values()) {
 201  0
                         MetaClass mc = location.resolveMetaClass(this, className);
 202  0
                     if(mc != null) {
 203  0
                             return mc;
 204  
                     }
 205  0
             }
 206  0
         return null;
 207  
         }
 208  
 
 209  
     /**
 210  
      * Get metadata representing a type from its byte code signature
 211  
      * 
 212  
      * @param fieldDescriptor
 213  
      *            The field descriptor as defined in section 4.3.2 of The Java
 214  
      *            Virtual Machine Specification
 215  
      * @return The type metadata
 216  
      */
 217  
     /*
 218  
      * FieldType: BaseType ObjectType ArrayType
 219  
      * 
 220  
      * BaseType: // see PrimitiveClass
 221  
      * 
 222  
      * ObjectType: L <classname> ;
 223  
      * 
 224  
      * ArrayType: [ ComponentType
 225  
      */
 226  
     @Override
 227  
         public MetaType resolveTypeForDescriptor(String fieldDescriptor) {
 228  
             MetaType mt; 
 229  0
         char typeCode = fieldDescriptor.charAt(0);
 230  0
         switch (typeCode) {
 231  
         case 'L':
 232  0
                         mt = resolveObjectType(fieldDescriptor);
 233  0
                         break;
 234  
         case '[':
 235  0
             mt = resolveArrayType(fieldDescriptor.substring(1));
 236  0
             break;
 237  
         default:
 238  0
                 mt = PrimitiveClass.valueOf(fieldDescriptor);
 239  
                 break;
 240  
         }
 241  0
         if(mt == null) {
 242  0
                 logger.info("Cannot resolve type "+fieldDescriptor);
 243  
         }
 244  0
         return mt;
 245  
     }
 246  
 
 247  
         private MetaType resolveObjectType(String fieldDescriptor) {
 248  0
                 String canonicalName = ClassNameHelper.internalToCanonicalName(fieldDescriptor);
 249  0
                 return resolveMetaClass(canonicalName);
 250  
         }
 251  
 
 252  
     private MetaArray resolveArrayType(String fieldDescriptor) {
 253  0
         MetaType arrayType = resolveTypeForDescriptor(fieldDescriptor);
 254  0
         return new DefaultArrayType(arrayType);
 255  
     }
 256  
 
 257  
     @Override
 258  
     public Collection<? extends MetaClass> findAllImplementors(String interfaceToFind) {
 259  0
         MetaClass mc = findMetaClass(interfaceToFind);
 260  
 
 261  0
         Collection<MetaClass> implementations = new ArrayList<MetaClass>();
 262  0
         MetaClassLoader classLoader = this;
 263  
         do {               
 264  0
             Iterator<? extends MetaClass> metaClasses = classLoader.getMetaClasses(); 
 265  0
             while(metaClasses.hasNext()) {
 266  0
                     MetaClass potentialImplementation = metaClasses.next();
 267  
                 try {
 268  0
                     if (!potentialImplementation.equals(mc) && mc.isAssignableFrom(potentialImplementation)) {
 269  0
                         implementations.add(potentialImplementation);
 270  
                     }
 271  
                 }
 272  0
                 catch (MissingResourceException mre) {
 273  0
                     continue;
 274  0
                 }
 275  0
             }
 276  0
             classLoader = classLoader.getParent();
 277  
         }
 278  0
         while (classLoader != null);
 279  0
         return implementations;
 280  
     }
 281  
 }