1 19 20 package org.netbeans; 21 22 import java.io.File ; 23 import java.io.IOException ; 24 import java.util.ArrayList ; 25 import java.util.Arrays ; 26 import java.util.Collections ; 27 import java.util.HashSet ; 28 import java.util.List ; 29 import java.util.Set ; 30 import java.util.StringTokenizer ; 31 import java.util.jar.Attributes ; 32 import java.util.jar.Manifest ; 33 import java.util.logging.Level ; 34 import org.openide.modules.Dependency; 35 import org.openide.modules.ModuleInfo; 36 import org.openide.modules.SpecificationVersion; 37 import org.openide.util.Exceptions; 38 import org.openide.util.NbBundle; 39 import org.openide.util.Union2; 40 41 50 public abstract class Module extends ModuleInfo { 51 52 public static final String PROP_RELOADABLE = "reloadable"; public static final String PROP_CLASS_LOADER = "classLoader"; public static final String PROP_MANIFEST = "manifest"; public static final String PROP_VALID = "valid"; public static final String PROP_PROBLEMS = "problems"; 58 59 protected Manifest manifest; 60 61 protected final ModuleManager mgr; 62 63 protected final Events events; 64 67 private final Object history; 68 69 private boolean enabled; 70 71 private final boolean autoload; 72 73 protected boolean reloadable; 74 75 private final boolean eager; 76 77 private String codeNameBase; 78 79 private int codeNameRelease; 80 81 private String codeName; 82 83 private String [] provides; 84 85 private Dependency[] dependenciesA; 86 87 private SpecificationVersion specVers; 88 89 protected ClassLoader classloader = null; 90 91 private PackageExport[] publicPackages; 92 93 private Set friendNames; 94 95 96 protected Module(ModuleManager mgr, Events ev, Object history, boolean reloadable, boolean autoload, boolean eager) throws IOException { 97 if (autoload && eager) throw new IllegalArgumentException ("A module may not be both autoload and eager"); this.mgr = mgr; 99 this.events = ev; 100 this.history = history; 101 this.reloadable = reloadable; 102 this.autoload = autoload; 103 this.eager = eager; 104 enabled = false; 105 } 106 107 108 protected Module(ModuleManager mgr, Events ev, Manifest manifest, Object history, ClassLoader classloader) throws InvalidException { 109 this.mgr = mgr; 110 this.events = ev; 111 this.manifest = manifest; 112 this.history = history; 113 this.classloader = classloader; 114 reloadable = false; 115 autoload = false; 116 eager = false; 117 enabled = false; 118 } 119 120 121 public ModuleManager getManager() { 122 return mgr; 123 } 124 125 public boolean isEnabled() { 126 return enabled; 127 } 128 129 void setEnabled(boolean enabled) { 131 132 if (isFixed() && ! enabled) throw new IllegalStateException ("Cannot disable a fixed module: " + this); this.enabled = enabled; 134 } 135 136 141 public boolean isValid() { 142 return mgr.get(getCodeNameBase()) == this; 143 } 144 145 152 public boolean isAutoload() { 153 return autoload; 154 } 155 156 165 public boolean isEager() { 166 return eager; 167 } 168 169 175 public Object getAttribute(String attr) { 176 return getManifest().getMainAttributes().getValue(attr); 177 } 178 179 public String getCodeName() { 180 return codeName; 181 } 182 183 public String getCodeNameBase() { 184 return codeNameBase; 185 } 186 187 public int getCodeNameRelease() { 188 return codeNameRelease; 189 } 190 191 public String [] getProvides() { 192 return provides; 193 } 194 197 public final boolean provides(String token) { 198 for (int i = 0; i < provides.length; i++) { 199 if (provides[i].equals(token)) { 200 return true; 201 } 202 } 203 return false; 204 } 205 206 public Set <Dependency> getDependencies() { 207 return new HashSet <Dependency>(Arrays.asList(dependenciesA)); 208 } 209 public final Dependency[] getDependenciesArray() { 212 return dependenciesA; 213 } 214 215 public SpecificationVersion getSpecificationVersion() { 216 return specVers; 217 } 218 219 public boolean owns(Class clazz) { 220 ClassLoader cl = clazz.getClassLoader(); 221 if (cl instanceof Util.ModuleProvider) { 222 return ((Util.ModuleProvider) cl).getModule() == this; 223 } 224 return false; 225 226 } 227 228 233 public PackageExport[] getPublicPackages() { 234 return publicPackages; 235 } 236 237 240 boolean isDeclaredAsFriend (Module module) { 241 if (friendNames == null) { 242 return true; 243 } 244 return friendNames.contains(module.getCodeNameBase()); 245 } 246 247 252 protected void parseManifest() throws InvalidException { 253 Attributes attr = manifest.getMainAttributes(); 254 codeName = attr.getValue("OpenIDE-Module"); if (codeName == null) { 257 InvalidException e = new InvalidException("Not a module: no OpenIDE-Module tag in manifest of " + this); Exceptions.attachLocalizedMessage(e, 260 NbBundle.getMessage(Module.class, 261 "EXC_not_a_module", 262 this.toString())); 263 throw e; 264 } 265 try { 266 if (codeName.indexOf(',') != -1) { 268 throw new InvalidException("Illegal code name syntax parsing OpenIDE-Module: " + codeName); } 270 Dependency.create(Dependency.TYPE_MODULE, codeName); 271 Object [] cnParse = Util.parseCodeName(codeName); 272 codeNameBase = (String )cnParse[0]; 273 codeNameRelease = (cnParse[1] != null) ? ((Integer )cnParse[1]).intValue() : -1; 274 if (cnParse[2] != null) throw new NumberFormatException (codeName); 275 String specVersS = attr.getValue("OpenIDE-Module-Specification-Version"); if (specVersS != null) { 278 try { 279 specVers = new SpecificationVersion(specVersS); 280 } catch (NumberFormatException nfe) { 281 throw (InvalidException)new InvalidException("While parsing OpenIDE-Module-Specification-Version: " + nfe.toString()).initCause(nfe); } 283 } else { 284 specVers = null; 285 } 286 String providesS = attr.getValue("OpenIDE-Module-Provides"); if (providesS == null) { 289 provides = new String [] {}; 290 } else { 291 StringTokenizer tok = new StringTokenizer (providesS, ", "); provides = new String [tok.countTokens()]; 293 for (int i = 0; i < provides.length; i++) { 294 String provide = tok.nextToken(); 295 if (provide.indexOf(',') != -1) { 296 throw new InvalidException("Illegal code name syntax parsing OpenIDE-Module-Provides: " + provide); } 298 Dependency.create(Dependency.TYPE_MODULE, provide); 299 if (provide.lastIndexOf('/') != -1) throw new IllegalArgumentException ("Illegal OpenIDE-Module-Provides: " + provide); provides[i] = provide; 301 } 302 if (new HashSet <String >(Arrays.asList(provides)).size() < provides.length) { 303 throw new IllegalArgumentException ("Duplicate entries in OpenIDE-Module-Provides: " + providesS); } 305 } 306 String [] additionalProvides = mgr.refineProvides (this); 307 if (additionalProvides != null) { 308 if (provides == null) { 309 provides = additionalProvides; 310 } else { 311 ArrayList <String > l = new ArrayList <String > (); 312 l.addAll (Arrays.asList (provides)); 313 l.addAll (Arrays.asList (additionalProvides)); 314 provides = l.toArray (provides); 315 } 316 } 317 318 String exportsS = attr.getValue("OpenIDE-Module-Public-Packages"); if (exportsS != null) { 321 if (exportsS.trim().equals("-")) { publicPackages = new PackageExport[0]; 323 } else { 324 StringTokenizer tok = new StringTokenizer (exportsS, ", "); List <PackageExport> exports = new ArrayList <PackageExport>(Math.max(tok.countTokens(), 1)); 326 while (tok.hasMoreTokens()) { 327 String piece = tok.nextToken(); 328 if (piece.endsWith(".*")) { String pkg = piece.substring(0, piece.length() - 2); 330 Dependency.create(Dependency.TYPE_MODULE, pkg); 331 if (pkg.lastIndexOf('/') != -1) throw new IllegalArgumentException ("Illegal OpenIDE-Module-Public-Packages: " + exportsS); exports.add(new PackageExport(pkg.replace('.', '/') + '/', false)); 333 } else if (piece.endsWith(".**")) { String pkg = piece.substring(0, piece.length() - 3); 335 Dependency.create(Dependency.TYPE_MODULE, pkg); 336 if (pkg.lastIndexOf('/') != -1) throw new IllegalArgumentException ("Illegal OpenIDE-Module-Public-Packages: " + exportsS); exports.add(new PackageExport(pkg.replace('.', '/') + '/', true)); 338 } else { 339 throw new IllegalArgumentException ("Illegal OpenIDE-Module-Public-Packages: " + exportsS); } 341 } 342 if (exports.isEmpty()) throw new IllegalArgumentException ("Illegal OpenIDE-Module-Public-Packages: " + exportsS); publicPackages = exports.toArray(new PackageExport[exports.size()]); 344 } 345 } else { 346 Util.err.warning("module " + codeNameBase + " does not declare OpenIDE-Module-Public-Packages in its manifest, so all packages are considered public by default: http://www.netbeans.org/download/dev/javadoc/OpenAPIs/org/openide/doc-files/upgrade.html#3.4-public-packages"); 348 publicPackages = null; 349 } 350 351 { 352 String friends = attr.getValue("OpenIDE-Module-Friends"); if (friends != null) { 355 StringTokenizer tok = new StringTokenizer (friends, ", "); HashSet <String > set = new HashSet <String > (); 357 while (tok.hasMoreTokens()) { 358 String piece = tok.nextToken(); 359 if (piece.indexOf('/') != -1) { 360 throw new IllegalArgumentException ("May specify only module code name bases in OpenIDE-Module-Friends, not major release versions: " + piece); } 362 Dependency.create(Dependency.TYPE_MODULE, piece); 364 set.add(piece); 366 } 367 if (set.isEmpty()) { 368 throw new IllegalArgumentException ("Empty OpenIDE-Module-Friends: " + friends); } 370 if (publicPackages == null || publicPackages.length == 0) { 371 throw new IllegalArgumentException ("No use specifying OpenIDE-Module-Friends without any public packages: " + friends); } 373 this.friendNames = set; 374 } 375 } 376 377 378 Set <Dependency> dependencies = new HashSet <Dependency>(20); 380 @SuppressWarnings ("deprecation") 383 Set <Dependency> openideDeps = Dependency.create(Dependency.TYPE_IDE, attr.getValue("OpenIDE-Module-IDE-Dependencies")); if (!openideDeps.isEmpty()) { 385 Dependency d = openideDeps.iterator().next(); 387 String name = d.getName(); 388 if (!name.startsWith("IDE/")) throw new IllegalStateException ("Weird IDE dep: " + name); dependencies.addAll(Dependency.create(Dependency.TYPE_MODULE, "org.openide/" + name.substring(4) + " > " + d.getVersion())); if (dependencies.size() != 1) throw new IllegalStateException ("Should be singleton: " + dependencies); 392 Util.err.warning("the module " + codeNameBase + " uses OpenIDE-Module-IDE-Dependencies which is deprecated. See http://openide.netbeans.org/proposals/arch/modularize.html"); } 394 dependencies.addAll(Dependency.create(Dependency.TYPE_JAVA, attr.getValue("OpenIDE-Module-Java-Dependencies"))); dependencies.addAll(Dependency.create(Dependency.TYPE_MODULE, attr.getValue("OpenIDE-Module-Module-Dependencies"))); String pkgdeps = attr.getValue("OpenIDE-Module-Package-Dependencies"); if (pkgdeps != null) { 398 dependencies.addAll(Dependency.create(Dependency.TYPE_PACKAGE, pkgdeps)); } 401 dependencies.addAll(Dependency.create(Dependency.TYPE_REQUIRES, attr.getValue("OpenIDE-Module-Requires"))); dependencies.addAll(Dependency.create(Dependency.TYPE_NEEDS, attr.getValue("OpenIDE-Module-Needs"))); dependencies.addAll(Dependency.create(Dependency.TYPE_RECOMMENDS, attr.getValue("OpenIDE-Module-Recommends"))); mgr.refineDependencies(this, dependencies); 406 dependenciesA = dependencies.toArray(new Dependency[dependencies.size()]); 407 } catch (IllegalArgumentException iae) { 408 throw (InvalidException) new InvalidException("While parsing " + codeName + " a dependency attribute: " + iae.toString()).initCause(iae); } 410 } 411 412 423 public abstract List <File > getAllJars(); 424 425 431 public boolean isReloadable() { 432 return reloadable; 433 } 434 435 442 public abstract void setReloadable(boolean r); 443 444 449 public abstract void reload() throws IOException ; 450 451 public ClassLoader getClassLoader() throws IllegalArgumentException { 453 if (!enabled) { 454 throw new IllegalArgumentException ("Not enabled: " + codeNameBase); } 456 assert classloader != null : "Should have had a non-null loader for " + this; 457 return classloader; 458 } 459 460 464 protected abstract void classLoaderUp(Set <Module> parents) throws IOException ; 465 466 467 protected abstract void classLoaderDown(); 468 469 protected abstract void cleanup(); 470 471 472 protected abstract void destroy(); 473 474 478 public abstract boolean isFixed(); 479 480 485 public File getJarFile() { 486 return null; 487 } 488 489 495 public Manifest getManifest() { 496 return manifest; 497 } 498 499 522 public Set <Object > getProblems() { if (! isValid()) throw new IllegalStateException ("Not valid: " + this); if (isEnabled()) return Collections.emptySet(); 525 Set <Object > problems = new HashSet <Object >(); 526 for (Union2<Dependency,InvalidException> problem : mgr.missingDependencies(this)) { 527 if (problem.hasFirst()) { 528 problems.add(problem.first()); 529 } else { 530 problems.add(problem.second()); 531 } 532 } 533 return problems; 534 } 535 536 final void firePropertyChange0(String prop, Object old, Object nue) { 538 if (Util.err.isLoggable(Level.FINE)) { 539 Util.err.fine("Module.propertyChange: " + this + " " + prop + ": " + old + " -> " + nue); 540 } 541 firePropertyChange(prop, old, nue); 542 } 543 544 547 public final Object getHistory() { 548 return history; 549 } 550 551 552 public String toString() { 553 String s = "Module:" + getCodeNameBase(); if (!isValid()) s += "[invalid]"; return s; 556 } 557 558 562 public static final class PackageExport { 563 564 public final String pkg; 565 566 public final boolean recursive; 567 568 public PackageExport(String pkg, boolean recursive) { 569 this.pkg = pkg; 570 this.recursive = recursive; 571 } 572 public String toString() { 573 return "PackageExport[" + pkg + (recursive ? "**/" : "") + "]"; } 575 } 576 577 } 578 | Popular Tags |