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 }