KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > modules > Dependency


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.openide.modules;
21
22 import java.util.Collections JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.HashSet JavaDoc;
25 import java.util.Map JavaDoc;
26 import java.util.Set JavaDoc;
27 import java.util.StringTokenizer JavaDoc;
28 import org.openide.util.Utilities;
29
30 /** A dependency a module can have.
31  * @author Jesse Glick
32  * @since 1.24
33  */

34 public final class Dependency {
35     /** Dependency on another module. */
36     public final static int TYPE_MODULE = 1;
37
38     /** Dependency on a package. */
39     public final static int TYPE_PACKAGE = 2;
40
41     /** Dependency on Java. */
42     public final static int TYPE_JAVA = 3;
43
44     /**
45      * Dependency on the IDE.
46      * @deprecated This type of dependency should no longer be used.
47      */

48     @Deprecated JavaDoc
49     public final static int TYPE_IDE = 4;
50
51     /** Dependency on a token.
52      * @see ModuleInfo#getProvides
53      * @since 2.3
54      */

55     public final static int TYPE_REQUIRES = 5;
56
57     /** Dependency on a token, but without need to have token provider be initialised sooner.
58      * @see ModuleInfo#getProvides
59      * @since 7.1
60      */

61     public final static int TYPE_NEEDS = 6;
62
63     /** An advisory dependency on a token. If at least one provider of such token is
64      * available, it is enabled. If there is no such provider, then nothing is done
65      * or reported.
66      *
67      * @see ModuleInfo#getProvides
68      * @since 7.1
69      */

70     public final static int TYPE_RECOMMENDS = 7;
71
72     /** Comparison by specification version. */
73     public final static int COMPARE_SPEC = 1;
74
75     /** Comparison by implementation version. */
76     public final static int COMPARE_IMPL = 2;
77
78     /** No comparison, just require the dependency to be present. */
79     public final static int COMPARE_ANY = 3;
80
81     /** @deprecated request dependencies on direct modules */
82     @Deprecated JavaDoc
83     public static final String JavaDoc IDE_NAME = System.getProperty("org.openide.major.version", "IDE"); // NOI18N
84

85     /** @deprecated request dependencies on direct modules */
86     @Deprecated JavaDoc
87     public static final SpecificationVersion IDE_SPEC = makeSpec(
88             System.getProperty("org.openide.specification.version")
89         ); // NOI18N
90

91     /** @deprecated request dependencies on direct modules */
92     @Deprecated JavaDoc
93     public static final String JavaDoc IDE_IMPL = System.getProperty("org.openide.version"); // NOI18N
94

95     /** Name, for purposes of dependencies, of the Java platform. */
96     public static final String JavaDoc JAVA_NAME = "Java"; // NOI18N
97

98     /** Specification version of the Java platform. */
99     public static final SpecificationVersion JAVA_SPEC = makeSpec(System.getProperty("java.specification.version")); // NOI18N
100

101     /** Implementation version of the Java platform. */
102     public static final String JavaDoc JAVA_IMPL = System.getProperty("java.version"); // NOI18N
103

104     /** Name, for purposes of dependencies, of the Java VM. */
105     public static final String JavaDoc VM_NAME = "VM"; // NOI18N
106

107     /** Specification version of the Java VM. */
108     public static final SpecificationVersion VM_SPEC = makeSpec(System.getProperty("java.vm.specification.version")); // NOI18N
109

110     /** Implementation version of the Java VM. */
111     public static final String JavaDoc VM_IMPL = System.getProperty("java.vm.version"); // NOI18N
112
private final int type;
113     private final int comparison;
114     private final String JavaDoc name;
115     private final String JavaDoc version;
116
117     private Dependency(int type, String JavaDoc name, int comparison, String JavaDoc version) {
118         this.type = type;
119         this.name = name.intern();
120         this.comparison = comparison;
121         this.version = (version != null) ? version.intern() : null;
122     }
123
124     /** Verify the format of a code name.
125      * Caller specifies whether a slash plus release version is permitted in this context.
126      */

127     private static void checkCodeName(String JavaDoc codeName, boolean slashOK)
128     throws IllegalArgumentException JavaDoc {
129         String JavaDoc base;
130         int slash = codeName.indexOf('/'); // NOI18N
131

132         if (slash == -1) {
133             base = codeName;
134         } else {
135             if (!slashOK) {
136                 throw new IllegalArgumentException JavaDoc("No slash permitted in: " + codeName); // NOI18N
137
}
138
139             base = codeName.substring(0, slash);
140
141             String JavaDoc rest = codeName.substring(slash + 1);
142             int dash = rest.indexOf('-'); // NOI18N
143

144             try {
145                 if (dash == -1) {
146                     int release = Integer.parseInt(rest);
147
148                     if (release < 0) {
149                         throw new IllegalArgumentException JavaDoc("Negative release number: " + codeName); // NOI18N
150
}
151                 } else {
152                     int release = Integer.parseInt(rest.substring(0, dash));
153                     int releaseMax = Integer.parseInt(rest.substring(dash + 1));
154
155                     if (release < 0) {
156                         throw new IllegalArgumentException JavaDoc("Negative release number: " + codeName); // NOI18N
157
}
158
159                     if (releaseMax <= release) {
160                         throw new IllegalArgumentException JavaDoc("Release number range must be increasing: " + codeName); // NOI18N
161
}
162                 }
163             } catch (NumberFormatException JavaDoc e) {
164                 throw new IllegalArgumentException JavaDoc(e.toString());
165             }
166         }
167
168         // Now check that the rest is a valid package.
169
StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(base, ".", true); // NOI18N
170

171         if ((tok.countTokens() % 2) == 0) {
172             throw new NumberFormatException JavaDoc("Even number of pieces: " + base); // NOI18N
173
}
174
175         boolean expectingPath = true;
176
177         while (tok.hasMoreTokens()) {
178             if (expectingPath) {
179                 expectingPath = false;
180
181                 String JavaDoc nt = tok.nextToken();
182                 if (!Utilities.isJavaIdentifier(nt) && !"enum".equals (nt)) { // NOI18N
183
throw new IllegalArgumentException JavaDoc("Bad package component in " + base); // NOI18N
184
}
185             } else {
186                 if (!".".equals(tok.nextToken())) { // NOI18N
187
throw new NumberFormatException JavaDoc("Expected dot in code name: " + base); // NOI18N
188
}
189
190                 expectingPath = true;
191             }
192         }
193     }
194
195     /** Parse dependencies from tags.
196     * @param type like Dependency.type
197     * @param body actual text of tag body; if <code>null</code>, returns nothing
198     * @return a set of dependencies
199     * @throws IllegalArgumentException if they are malformed or inconsistent
200     */

201     public static Set JavaDoc<Dependency> create(int type, String JavaDoc body) throws IllegalArgumentException JavaDoc {
202         if (body == null) {
203             return Collections.emptySet();
204         }
205
206         Set JavaDoc<Dependency> deps = new HashSet JavaDoc<Dependency>(5);
207
208         // First split on commas.
209
StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(body, ","); // NOI18N
210

211         if (!tok.hasMoreTokens()) {
212             throw new IllegalArgumentException JavaDoc("No deps given: \"" + body + "\""); // NOI18N
213
}
214
215         Map JavaDoc<DependencyKey, Dependency> depsByKey = new HashMap JavaDoc<DependencyKey, Dependency>(11);
216
217         while (tok.hasMoreTokens()) {
218             String JavaDoc onedep = tok.nextToken();
219             StringTokenizer JavaDoc tok2 = new StringTokenizer JavaDoc(onedep, " \t\n\r"); // NOI18N
220

221             if (!tok2.hasMoreTokens()) {
222                 throw new IllegalArgumentException JavaDoc("No name in dependency: " + onedep); // NOI18N
223
}
224
225             String JavaDoc name = tok2.nextToken();
226             int comparison;
227             String JavaDoc version;
228
229             if (tok2.hasMoreTokens()) {
230                 String JavaDoc compthing = tok2.nextToken();
231
232                 if (compthing.equals(">")) { // NOI18N
233
comparison = Dependency.COMPARE_SPEC;
234                 } else if (compthing.equals("=")) { // NOI18N
235
comparison = Dependency.COMPARE_IMPL;
236                 } else {
237                     throw new IllegalArgumentException JavaDoc("Strange comparison string: " + compthing); // NOI18N
238
}
239
240                 if (!tok2.hasMoreTokens()) {
241                     throw new IllegalArgumentException JavaDoc("Comparison string without version: " + onedep); // NOI18N
242
}
243
244                 version = tok2.nextToken();
245
246                 if (tok2.hasMoreTokens()) {
247                     throw new IllegalArgumentException JavaDoc("Trailing garbage in dependency: " + onedep); // NOI18N
248
}
249
250                 if (comparison == Dependency.COMPARE_SPEC) {
251                     try {
252                         new SpecificationVersion(version);
253                     } catch (NumberFormatException JavaDoc nfe) {
254                         throw new IllegalArgumentException JavaDoc(nfe.toString());
255                     }
256                 }
257             } else {
258                 comparison = Dependency.COMPARE_ANY;
259                 version = null;
260             }
261
262             if (type == Dependency.TYPE_MODULE) {
263                 checkCodeName(name, true);
264
265                 if ((name.indexOf('-') != -1) && (comparison == Dependency.COMPARE_IMPL)) {
266                     throw new IllegalArgumentException JavaDoc(
267                         "Cannot have an implementation dependency on a ranged release version: " + onedep
268                     ); // NOI18N
269
}
270             } else if (type == Dependency.TYPE_PACKAGE) {
271                 int idx = name.indexOf('[');
272
273                 if (idx != -1) {
274                     if (idx > 0) {
275                         checkCodeName(name.substring(0, idx), false);
276                     }
277
278                     if (name.charAt(name.length() - 1) != ']') {
279                         throw new IllegalArgumentException JavaDoc("No close bracket on package dep: " + name); // NOI18N
280
}
281
282                     checkCodeName(name.substring(idx + 1, name.length() - 1), false);
283                 } else {
284                     checkCodeName(name, false);
285                 }
286
287                 if ((idx == 0) && (comparison != Dependency.COMPARE_ANY)) {
288                     throw new IllegalArgumentException JavaDoc(
289                         "Cannot use a version comparison on a package dependency when only a sample class is given"
290                     ); // NOI18N
291
}
292
293                 if ((idx > 0) && (name.substring(idx + 1, name.length() - 1).indexOf('.') != -1)) {
294                     throw new IllegalArgumentException JavaDoc(
295                         "Cannot have a sample class with dots when package is specified"
296                     ); // NOI18N
297
}
298             } else if (type == Dependency.TYPE_JAVA) {
299                 if (!(name.equals(JAVA_NAME) || name.equals(VM_NAME))) { // NOI18N
300
throw new IllegalArgumentException JavaDoc("Java dependency must be on \"Java\" or \"VM\": " + name); // NOI18N
301
}
302
303                 if (comparison == Dependency.COMPARE_ANY) {
304                     throw new IllegalArgumentException JavaDoc("Must give a comparison for a Java dep: " + body); // NOI18N
305
}
306             } else if (type == Dependency.TYPE_IDE) {
307                 if (!(name.equals("IDE"))) { // NOI18N
308

309                     int slash = name.indexOf("/"); // NOI18N
310
boolean ok;
311
312                     if (slash == -1) {
313                         ok = false;
314                     } else {
315                         if (!name.substring(0, slash).equals("IDE")) { // NOI18N
316
ok = false;
317                         }
318
319                         try {
320                             int v = Integer.parseInt(name.substring(slash + 1));
321                             ok = (v >= 0);
322                         } catch (NumberFormatException JavaDoc e) {
323                             ok = false;
324                         }
325                     }
326
327                     if (!ok) {
328                         throw new IllegalArgumentException JavaDoc("Invalid IDE dependency: " + name); // NOI18N
329
}
330                 }
331
332                 if (comparison == Dependency.COMPARE_ANY) {
333                     throw new IllegalArgumentException JavaDoc("Must give a comparison for an IDE dep: " + body); // NOI18N
334
}
335             } else if (type == Dependency.TYPE_REQUIRES) {
336                 if (comparison != Dependency.COMPARE_ANY) {
337                     throw new IllegalArgumentException JavaDoc("Cannot give a comparison for a token requires dep: " + body); // NOI18N
338
}
339
340                 checkCodeName(name, false);
341             } else if (type == Dependency.TYPE_NEEDS) {
342                 if (comparison != Dependency.COMPARE_ANY) {
343                     throw new IllegalArgumentException JavaDoc("Cannot give a comparison for a token needs dep: " + body); // NOI18N
344
}
345
346                 checkCodeName(name, false);
347             } else if (type == Dependency.TYPE_RECOMMENDS) {
348                 if (comparison != Dependency.COMPARE_ANY) {
349                     throw new IllegalArgumentException JavaDoc("Cannot give a comparison for a token needs dep: " + body); // NOI18N
350
}
351
352                 checkCodeName(name, false);
353             } else {
354                 throw new IllegalArgumentException JavaDoc("unknown type"); // NOI18N
355
}
356
357             Dependency nue = new Dependency(type, name, comparison, version);
358             DependencyKey key = new DependencyKey(nue);
359
360             if (depsByKey.containsKey(key)) {
361                 throw new IllegalArgumentException JavaDoc(
362                     "Dependency " + nue + " duplicates the similar dependency " + depsByKey.get(key)
363                 ); // NOI18N
364
} else {
365                 deps.add(nue);
366                 depsByKey.put(key, nue);
367             }
368         }
369
370         return deps;
371     }
372
373     /** Get the type. */
374     public final int getType() {
375         return type;
376     }
377
378     /** Get the name of the depended-on object. */
379     public final String JavaDoc getName() {
380         return name;
381     }
382
383     /** Get the comparison type. */
384     public final int getComparison() {
385         return comparison;
386     }
387
388     /** Get the version to compare against (or null). */
389     public final String JavaDoc getVersion() {
390         return version;
391     }
392
393     /** Overridden to compare contents. */
394     public boolean equals(Object JavaDoc o) {
395         if (o.getClass() != Dependency.class) {
396             return false;
397         }
398
399         Dependency d = (Dependency) o;
400
401         return (type == d.type) && (comparison == d.comparison) && name.equals(d.name) &&
402         Utilities.compareObjects(version, d.version);
403     }
404
405     /** Overridden to hash by contents. */
406     public int hashCode() {
407         return 772067 ^ type ^ name.hashCode();
408     }
409
410     /** Unspecified string representation for debugging. */
411     public String JavaDoc toString() {
412         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(100);
413
414         if (type == TYPE_MODULE) {
415             buf.append("module "); // NOI18N
416
} else if (type == TYPE_PACKAGE) {
417             buf.append("package "); // NOI18N
418
} else if (type == TYPE_REQUIRES) {
419             buf.append("requires "); // NOI18N
420
} else if (type == TYPE_NEEDS) {
421             buf.append("needs "); // NOI18N
422
} else if (type == TYPE_RECOMMENDS) {
423             buf.append("recommends "); // NOI18N
424
}
425
426         buf.append(name);
427
428         if (comparison == COMPARE_IMPL) {
429             buf.append(" = "); // NOI18N
430
buf.append(version);
431         } else if (comparison == COMPARE_SPEC) {
432             buf.append(" > "); // NOI18N
433
buf.append(version);
434         }
435
436         return buf.toString();
437     }
438
439     /** Try to make a specification version from a string.
440      * Deal with errors gracefully and try to recover something from it.
441      * E.g. "1.4.0beta" is technically erroneous; correct to "1.4.0".
442      */

443     private static SpecificationVersion makeSpec(String JavaDoc vers) {
444         if (vers != null) {
445             try {
446                 return new SpecificationVersion(vers);
447             } catch (NumberFormatException JavaDoc nfe) {
448                 System.err.println("WARNING: invalid specification version: " + vers); // NOI18N
449
}
450
451             do {
452                 vers = vers.substring(0, vers.length() - 1);
453
454                 try {
455                     return new SpecificationVersion(vers);
456                 } catch (NumberFormatException JavaDoc nfe) {
457                     // ignore
458
}
459             } while (vers.length() > 0);
460         }
461
462         // Nothing decent in it at all; use zero.
463
return new SpecificationVersion("0"); // NOI18N
464
}
465
466     /** Key for checking for duplicates among dependencies.
467      * The unique characteristics of a dependency are:
468      * 1. The basic name. No release versions, no sample classes for packages
469      * (though if you specify only the class and not the package, this is different).
470      * 2. The type of dependency (module, package, etc.).
471      * Sample things which ought not be duplicated:
472      * 1. Sample classes within a package.
473      * 2. The same module with different release versions (use ranged releases as needed).
474      * 3. Impl & spec comparisons (the impl comparison is stricter anyway).
475      * 4. Different versions of the same thing (makes no sense).
476      */

477     private static final class DependencyKey {
478         private final int type;
479         private final String JavaDoc name;
480
481         public DependencyKey(Dependency d) {
482             type = d.getType();
483
484             switch (type) {
485             case TYPE_MODULE:
486             case TYPE_IDE:
487
488                 String JavaDoc codeName = d.getName();
489                 int idx = codeName.lastIndexOf('/');
490
491                 if (idx == -1) {
492                     name = codeName;
493                 } else {
494                     name = codeName.substring(0, idx);
495                 }
496
497                 break;
498
499             case TYPE_PACKAGE:
500
501                 String JavaDoc pkgName = d.getName();
502                 idx = pkgName.indexOf('[');
503
504                 if (idx != -1) {
505                     if (idx == 0) {
506                         // [org.apache.jasper.Constants]
507
// Keep the [] only to differentiate it from a package name:
508
name = pkgName;
509                     } else {
510                         // org.apache.jasper[Constants]
511
name = pkgName.substring(0, idx);
512                     }
513                 } else {
514                     // org.apache.jasper
515
name = pkgName;
516                 }
517
518                 break;
519
520             default:
521
522                 // TYPE_REQUIRES, TYPE_JAVA
523
name = d.getName();
524
525                 break;
526             }
527
528             //System.err.println("Key for " + d + " is " + this);
529
}
530
531         public int hashCode() {
532             return name.hashCode();
533         }
534
535         public boolean equals(Object JavaDoc o) {
536             return (o instanceof DependencyKey) && ((DependencyKey) o).name.equals(name) &&
537             (((DependencyKey) o).type == type);
538         }
539
540         public String JavaDoc toString() {
541             return "DependencyKey[" + name + "," + type + "]"; // NOI18N
542
}
543     }
544 }
545
Popular Tags