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    }