1 19 20 package org.netbeans.modules.apisupport.project.universe; 21 22 import java.io.DataInput ; 23 import java.io.DataInputStream ; 24 import java.io.File ; 25 import java.io.IOException ; 26 import java.io.InputStream ; 27 import java.util.ArrayList ; 28 import java.util.Arrays ; 29 import java.util.Collections ; 30 import java.util.Enumeration ; 31 import java.util.HashSet ; 32 import java.util.Iterator ; 33 import java.util.List ; 34 import java.util.Set ; 35 import java.util.StringTokenizer ; 36 import java.util.jar.JarEntry ; 37 import java.util.jar.JarFile ; 38 import org.netbeans.modules.apisupport.project.ManifestManager; 39 import org.netbeans.modules.apisupport.project.Util; 40 import org.netbeans.spi.project.support.ant.PropertyUtils; 41 import org.openide.ErrorManager; 42 43 abstract class AbstractEntry implements ModuleEntry { 44 45 private String localizedName; 46 private Set <String > publicClassNames; 47 48 protected abstract LocalizedBundleInfo getBundleInfo(); 49 50 public String getLocalizedName() { 51 if (localizedName == null) { 52 localizedName = getBundleInfo().getDisplayName(); 53 if (localizedName == null) { 54 localizedName = getCodeNameBase(); 55 } 56 } 57 return localizedName; 58 } 59 60 public String getCategory() { 61 return getBundleInfo().getCategory(); 62 } 63 64 public String getShortDescription() { 65 return getBundleInfo().getShortDescription(); 66 } 67 68 public String getLongDescription() { 69 return getBundleInfo().getLongDescription(); 70 } 71 72 public int compareTo(Object o) { 73 int retval = getLocalizedName().compareTo(((ModuleEntry) o).getLocalizedName()); 74 return (retval != 0) ? retval : getCodeNameBase().compareTo(((ModuleEntry) o).getCodeNameBase()); 75 } 76 77 public synchronized Set <String > getPublicClassNames() { 78 if (publicClassNames == null) { 79 try { 80 publicClassNames = computePublicClassNamesInMainModule(); 81 String [] cpext = PropertyUtils.tokenizePath(getClassPathExtensions()); 82 for (int i = 0; i < cpext.length; i++) { 83 File ext = new File (cpext[i]); 84 if (!ext.isFile()) { 85 Util.err.log(ErrorManager.WARNING, "Could not find Class-Path extension " + ext + " of " + this); 86 continue; 87 } 88 scanJarForPublicClassNames(publicClassNames, ext); 89 } 90 } catch (IOException e) { 91 publicClassNames = Collections.EMPTY_SET; 92 Util.err.annotate(e, ErrorManager.UNKNOWN, "While scanning for public classes in " + this, null, null, null); Util.err.notify(ErrorManager.INFORMATIONAL, e); 94 } 95 } 96 return publicClassNames; 97 } 98 99 protected final void scanJarForPublicClassNames(Set <String > result, File jar) throws IOException { 100 ManifestManager.PackageExport[] pkgs = getPublicPackages(); 101 Set <String > publicPackagesSlashNonRec = new HashSet (); 102 List <String > publicPackagesSlashRec = new ArrayList (); 103 for (int i = 0; i < pkgs.length; i++) { 104 String name = pkgs[i].getPackage().replace('.', '/') + '/'; 105 if (pkgs[i].isRecursive()) { 106 publicPackagesSlashRec.add(name); 107 } else { 108 publicPackagesSlashNonRec.add(name); 109 } 110 } 111 JarFile jf = new JarFile (jar); 112 try { 113 Enumeration entries = jf.entries(); 114 ENTRY: while (entries.hasMoreElements()) { 115 JarEntry entry = (JarEntry ) entries.nextElement(); 116 String path = entry.getName(); 117 if (!path.endsWith(".class")) { continue; 119 } 120 int slash = path.lastIndexOf('/'); 121 if (slash == -1) { 122 continue; 123 } 124 String pkg = path.substring(0, slash + 1); 125 if (!publicPackagesSlashNonRec.contains(pkg)) { 126 boolean pub = false; 127 Iterator it = publicPackagesSlashRec.iterator(); 128 while (it.hasNext()) { 129 if (pkg.startsWith((String ) it.next())) { 130 pub = true; 131 break; 132 } 133 } 134 if (!pub) { 135 continue; 136 } 137 } 138 StringTokenizer tok = new StringTokenizer (path, "$"); while (tok.hasMoreTokens()) { 140 String component = tok.nextToken(); 141 char c = component.charAt(0); 142 if (c >= '0' && c <= '9') { 143 continue ENTRY; 145 } 146 } 147 if (!isPublic(jf, entry)) { 148 continue; 149 } 150 result.add(path.substring(0, path.length() - 6).replace('/', '.')); 151 } 152 } finally { 153 jf.close(); 154 } 155 } 156 157 protected abstract Set <String > computePublicClassNamesInMainModule() throws IOException ; 158 159 164 protected static boolean isDeclaredAsFriend(String [] friends, String cnb) { 165 return friends == null ? true : Arrays.binarySearch(friends, cnb) >= 0; 166 } 167 168 169 private static boolean isPublic(JarFile jf, JarEntry entry) throws IOException { 170 InputStream is = jf.getInputStream(entry); 171 try { 172 DataInput input = new DataInputStream (is); 173 skip(input, 8); int size = input.readUnsignedShort() - 1; for (int i = 0; i < size; i++) { 177 byte tag = input.readByte(); 178 switch (tag) { 179 case 1: input.readUTF(); 181 break; 182 case 3: case 4: case 9: case 10: case 11: case 12: skip(input, 4); 189 break; 190 case 7: case 8: skip(input, 2); 193 break; 194 case 5: case 6: skip(input, 8); 197 i++; break; 199 default: 200 throw new IOException ("Unrecognized constant pool tag " + tag + " at index " + i); } 202 } 203 int accessFlags = input.readUnsignedShort(); 204 return (accessFlags & 0x0001) > 0; 205 } finally { 206 is.close(); 207 } 208 } 209 private static void skip(DataInput input, int bytes) throws IOException { 210 int skipped = input.skipBytes(bytes); 211 if (skipped != bytes) { 212 throw new IOException (); 213 } 214 } 215 216 } 217 | Popular Tags |