1 19 20 package org.netbeans.modules.apisupport.project.queries; 21 22 import java.beans.PropertyChangeEvent ; 23 import java.beans.PropertyChangeListener ; 24 import java.io.File ; 25 import java.io.IOException ; 26 import java.io.InputStream ; 27 import java.net.MalformedURLException ; 28 import java.net.URI ; 29 import java.net.URL ; 30 import java.util.ArrayList ; 31 import java.util.Enumeration ; 32 import java.util.HashMap ; 33 import java.util.HashSet ; 34 import java.util.Iterator ; 35 import java.util.List ; 36 import java.util.Map ; 37 import java.util.StringTokenizer ; 38 import java.util.zip.ZipEntry ; 39 import java.util.zip.ZipException ; 40 import java.util.zip.ZipFile ; 41 import javax.swing.event.ChangeEvent ; 42 import javax.swing.event.ChangeListener ; 43 import org.netbeans.api.java.queries.SourceForBinaryQuery; 44 import org.netbeans.modules.apisupport.project.NbModuleProjectType; 45 import org.netbeans.modules.apisupport.project.Util; 46 import org.netbeans.modules.apisupport.project.universe.ModuleList; 47 import org.netbeans.modules.apisupport.project.universe.NbPlatform; 48 import org.netbeans.modules.apisupport.project.universe.TestEntry; 49 import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation; 50 import org.openide.ErrorManager; 51 import org.openide.filesystems.FileObject; 52 import org.openide.filesystems.FileUtil; 53 import org.openide.filesystems.URLMapper; 54 import org.openide.xml.XMLUtil; 55 import org.w3c.dom.Document ; 56 import org.w3c.dom.Element ; 57 import org.xml.sax.InputSource ; 58 import org.xml.sax.SAXException ; 59 60 65 public final class GlobalSourceForBinaryImpl implements SourceForBinaryQueryImplementation { 66 67 68 static boolean quiet = false; 69 70 public SourceForBinaryQuery.Result findSourceRoots(URL binaryRoot) { 71 try { 72 { String binaryRootS = binaryRoot.toExternalForm(); 74 URL result = null; 75 if (binaryRootS.startsWith("jar:file:")) { if (binaryRootS.endsWith("/xtest/lib/nbjunit.jar!/")) { result = new URL (binaryRootS.substring("jar:".length(), binaryRootS.length() - "/xtest/lib/nbjunit.jar!/".length()) + "/xtest/nbjunit/src/"); } else if (binaryRootS.endsWith("/xtest/lib/nbjunit-ide.jar!/")) { result = new URL (binaryRootS.substring("jar:".length(), binaryRootS.length() - "/xtest/lib/nbjunit-ide.jar!/".length()) + "/xtest/nbjunit/ide/src/"); } else if (binaryRootS.endsWith("/xtest/lib/insanelib.jar!/")) { result = new URL (binaryRootS.substring("jar:".length(), binaryRootS.length() - "/xtest/lib/insanelib.jar!/".length()) + "/performance/insanelib/src/"); } else { 83 TestEntry testJar = TestEntry.get(archiveURLToFile(binaryRoot)); 85 if (testJar != null) { 86 result = testJar.getSrcDir(); 87 } 88 } 89 final FileObject resultFO = result != null ? URLMapper.findFileObject(result) : null; 90 if (resultFO != null) { 91 return new SourceForBinaryQuery.Result() { 92 public FileObject[] getRoots() { 93 return new FileObject[] {resultFO}; 94 } 95 public void addChangeListener(ChangeListener l) {} 96 public void removeChangeListener(ChangeListener l) {} 97 }; 98 } 99 } 100 } 101 NbPlatform supposedPlaf = null; 102 for (Iterator it = NbPlatform.getPlatforms().iterator(); it.hasNext(); ) { 103 NbPlatform plaf = (NbPlatform) it.next(); 104 if (binaryRoot.toExternalForm().indexOf(plaf.getDestDir().toURI().toURL().toExternalForm()) != -1) { 106 supposedPlaf = plaf; 107 break; 108 } 109 } 110 if (supposedPlaf == null) { 111 return null; 112 } 113 if (!binaryRoot.getProtocol().equals("jar")) { Util.err.log(binaryRoot + " is not an archive file."); return null; 116 } 117 File binaryRootF = archiveURLToFile(binaryRoot); 118 FileObject fo = FileUtil.toFileObject(binaryRootF); 119 if (fo == null) { 120 Util.err.log("Cannot found FileObject for " + binaryRootF + "(" + binaryRoot + ")"); return null; 122 } 123 return new NbPlatformResult(supposedPlaf, binaryRoot, fo.getName().replace('-', '.')); 128 } catch (IOException ex) { 129 throw new AssertionError (ex); 130 } 131 } 132 133 private static final class NbPlatformResult implements 134 SourceForBinaryQuery.Result, PropertyChangeListener { 135 136 private final List <ChangeListener > listeners = new ArrayList (); 137 private final NbPlatform platform; 138 private final URL binaryRoot; 139 private final String cnb; 140 141 private boolean alreadyListening; 142 143 NbPlatformResult(final NbPlatform platform, final URL binaryRoot, final String cnb) { 144 this.platform = platform; 145 this.binaryRoot = binaryRoot; 146 this.cnb = cnb; 147 } 150 151 public FileObject[] getRoots() { 152 final List <FileObject> candidates = new ArrayList (); 153 URL [] roots = platform.getSourceRoots(); 154 try { 155 for (int i = 0; i < roots.length; i++) { 156 if (roots[i].getProtocol().equals("jar")) { File nbSrcF = archiveURLToFile(roots[i]); 159 if (!nbSrcF.exists()) { 160 continue; 161 } 162 NetBeansSourcesParser nbsp; 163 try { 164 nbsp = NetBeansSourcesParser.getInstance(nbSrcF); 165 } catch (ZipException e) { 166 if (!quiet) { 167 Util.err.annotate(e, ErrorManager.UNKNOWN, nbSrcF + " does not seem to be a valid ZIP file.", null, null, null); Util.err.notify(ErrorManager.INFORMATIONAL, e); 169 } 170 continue; 171 } 172 if (nbsp == null) { 173 continue; 174 } 175 String pathInZip = nbsp.findSourceRoot(cnb); 176 if (pathInZip == null) { 177 continue; 178 } 179 URL u = new URL (roots[i], pathInZip); 180 FileObject entryFO = URLMapper.findFileObject(u); 181 if (entryFO != null) { 182 candidates.add(entryFO); 183 } 184 } else { 185 String relPath = resolveSpecialNBSrcPath(binaryRoot); 189 if (relPath == null) { 190 continue; 191 } 192 URL url = new URL (roots[i], relPath); 193 FileObject dir = URLMapper.findFileObject(url); 194 if (dir != null) { 195 candidates.add(dir); 196 } } 198 } 199 } catch (IOException ex) { 200 throw new AssertionError (ex); 201 } 202 return (FileObject[]) candidates.toArray(new FileObject[candidates.size()]); 203 } 204 205 public void addChangeListener(ChangeListener l) { 206 synchronized (listeners) { 208 listeners.add(l); 209 } 210 if (!alreadyListening) { 211 platform.addPropertyChangeListener(this); 212 alreadyListening = true; 213 } 214 } 215 216 public void removeChangeListener(ChangeListener l) { 217 synchronized (listeners) { 218 listeners.remove(l); 219 } 220 if (listeners.isEmpty()) { 221 platform.removePropertyChangeListener(this); 222 alreadyListening = false; 223 } 224 } 225 226 public void propertyChange(PropertyChangeEvent evt) { 227 if (evt.getPropertyName() == NbPlatform.PROP_SOURCE_ROOTS) { 228 Iterator it; 229 synchronized (listeners) { 230 if (listeners.isEmpty()) { 231 return; 232 } 233 it = new HashSet (listeners).iterator(); 234 } 235 ChangeEvent ev = new ChangeEvent (this); 236 while (it.hasNext()) { 237 ((ChangeListener ) it.next()).stateChanged(ev); 238 } 239 } 240 } 241 242 } 243 244 private static String resolveSpecialNBSrcPath(URL binaryRoot) throws MalformedURLException { 245 String binaryRootS = binaryRoot.toExternalForm(); 246 String result = null; 247 if (binaryRootS.startsWith("jar:file:")) { if (binaryRootS.endsWith("/modules/org-netbeans-modules-nbjunit.jar!/")) { result = "xtest/nbjunit/src/"; } else if (binaryRootS.endsWith("/modules/org-netbeans-modules-nbjunit-ide.jar!/")) { result = "xtest/nbjunit/ide/src/"; } else if (binaryRootS.endsWith("/modules/ext/insanelib.jar!/")) { result = "performance/insanelib/src/"; } else { 255 result = null; 256 } 257 } 258 return result; 259 } 260 261 private static File archiveURLToFile(final URL archiveURL) { 262 return new File (URI.create(FileUtil.getArchiveFile(archiveURL).toExternalForm())); 263 } 264 265 public static final class NetBeansSourcesParser { 266 267 268 private static final Map <File , NetBeansSourcesParser> instances = new HashMap (); 269 270 private static final String NBBUILD_ENTRY = "nbbuild/"; 272 private Map <String ,String > cnbToPrjDir; 273 private final ZipFile nbSrcZip; 274 private final String zipNBCVSRoot; 275 276 280 public static NetBeansSourcesParser getInstance(File nbSrcZip) throws ZipException , IOException { 281 NetBeansSourcesParser nbsp = (NetBeansSourcesParser) instances.get(nbSrcZip); 282 if (nbsp == null) { 283 ZipFile nbSrcZipFile = new ZipFile (nbSrcZip); 284 String zipNBCVSRoot = NetBeansSourcesParser.findNBCVSRoot(nbSrcZipFile); 285 if (zipNBCVSRoot != null) { 286 nbsp = new NetBeansSourcesParser(nbSrcZipFile, zipNBCVSRoot); 287 instances.put(nbSrcZip, nbsp); 288 } 289 } 290 return nbsp; 291 } 292 293 NetBeansSourcesParser(ZipFile nbSrcZip, String zipNBCVSRoot) { 294 this.nbSrcZip = nbSrcZip; 295 this.zipNBCVSRoot = zipNBCVSRoot; 296 } 297 298 String findSourceRoot(final String cnb) { 299 if (cnbToPrjDir == null) { 300 try { 301 doScanZippedNetBeansOrgSources(); 302 } catch (IOException ex) { 303 Util.err.notify(ErrorManager.WARNING, ex); 304 } 305 } 306 return (String ) cnbToPrjDir.get(cnb); 307 } 308 309 private static String findNBCVSRoot(final ZipFile nbSrcZip) { 310 String nbRoot = null; 311 for (Enumeration <? extends ZipEntry > en = nbSrcZip.entries(); en.hasMoreElements(); ) { 312 ZipEntry entry = (ZipEntry ) en.nextElement(); 313 if (!entry.isDirectory()) { 314 continue; 315 } 316 String name = entry.getName(); 317 if (!name.equals(NBBUILD_ENTRY) && 318 !(name.endsWith(NBBUILD_ENTRY) && name.substring(name.indexOf('/') + 1).equals(NBBUILD_ENTRY))) { 319 continue; 320 } 321 ZipEntry xmlEntry = nbSrcZip.getEntry(name + "nbproject/project.xml"); if (xmlEntry != null) { 323 nbRoot = name.substring(0, name.length() - NBBUILD_ENTRY.length()); 324 break; 325 } 326 } 327 return nbRoot; 328 } 329 330 private void doScanZippedNetBeansOrgSources() throws IOException { 331 cnbToPrjDir = new HashMap (); 332 for (Enumeration <? extends ZipEntry > en = nbSrcZip.entries(); en.hasMoreElements(); ) { 333 ZipEntry entry = (ZipEntry ) en.nextElement(); 334 if (!entry.isDirectory()) { 335 continue; 336 } 337 String path = entry.getName().substring(0, entry.getName().length() - 1); if (this.zipNBCVSRoot != null && (!path.startsWith(this.zipNBCVSRoot) || path.equals(this.zipNBCVSRoot))) { 339 continue; 340 } 341 StringTokenizer st = new StringTokenizer (path, "/"); if (st.countTokens() > ModuleList.DEPTH_NB_ALL) { 343 continue; 344 } 345 String name = path.substring(path.lastIndexOf('/') + 1, path.length()); 346 if (ModuleList.EXCLUDED_DIR_NAMES.contains(name)) { 347 continue; 349 } 350 ZipEntry src = nbSrcZip.getEntry(entry.getName() + "src/"); if (src == null || !src.isDirectory()) { 353 continue; 354 } 355 356 ZipEntry projectXML = nbSrcZip.getEntry(entry.getName() + "nbproject/project.xml"); if (projectXML == null) { 358 continue; 359 } 360 String cnb = parseCNB(projectXML); 361 if (cnb != null) { 362 cnbToPrjDir.put(cnb, entry.getName() + "src/"); } 364 } 365 } 366 367 private String parseCNB(final ZipEntry projectXML) throws IOException { 368 Document doc; 369 InputStream is = nbSrcZip.getInputStream(projectXML); 370 try { 371 doc = XMLUtil.parse(new InputSource (is), false, true, null, null); 372 } catch (SAXException e) { 373 throw (IOException ) new IOException (projectXML + ": " + e.toString()).initCause(e); } finally { 375 is.close(); 376 } 377 Element docel = doc.getDocumentElement(); 378 Element type = Util.findElement(docel, "type", "http://www.netbeans.org/ns/project/1"); String cnb = null; 380 if (Util.findText(type).equals("org.netbeans.modules.apisupport.project")) { Element cfg = Util.findElement(docel, "configuration", "http://www.netbeans.org/ns/project/1"); Element data = Util.findElement(cfg, "data", NbModuleProjectType.NAMESPACE_SHARED); if (data != null) { 384 cnb = Util.findText(Util.findElement(data, "code-name-base", NbModuleProjectType.NAMESPACE_SHARED)); } 386 } 387 return cnb; 388 } 389 390 } 391 392 } 393 | Popular Tags |