1 19 20 package org.netbeans.modules.project.libraries; 21 22 import java.beans.PropertyChangeListener ; 23 import java.beans.PropertyChangeSupport ; 24 import java.io.File ; 25 import java.io.IOException ; 26 import java.io.InputStream ; 27 import java.io.OutputStream ; 28 import java.io.OutputStreamWriter ; 29 import java.io.PrintWriter ; 30 import java.net.URL ; 31 import java.util.Collections ; 32 import java.util.HashMap ; 33 import java.util.Iterator ; 34 import java.util.List ; 35 import java.util.Map ; 36 import java.util.Properties ; 37 import java.util.ResourceBundle ; 38 import java.util.Set ; 39 import java.util.StringTokenizer ; 40 import java.util.TreeSet ; 41 import javax.xml.parsers.ParserConfigurationException ; 42 import org.netbeans.spi.project.libraries.LibraryImplementation; 43 import org.netbeans.spi.project.libraries.LibraryTypeProvider; 44 import org.openide.ErrorManager; 45 import org.openide.filesystems.FileChangeAdapter; 46 import org.openide.filesystems.FileEvent; 47 import org.openide.filesystems.FileLock; 48 import org.openide.filesystems.FileObject; 49 import org.openide.filesystems.FileSystem; 50 import org.openide.filesystems.FileUtil; 51 import org.openide.filesystems.Repository; 52 import org.openide.util.NbBundle; 53 import org.openide.xml.XMLUtil; 54 import org.xml.sax.InputSource ; 55 import org.xml.sax.SAXException ; 56 57 public class LibrariesStorage extends FileChangeAdapter implements WritableLibraryProvider { 58 59 private static final String NB_HOME_PROPERTY = "netbeans.home"; private static final String LIBRARIES_REPOSITORY = "org-netbeans-api-project-libraries/Libraries"; private static final String TIME_STAMPS_FILE = "libraries-timestamps.properties"; private static final String XML_EXT = "xml"; 64 private FileObject storage = null; 66 67 private Map <String , LibraryImplementation> libraries; 68 69 private Map <String , LibraryImplementation> librariesByFileNames; 70 71 private ResourceBundle bundle; 74 75 private PropertyChangeSupport support; 76 77 private boolean initialized; 80 81 private Properties timeStamps; 82 83 84 87 public LibrariesStorage() { 88 this.support = new PropertyChangeSupport (this); 89 } 90 91 94 LibrariesStorage (FileObject storage) { 95 this (); 96 this.storage = storage; 97 } 98 99 100 101 105 private static final FileObject createStorage () { 106 FileSystem storageFS = Repository.getDefault().getDefaultFileSystem(); 107 try { 108 return FileUtil.createFolder(storageFS.getRoot(), LIBRARIES_REPOSITORY); 109 } catch (IOException e) { 110 return null; 111 } 112 } 113 114 115 private void loadFromStorage() { 118 libraries = new HashMap <String ,LibraryImplementation>(); 120 librariesByFileNames = new HashMap <String ,LibraryImplementation>(); 121 LibraryDeclarationHandlerImpl handler = new LibraryDeclarationHandlerImpl(); 122 LibraryDeclarationConvertorImpl convertor = new LibraryDeclarationConvertorImpl(); 123 LibraryDeclarationParser parser = new LibraryDeclarationParser(handler,convertor); 124 for (FileObject descriptorFile : storage.getChildren()) { 126 if (XML_EXT.equalsIgnoreCase(descriptorFile.getExt())) { 127 try { 128 handler.setLibrary (null); 129 readLibrary (descriptorFile, parser); 130 LibraryImplementation impl = handler.getLibrary (); 131 if (impl != null) { 132 LibraryTypeProvider provider = LibraryTypeRegistry.getDefault().getLibraryTypeProvider (impl.getType()); 133 if (provider == null) { 134 ErrorManager.getDefault().log(ErrorManager.WARNING, "LibrariesStorage: Can not invoke LibraryTypeProvider.libraryCreated(), the library type provider is unknown."); } 136 else if (libraries.keySet().contains(impl.getName())) { 137 ErrorManager.getDefault().log(ErrorManager.WARNING, "LibrariesStorage: Library \"" 138 +impl.getName()+"\" is already defined, skeeping the definition from: " 139 + FileUtil.getFileDisplayName(descriptorFile)); 140 } 141 else { 142 if (!isUpToDate(descriptorFile)) { 143 provider.libraryCreated (impl); 144 updateTimeStamp(descriptorFile); 145 } 146 librariesByFileNames.put(descriptorFile.getPath(),impl); 147 libraries.put (impl.getName(),impl); 148 } 149 } 150 } catch (SAXException e) { 151 ErrorManager.getDefault().notify (e); 152 } catch (ParserConfigurationException e) { 153 ErrorManager.getDefault().notify (e); 154 } catch (IOException e) { 155 ErrorManager.getDefault().notify (e); 156 } catch (RuntimeException e) { 157 ErrorManager.getDefault().notify (e); 159 } 160 } 161 } 162 try { 163 saveTimeStamps(); 164 } catch (IOException ioe) { 165 ErrorManager.getDefault().notify(ioe); 166 } 167 } 168 169 private synchronized void initStorage () { 170 if (!initialized) { 171 if (this.storage == null) { 172 this.storage = createStorage(); 173 if (storage == null) { 174 libraries = Collections.emptyMap(); 176 librariesByFileNames = Collections.emptyMap(); 177 initialized = true; 178 return; 179 } 180 } 181 this.loadFromStorage(); 182 this.storage.addFileChangeListener (this); 183 initialized = true; 184 } 185 } 186 187 private static LibraryImplementation readLibrary (FileObject descriptorFile) throws SAXException , ParserConfigurationException , IOException { 188 return readLibrary (descriptorFile, (LibraryImplementation) null); 189 } 190 191 private static LibraryImplementation readLibrary (FileObject descriptorFile, LibraryImplementation impl) throws SAXException , ParserConfigurationException , IOException { 192 LibraryDeclarationHandlerImpl handler = new LibraryDeclarationHandlerImpl(); 193 LibraryDeclarationConvertorImpl convertor = new LibraryDeclarationConvertorImpl(); 194 LibraryDeclarationParser parser = new LibraryDeclarationParser(handler,convertor); 195 handler.setLibrary (impl); 196 readLibrary (descriptorFile, parser); 197 return handler.getLibrary(); 198 } 199 200 private static void readLibrary (FileObject descriptorFile, LibraryDeclarationParser parser) throws SAXException , ParserConfigurationException , IOException { 201 URL baseURL = descriptorFile.getURL(); 202 InputSource input = new InputSource (baseURL.toExternalForm()); 203 input.setByteStream(descriptorFile.getInputStream()); try { 205 parser.parse(input); 206 } catch (SAXException e) { 207 ErrorManager.getDefault().annotate(e, ErrorManager.UNKNOWN, "From " + baseURL, null, null, null); 208 throw e; 209 } 210 } 211 212 private void writeLibrary (final FileObject storage, final LibraryImplementation library) throws IOException { 213 storage.getFileSystem().runAtomicAction( 214 new FileSystem.AtomicAction() { 215 public void run() throws IOException { 216 String libraryType = library.getType (); 217 LibraryTypeProvider libraryTypeProvider = LibraryTypeRegistry.getDefault().getLibraryTypeProvider (libraryType); 218 if (libraryTypeProvider == null) { 219 ErrorManager.getDefault().log (ErrorManager.WARNING, "LibrariesStorage: Cannot store library, the library type is not recognized by any of installed LibraryTypeProviders."); return; 221 } 222 FileObject fo = storage.createData (library.getName(),"xml"); writeLibraryDefinition (fo, library, libraryTypeProvider); 224 } 225 } 226 ); 227 } 228 229 private static void writeLibraryDefinition (final FileObject definitionFile, final LibraryImplementation library, final LibraryTypeProvider libraryTypeProvider) throws IOException { 230 FileLock lock = null; 231 PrintWriter out = null; 232 try { 233 lock = definitionFile.lock(); 234 out = new PrintWriter (new OutputStreamWriter (definitionFile.getOutputStream (lock),"UTF-8")); 235 out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); out.println("<!DOCTYPE library PUBLIC \"-//NetBeans//DTD Library Declaration 1.0//EN\" \"http://www.netbeans.org/dtds/library-declaration-1_0.dtd\">"); out.println("<library version=\"1.0\">"); out.println("\t<name>"+library.getName()+"</name>"); out.println("\t<type>"+library.getType()+"</type>"); 241 String description = library.getDescription(); 242 if (description != null && description.length() > 0) { 243 out.println("\t<description>"+description+"</description>"); } 245 String localizingBundle = library.getLocalizingBundle(); 246 if (localizingBundle != null && localizingBundle.length() > 0) { 247 out.println("\t<localizing-bundle>"+XMLUtil.toElementContent(localizingBundle)+"</localizing-bundle>"); } 249 String [] volumeTypes = libraryTypeProvider.getSupportedVolumeTypes (); 250 for (String vtype : volumeTypes) { 251 out.println("\t<volume>"); out.println ("\t\t<type>" + vtype + "</type>"); List <URL > volume = library.getContent(vtype); 254 if (volume != null) { 255 for (URL url : volume) { 257 out.println("\t\t<resource>"+XMLUtil.toElementContent(url.toExternalForm())+"</resource>"); } 259 } 260 out.println("\t</volume>"); } 262 out.println("</library>"); } finally { 264 if (out != null) 265 out.close(); 266 if (lock != null) 267 lock.releaseLock(); 268 } 269 } 270 271 272 private void fireLibrariesChanged () { 273 this.support.firePropertyChange(PROP_LIBRARIES,null,null); 274 } 275 276 277 public final void addPropertyChangeListener (PropertyChangeListener listener) { 278 this.support.addPropertyChangeListener(listener); 279 } 280 281 282 public final void removePropertyChangeListener (PropertyChangeListener listener) { 283 this.support.removePropertyChangeListener(listener); 284 } 285 286 289 public final LibraryImplementation[] getLibraries() { 290 this.initStorage(); 291 assert this.storage != null : "Storage is not initialized"; 292 return libraries.values().toArray(new LibraryImplementation[libraries.size()]); 293 } 295 296 public void addLibrary (LibraryImplementation library) throws IOException { 297 this.initStorage(); 298 assert this.storage != null : "Storage is not initialized"; 299 writeLibrary(this.storage,library); 300 } 301 302 public void removeLibrary (LibraryImplementation library) throws IOException { 303 this.initStorage(); 304 assert this.storage != null : "Storage is not initialized"; 305 for (String key : librariesByFileNames.keySet()) { 306 LibraryImplementation lib = this.librariesByFileNames.get(key); 307 if (library.equals (lib)) { 308 FileObject fo = this.storage.getFileSystem().findResource (key); 309 if (fo != null) { 310 fo.delete(); 311 return; 312 } 313 } 314 } 315 } 316 317 public void updateLibrary(final LibraryImplementation oldLibrary, final LibraryImplementation newLibrary) throws IOException { 318 this.initStorage(); 319 assert this.storage != null : "Storage is not initialized"; 320 for (String key : librariesByFileNames.keySet()) { 321 LibraryImplementation lib = librariesByFileNames.get(key); 322 if (oldLibrary.equals(lib)) { 323 final FileObject fo = this.storage.getFileSystem().findResource(key); 324 if (fo != null) { 325 String libraryType = newLibrary.getType (); 326 final LibraryTypeProvider libraryTypeProvider = LibraryTypeRegistry.getDefault().getLibraryTypeProvider (libraryType); 327 if (libraryTypeProvider == null) { 328 ErrorManager.getDefault().log (ErrorManager.WARNING, "LibrariesStorageL Cannot store library, the library type is not recognized by any of installed LibraryTypeProviders."); return; 330 } 331 this.storage.getFileSystem().runAtomicAction( 332 new FileSystem.AtomicAction() { 333 public void run() throws IOException { 334 writeLibraryDefinition (fo, newLibrary, libraryTypeProvider); 335 } 336 } 337 ); 338 } 339 } 340 } 341 } 342 343 344 public void fileDataCreated(FileEvent fe) { 345 FileObject fo = fe.getFile(); 346 try { 347 final LibraryImplementation impl = readLibrary (fo); 348 if (impl != null) { 349 LibraryTypeProvider provider = LibraryTypeRegistry.getDefault().getLibraryTypeProvider (impl.getType()); 350 if (provider == null) { 351 ErrorManager.getDefault().log(ErrorManager.WARNING, "LibrariesStorage: Can not invoke LibraryTypeProvider.libraryCreated(), the library type provider is unknown."); } 353 else { 354 synchronized (this) { 355 this.libraries.put (impl.getName(), impl); 356 this.librariesByFileNames.put (fo.getPath(), impl); 357 } 358 try { 361 provider.libraryCreated (impl); 362 updateTimeStamp(fo); 363 saveTimeStamps(); 364 } catch (RuntimeException e) { 365 String message = NbBundle.getMessage(LibrariesStorage.class,"MSG_libraryCreatedError"); 366 ErrorManager.getDefault().notify(ErrorManager.getDefault().annotate(e,message)); 367 } 368 this.fireLibrariesChanged(); 369 } 370 } 371 } catch (SAXException e) { 372 ErrorManager.getDefault().notify (e); 373 } catch (ParserConfigurationException e) { 374 ErrorManager.getDefault().notify (e); 375 } catch (IOException e) { 376 ErrorManager.getDefault().notify (e); 377 } 378 } 379 380 public void fileDeleted(FileEvent fe) { 381 String fileName = fe.getFile().getPath(); 382 LibraryImplementation impl; 383 synchronized (this) { 384 impl = this.librariesByFileNames.remove(fileName); 385 if (impl != null) { 386 this.libraries.remove (impl.getName()); 387 } 388 } 389 if (impl != null) { 390 LibraryTypeProvider provider = LibraryTypeRegistry.getDefault().getLibraryTypeProvider (impl.getType()); 391 if (provider == null) { 392 ErrorManager.getDefault().log(ErrorManager.WARNING, "LibrariesStorage: Cannot invoke LibraryTypeProvider.libraryDeleted(), the library type provider is unknown."); } 394 else { 395 try { 398 provider.libraryDeleted (impl); 399 } catch (RuntimeException e) { 400 String message = NbBundle.getMessage(LibrariesStorage.class,"MSG_libraryDeletedError"); 401 ErrorManager.getDefault().notify(ErrorManager.getDefault().annotate(e,message)); 402 } 403 } 404 this.fireLibrariesChanged(); 405 } 406 } 407 408 public void fileChanged(FileEvent fe) { 409 FileObject definitionFile = fe.getFile(); 410 String fileName = definitionFile.getPath(); 411 LibraryImplementation impl; 412 synchronized (this) { 413 impl = this.librariesByFileNames.get(fileName); 414 } 415 if (impl != null) { 416 try { 417 readLibrary (definitionFile, impl); 418 LibraryTypeProvider provider = LibraryTypeRegistry.getDefault().getLibraryTypeProvider (impl.getType()); 419 if (provider == null) { 420 ErrorManager.getDefault().log(ErrorManager.WARNING, "LibrariesStorage: Can not invoke LibraryTypeProvider.libraryCreated(), the library type provider is unknown."); } 422 try { 423 provider.libraryCreated (impl); 425 updateTimeStamp(definitionFile); 426 saveTimeStamps(); 427 } catch (RuntimeException e) { 428 String message = NbBundle.getMessage(LibrariesStorage.class,"MSG_libraryCreatedError"); 429 ErrorManager.getDefault().notify(ErrorManager.getDefault().annotate(e,message)); 430 } 431 } catch (SAXException se) { 432 ErrorManager.getDefault().notify(se); 433 } catch (ParserConfigurationException pce) { 434 ErrorManager.getDefault().notify(pce); 435 } catch (IOException ioe) { 436 ErrorManager.getDefault().notify(ioe); 437 } 438 } 439 } 440 441 protected final ResourceBundle getBundle() { 442 if (bundle == null) { 443 bundle = NbBundle.getBundle(LibrariesStorage.class); 444 } 445 return bundle; 446 } 447 448 private boolean isUpToDate (FileObject libraryDefinition) { 449 Properties timeStamps = getTimeStamps(); 450 String ts = (String ) timeStamps.get (libraryDefinition.getNameExt()); 451 return ts == null ? false : Long.parseLong(ts) >= libraryDefinition.lastModified().getTime(); 452 } 453 454 private void updateTimeStamp (FileObject libraryDefinition) { 455 Properties timeStamps = getTimeStamps(); 456 timeStamps.put(libraryDefinition.getNameExt(), Long.toString(libraryDefinition.lastModified().getTime())); 457 } 458 459 private void saveTimeStamps () throws IOException { 460 if (this.storage != null) { 461 Properties timeStamps = getTimeStamps(); 462 if (timeStamps.get(NB_HOME_PROPERTY) == null) { 463 String currNbLoc = getNBRoots(); 464 timeStamps.put(NB_HOME_PROPERTY,currNbLoc); 465 } 466 FileObject parent = storage.getParent(); 467 FileObject timeStampFile = parent.getFileObject(TIME_STAMPS_FILE); 468 if (timeStampFile == null) { 469 timeStampFile = parent.createData(TIME_STAMPS_FILE); 470 } 471 FileLock lock = timeStampFile.lock(); 472 try { 473 OutputStream out = timeStampFile.getOutputStream(lock); 474 try { 475 timeStamps.store (out, null); 476 } finally { 477 out.close(); 478 } 479 } finally { 480 lock.releaseLock(); 481 } 482 } 483 } 484 485 private Properties getTimeStamps () { 486 if (this.timeStamps == null) { 487 this.timeStamps = new Properties (); 488 if (this.storage != null) { 489 FileObject timeStampFile = storage.getParent().getFileObject(TIME_STAMPS_FILE); 490 if (timeStampFile != null) { 491 try { 492 InputStream in = timeStampFile.getInputStream(); 493 try { 494 this.timeStamps.load (in); 495 } finally { 496 in.close(); 497 } 498 String nbLoc = (String ) this.timeStamps.get (NB_HOME_PROPERTY); 499 String currNbLoc = getNBRoots (); 500 if (nbLoc == null || !nbLoc.equals (currNbLoc)) { 501 this.timeStamps.clear(); 502 } 503 } catch (IOException ioe) { 504 ErrorManager.getDefault().notify(ioe); 505 } 506 } 507 } 508 } 509 return this.timeStamps; 510 } 511 512 private static String getNBRoots () { 513 Set <String > result = new TreeSet <String >(); 514 String currentNbLoc = System.getProperty ("netbeans.home"); if (currentNbLoc != null) { 516 File f = FileUtil.normalizeFile(new File (currentNbLoc)); 517 if (f.isDirectory()) { 518 result.add (f.getAbsolutePath()); 519 } 520 } 521 currentNbLoc = System.getProperty ("netbeans.dirs"); if (currentNbLoc != null) { 523 StringTokenizer tok = new StringTokenizer (currentNbLoc, File.pathSeparator); 524 while (tok.hasMoreTokens()) { 525 File f = FileUtil.normalizeFile(new File (tok.nextToken())); 526 result.add(f.getAbsolutePath()); 527 } 528 } 529 StringBuffer sb = new StringBuffer (); 530 for (Iterator <String > it = result.iterator(); it.hasNext();) { 531 sb.append(it.next()); 532 if (it.hasNext()) { 533 sb.append(":"); } 535 } 536 return sb.toString(); 537 } 538 539 } 540 | Popular Tags |