Changeset 4202
- Timestamp:
- Apr 1, 2008, 2:55:44 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 10 added
- 16 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/clients/web/net/sf/basedb/clients/web/extensions/ExtensionsControl.java
r4198 r4202 28 28 import java.util.Set; 29 29 import java.util.TimerTask; 30 31 import javax.servlet.jsp.PageContext; 30 32 31 33 import net.sf.basedb.clients.web.servlet.ExtensionsServlet; … … 112 114 // Load settings 113 115 File settingsFile = new File(directory.getExtensionDirectory(), "settings.xml"); 114 settings = new Settings( settingsFile);116 settings = new Settings(extensionsDir, settingsFile); 115 117 extensionsDir.addIgnore(settingsFile); 116 118 … … 187 189 } 188 190 191 /** 192 Create a new {@link JspContext} object. 193 @param sc The current session control 194 @param pageContext Page context for the executing JSP page 195 */ 196 public static JspContext createContext(SessionControl sc, PageContext pageContext) 197 { 198 return new JspContext(extensionsDir, sc, pageContext); 199 } 189 200 190 201 private final Set<Permission> permissions; … … 435 446 public ExtensionsFile getFileByExtensionId(String extensionId) 436 447 { 437 Object o = registry.getAttribute(extensionId, "FILE"); 438 ExtensionsFile file = null; 439 if (o instanceof ExtensionsFile) 440 { 441 file = (ExtensionsFile)o; 442 } 443 return file; 448 return extensionsDir.getFileByExtensionId(extensionId); 444 449 } 445 450 -
trunk/src/clients/web/net/sf/basedb/clients/web/extensions/ExtensionsDirectory.java
r4198 r4202 34 34 import java.util.Map; 35 35 import java.util.Set; 36 import java.util.TreeMap; 36 37 import java.util.regex.Pattern; 37 38 … … 80 81 this.rootUrl = rootUrl; 81 82 82 this.installedFiles = new HashMap<File, ExtensionsFile>();83 this.installedFiles = new TreeMap<File, ExtensionsFile>(); 83 84 this.installedExtensions = new HashMap<String, ExtensionsFile>(); 84 85 this.staticIgnore = new HashSet<File>(); … … 112 113 /** 113 114 Get the URL that points to the resources directory when accessed 114 through the web server. The URL is not a full URL, it doesn't include115 the server name. For example, /base2/resources115 through the web server. The URL only includes the local server path, 116 not the server name. For example, /base2/resources 116 117 @return The URL 117 118 */ … … 122 123 123 124 /** 125 Get the URL that points to the resources directory for a specific 126 extensions file when accessed through the web server. The URL only 127 includes the local server path, not the server name. For example, 128 /base2/resources/example-extensions.jar 129 @return The URL 130 */ 131 public String getResourcesUrl(ExtensionsFile extFile) 132 { 133 return resourcesUrl + "/" + extFile.getName(); 134 } 135 136 /** 124 137 Get the URL that points to the root directory when accessed 125 through the web server. The URL is not a full URL, it doesn't include126 the server name. For example, /base2138 through the web server. The URL only includes the local server path, 139 not the server name. For example, /base2 127 140 @return The URL 128 141 */ … … 178 191 { 179 192 return installedFiles.get(new File(extensionsDir, filename)); 193 } 194 195 /** 196 Get information about the file a given extension or extension 197 point is defined in. 198 @param extensionId The ID of an extension or extension point 199 @return Information about the file the extension is defined in, 200 or null if no extension with the given ID is found 201 */ 202 ExtensionsFile getFileByExtensionId(String extensionId) 203 { 204 return installedExtensions.get(extensionId); 205 } 206 207 void addRegistered(String id, ExtensionsFile file) 208 { 209 ExtensionsFile other = installedExtensions.get(id); 210 if (other == null) 211 { 212 installedExtensions.put(id, file); 213 } 214 else if (other != file) 215 { 216 throw new RuntimeException("Extension '" + id + 217 "' is already registered in file: " + other.getName()); 218 } 219 } 220 221 void removeRegistered(String id, ExtensionsFile file) 222 { 223 ExtensionsFile other = installedExtensions.get(id); 224 if (other == file) 225 { 226 installedExtensions.remove(id); 227 } 180 228 } 181 229 … … 202 250 try 203 251 { 204 // Re-scan failed JAR/XML files; Doesn't affect manually added ignore files 205 if (forceUpdate) resetIgnore(); 252 if (forceUpdate) 253 { 254 // Re-scan failed JAR/XML files; Doesn't affect manually added ignore files 255 resetIgnore(); 256 installedExtensions.clear(); 257 } 206 258 207 259 // 1. Unregister all extensions that no longer exists … … 271 323 272 324 // Remove extracted resources 273 File homeDir = new File(resourcesDir, extFile.getName()); 274 int numResources = extFile.removeResources(homeDir); 325 int numResources = extFile.removeResources(); 275 326 276 327 // Set scan result messages … … 284 335 catch (Exception ex) 285 336 { 337 extFile.setError(true); 286 338 results.addErrorMessage(extFile, 287 339 "Could not unregister extensions: " + ex.getMessage()); … … 330 382 log.debug("Found new file: " + file.getName()); 331 383 ExtensionsFile extFile = 332 new ExtensionsFile(this, file, createXmlLoader());384 new ExtensionsFile(this, file, new File(resourcesDir, file.getName()), createXmlLoader()); 333 385 334 386 // Is is a valid extensions file? … … 346 398 { 347 399 // Not a valid extensions file; add to ignore list 348 log.info("Not a valid extensions file: " + file.getName()); 400 Throwable validationError = extFile.getValidationError(); 401 log.info("Not a valid extensions file: " + file.getName(), validationError); 349 402 ignore.add(file); 350 403 351 404 // Set scan result messages 352 405 results.setStatus(extFile, "Ignored"); 353 results.addMessage(extFile, "Not a valid extensions XML or JAR file"); 406 String msg = validationError != null ? validationError.getMessage() : ""; 407 results.addMessage(extFile, "Not a valid extensions XML or JAR file: " + msg); 354 408 } 355 409 } … … 411 465 (isNew ? "new" : isModified ? "modified" : "forced update")); 412 466 467 // Reset error flag 468 extFile.setError(false); 469 413 470 // Set home directory for resources on value converters 414 String homePath = resourcesUrl + "/" + extFile.getName(); 471 String homePath = getResourcesUrl(extFile); 472 log.debug("Home URL=" + homePath); 415 473 variableConverter.setVariable("HOME", homePath); 416 474 pathConverter.setHome(homePath); 417 log.debug("Home URL=" + homePath);418 475 extFile.loadExtensions(); 419 476 log.debug(extFile.getName() + " has been loaded"); … … 427 484 catch (Exception ex) 428 485 { 486 extFile.setError(true); 429 487 results.addErrorMessage(extFile, 430 488 "Could not load extensions: " + ex.getMessage()); … … 455 513 for (ExtensionsFile extFile : installedFiles.values()) 456 514 { 515 // Do not extract from files with an error 516 if (extFile.hasError()) continue; 517 457 518 try 458 519 { 459 520 if (forceUpdate || extFile.isModified()) 460 521 { 461 File homeDir = new File(resourcesDir, extFile.getName()); 462 int numResources = extFile.extractResources(homeDir, resourcePattern, "$1", forceUpdate); 522 int numResources = extFile.extractResources(resourcePattern, "$1", forceUpdate); 463 523 if (numResources > 0) 464 524 { … … 470 530 catch (Exception ex) 471 531 { 532 extFile.setError(true); 472 533 results.addErrorMessage(extFile, "Could not extract resources: " + ex.getMessage()); 473 534 log.error("Could not extract resources from " + extFile.getName(), ex); … … 478 539 /** 479 540 Register extensions with the registry. Unless forceUpdate is TRUE only 480 new and modified extensions are registered. 481 */ 482 private void registerExtensions(Registry registry, boolean forceUpdate, ScanResults results) 541 new and modified extensions are registered. Extensions files that has 542 the {@link ExtensionsFile#hasError()} flag set are automatically disabled. 543 */ 544 private void registerExtensions(Registry registry, boolean forceUpdate, ScanResults results) 483 545 { 484 546 for (ExtensionsFile extFile : installedFiles.values()) 485 547 { 548 // Update the last modified information 549 extFile.resetModified(); 550 551 // Do not register extensions that has an error 552 if (extFile.hasError()) continue; 553 486 554 try 487 555 { 556 extFile.unregisterMissing(registry); 488 557 int num = extFile.registerExtensionPoints(registry, forceUpdate); 489 558 if (num > 0) … … 494 563 catch (Exception ex) 495 564 { 565 extFile.setError(true); 496 566 results.addErrorMessage(extFile, 497 567 "Could not register extension points: " + ex.getMessage()); … … 502 572 for (ExtensionsFile extFile : installedFiles.values()) 503 573 { 574 // Do not register extensions that has an error 575 if (extFile.hasError()) continue; 576 504 577 try 505 578 { 506 579 int num = extFile.registerExtensions(registry, forceUpdate); 507 extFile.resetModified();508 580 results.addMessage(extFile, num + " extensions registered."); 509 581 } 510 582 catch (Exception ex) 511 583 { 584 extFile.setError(true); 512 585 results.addErrorMessage(extFile, 513 586 "Could not register extensions: " + ex.getMessage()); … … 518 591 519 592 593 /** 594 Creates a new XmlLoader and registers the {@link #variableConverter} 595 and {@link #pathConverter} with it. 596 */ 520 597 private XmlLoader createXmlLoader() 521 598 { … … 526 603 } 527 604 605 /** 606 Clears all files that has been added to the 607 {@link #ignore} set. All files in {@link #staticIgnore} 608 are re-added. 609 */ 528 610 private void resetIgnore() 529 611 { -
trunk/src/clients/web/net/sf/basedb/clients/web/extensions/ExtensionsFile.java
r4198 r4202 25 25 import java.io.File; 26 26 import java.io.FileInputStream; 27 import java.io.FileNotFoundException; 27 28 import java.io.FileOutputStream; 28 29 import java.io.IOException; … … 56 57 @base.modified $Date:2008-03-20 12:15:25 +0100 (Thu, 20 Mar 2008) $ 57 58 */ 58 public class ExtensionsFile 59 public class ExtensionsFile 60 implements Comparable<ExtensionsFile> 59 61 { 60 62 private static final org.apache.log4j.Logger log = … … 63 65 private final ExtensionsDirectory directory; 64 66 private final File file; 67 private final File resourcesDir; 65 68 private final XmlLoader loader; 66 69 private final boolean isJar; … … 68 71 private boolean hasValidated; 69 72 private boolean isValid; 73 private Throwable validationError; 70 74 71 75 private long lastModified; 72 76 private long size; 73 77 private About about; 78 private boolean hasError; 74 79 75 80 /** … … 77 82 @param directory The directory with extensions; 78 83 @param file The XML or JAR file containting the extension definition 84 @param resourcesDir The directory where resources are extracted 79 85 @param loader The XML loader to use 80 86 */ 81 public ExtensionsFile(ExtensionsDirectory directory, File file, XmlLoader loader) 87 public ExtensionsFile(ExtensionsDirectory directory, File file, 88 File resourcesDir, XmlLoader loader) 82 89 { 83 90 this.directory = directory; 84 91 this.file = file; 92 this.resourcesDir = resourcesDir; 85 93 this.loader = loader; 86 94 this.isJar = file.getName().endsWith(".jar"); 87 95 } 96 97 /* 98 From the Comparable interface 99 ----------------------------- 100 */ 101 @Override 102 public int compareTo(ExtensionsFile other) 103 { 104 return this.file.compareTo(other.file); 105 } 106 // ------------------------------ 88 107 89 108 /** … … 138 157 } 139 158 159 /** 160 If the file is a new file not previously registered with the 161 extension system. Thew 'new' status is changed when {@link #resetModified()} 162 is called which usually happens when all extensions has been registered. 163 @return TRUE if the file is a new file, FALSE otherwise 164 */ 140 165 public boolean isNew() 141 166 { … … 153 178 154 179 @return TRUE if the file is valid, FALSE otherwise 180 @see #getValidationError() 155 181 */ 156 182 public boolean isValid() … … 158 184 if (!hasValidated || isModified()) 159 185 { 160 validate(); 186 try 187 { 188 validate(); 189 } 190 catch (Exception ex) 191 {} 161 192 } 162 193 return isValid; 194 } 195 196 /** 197 Get more information about the error that caused the validation 198 to fail. 199 @return An exception or null if the validation succeeded 200 */ 201 public Throwable getValidationError() 202 { 203 return validationError; 204 } 205 206 /** 207 If there was an error when registering the extensions in this file. 208 This property is only set if the file has been determined to be a 209 valid extensions file by the {@link #isValid()} method. Extensions that 210 has an error are automatically disabled. 211 212 @return TRUE if there was some error, FALSE if everything is ok 213 */ 214 public boolean hasError() 215 { 216 return hasError; 217 } 218 219 /** 220 Sets the error status. 221 */ 222 void setError(boolean error) 223 { 224 this.hasError = error; 163 225 } 164 226 … … 215 277 } 216 278 279 /** 280 Load the extension definitions from the XML or JAR file. 281 */ 217 282 void loadExtensions() 218 283 { 284 if (!loader.hasValidFile()) validate(); 219 285 if (isJar) 220 286 { 221 about = load ExtensionsJar();287 about = loadJar(); 222 288 } 223 289 else 224 290 { 225 about = loadExtensionsXml(); 226 } 227 } 228 229 291 about = loadXml(); 292 } 293 } 294 230 295 private void validate() 231 296 { 232 297 hasValidated = true; 298 isValid = false; 299 validationError = null; 300 try 301 { 302 if (isJar) 303 { 304 validateJar(); 305 } 306 else 307 { 308 validateXml(); 309 } 310 } 311 catch (RuntimeException ex) 312 { 313 validationError = ex.getCause(); 314 throw ex; 315 } 233 316 isValid = true; 234 317 } 235 318 236 private About loadExtensionsXml() 237 { 319 /** 320 Try to validate an XML file with extensions. The XML file is valid 321 if it matches the extension definition XML file format. 322 @return The global about information or null if not present 323 */ 324 private About validateXml() 325 { 326 log.info("Validating extensions in XML file: " + file.getName()); 238 327 About about = null; 239 328 try 240 329 { 241 about = loader.loadXmlFile(new FileInputStream(file), 242 file.getAbsolutePath(), null, true); 330 about = loader.validateXmlFile(new FileInputStream(file), file.getName()); 243 331 } 244 332 catch (Exception ex) 245 333 { 246 throw new RuntimeException(ex); 247 } 334 log.error("Error validating extensions in XML file: " + file, ex); 335 throw new RuntimeException(file + " is not a valid extensions file", ex); 336 } 337 log.info("Extensions in XML file are valid: " + file.getName()); 248 338 return about; 249 339 } 250 340 251 private About loadExtensionsJar() 252 { 253 log.info("Loading extension JAR file: " + file.getName()); 341 /** 342 Try to validate a JAR file with extensions. The JAR file is valid 343 if it contains a file 'META-INF/extensions.xml' which is a valid 344 extension definition XML file. 345 @return The global about information or null if not present 346 */ 347 private About validateJar() 348 { 349 log.info("Validating extensions in JAR file: " + file.getName()); 254 350 InputStream in = null; 255 351 ZipFile zipFile = null; … … 257 353 try 258 354 { 259 ClassLoader jarLoader = JarClassLoader.getInstance(file.getAbsolutePath(), true);260 355 zipFile = new ZipFile(file); 261 356 ZipEntry zipEntry = zipFile.getEntry("META-INF/extensions.xml"); 357 if (zipEntry == null) 358 { 359 throw new FileNotFoundException("META-INF/extensions.xml"); 360 } 262 361 in = zipFile.getInputStream(zipEntry); 263 about = loader. loadXmlFile(in, file.getAbsolutePath(), jarLoader, true);362 about = loader.validateXmlFile(in, file.getName()); 264 363 } 265 364 catch (Exception ex) 266 365 { 267 log.error("Error loading extensionsJAR file: " + file, ex);268 throw new RuntimeException( ex);366 log.error("Error validating extensions in JAR file: " + file, ex); 367 throw new RuntimeException(file + " is not a valid extensions file", ex); 269 368 } 270 369 finally … … 278 377 {} 279 378 } 379 log.info("Extensions in JAR file are valid: " + file.getName()); 380 return about; 381 } 382 383 /** 384 Load extensions from a validated XML file. 385 @return The global about information or null if not present 386 */ 387 private About loadXml() 388 { 389 log.info("Loading extensions from XML file: " + file.getName()); 390 About about = null; 391 try 392 { 393 about = loader.loadLastValidatedFile(null, true); 394 } 395 catch (Exception ex) 396 { 397 log.error("Error loading extensions from XML file: " + file, ex); 398 throw new RuntimeException(ex); 399 } 400 log.info("Extensions loaded from XML file: " + file.getName()); 401 return about; 402 } 403 404 /** 405 Load extensions from a validated JAR file. 406 @return The global about information or null if not present 407 */ 408 private About loadJar() 409 { 410 log.info("Loading extensions from JAR file: " + file.getName()); 411 About about = null; 412 try 413 { 414 ClassLoader jarLoader = JarClassLoader.getInstance(file.getAbsolutePath(), true); 415 about = loader.loadLastValidatedFile(jarLoader, true); 416 } 417 catch (Exception ex) 418 { 419 log.error("Error loading extensions from JAR file: " + file, ex); 420 throw new RuntimeException(ex); 421 } 422 log.info("Extensions loaded from JAR file: " + file.getName()); 280 423 return about; 281 424 } … … 285 428 if the file is an XML file. 286 429 287 @param toDir The directory to extract the resources to288 430 @param filter A regular expression that must match all files 289 431 that should be extracted, or null to every file … … 295 437 @return The number of extracted files 296 438 */ 297 int extractResources( File toDir,Pattern filter, String replacement, boolean forceOverwrite)439 int extractResources(Pattern filter, String replacement, boolean forceOverwrite) 298 440 { 299 441 if (!isJar) return 0; 300 442 301 443 log.info("Extracting resources from " + file.getName() + 302 " to " + toDir.getAbsolutePath() + "; forceOverwrite=" + forceOverwrite);444 " to " + resourcesDir.getAbsolutePath() + "; forceOverwrite=" + forceOverwrite); 303 445 log.debug("filter=" + filter + "; replacement=" + replacement); 304 446 … … 307 449 { 308 450 ZipInputStream zipStream = new ZipInputStream(new FileInputStream(file)); 309 ZipEntry zipEntry ;451 ZipEntry zipEntry = null; 310 452 while ((zipEntry = zipStream.getNextEntry()) != null) 311 453 { … … 348 490 { 349 491 long time = zipEntry.getTime(); 350 File extractTo = new File( toDir, extractionName);492 File extractTo = new File(resourcesDir, extractionName); 351 493 352 494 boolean modified = extractTo.lastModified() != time || … … 377 519 } 378 520 379 int removeResources(File dir) 380 { 381 log.info("Removing resource files from " + dir.getAbsolutePath()); 521 /** 522 Remove all extracted resources. This method simply removes all 523 files and directories it can find in the home directory of the 524 extensions. Files from two different extension packages should 525 thus never be mixed in the same directory. 526 @return The number of removed files 527 */ 528 int removeResources() 529 { 530 log.info("Removing resource files from " + resourcesDir.getAbsolutePath()); 382 531 int numRemoved = 0; 383 532 384 533 List<File> directories = new ArrayList<File>(); 385 directories.add( dir);534 directories.add(resourcesDir); 386 535 387 536 while (directories.size() > 0) … … 416 565 } 417 566 } 418 log.info("Removed " + numRemoved + " resource files from " + dir.getAbsolutePath());567 log.info("Removed " + numRemoved + " resource files from " + resourcesDir.getAbsolutePath()); 419 568 return numRemoved; 420 569 } 421 570 571 /** 572 Register all extensions with a registry. 573 @param registry The registry 574 @param forceUpdate TRUE to force an update of already registered 575 extensions, FALSE to only update if the extension package has 576 been modified 577 @return The number of registered or updated extensions 578 */ 422 579 int registerExtensions(Registry registry, boolean forceUpdate) 423 580 { 424 581 for (Extension ext : loader.getExtensions()) 425 582 { 426 registry.setAttribute(ext.getId(), "FILE", this);583 directory.addRegistered(ext.getId(), this); 427 584 } 428 585 return loader.registerExtensions(registry, forceUpdate || isModified()); 429 586 } 430 587 588 /** 589 Register all extension points with a registry. 590 @param registry The registry 591 @param forceUpdate TRUE to force an update of already registered 592 extension points, FALSE to only update if the extension package 593 has been modified 594 @return The number of registered or updated extensions 595 */ 431 596 int registerExtensionPoints(Registry registry, boolean forceUpdate) 432 597 { 433 598 for (ExtensionPoint ep : loader.getExtensionPoints()) 434 599 { 435 registry.setAttribute(ep.getId(), "FILE", this);600 directory.addRegistered(ep.getId(), this); 436 601 } 437 602 return loader.registerExtensionPoints(registry, forceUpdate || isModified()); 438 603 } 439 604 605 /** 606 Unregister extensions and extension points that have been removed 607 from this package after an update. 608 609 @param registry The registry 610 @return The number of unregistered extensions and extension points 611 */ 612 int unregisterMissing(Registry registry) 613 { 614 // TODO - implement 615 return 0; 616 } 617 618 /** 619 Unregister all extensions and extension points. 620 621 @param registry The registry 622 @return The number of unregistered extensions and extension points 623 */ 440 624 int unregisterAll(Registry registry) 441 625 { 626 for (Extension ext : loader.getExtensions()) 627 { 628 directory.removeRegistered(ext.getId(), this); 629 } 630 for (ExtensionPoint ep : loader.getExtensionPoints()) 631 { 632 directory.removeRegistered(ep.getId(), this); 633 } 442 634 int numExt = loader.unregisterExtensionPoints(registry); 443 635 numExt += loader.unregisterExtensions(registry); -
trunk/src/clients/web/net/sf/basedb/clients/web/extensions/JspContext.java
r4187 r4202 1 1 /** 2 $Id $2 $Id:JspContext.java 4187 2008-03-20 11:15:25Z nicklas $ 3 3 4 4 Copyright (C) Authors contributing to this file. … … 24 24 package net.sf.basedb.clients.web.extensions; 25 25 26 import java.io.IOException; 27 import java.io.Writer; 26 import java.util.Collection; 28 27 import java.util.HashSet; 29 28 import java.util.Set; 30 29 30 import javax.servlet.jsp.JspWriter; 31 31 import javax.servlet.jsp.PageContext; 32 32 … … 65 65 @author nicklas 66 66 @version 2.7 67 @base.modified $Date $67 @base.modified $Date:2008-03-20 12:15:25 +0100 (Thu, 20 Mar 2008) $ 68 68 */ 69 69 public class JspContext … … 71 71 { 72 72 73 private final ExtensionsDirectory directory; 74 private final PageContext pageContext; 75 73 76 private Set<String> scripts; 74 77 private Set<String> stylesheets; 75 78 76 private Writer out; 77 private PageContext pageContext; 78 79 public JspContext(SessionControl sc, PageContext pageContext) 79 JspContext(ExtensionsDirectory directory, SessionControl sc, 80 PageContext pageContext) 80 81 { 81 82 super(sc); 83 this.directory = directory; 82 84 this.pageContext = pageContext; 83 85 } 84 85 public void setOut(Writer out) 86 { 87 this.out = out; 88 } 89 90 public Writer getOut() 91 { 92 return out; 93 } 94 86 87 /** 88 Get the JSP Page context object for the current request. 89 */ 95 90 public PageContext getPageContext() 96 91 { 97 92 return pageContext; 98 93 } 94 95 /** 96 Get a writer object that can be used to return generated text 97 to the response that is sent back to the browser. 98 <p> 99 100 Note! The writer is only intended to be used by render 101 objects when rendering the extensions. Using the writer 102 from the ActionFactory#prepareContext(Context, Extension)} or 103 {@link RendererFactory#prepareContext(Context, Extension)} 104 method may produce unpredictable results. 105 106 @return A {@link JspWriter} object 107 */ 108 public JspWriter getOut() 109 { 110 return pageContext.getOut(); 111 } 99 112 100 113 /** 114 Get the URL to the web application root as a string. The URL 115 only includes the path information, not the server name or protocol. 116 */ 101 117 public String getRoot() 102 118 { … … 104 120 } 105 121 106 // TODO 107 public String getHome() 122 /** 123 Get the URL to the home directory for a given extension. The URL 124 only includes the path information, not the server name or protocol. 125 @param extension The extension 126 */ 127 public String getHome(Extension extension) 108 128 { 109 return ""; 129 ExtensionsFile file = directory.getFileByExtensionId(extension.getId()); 130 return file == null ? null : directory.getResourcesUrl(file); 110 131 } 111 132 … … 158 179 } 159 180 181 /** 182 Get all scripts that has been added to this context. 183 @return A collection of scripts 184 */ 185 public Collection<String> getScripts() 186 { 187 return scripts; 188 } 160 189 161 public void writeScripts() 162 throws IOException 190 /** 191 Get all stylesheets that has been added to this context. 192 @return A collection of stylesheets 193 */ 194 public Collection<String> getStylesheets() 163 195 { 164 if (scripts == null) return; 165 for (String script : scripts) 166 { 167 out.write("<script language=\"JavaScript\" type=\"text/javascript\" src=\""); 168 out.write(script); 169 out.write("\"></script>\n"); 170 } 196 return stylesheets; 171 197 } 172 198 -
trunk/src/clients/web/net/sf/basedb/clients/web/extensions/ScanResults.java
r4198 r4202 25 25 26 26 import java.util.Collection; 27 import java.util.HashMap;28 27 import java.util.LinkedList; 29 28 import java.util.List; 30 29 import java.util.Map; 30 import java.util.TreeMap; 31 31 32 32 /** … … 63 63 this.manualScan = manualScan; 64 64 this.forceUpdate = forceUpdate; 65 this.fileResults = new HashMap<ExtensionsFile, FileResults>();65 this.fileResults = new TreeMap<ExtensionsFile, FileResults>(); 66 66 this.hasError = false; 67 67 this.numErrorFiles = 0; … … 167 167 168 168 169 170 169 void setStatus(ExtensionsFile extFile, String status) 171 170 { -
trunk/src/clients/web/net/sf/basedb/clients/web/extensions/Settings.java
r4198 r4202 69 69 private static final String AUTO_INSTALL = "auto-install"; 70 70 71 private final ExtensionsDirectory directory; 71 72 private final File file; 72 73 private boolean hasChanged; … … 82 83 @param file The file to load/save settings in 83 84 */ 84 public Settings( File file)85 public Settings(ExtensionsDirectory directory, File file) 85 86 { 87 this.directory = directory; 86 88 this.file = file; 87 89 this.presets = new Presets(); … … 113 115 { 114 116 if (extensionPoint == null) return false; 117 ExtensionsFile extFile = directory.getFileByExtensionId(extensionPoint.getId()); 118 if (extFile != null && (extFile.hasError() || !extFile.isValid())) return false; 115 119 return disabledExtensionPoints.getSetting(extensionPoint.getId()) == null; 116 120 } … … 120 124 { 121 125 if (extension == null) return false; 126 ExtensionsFile extFile = directory.getFileByExtensionId(extension.getId()); 127 if (extFile != null && (extFile.hasError() || !extFile.isValid())) return false; 122 128 return disabledExtensions.getSetting(extension.getId()) == null; 123 129 } -
trunk/src/clients/web/net/sf/basedb/clients/web/extensions/toolbar/CompactButtonRenderer.java
r4198 r4202 28 28 29 29 import net.sf.basedb.clients.web.extensions.JspContext; 30 import net.sf.basedb.clients.web.util.HTML; 30 31 import net.sf.basedb.util.extensions.Renderer; 31 32 … … 49 50 } 50 51 52 /** 53 Generates a linked icon: 54 <pre class="code"> 55 <a 56 id="[id]" 57 class="[clazz]" 58 style="[style]" 59 href="javascript:[onClick]" 60 title="[title]: [tooltip]" 61 ><img src="[icon]" border="0"></a> 62 </pre> 63 64 If the button isn't visible nothing is generated. If the button isn't enabled, 65 the href attribute is not generated. 66 */ 51 67 public void render(ButtonAction btn) 52 68 { 69 if (!btn.isVisible()) return; 53 70 Writer out = context.getOut(); 54 71 try 55 72 { 56 out.write("<a href=\"javascript:"); 57 out.write(btn.getOnClick()); 58 out.write("\" title=\""); 59 out.write(btn.getTitle()); 60 out.write("\"><img src=\""); 61 out.write(btn.getIcon()); 62 out.write("\" border=\"0\"></a>\n"); 73 out.write("<a"); 74 if (btn.getId() != null) out.write(" id=\"" + btn.getId() + "\""); 75 if (btn.getClazz() != null) out.write(" class=\"" + btn.getClazz() + "\""); 76 if (btn.getStyle() != null) out.write(" style=\"" + btn.getStyle() + "\""); 77 if (btn.isEnabled() && btn.getOnClick() != null) 78 { 79 out.write(" href=\"javascript:" + btn.getOnClick() + "\""); 80 } 81 String title = btn.getTitle(); 82 if (btn.getTooltip() != null) 83 { 84 title = title == null ? btn.getTooltip() : title + ": " + btn.getTooltip(); 85 } 86 if (title != null) out.write(" title=\"" + HTML.encodeTags(title) + "\""); 87 out.write("><img"); 88 if (btn.getIcon() != null) out.write(" src=\"" + btn.getIcon() + "\""); 89 out.write(" border=\"0\"></a>\n"); 63 90 } 64 91 catch (IOException ex) -
trunk/src/clients/web/net/sf/basedb/clients/web/extensions/toolbar/CompactButtonRendererFactory.java
r4198 r4202 30 30 31 31 /** 32 Factory that create {@link CompactButtonRenderer} objects 33 for rendering {@link ButtonAction}:s. 32 34 33 35 @author nicklas 34 36 @version 2.7 35 37 @base.modified $Date:2008-03-20 12:15:25 +0100 (Thu, 20 Mar 2008) $ 36 38 */ 37 39 public class CompactButtonRendererFactory 38 40 extends AbstractJspRendererFactory<ButtonAction> … … 42 44 {} 43 45 46 @Override 44 47 public CompactButtonRenderer getRenderer(Context context, Extension extension) 45 48 { -
trunk/src/clients/web/net/sf/basedb/clients/web/extensions/toolbar/FixedButtonFactory.java
r4198 r4202 91 91 92 92 /* 93 From the ToolbarButtonAction interface93 From the ButtonAction interface 94 94 -------------------------------- 95 95 */ -
trunk/src/core/net/sf/basedb/util/extensions/Registry.java
r4198 r4202 27 27 import java.util.Collection; 28 28 import java.util.Collections; 29 import java.util.Comparator; 29 30 import java.util.HashMap; 30 31 import java.util.Iterator; … … 56 57 { 57 58 59 private static final Comparator<ExtensionPoint<?>> EXTENSIONPOINT_COMPARATOR = 60 new Comparator<ExtensionPoint<?>>() 61 { 62 @Override 63 public int compare(ExtensionPoint<?> o1, ExtensionPoint<?> o2) 64 { 65 return o1.getName().compareTo(o2.getName()); 66 } 67 }; 68 58 69 private final Map<String, RegisteredExtensionPoint<?>> extensionPoints; 59 70 private final Map<String, RegisteredExtension<?>> extensions; … … 192 203 List<ExtensionPoint<?>> copy = 193 204 new ArrayList<ExtensionPoint<?>>(extensionPoints.values()); 205 Collections.sort(copy, EXTENSIONPOINT_COMPARATOR); 194 206 return Collections.unmodifiableList(copy).iterator(); 195 207 } 196 197 208 198 209 /** … … 429 440 */ 430 441 private static final ExtensionsFilter DEFAULT_FILTER = new DefaultFilter(); 431 442 432 443 /** 433 444 Internal representation of an extension point. -
trunk/src/core/net/sf/basedb/util/extensions/xml/XmlLoader.java
r4198 r4202 136 136 private Map<Object, String> factoryParameters; 137 137 138 // The last document that was validated 139 private Document validatedDom; 140 138 141 /** 139 142 Create a new XML loader instance. … … 179 182 /** 180 183 Load an extensions definition XML file. This method may be called 181 multiple times with different XML files. 184 multiple times with different XML files. The loading may also be 185 done by a two-step process where the first step validates the file 186 and the second step loads the extensions. See {@link 187 #validateXmlFile(InputStream, String)} and {@link 188 #loadLastValidatedFile(ClassLoader, boolean)}. 182 189 183 190 @param xmlFile An input stream to read the XML data from … … 201 208 @throws InstantiationException If a factory class can't be instantiated, 202 209 for example, because it is an abstract class or an interface 210 @see #validateXmlFile(InputStream, String) 211 @see #loadLastValidatedFile(ClassLoader, boolean) 203 212 */ 204 213 public About loadXmlFile(InputStream xmlFile, String filename, … … 207 216 IllegalAccessException, InstantiationException 208 217 { 218 validateXmlFile(xmlFile, filename); 219 return loadLastValidatedFile(classLoader, clear); 220 } 221 222 /** 223 Validate an XML file against the extensions definition schema. If the 224 file is valid you may continue to load the extensions. See 225 {@link #loadLastValidatedFile(ClassLoader, boolean)}. 226 227 @param xmlFile An input stream to read the XML data from 228 @param filename The original filename the stream is coming from, or null 229 if not known. This value is only used when generating error messages 230 @return Information about the extension, or null if no such information 231 is available 232 @throws JDOMException If validation of the XML file fails 233 @throws IOException If there is an error reading the XML file 234 */ 235 public About validateXmlFile(InputStream xmlFile, String filename) 236 throws IOException, JDOMException 237 { 238 validatedDom = null; 239 validatedDom = loadDocument(xmlFile, filename); 240 About globalAbout = loadGlobalAbout(validatedDom); 241 return globalAbout; 242 } 243 244 /** 245 Continue loading extensions from the last validated XML file. This is 246 the second step in a two-step process and requires that 247 {@link #validateXmlFile(InputStream, String)} has been successfully called 248 first. 249 250 @param classLoader The classloader to use when loading classes that are 251 named in the XML file, or null to use the default classloader (=the same 252 class loader that loaded the BASE core classes) 253 @param clear TRUE to clear all already loaded extensions before loading 254 the extensions in this file 255 @return Information about the extension, or null if no such information 256 is available 257 @throws ClassNotFoundException If a class named in the XML file can't 258 be found 259 @throws NoSuchMethodException If a factory class doesn't implement a 260 public, no-argument constructor 261 @throws IllegalAccessException If a factory class constructor isn't 262 public 263 @throws InstantiationException If a factory class can't be instantiated, 264 for example, because it is an abstract class or an interface 265 */ 266 public About loadLastValidatedFile(ClassLoader classLoader, boolean clear) 267 throws ClassNotFoundException, IllegalAccessException, 268 InstantiationException, NoSuchMethodException 269 { 270 if (validatedDom == null) 271 { 272 throw new NullPointerException("No file has been validated"); 273 } 209 274 if (clear) 210 275 { … … 212 277 extensions.clear(); 213 278 } 214 Document dom = loadDocument(xmlFile, filename);215 About globalAbout = loadGlobalAbout(dom);216 loadExtension Points(dom, classLoader, globalAbout);217 loadExtensions(dom, classLoader, globalAbout);279 About globalAbout = loadGlobalAbout(validatedDom); 280 loadExtensionPoints(validatedDom, classLoader, globalAbout); 281 loadExtensions(validatedDom, classLoader, globalAbout); 282 validatedDom = null; 218 283 return globalAbout; 284 } 285 286 /** 287 Checks if an XML file has passed validation in the 288 {@link #validateXmlFile(InputStream, String)} method. If so, 289 the {@link #loadLastValidatedFile(ClassLoader, boolean)} can be called 290 to continue loading the extensions. 291 <p> 292 Note that once the file has been loaded this flag is reset to 293 FALSE. 294 295 @return TRUE if a file has been validated, FALSE otherwise 296 */ 297 public boolean hasValidFile() 298 { 299 return validatedDom != null; 219 300 } 220 301 -
trunk/www/admin/extensions/details.jsp
r4198 r4202 43 43 import="net.sf.basedb.clients.web.extensions.ExtensionsFile" 44 44 import="net.sf.basedb.clients.web.extensions.ScanResults" 45 import="net.sf.basedb.clients.web.extensions.ScanResults.FileResults" 45 46 import="net.sf.basedb.clients.web.formatter.FormatterFactory" 46 47 import="net.sf.basedb.util.formatter.Formatter" … … 85 86 ExtensionPoint<?> ep = null; 86 87 ExtensionsFile file = null; 88 ExtensionsFile extFile = null; 89 ExtensionsFile epFile = null; 90 87 91 if (filename != null) 88 92 { … … 102 106 } 103 107 extensionPointId = ext.getExtends(); 104 //if (file == null) file = ec.getFileByExtensionId(extensionId);108 extFile = ec.getFileByExtensionId(extensionId); 105 109 } 106 110 … … 112 116 throw new ItemNotFoundException("ExtensionPoint[id=" + extensionPointId + "]"); 113 117 } 114 //if (file == null) file = ec.getFileByExtensionId(extensionPointId);118 epFile = ec.getFileByExtensionId(extensionPointId); 115 119 } 116 120 %> … … 177 181 { 178 182 boolean isEnabled = ec.isEnabled(ext); 183 boolean hasError = extFile != null && extFile.hasError(); 184 boolean allow = writePermission && !hasError; 179 185 %> 180 186 <tbl:button 181 187 onclick="<%="enableExtension(" + (isEnabled ? "0" : "1") + ")"%>" 182 188 title="<%=isEnabled ? "Disable" : "Enable" %>" 183 image="<%= writePermission? "joust/extension.png" : "joust/extensiondisabled.png" %>"189 image="<%=allow ? "joust/extension.png" : "joust/extensiondisabled.png" %>" 184 190 tooltip="Disable this extension" 185 disabled="<%=! writePermission%>"191 disabled="<%=!allow%>" 186 192 /> 187 193 <tbl:button … … 196 202 { 197 203 boolean isEnabled = ec.isEnabled(ep); 204 boolean hasError = epFile != null && epFile.hasError(); 205 boolean allow = writePermission && !hasError; 198 206 %> 199 207 <tbl:button 200 208 onclick="<%="enableExtensionPoint(" + (isEnabled ? "0" : "1") + ")"%>" 201 209 title="<%=isEnabled ? "Disable" : "Enable" %>" 202 image="<%= writePermission? "joust/extensionpoint.png" : "joust/extensionpointdisabled.png" %>"210 image="<%=allow ? "joust/extensionpoint.png" : "joust/extensionpointdisabled.png" %>" 203 211 tooltip="Disable this extension point" 204 disabled="<%=! writePermission%>"212 disabled="<%=!allow%>" 205 213 /> 206 214 <tbl:button … … 214 222 else if (file != null) 215 223 { 224 boolean hasError = file.hasError(); 225 boolean allow = writePermission && !hasError; 216 226 %> 217 227 <tbl:button 218 228 onclick="enableFile(1)" 219 229 title="Enable all" 220 image="<%= writePermission? "joust/extension.png" : "joust/extensiondisabled.png" %>"230 image="<%=allow ? "joust/extension.png" : "joust/extensiondisabled.png" %>" 221 231 tooltip="Enable all extensions in this file" 222 disabled="<%=! writePermission%>"232 disabled="<%=!allow%>" 223 233 /> 224 234 <tbl:button 225 235 onclick="enableFile(0)" 226 236 title="Disable all" 227 image="<%= writePermission? "joust/extension.png" : "joust/extensiondisabled.png" %>"237 image="<%=allow ? "joust/extension.png" : "joust/extensiondisabled.png" %>" 228 238 tooltip="Disable all extensions in this file" 229 disabled="<%=! writePermission%>"239 disabled="<%=!allow%>" 230 240 /> 231 241 <% … … 266 276 About about = ext.getAbout(); 267 277 if (about == null) about = new AboutBean(); 268 ExtensionsFile extFile = ec.getFileByExtensionId(ext.getId());269 278 %> 270 279 </a> … … 282 291 <td> 283 292 <a href="javascript:showFile('<%=HTML.javaScriptEncode(extFile.getName())%>')" 284 ><%=extFile.getName()%></a> (<%=extFile.isModified() ? "Modified" : "Up to date" %>) 293 ><%=extFile.getName()%></a> 294 (<%=extFile.isModified() ? "Modified" : "Up to date" %>; 295 <%=extFile.hasError() ? "Error" : "Ok" %>) 285 296 </td> 286 297 </tr> … … 326 337 if (ep != null) 327 338 { 328 ExtensionsFile epFile = ec.getFileByExtensionId(ep.getId());329 339 if (ext != null) 330 340 { … … 347 357 <td> 348 358 <a href="javascript:showFile('<%=HTML.javaScriptEncode(epFile.getName())%>')" 349 ><%=epFile.getName()%></a> (<%=epFile.isModified() ? "Modified" : "Up to date" %>) 359 ><%=epFile.getName()%></a> 360 (<%=epFile.isModified() ? "Modified" : "Up to date" %>; 361 <%=epFile.hasError() ? "Error" : "Ok" %>) 350 362 </td> 351 363 </tr> … … 385 397 <td class="prompt">Up to date</td> 386 398 <td><%=file.isModified() ? "No" : "Yes"%></td> 399 </tr> 400 <tr> 401 <td class="prompt">Errors</td> 402 <td> 403 <% 404 if (file.hasError()) 405 { 406 ScanResults results = ec.getLastScanResults(); 407 FileResults fileResults = results.getResults(file); 408 List<String> messages = fileResults.getMessages(); 409 Throwable validationError = file.getValidationError(); 410 for (String msg : messages) 411 { 412 %> 413 <li><%=HTML.niceFormat(msg)%> 414 <% 415 } 416 if (validationError != null) 417 { 418 %> 419 <li><%=HTML.niceFormat(validationError.getMessage())%> 420 <% 421 } 422 } 423 else 424 { 425 %> 426 No 427 <% 428 } 429 %> 430 </td> 387 431 </tr> 388 432 <tr> -
trunk/www/admin/extensions/scan_results.jsp
r4198 r4202 115 115 List<String> messages = fileResults.getMessages(); 116 116 boolean hasMessages = messages != null && messages.size() > 0; 117 Throwable validationError = extFile.getValidationError(); 117 118 %> 118 119 <tr> … … 128 129 </tr> 129 130 <% 130 if (hasMessages )131 if (hasMessages || validationError != null) 131 132 { 132 133 %> … … 138 139 %> 139 140 <li><%=HTML.niceFormat(msg)%> 141 <% 142 } 143 if (validationError != null) 144 { 145 %> 146 <li><%=HTML.niceFormat(validationError.getMessage())%> 140 147 <% 141 148 } -
trunk/www/admin/extensions/tree.jsp
r4198 r4202 50 50 if (name == null) name = id; 51 51 String icon = ec.isEnabled(ep) ? "ExtensionPoint" : "ExtensionPointDisabled"; 52 ExtensionsFile f = ec.getFileByExtensionId(id); 53 if (f.hasError()) icon = "ExtensionPointError"; 52 54 String joust = "ep = JoustMenu.addChildItem(" + parentNode +", '" + icon + "', " + 53 55 "'" + HTML.javaScriptEncode(name) + "', 'extensionPointOnClick(\"" + id + "\")', " + … … 61 63 String name = about == null || about.getName() == null ? id : about.getName(); 62 64 String icon = ec.isEnabled(ext) ? "Extension" : "ExtensionDisabled"; 65 ExtensionsFile f = ec.getFileByExtensionId(id); 66 if (f.hasError()) icon = "ExtensionError"; 63 67 String joust = "ext = JoustMenu.addChildItem(" + parentNode + ", '" + icon + "', " + 64 68 "'" + HTML.javaScriptEncode(name) + "', 'extensionOnClick(\"" + id + "\")', " + … … 90 94 IconStore.addIcon('ExtensionPointDisabled', path + 'extensionpointdisabled.png', 16, 16); 91 95 IconStore.addIcon('ExtensionPointDisabledSelected', path + 'extensionpointdisabledselected.png', 16, 16); 96 IconStore.addIcon('ExtensionPointError', path + 'extensionpointerror.png', 16, 16); 97 IconStore.addIcon('ExtensionPointErrorSelected', path + 'extensionpointerrorselected.png', 16, 16); 92 98 IconStore.addIcon('Extension', path + 'extension.png', 16, 16); 93 99 IconStore.addIcon('ExtensionSelected', path + 'extensionselected.png', 16, 16); 94 100 IconStore.addIcon('ExtensionDisabled', path + 'extensiondisabled.png', 16, 16); 95 101 IconStore.addIcon('ExtensionDisabledSelected', path + 'extensiondisabledselected.png', 16, 16); 102 IconStore.addIcon('ExtensionError', path + 'extensionerror.png', 16, 16); 103 IconStore.addIcon('ExtensionErrorSelected', path + 'extensionerrorselected.png', 16, 16); 96 104 IconStore.addIcon('XmlFile', path + 'item.gif', 18, 16); 105 IconStore.addIcon('XmlFileError', path + 'itemerror.gif', 18, 16); 97 106 IconStore.addIcon('XmlFileSelected', path + 'itemselected.gif', 18, 16); 107 IconStore.addIcon('XmlFileErrorSelected', path + 'itemerrorselected.gif', 18, 16); 98 108 IconStore.addIcon('JarFile', path + 'jarfile.png', 18, 16); 109 IconStore.addIcon('JarFileError', path + 'jarfileerror.png', 18, 16); 99 110 IconStore.addIcon('JarFileSelected', path + 'jarfileselected.png', 18, 16); 111 IconStore.addIcon('JarFileErrorSelected', path + 'jarfileerrorselected.png', 18, 16); 100 112 101 113 var byExtPoint = JoustMenu.addMenuItem(-1, 'Root', 'By extension point', 'rootOnClick()', '', ''); … … 130 142 String efName = ef.getName(); 131 143 String icon = ef.isJar() ? "JarFile" : "XmlFile"; 144 if (ef.hasError()) icon += "Error"; 132 145 String id = efName; 133 146 %> -
trunk/www/include/menu.jsp
r4190 r4202 952 952 <% 953 953 // Extensions menu 954 JspContext context = new JspContext(sc, pageContext);954 JspContext context = ExtensionsControl.createContext(sc, pageContext); 955 955 ExtensionsInvoker<MenuItemAction> invoker = 956 956 (ExtensionsInvoker<MenuItemAction>)ExtensionsControl.useExtensions(context, -
trunk/www/views/experiments/bioassaysets/analysis_tree.jsp
r4190 r4202 79 79 <%@ taglib prefix="base" uri="/WEB-INF/base.tld" %> 80 80 <%@ taglib prefix="tbl" uri="/WEB-INF/table.tld" %> 81 <%@ taglib prefix="t" uri="/WEB-INF/tab.tld" %> 82 <%@ taglib prefix="p" uri="/WEB-INF/path.tld" %> 81 <%@ taglib prefix="ext" uri="/WEB-INF/extensions.tld" %> 83 82 <%! 84 83 private static final Item itemType = Item.BIOASSAYSET; … … 280 279 int numListed = 0; 281 280 282 JspContext jspContext = new JspContext(sc, pageContext);283 ExtensionsInvoker <ButtonAction> invoker =284 (ExtensionsInvoker<ButtonAction>)ExtensionsControl.useExtensions(jspContext,"net.sf.basedb.clients.web.bioassayset.list.tools");281 JspContext jspContext = ExtensionsControl.createContext(sc, pageContext); 282 ExtensionsInvoker invoker = ExtensionsControl.useExtensions(jspContext, 283 "net.sf.basedb.clients.web.bioassayset.list.tools"); 285 284 %> 286 285 <base:page type="include"> 287 286 <base:body> 288 <% 289 jspContext.setOut(out); 290 jspContext.writeScripts(); 291 %> 287 <ext:scripts context="<%=jspContext%>" /> 288 <ext:stylesheets context="<%=jspContext%>" /> 292 289 <script language="JavaScript"> 293 290 var submitPage = '<%=transformationId != 0 ? "../bioassaysets/index.jsp" : "index.jsp"%>'; … … 887 884 } 888 885 %> 889 <% 890 jspContext.setCurrentItem(item); 891 jspContext.setOut(out); 892 invoker.renderDefault(); 893 %> 894 886 <ext:render extensions="<%=invoker%>" context="<%=jspContext%>" item="<%=item%>" /> 895 887 </nobr> 896 888 </tbl:cell> … … 949 941 } 950 942 %> 951 <% 952 jspContext.setCurrentItem(item); 953 jspContext.setOut(out); 954 invoker.renderDefault(); 955 %> 943 <ext:render extensions="<%=invoker%>" context="<%=jspContext%>" item="<%=item%>" /> 956 944 </nobr> 957 945 </tbl:cell> … … 975 963 } 976 964 %> 977 <% 978 jspContext.setCurrentItem(item); 979 jspContext.setOut(out); 980 invoker.renderDefault(); 981 %> 982 965 <ext:render extensions="<%=invoker%>" context="<%=jspContext%>" item="<%=item%>" /> 983 966 </nobr> 984 967 </tbl:cell>
Note: See TracChangeset
for help on using the changeset viewer.