001    /*
002     * Copyright 2010 The Apache Software Foundation.
003     * 
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     * 
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.vafer.jdependency;
017    
018    import java.io.IOException;
019    import java.io.InputStream;
020    import java.util.HashMap;
021    import java.util.HashSet;
022    import java.util.Map;
023    import java.util.Set;
024    import java.util.jar.JarEntry;
025    import java.util.jar.JarInputStream;
026    
027    import org.objectweb.asm.ClassReader;
028    import org.vafer.jdependency.asm.DependenciesClassAdapter;
029    
030    public final class Clazzpath {
031    
032        private final Set<ClazzpathUnit> units = new HashSet();
033        private final Map<String, Clazz> missing = new HashMap();
034        private final Map<String, Clazz> clazzes = new HashMap();
035    
036        public Clazzpath() {
037        }
038    
039        public boolean removeClazzpathUnit( final ClazzpathUnit pUnit ) {
040            
041            final Set<Clazz> unitClazzes = pUnit.getClazzes();
042    
043            for (Clazz clazz : unitClazzes) {
044                clazz.removeClazzpathUnit(pUnit);
045                if (clazz.getClazzpathUnits().size() == 0) {
046                    clazzes.remove(clazz.toString());
047                    // missing.put(clazz.toString(), clazz);
048                }
049            }
050            
051            return units.remove(pUnit);
052        }
053    
054        public ClazzpathUnit addClazzpathUnit( final InputStream pInputStream, final String pId ) throws IOException {
055    
056            final Map unitClazzes = new HashMap();
057            final Map unitDependencies = new HashMap();
058    
059            final ClazzpathUnit unit = new ClazzpathUnit(pId, unitClazzes, unitDependencies);
060            
061            final JarInputStream inputStream = new JarInputStream(pInputStream);
062            
063            while (true) {
064                final JarEntry entry = inputStream.getNextJarEntry();
065                
066                if (entry == null) {
067                    break;
068                }
069    
070                final String entryName = entry.getName();
071                if (entryName.endsWith(".class")) {
072    
073                    final String clazzName = entryName.substring(0, entryName.length() - 6).replace('/', '.');
074    
075                    Clazz clazz = getClazz(clazzName);
076    
077                    if (clazz == null) {
078                        clazz = missing.get(clazzName);
079    
080                        if (clazz != null) {
081                            // already marked missing
082                            clazz = missing.remove(clazzName);
083                        } else {
084                            clazz = new Clazz(clazzName);
085                        }
086                    }
087                    
088                    clazz.addClazzpathUnit(unit);
089    
090                    clazzes.put(clazzName, clazz);
091                    unitClazzes.put(clazzName, clazz);
092    
093                    final DependenciesClassAdapter v = new DependenciesClassAdapter();
094                    new ClassReader(inputStream).accept(v, ClassReader.EXPAND_FRAMES | ClassReader.SKIP_DEBUG);
095                    final Set<String> depNames = v.getDependencies();
096    
097                    for (String depName : depNames) {
098    
099                        Clazz dep = getClazz(depName);
100    
101                        if (dep == null) {
102                            // there is no such clazz yet
103                            dep = missing.get(depName);
104                        }
105    
106                        if (dep == null) {
107                            // it is also not recorded to be missing
108                            dep = new Clazz(depName);
109                            dep.addClazzpathUnit(unit);
110                            missing.put(depName, dep);
111                        }
112    
113                        if (dep != clazz) {
114                            unitDependencies.put(depName, dep);
115                            clazz.addDependency(dep);
116                        }
117                    }
118                }
119            }
120    
121            units.add(unit);
122    
123            return unit;
124        }
125    
126        public Set getClazzes() {
127            final Set all = new HashSet();
128            for (Clazz clazz : clazzes.values()) {
129                all.add(clazz);
130            }
131            return all;
132        }
133    
134        public Set getClashedClazzes() {
135            final Set all = new HashSet();
136            for (Clazz clazz : clazzes.values()) {          
137                if (clazz.getClazzpathUnits().size() > 1) {
138                    all.add(clazz);
139                }
140            }
141            return all; 
142        }
143    
144        public Set getMissingClazzes() {
145            final Set all = new HashSet();
146            for (Clazz clazz : missing.values()) {
147                all.add(clazz);
148            }
149            return all;
150        }
151        
152        public Clazz getClazz(final String pClazzName) {
153            return (Clazz) clazzes.get(pClazzName);
154        }
155    
156        public ClazzpathUnit[] getUnits() {
157            return (ClazzpathUnit[]) units.toArray(new ClazzpathUnit[units.size()]);
158        }
159    
160    }