KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > Module


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans;
21
22 import java.io.File JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.Arrays JavaDoc;
26 import java.util.Collections JavaDoc;
27 import java.util.HashSet JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.Set JavaDoc;
30 import java.util.StringTokenizer JavaDoc;
31 import java.util.jar.Attributes JavaDoc;
32 import java.util.jar.Manifest JavaDoc;
33 import java.util.logging.Level JavaDoc;
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 /** Object representing one module, possibly installed.
42  * Responsible for opening of module JAR file; reading
43  * manifest; parsing basic information such as dependencies;
44  * and creating a classloader for use by the installer.
45  * Methods not defined in ModuleInfo must be called from within
46  * the module manager's read mutex as a rule.
47  * @author Jesse Glick
48  * @since 2.1 the class was made public abstract
49  */

50 public abstract class Module extends ModuleInfo {
51     
52     public static final String JavaDoc PROP_RELOADABLE = "reloadable"; // NOI18N
53
public static final String JavaDoc PROP_CLASS_LOADER = "classLoader"; // NOI18N
54
public static final String JavaDoc PROP_MANIFEST = "manifest"; // NOI18N
55
public static final String JavaDoc PROP_VALID = "valid"; // NOI18N
56
public static final String JavaDoc PROP_PROBLEMS = "problems"; // NOI18N
57

58     /** module manifest */
59     protected Manifest JavaDoc manifest;
60     /** manager which owns this module */
61     protected final ModuleManager mgr;
62     /** event logging (should not be much here) */
63     protected final Events events;
64     /** associated history object
65      * @see ModuleHistory
66      */

67     private final Object JavaDoc history;
68     /** true if currently enabled; manipulated by ModuleManager */
69     private boolean enabled;
70     /** whether it is supposed to be automatically loaded when required */
71     private final boolean autoload;
72     /** */
73     protected boolean reloadable;
74     /** if true, this module is eagerly turned on whenever it can be */
75     private final boolean eager;
76     /** code name base (no slash) */
77     private String JavaDoc codeNameBase;
78     /** code name release, or -1 if undefined */
79     private int codeNameRelease;
80     /** full code name */
81     private String JavaDoc codeName;
82     /** provided tokens */
83     private String JavaDoc[] provides;
84     /** set of dependencies parsed from manifest */
85     private Dependency[] dependenciesA;
86     /** specification version parsed from manifest, or null */
87     private SpecificationVersion specVers;
88     /** currently active module classloader */
89     protected ClassLoader JavaDoc classloader = null;
90     /** public packages, may be null */
91     private PackageExport[] publicPackages;
92     /** Set<String> of CNBs of friend modules or null */
93     private Set JavaDoc/*<String>*/ friendNames;
94     
95     /** Use ModuleManager.create as a factory. */
96     protected Module(ModuleManager mgr, Events ev, Object JavaDoc history, boolean reloadable, boolean autoload, boolean eager) throws IOException JavaDoc {
97         if (autoload && eager) throw new IllegalArgumentException JavaDoc("A module may not be both autoload and eager"); // NOI18N
98
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     /** Create a special-purpose "fixed" JAR. */
108     protected Module(ModuleManager mgr, Events ev, Manifest JavaDoc manifest, Object JavaDoc history, ClassLoader JavaDoc 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     /** Get the associated module manager. */
121     public ModuleManager getManager() {
122         return mgr;
123     }
124     
125     public boolean isEnabled() {
126         return enabled;
127     }
128     
129     // Access from ModuleManager:
130
void setEnabled(boolean enabled) {
131         /* #13647: actually can happen if loading of bootstrap modules is rolled back: */
132         if (isFixed() && ! enabled) throw new IllegalStateException JavaDoc("Cannot disable a fixed module: " + this); // NOI18N
133
this.enabled = enabled;
134     }
135     
136     /** Normally a module once created and managed is valid
137      * (that is, either installed or not, but at least managed).
138      * If it is deleted any remaining references to it become
139      * invalid.
140      */

141     public boolean isValid() {
142         return mgr.get(getCodeNameBase()) == this;
143     }
144     
145     /** Is this module automatically loaded?
146      * If so, no information about its state is kept
147      * permanently beyond the existence of its JAR file;
148      * it is enabled when some real module needs it to be,
149      * and disabled when this is no longer the case.
150      * @see <a HREF="http://www.netbeans.org/issues/show_bug.cgi?id=9779">#9779</a>
151      */

152     public boolean isAutoload() {
153         return autoload;
154     }
155     
156     /** Is this module eagerly enabled?
157      * If so, no information about its state is kept permanently.
158      * It is turned on whenever it can be, i.e. whenever it meets all of
159      * its dependencies. This may be used to implement "bridge" modules with
160      * simple functionality that just depend on two normal modules.
161      * A module may not be simultaneously eager and autoload.
162      * @see <a HREF="http://www.netbeans.org/issues/show_bug.cgi?id=17501">#17501</a>
163      * @since org.netbeans.core/1 1.3
164      */

165     public boolean isEager() {
166         return eager;
167     }
168     
169     /** Get an associated arbitrary attribute.
170      * Right now, simply provides the main attributes of the manifest.
171      * In the future some of these could be suppressed (if only of dangerous
172      * interest, e.g. Class-Path) or enhanced with other information available
173      * from the core (if needed).
174      */

175     public Object JavaDoc getAttribute(String JavaDoc attr) {
176         return getManifest().getMainAttributes().getValue(attr);
177     }
178     
179     public String JavaDoc getCodeName() {
180         return codeName;
181     }
182     
183     public String JavaDoc getCodeNameBase() {
184         return codeNameBase;
185     }
186     
187     public int getCodeNameRelease() {
188         return codeNameRelease;
189     }
190     
191     public String JavaDoc[] getProvides() {
192         return provides;
193     }
194     /** Test whether the module provides a given token or not.
195      * @since JST-PENDING again used from NbProblemDisplayer
196      */

197     public final boolean provides(String JavaDoc 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 JavaDoc<Dependency> getDependencies() {
207         return new HashSet JavaDoc<Dependency>(Arrays.asList(dependenciesA));
208     }
209     // Faster to loop over:
210
// @since JST-PENDING called from NbInstaller
211
public final Dependency[] getDependenciesArray() {
212         return dependenciesA;
213     }
214     
215     public SpecificationVersion getSpecificationVersion() {
216         return specVers;
217     }
218     
219     public boolean owns(Class JavaDoc clazz) {
220         ClassLoader JavaDoc cl = clazz.getClassLoader();
221         if (cl instanceof Util.ModuleProvider) {
222             return ((Util.ModuleProvider) cl).getModule() == this;
223         }
224         return false;
225         
226     }
227     
228     /** Get all packages exported by this module to other modules.
229      * @return a list (possibly empty) of exported packages, or null to export everything
230      * @since org.netbeans.core/1 > 1.4
231      * @see "#19621"
232      */

233     public PackageExport[] getPublicPackages() {
234         return publicPackages;
235     }
236     
237     /** Checks whether we use friends attribute and if so, then
238      * whether the name of module is listed there.
239      */

240     boolean isDeclaredAsFriend (Module module) {
241         if (friendNames == null) {
242             return true;
243         }
244         return friendNames.contains(module.getCodeNameBase());
245     }
246     
247     /** Parse information from the current manifest.
248      * Includes code name, specification version, and dependencies.
249      * If anything is in an invalid format, throws an exception with
250      * some kind of description of the problem.
251      */

252     protected void parseManifest() throws InvalidException {
253         Attributes JavaDoc attr = manifest.getMainAttributes();
254         // Code name
255
codeName = attr.getValue("OpenIDE-Module"); // NOI18N
256
if (codeName == null) {
257             InvalidException e = new InvalidException("Not a module: no OpenIDE-Module tag in manifest of " + /* #17629: important! */this); // NOI18N
258
// #29393: plausible user mistake, deal with it politely.
259
Exceptions.attachLocalizedMessage(e,
260                                               NbBundle.getMessage(Module.class,
261                                                                   "EXC_not_a_module",
262                                                                   this.toString()));
263             throw e;
264         }
265         try {
266             // This has the side effect of checking syntax:
267
if (codeName.indexOf(',') != -1) {
268                 throw new InvalidException("Illegal code name syntax parsing OpenIDE-Module: " + codeName); // NOI18N
269
}
270             Dependency.create(Dependency.TYPE_MODULE, codeName);
271             Object JavaDoc[] cnParse = Util.parseCodeName(codeName);
272             codeNameBase = (String JavaDoc)cnParse[0];
273             codeNameRelease = (cnParse[1] != null) ? ((Integer JavaDoc)cnParse[1]).intValue() : -1;
274             if (cnParse[2] != null) throw new NumberFormatException JavaDoc(codeName);
275             // Spec vers
276
String JavaDoc specVersS = attr.getValue("OpenIDE-Module-Specification-Version"); // NOI18N
277
if (specVersS != null) {
278                 try {
279                     specVers = new SpecificationVersion(specVersS);
280                 } catch (NumberFormatException JavaDoc nfe) {
281                     throw (InvalidException)new InvalidException("While parsing OpenIDE-Module-Specification-Version: " + nfe.toString()).initCause(nfe); // NOI18N
282
}
283             } else {
284                 specVers = null;
285             }
286             // Token provides
287
String JavaDoc providesS = attr.getValue("OpenIDE-Module-Provides"); // NOI18N
288
if (providesS == null) {
289                 provides = new String JavaDoc[] {};
290             } else {
291                 StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(providesS, ", "); // NOI18N
292
provides = new String JavaDoc[tok.countTokens()];
293                 for (int i = 0; i < provides.length; i++) {
294                     String JavaDoc provide = tok.nextToken();
295                     if (provide.indexOf(',') != -1) {
296                         throw new InvalidException("Illegal code name syntax parsing OpenIDE-Module-Provides: " + provide); // NOI18N
297
}
298                     Dependency.create(Dependency.TYPE_MODULE, provide);
299                     if (provide.lastIndexOf('/') != -1) throw new IllegalArgumentException JavaDoc("Illegal OpenIDE-Module-Provides: " + provide); // NOI18N
300
provides[i] = provide;
301                 }
302                 if (new HashSet JavaDoc<String JavaDoc>(Arrays.asList(provides)).size() < provides.length) {
303                     throw new IllegalArgumentException JavaDoc("Duplicate entries in OpenIDE-Module-Provides: " + providesS); // NOI18N
304
}
305             }
306             String JavaDoc[] additionalProvides = mgr.refineProvides (this);
307             if (additionalProvides != null) {
308                 if (provides == null) {
309                     provides = additionalProvides;
310                 } else {
311                     ArrayList JavaDoc<String JavaDoc> l = new ArrayList JavaDoc<String JavaDoc> ();
312                     l.addAll (Arrays.asList (provides));
313                     l.addAll (Arrays.asList (additionalProvides));
314                     provides = l.toArray (provides);
315                 }
316             }
317             
318             // Exports
319
String JavaDoc exportsS = attr.getValue("OpenIDE-Module-Public-Packages"); // NOI18N
320
if (exportsS != null) {
321                 if (exportsS.trim().equals("-")) { // NOI18N
322
publicPackages = new PackageExport[0];
323                 } else {
324                     StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(exportsS, ", "); // NOI18N
325
List JavaDoc<PackageExport> exports = new ArrayList JavaDoc<PackageExport>(Math.max(tok.countTokens(), 1));
326                     while (tok.hasMoreTokens()) {
327                         String JavaDoc piece = tok.nextToken();
328                         if (piece.endsWith(".*")) { // NOI18N
329
String JavaDoc pkg = piece.substring(0, piece.length() - 2);
330                             Dependency.create(Dependency.TYPE_MODULE, pkg);
331                             if (pkg.lastIndexOf('/') != -1) throw new IllegalArgumentException JavaDoc("Illegal OpenIDE-Module-Public-Packages: " + exportsS); // NOI18N
332
exports.add(new PackageExport(pkg.replace('.', '/') + '/', false));
333                         } else if (piece.endsWith(".**")) { // NOI18N
334
String JavaDoc pkg = piece.substring(0, piece.length() - 3);
335                             Dependency.create(Dependency.TYPE_MODULE, pkg);
336                             if (pkg.lastIndexOf('/') != -1) throw new IllegalArgumentException JavaDoc("Illegal OpenIDE-Module-Public-Packages: " + exportsS); // NOI18N
337
exports.add(new PackageExport(pkg.replace('.', '/') + '/', true));
338                         } else {
339                             throw new IllegalArgumentException JavaDoc("Illegal OpenIDE-Module-Public-Packages: " + exportsS); // NOI18N
340
}
341                     }
342                     if (exports.isEmpty()) throw new IllegalArgumentException JavaDoc("Illegal OpenIDE-Module-Public-Packages: " + exportsS); // NOI18N
343
publicPackages = exports.toArray(new PackageExport[exports.size()]);
344                 }
345             } else {
346                 // XXX new link?
347
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                 // friends
353
String JavaDoc friends = attr.getValue("OpenIDE-Module-Friends"); // NOI18N
354
if (friends != null) {
355                     StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(friends, ", "); // NOI18N
356
HashSet JavaDoc<String JavaDoc> set = new HashSet JavaDoc<String JavaDoc> ();
357                     while (tok.hasMoreTokens()) {
358                         String JavaDoc piece = tok.nextToken();
359                         if (piece.indexOf('/') != -1) {
360                             throw new IllegalArgumentException JavaDoc("May specify only module code name bases in OpenIDE-Module-Friends, not major release versions: " + piece); // NOI18N
361
}
362                         // Indirect way of checking syntax:
363
Dependency.create(Dependency.TYPE_MODULE, piece);
364                         // OK, add it.
365
set.add(piece);
366                     }
367                     if (set.isEmpty()) {
368                         throw new IllegalArgumentException JavaDoc("Empty OpenIDE-Module-Friends: " + friends); // NOI18N
369
}
370                     if (publicPackages == null || publicPackages.length == 0) {
371                         throw new IllegalArgumentException JavaDoc("No use specifying OpenIDE-Module-Friends without any public packages: " + friends); // NOI18N
372
}
373                     this.friendNames = set;
374                 }
375             }
376             
377             
378             // Dependencies
379
Set JavaDoc<Dependency> dependencies = new HashSet JavaDoc<Dependency>(20);
380             // First convert IDE/1 -> org.openide/1, so we never have to deal with
381
// "IDE deps" internally:
382
@SuppressWarnings JavaDoc("deprecation")
383             Set JavaDoc<Dependency> openideDeps = Dependency.create(Dependency.TYPE_IDE, attr.getValue("OpenIDE-Module-IDE-Dependencies")); // NOI18N
384
if (!openideDeps.isEmpty()) {
385                 // If empty, leave it that way; NbInstaller will add it anyway.
386
Dependency d = openideDeps.iterator().next();
387                 String JavaDoc name = d.getName();
388                 if (!name.startsWith("IDE/")) throw new IllegalStateException JavaDoc("Weird IDE dep: " + name); // NOI18N
389
dependencies.addAll(Dependency.create(Dependency.TYPE_MODULE, "org.openide/" + name.substring(4) + " > " + d.getVersion())); // NOI18N
390
if (dependencies.size() != 1) throw new IllegalStateException JavaDoc("Should be singleton: " + dependencies); // NOI18N
391

392                 Util.err.warning("the module " + codeNameBase + " uses OpenIDE-Module-IDE-Dependencies which is deprecated. See http://openide.netbeans.org/proposals/arch/modularize.html"); // NOI18N
393
}
394             dependencies.addAll(Dependency.create(Dependency.TYPE_JAVA, attr.getValue("OpenIDE-Module-Java-Dependencies"))); // NOI18N
395
dependencies.addAll(Dependency.create(Dependency.TYPE_MODULE, attr.getValue("OpenIDE-Module-Module-Dependencies"))); // NOI18N
396
String JavaDoc pkgdeps = attr.getValue("OpenIDE-Module-Package-Dependencies"); // NOI18N
397
if (pkgdeps != null) {
398                 // XXX: Util.err.log(ErrorManager.WARNING, "Warning: module " + codeNameBase + " uses the OpenIDE-Module-Package-Dependencies manifest attribute, which is now deprecated: XXX URL TBD");
399
dependencies.addAll(Dependency.create(Dependency.TYPE_PACKAGE, pkgdeps)); // NOI18N
400
}
401             dependencies.addAll(Dependency.create(Dependency.TYPE_REQUIRES, attr.getValue("OpenIDE-Module-Requires"))); // NOI18N
402
dependencies.addAll(Dependency.create(Dependency.TYPE_NEEDS, attr.getValue("OpenIDE-Module-Needs"))); // NOI18N
403
dependencies.addAll(Dependency.create(Dependency.TYPE_RECOMMENDS, attr.getValue("OpenIDE-Module-Recommends"))); // NOI18N
404
// Permit the concrete installer to make some changes:
405
mgr.refineDependencies(this, dependencies);
406             dependenciesA = dependencies.toArray(new Dependency[dependencies.size()]);
407         } catch (IllegalArgumentException JavaDoc iae) {
408             throw (InvalidException) new InvalidException("While parsing " + codeName + " a dependency attribute: " + iae.toString()).initCause(iae); // NOI18N
409
}
410     }
411
412     /** Get all JARs loaded by this module.
413      * Includes the module itself, any locale variants of the module,
414      * any extensions specified with Class-Path, any locale variants
415      * of those extensions.
416      * The list will be in classpath order (patches first).
417      * Currently the temp JAR is provided in the case of test modules, to prevent
418      * sporadic ZIP file exceptions when background threads (like Java parsing) tries
419      * to open libraries found in the library path.
420      * JARs already present in the classpath are <em>not</em> listed.
421      * @return a list of JARs
422      */

423     public abstract List JavaDoc<File JavaDoc> getAllJars();
424
425     /** Is this module supposed to be easily reloadable?
426      * If so, it is suitable for testing inside the IDE.
427      * Controls whether a copy of the JAR file is made before
428      * passing it to the classloader, which can affect locking
429      * and refreshing of the JAR.
430      */

431     public boolean isReloadable() {
432         return reloadable;
433     }
434     
435     /** Set whether this module is supposed to be reloadable.
436      * Has no immediate effect, only impacts what happens the
437      * next time it is enabled (after having been disabled if
438      * necessary).
439      * Must be called from within a write mutex.
440      * @param r whether the module should be considered reloadable
441      */

442     public abstract void setReloadable(boolean r);
443
444     /** Reload this module. Access from ModuleManager.
445      * If an exception is thrown, the module is considered
446      * to be in an invalid state.
447      * @since JST-PENDING: needed from ModuleSystem
448      */

449     public abstract void reload() throws IOException JavaDoc;
450     
451     // impl of ModuleInfo method
452
public ClassLoader JavaDoc getClassLoader() throws IllegalArgumentException JavaDoc {
453         if (!enabled) {
454             throw new IllegalArgumentException JavaDoc("Not enabled: " + codeNameBase); // NOI18N
455
}
456         assert classloader != null : "Should have had a non-null loader for " + this;
457         return classloader;
458     }
459
460     // Access from ModuleManager:
461
/** Turn on the classloader. Passed a list of parent modules to use.
462      * The parents should already have had their classloaders initialized.
463      */

464     protected abstract void classLoaderUp(Set JavaDoc<Module> parents) throws IOException JavaDoc;
465
466     /** Turn off the classloader and release all resources. */
467     protected abstract void classLoaderDown();
468     /** Should be called after turning off the classloader of one or more modules & GC'ing. */
469     protected abstract void cleanup();
470     
471     /** Notify the module that it is being deleted. */
472     protected abstract void destroy();
473     
474     /**
475      * Fixed modules are treated differently.
476      * @see FixedModule
477      */

478     public abstract boolean isFixed();
479     
480     /** Get the JAR this module is packaged in.
481      * May be null for modules installed specially, e.g.
482      * automatically from the classpath.
483      * @see #isFixed
484      */

485     public File JavaDoc getJarFile() {
486         return null;
487     }
488     
489     /** Get the JAR manifest.
490      * Should never be null, even if disabled.
491      * Might change if a module is reloaded.
492      * It is not guaranteed that change events will be fired
493      * for changes in this property.
494      */

495     public Manifest JavaDoc getManifest() {
496         return manifest;
497     }
498     
499     /** Get a set of {@link org.openide.modules.Dependency} objects representing missed dependencies.
500      * This module is examined to see
501      * why it would not be installable.
502      * If it is enabled, there are no problems.
503      * If it is in fact installable (possibly only
504      * by also enabling some other managed modules which are currently disabled), and
505      * all of its non-module dependencies are met, the returned set will be empty.
506      * Otherwise it will contain a list of reasons why this module cannot be installed:
507      * non-module dependencies which are not met; and module dependencies on modules
508      * which either do not exist in the managed set, or are the wrong version,
509      * or themselves cannot be installed
510      * for some reason or another (which may be separately examined).
511      * Note that in the (illegal) situation of two or more modules forming a cyclic
512      * dependency cycle, none of them will be installable, and the missing dependencies
513      * for each will be stated as the dependencies on the others. Again other modules
514      * dependent on modules in the cycle will list failed dependencies on the cyclic modules.
515      * Missing package dependencies are not guaranteed to be reported unless an install
516      * of the module has already been attempted, and failed due to them.
517      * The set may also contain {@link InvalidException}s representing known failures
518      * of the module to be installed, e.g. due to classloader problems, missing runtime
519      * resources, or failed ad-hoc dependencies. Again these are not guaranteed to be
520      * reported unless an install has already been attempted and failed due to them.
521      */

522     public Set JavaDoc<Object JavaDoc> getProblems() { // cannot use Union2<Dependency,InvalidException> without being binary-incompatible
523
if (! isValid()) throw new IllegalStateException JavaDoc("Not valid: " + this); // NOI18N
524
if (isEnabled()) return Collections.emptySet();
525         Set JavaDoc<Object JavaDoc> problems = new HashSet JavaDoc<Object JavaDoc>();
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     // Access from ChangeFirer:
537
final void firePropertyChange0(String JavaDoc prop, Object JavaDoc old, Object JavaDoc 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     /** Get the history object representing what has happened to this module before.
545      * @see ModuleHistory
546      */

547     public final Object JavaDoc getHistory() {
548         return history;
549     }
550     
551     /** String representation for debugging. */
552     public String JavaDoc toString() {
553         String JavaDoc s = "Module:" + getCodeNameBase(); // NOI18N
554
if (!isValid()) s += "[invalid]"; // NOI18N
555
return s;
556     }
557
558     /** Struct representing a package exported from a module.
559      * @since org.netbeans.core/1 > 1.4
560      * @see Module#getPublicPackages
561      */

562     public static final class PackageExport {
563         /** Package to export, in the form <samp>org/netbeans/modules/foo/</samp>. */
564         public final String JavaDoc pkg;
565         /** If true, export subpackages also. */
566         public final boolean recursive;
567         /** Create a package export struct with the named parameters. */
568         public PackageExport(String JavaDoc pkg, boolean recursive) {
569             this.pkg = pkg;
570             this.recursive = recursive;
571         }
572         public String JavaDoc toString() {
573             return "PackageExport[" + pkg + (recursive ? "**/" : "") + "]"; // NOI18N
574
}
575     }
576
577 }
578
Popular Tags