001    /*
002     * Licensed under the Apache License, Version 2.0 (the "License");
003     * you may not use this file except in compliance with the License.
004     * You may obtain a copy of the License at
005     *
006     *      http://www.apache.org/licenses/LICENSE-2.0
007     *
008     * Unless required by applicable law or agreed to in writing, software
009     * distributed under the License is distributed on an "AS IS" BASIS,
010     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011     * See the License for the specific language governing permissions and
012     * limitations under the License.
013     */
014    package org.apache.commons.classscan.builtin;
015    
016    import java.io.InputStream;
017    import java.util.Collection;
018    import java.util.HashMap;
019    import java.util.Iterator;
020    import java.util.Map;
021    
022    import org.apache.commons.classscan.ClassPathElement;
023    import org.apache.commons.classscan.ClassFile;
024    import org.apache.commons.classscan.model.MetaClass;
025    import org.apache.commons.classscan.spi.model.SpiMetaClass;
026    import org.apache.commons.classscan.spi.model.SpiMetaClassLoader;
027    import org.apache.commons.classscan.spi.model.SpiMetaClassPathElement;
028    import org.apache.commons.classscan.spi.model.SpiMetaRegistry;
029    import org.apache.commons.classscan.util.NameSet;
030    import org.slf4j.Logger;
031    import org.slf4j.LoggerFactory;
032    
033    public class DefaultMetaClassPathElement implements SpiMetaClassPathElement {
034    
035        private static final Logger logger = LoggerFactory.getLogger(DefaultMetaClassPathElement.class);
036    
037            private final String baseUrl;   
038        private Map<String, SpiMetaClass> workClasses = new HashMap<String, SpiMetaClass>();
039        private NameSet<SpiMetaClass> sealedClasses;
040    
041            public DefaultMetaClassPathElement(SpiMetaRegistry metaRegistry, ClassPathElement classPathElement) {
042                    this.baseUrl = classPathElement.getLocation();
043    
044                    for(ClassFile classPathFile : classPathElement) {
045                            addFile(metaRegistry, classPathFile);
046                    }
047        }
048    
049            private void addFile(SpiMetaRegistry metaRegistry, ClassFile classPathFile) {
050                    String className = classPathFile.getClassName();
051                    try {
052                            InputStream byteStream = classPathFile.getBytes();
053                            try {
054                                    SpiMetaClass mc= metaRegistry.createMetaClass(this, className, byteStream);
055                                    addMetaClass(mc);
056                            }
057                            finally {
058                                    byteStream.close();
059                            }
060                    } catch (Exception e) {
061                            logger.info("Exception while loading "+className, e);
062                    }
063            }
064    
065        void addMetaClass(SpiMetaClass mc) {
066            String name= mc.getName();
067            if (workClasses.containsKey(name)) {
068                return;
069            }
070            workClasses.put(name, mc);
071        }
072    
073            @Override
074            public boolean resolve(SpiMetaClassLoader classLoader) {
075            if( workClasses.isEmpty() ) {
076                    sealedClasses = NameSet.emptyNameSet();
077            }
078            else {
079                    Iterator<Map.Entry<String, SpiMetaClass>> metaClasses = workClasses.entrySet().iterator();
080                    while(metaClasses.hasNext()) {
081                            Map.Entry<String, SpiMetaClass> entry = metaClasses.next();
082                            if(!entry.getValue().resolve(classLoader)) {
083                                    logger.info("Could not resolve dependencies of "+entry.getKey());
084                                    metaClasses.remove();
085                            }
086                    }
087                    sealedClasses = new NameSet<SpiMetaClass>(SpiMetaClass.class, workClasses.values());
088            }
089    
090            workClasses = null;
091            if( sealedClasses.isEmpty() ) {
092                    logger.info("No classes in "+baseUrl);
093                    return false;
094            }       
095            return true;
096            }
097    
098            @Override
099            public MetaClass resolveMetaClass(SpiMetaClassLoader classLoader, String className) {
100                    if(workClasses==null) {
101                            return sealedClasses.getValue(className);
102                    }
103                    SpiMetaClass workClass = workClasses.get(className);
104                    if( workClass != null && workClass.resolve(classLoader) ) {
105                            return workClass;
106                    }
107                    return null;
108            }
109    
110            @Override
111            public Collection<? extends MetaClass> getMetaClasses() {
112                    return sealedClasses;
113            }
114    
115            @Override
116            public MetaClass getMetaClass(String className) {
117                    return sealedClasses.getValue(className);
118            }
119    
120            @Override
121            public String getName() {
122                    return baseUrl;
123            }
124    }