/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License.
*/
/** Similar to {@link NbBundle#getLocalizingSuffixes} but optimized. * @since JST-PENDING: Called from InstalledFileLocatorImpl
*/ publicstaticsynchronized String[] getLocalizingSuffixesFast() { return LocaleVariants.getLocalizingSuffixesFast();
}
/** * Make a temporary copy of a JAR file.
*/ static File makeTempJar(File moduleFile) throws IOException {
String prefix = moduleFile.getName(); if (prefix.endsWith(".jar") || prefix.endsWith(".JAR")) { // NOI18N
prefix = prefix.substring(0, prefix.length() - 4);
} if (prefix.length() < 3) prefix += '.'; if (prefix.length() < 3) prefix += '.'; if (prefix.length() < 3) prefix += '.';
String suffix = "-test.jar"; // NOI18N
File physicalModuleFile = Files.createTempFile(prefix, suffix).toFile();
physicalModuleFile.deleteOnExit();
InputStream is = new FileInputStream(moduleFile); try {
OutputStream os = new FileOutputStream(physicalModuleFile); try { byte[] buf = newbyte[4096]; int i; while ((i = is.read(buf)) != -1) {
os.write(buf, 0, i);
}
} finally {
os.close();
}
} finally {
is.close();
}
err.fine("Made " + physicalModuleFile); return physicalModuleFile;
}
// XXX ought to be some way to get localized messages for these...
/** Check whether a simple dependency is met. * Only applicable to Java dependencies.
*/ staticboolean checkJavaDependency(Dependency dep) throws IllegalArgumentException { // Note that "any" comparison is not possible for this type. if (dep.getType() == Dependency.TYPE_JAVA) { if (dep.getName().equals(Dependency.JAVA_NAME)) { if (dep.getComparison() == Dependency.COMPARE_SPEC) { returnnew SpecificationVersion(dep.getVersion()).compareTo(Dependency.JAVA_SPEC) <= 0;
} else { return dep.getVersion().equals(Dependency.JAVA_IMPL);
}
} else { if (dep.getComparison() == Dependency.COMPARE_SPEC) { returnnew SpecificationVersion(dep.getVersion()).compareTo(Dependency.VM_SPEC) <= 0;
} else { return dep.getVersion().equals(Dependency.VM_IMPL);
}
}
} else { thrownew IllegalArgumentException();
}
}
/** Check whether a package dependency is met. * A classloader must be supplied to check in. * @param dep a module dependency * @param cl a package-accessible classloader * @return true if a package dependency is met * @throws IllegalArgumentException * @since 2.14
*/ publicstaticboolean checkPackageDependency(Dependency dep, ClassLoader cl) throws IllegalArgumentException { if (dep.getType() != Dependency.TYPE_PACKAGE) { thrownew IllegalArgumentException("Not a package dependency"); // NOI18N
} if (! (cl instanceof ProxyClassLoader) && cl != Util.class.getClassLoader()) { thrownew IllegalArgumentException("Not a package-accessible classloader: " + cl); // NOI18N
}
String name = dep.getName();
String version = dep.getVersion(); int comparison = dep.getComparison();
String packageName, sampleName; int idx = name.indexOf('['); if (idx == -1) {
packageName = name;
sampleName = null;
} elseif (idx == 0) {
packageName = null;
sampleName = name.substring(1, name.length() - 1);
} else {
packageName = name.substring(0, idx);
sampleName = name.substring(idx + 1, name.length() - 1); if (sampleName.indexOf('.') == -1) { // Unqualified class name; prefix it automatically.
sampleName = packageName + '.' + sampleName;
}
} Class<?> sampleClass = null; if (sampleName != null) { try {
sampleClass = cl.loadClass(sampleName);
} catch (ClassNotFoundException cnfe) { if (packageName == null) { // This was all we were relying on, so it is an error.
err.log(Level.FINE, null, cnfe);
err.fine("Probed class could not be found"); returnfalse;
} // Else let the regular package check take care of it; // this was only run to enforce that the package defs were loaded.
} catch (RuntimeException e) { // SecurityException, etc. Package exists but is corrupt.
err.log(Level.WARNING, null, e);
err.fine("Assuming package " + packageName + " is corrupt"); returnfalse;
} catch (LinkageError le) { // NoClassDefFoundError, etc. Package exists but is corrupt.
err.log(Level.WARNING, null, le);
err.fine("Assuming package " + packageName + " is corrupt"); returnfalse;
}
} if (packageName != null) { Package pkg; if (cl instanceof ProxyClassLoader) {
pkg = ((ProxyClassLoader) cl).getPackage(packageName);
} else {
pkg = Package.getPackage(packageName);
} if (pkg == null && sampleClass != null) {
pkg = sampleClass.getPackage();
} if (pkg == null) {
err.fine("No package with the name " + packageName + " found"); returnfalse;
} if (comparison == Dependency.COMPARE_ANY) { returntrue;
} elseif (comparison == Dependency.COMPARE_SPEC) { if (pkg.getSpecificationVersion() == null) {
err.fine("Package " + packageName + " did not give a specification version"); returnfalse;
} else { try {
SpecificationVersion versionSpec = new SpecificationVersion(version);
SpecificationVersion pkgSpec = new SpecificationVersion(pkg.getSpecificationVersion().trim()); if (versionSpec.compareTo(pkgSpec) <= 0) { returntrue;
} else {
err.fine("Loaded package " + packageName + " was only of version " + pkgSpec + " but " + versionSpec + " was requested"); returnfalse;
}
} catch (NumberFormatException nfe) {
err.log(Level.WARNING, null, nfe);
err.fine("Will not honor a dependency on non-numeric package spec version"); returnfalse;
}
}
} else { // COMPARE_IMPL if (pkg.getImplementationVersion() == null) {
err.fine("Package " + packageName + " had no implementation version"); returnfalse;
} elseif (! pkg.getImplementationVersion().trim().equals(version)) {
err.fine("Package " + packageName + " had the wrong impl version: " + pkg.getImplementationVersion()); returnfalse;
} else { returntrue;
}
}
} else { // Satisfied sample class. returntrue;
}
}
/** * Interface for a classloader to declare that it comes from a module. * @since 2.1
*/ publicinterface ModuleProvider {
Module getModule();
}
/** * Enumerate (direct) interdependencies among a set of modules. * If used in a topological sort, the result will be a reverse-order * list of modules (suitable for disabling; reverse for enabling). * @param modules some modules * @param modulesByName map from module cnbs to modules (may contain unrelated modules) * @param _providersOf map from tokens to sets of modules providing them (may mention unrelated modules) * @return a map from modules to lists of modules they depend on * @see Utilities#topologicalSort * JST-PENDING needed from tests
*/ publicstatic Map<Module,List<Module>> moduleDependencies(Collection<Module> modules, Map<String,Module> modulesByName, Map<String,Set<Module>> _providersOf) { return moduleDependencies(modules, modulesByName, _providersOf, Collections.<String, Collection<Module>>emptyMap());
}
static Map<Module,List<Module>> moduleDependencies(Collection<Module> modules, Map<String,Module> modulesByName, Map<String,Set<Module>> _providersOf,
Map<String, Collection<Module>> fragments) {
Set<Module> modulesSet = (modules instanceof Set) ? (Set<Module>)modules : new HashSet<Module>(modules);
Map<String,List<Module>> providersOf = new HashMap<String,List<Module>>(_providersOf.size() * 2 + 1); for (Map.Entry<String, Set<Module>> entry: _providersOf.entrySet()) {
Set<Module> providers = entry.getValue(); if (providers != null) {
List<Module> availableProviders = new LinkedList<Module>(providers);
availableProviders.retainAll(modulesSet); if (!availableProviders.isEmpty()) {
providersOf.put(entry.getKey(), availableProviders);
}
}
}
Map<Module,List<Module>> m = new HashMap<Module,List<Module>>(); for (Module m1: modules) {
List<Module> l = null; for (Dependency dep : m1.getDependenciesArray()) { if (dep.getType() == Dependency.TYPE_REQUIRES) {
List<Module> providers = providersOf.get(dep.getName());
if (m2 != null && modulesSet.contains(m2)) {
l = fillMapSlot(m, m1);
l.add(m2);
}
}
} // include module fragment _contents_ into the module dependencies, // so the dependent modules are enabled before the host+fragment merged // classloader will activate
Collection<Module> frags = fragments.get(m1.getCodeNameBase()); if (frags != null && !frags.isEmpty()) {
frags = new HashSet<>(frags);
frags.retainAll(modules);
for (Module f : frags) {
List<Module> fragmentDep = fillMapSlot(m, f); // move fragment after its host module in the sort order
fragmentDep.add(m1); for (Dependency dep : f.getDependenciesArray()) { if (dep.getType() == Dependency.TYPE_REQUIRES) {
Collection<Module> providers = providersOf.get(dep.getName()); if (providers != null) { if (providers.contains(m1)) {
providers = new ArrayList<>(providers);
}
l = fillMapSlot(m, m1);
l.addAll(providers);
}
} elseif (dep.getType() == Dependency.TYPE_MODULE) {
String cnb = (String) parseCodeName(dep.getName())[0];
Module m2 = modulesByName.get(cnb);
if (m2 != null && m2 != m1 && modulesSet.contains(m2)) {
l = fillMapSlot(m, m1);
l.add(m2);
}
}
}
} if (l != null) {
l.remove(m1); // remove fragments for m1 from m1's dependencies
l.removeAll(frags);
}
} if (l != null) {
m.put(m1, l);
}
}
return m;
}
privatestatic List<Module> fillMapSlot(Map<Module, List<Module>> map, Module module) {
List<Module> l = map.get(module); if (l == null) {
l = new LinkedList<>();
map.put(module, l);
} return l;
}
/** * Get dependencies forward or backwards starting from one module. * @see #moduleDependencies * @see ModuleManager#getModuleInterdependencies
*/ static Set<Module> moduleInterdependencies(Module m, boolean reverse, boolean transitive, boolean considerNeeds,
Set<Module> modules, Map<String,Module> modulesByName, Map<String,Set<Module>> providersOf) { // XXX these algorithms could surely be made faster using standard techniques // for now the speed is not critical however if (reverse) {
Set<Module> s = new HashSet<Module>(); for (Module m2: modules) { if (m2 == m) { continue;
} if (moduleInterdependencies(m2, false, transitive, considerNeeds, modules, modulesByName, providersOf).contains(m)) {
s.add(m2);
}
} return s;
} else {
Set<Module> s = new HashSet<Module>(); for (Dependency dep : m.getDependenciesArray()) { boolean needsProvider = dep.getType() == Dependency.TYPE_REQUIRES ||
considerNeeds && dep.getType() == Dependency.TYPE_NEEDS; if (m instanceof NetigsoModule && dep.getType() == Dependency.TYPE_RECOMMENDS) {
needsProvider = true;
} if (needsProvider) {
Set<Module> providers = providersOf.get(dep.getName()); if (providers != null) {
s.addAll(providers);
}
} elseif (dep.getType() == Dependency.TYPE_MODULE) {
String cnb = (String)parseCodeName(dep.getName())[0];
Module m2 = modulesByName.get(cnb); if (m2 != null) {
s.add(m2);
}
}
}
s.remove(m); if (transitive) {
Set<Module> toAdd; do {
toAdd = new HashSet<Module>(); for (Module m2: s) {
Set<Module> s2 = moduleInterdependencies(m2, false, false, considerNeeds, modules, modulesByName, providersOf);
s2.remove(m);
s2.removeAll(s);
toAdd.addAll(s2);
}
s.addAll(toAdd);
} while (!toAdd.isEmpty());
} return s;
}
}
/** Get a filter for JAR files. */ static FilenameFilter jarFilter() { returnnew JarFilter();
} privatestaticfinalclass JarFilter implements FilenameFilter {
JarFilter() {} publicboolean accept(File dir, String name) {
String n = name.toLowerCase(Locale.US); return n.endsWith(".jar"); // NOI18N
}
}
/** Convert a class file name to a resource name suitable for Beans.instantiate. * @param name resource name of class file * @return class name without the <code>.class</code>/<code>.ser</code> extension, and using dots as package separator * @throws IllegalArgumentException if the name did not have a valid extension, or originally contained dots outside the extension, etc. * @since JST-PENDING: used from NbInstaller
*/ publicstatic String createPackageName(String name) throws IllegalArgumentException {
String clExt = ".class"; // NOI18N if (!name.endsWith(clExt)) { // try different extension
clExt = ".ser"; // NOI18N
} if (name.endsWith(clExt)) {
String bareName = name.substring(0, name.length() - clExt.length()); if (bareName.length() == 0) { // ".class" // NOI18N thrownew IllegalArgumentException("Bad class file name: " + name); // NOI18N
} if (bareName.charAt(0) == '/') { // "/foo/bar.class" // NOI18N thrownew IllegalArgumentException("Bad class file name: " + name); // NOI18N
} if (bareName.charAt(bareName.length() - 1) == '/') { // "foo/bar/.class" // NOI18N thrownew IllegalArgumentException("Bad class file name: " + name); // NOI18N
} if (bareName.indexOf('.') != -1) { // "foo.bar.class" // NOI18N thrownew IllegalArgumentException("Bad class file name: " + name); // NOI18N
} return bareName.replace('/', '.'); // NOI18N
} else { // "foo/bar" or "foo.bar" // NOI18N thrownew IllegalArgumentException("Bad class file name: " + name); // NOI18N
}
}
/** A lookup implementation specialized for modules. * Its primary advantage over e.g. AbstractLookup is that * it is possible to add modules to the set at one time and * fire changes in the set of modules later on. ModuleManager * uses this to add modules immediately in create() and destroy(), * but only fire lookup events later and asynchronously, from the * read mutex.
*/ staticfinalclass ModuleLookup extends Lookup {
ModuleLookup() {} privatefinal Set<Module> modules = new HashSet<Module>(100); privatefinal Set<ModuleResult> results = Collections.newSetFromMap(new WeakHashMap<>(10)); /** Add a module to the set. */ publicvoid add(Module m) { synchronized (modules) {
modules.add(m);
}
} /** Remove a module from the set. */ publicvoid remove(Module m) { synchronized (modules) {
modules.remove(m);
}
} /** Fire changes to all result listeners. */ publicvoid changed() { synchronized (results) { for (ModuleResult moduleResult : results) {
moduleResult.changed();
}
}
} public <T> T lookup(Class<T> clazz) { if ((clazz == Module.class || clazz == ModuleInfo.class || clazz == Object.class || clazz == null)
&& ! modules.isEmpty()) { synchronized (modules) { return clazz.cast(modules.iterator().next());
}
} else { returnnull;
}
}
@SuppressWarnings("unchecked") public <T> Lookup.Result<T> lookup(Lookup.Template<T> t) { Class<T> clazz = t.getType(); if (clazz == Module.class || clazz == ModuleInfo.class ||
clazz == Object.class || clazz == null) { return (Lookup.Result<T>)(Object) new ModuleResult((Lookup.Template<Module>) t);
} else { return Lookup.EMPTY.lookup(t);
}
} public @Override String toString() { synchronized (modules) { return"ModuleLookup" + modules; // NOI18N
}
} privatefinalclass ModuleResult extends Lookup.Result<Module> { privatefinal Lookup.Template<? super Module> t; privatefinal Set<LookupListener> listeners = new HashSet<LookupListener>(10); public ModuleResult(Lookup.Template<? super Module> t) { this.t = t; synchronized (results) {
results.add(this);
}
} publicvoid addLookupListener(LookupListener l) { synchronized (listeners) {
listeners.add(l);
}
} publicvoid removeLookupListener(LookupListener l) { synchronized (listeners) {
listeners.remove(l);
}
} publicvoid changed() {
LookupListener[] _listeners; synchronized (listeners) { if (listeners.isEmpty()) { return;
}
_listeners = listeners.toArray(new LookupListener[0]);
}
LookupEvent ev = new LookupEvent(this); for (int i = 0; i < _listeners.length; i++) {
_listeners[i].resultChanged(ev);
}
} public Collection<Module> allInstances() { synchronized (modules) {
String id = t.getId();
Object inst = t.getInstance(); if (id != null) {
Iterator<Module> it = modules.iterator(); while (it.hasNext()) {
Module m = it.next(); if (id.equals(ModuleItem.PREFIX + m.getCodeNameBase())) { if (inst == null || inst == m) { return Collections.<Module>singleton(m);
}
}
} return Collections.<Module>emptySet();
} elseif (inst != null) { return modules.contains(inst) ? Collections.<Module>singleton(Module.class.cast(inst)) : Collections.<Module>emptySet();
} else { // Regular lookup based on type. returnnew HashSet<Module>(modules);
}
}
} public @Override Set<Class<? extends Module>> allClasses() { return Collections.<Class<? extends Module>>singleton(Module.class);
} public @Override Collection<? extends Lookup.Item<Module>> allItems() {
Collection<Module> insts = allInstances();
ArrayList<ModuleItem> list = new ArrayList<ModuleItem>(Math.max(1, insts.size())); for (Module m: insts) {
list.add(new ModuleItem(m));
} return list;
} public @Override String toString() { return"ModuleResult:" + t; // NOI18N
}
} privatestaticfinalclass ModuleItem extends Lookup.Item<Module> { publicstaticfinal String PREFIX = "Module["; // NOI18N privatefinal Module item; public ModuleItem(Module item) { this.item = item;
} public Module getInstance() { return item;
} publicClass<? extends Module> getType() { return Module.class;
} public String getId() { return PREFIX + item.getCodeNameBase();
} public String getDisplayName() { return item.getDisplayName();
}
}
}
// OK to not release this memory; module deletion is rare: holds 45kB for 173 modules (June 2005) privatestaticfinal Map<String,Object[]> codeNameParseCache = new HashMap<String,Object[]>(200); // Map<String,[String,int]> /** Find the code name base and major release version from a code name. * Caches these parses. Thread-safe (i.e. OK from read mutex). * @return an array consisting of the code name base (String) followed by the release version (Integer or null) * followed by another end-range version (Integer or null) * @throws NumberFormatException if the release version is mangled * @since JST-PENDING: used from NbInstaller
*/ publicstatic Object[] parseCodeName(String cn) throws NumberFormatException { synchronized (codeNameParseCache) {
Object[] r = codeNameParseCache.get(cn); if (r == null) {
r = new Object[3]; int i = cn.lastIndexOf('/'); if (i == -1) {
r[0] = cn;
} else {
r[0] = cn.substring(0, i).intern();
String end = cn.substring(i + 1); int j = end.indexOf('-'); if (j == -1) {
r[1] = Integer.valueOf(end);
} else {
r[1] = Integer.valueOf(end.substring(0, j));
r[2] = Integer.valueOf(end.substring(j + 1));
}
}
codeNameParseCache.put(cn.intern(), r);
} return r;
}
}
/** Get API module dependency, if any, for a module. * @param dependencies module dependencies * @param cnb code name base of API module * @return a fake spec version (0.x.y if x.y w/ no major release, else r.x.y); or null if no dep * @since JST-PENDING: used from NbInstaller
*/ publicstatic SpecificationVersion getModuleDep(Set<Dependency> dependencies, String cnb) { for (Dependency d : dependencies) { if (d.getType() == Dependency.TYPE_MODULE &&
d.getComparison() == Dependency.COMPARE_SPEC) { try {
Object[] p = parseCodeName(d.getName()); if (!p[0].equals(cnb)) { continue;
} int rel = ((Integer)p[1]).intValue(); // ignore any end range, consider only start if (rel == -1) rel = 0; // XXX will this lead to incorrect semantics? returnnew SpecificationVersion("" + rel + "." + d.getVersion()); // NOI18N
} catch (NumberFormatException nfe) {
Util.err.log(Level.WARNING, null, nfe); returnnull;
}
}
} returnnull;
}
/** * Transitively fill out a set of modules with all of its module dependencies. * Dependencies on missing modules are silently ignored, but dependencies * on present but uninstallable (problematic) modules are included. * @param mgr the manager * @param modules a mutable set of modules * @since JST-PENDING: used from NbInstaller
*/ publicstaticvoid transitiveClosureModuleDependencies(ModuleManager mgr, Set<Module> modules) {
Set<Module> nue = null; // Set of newly appended modules while (nue == null || !nue.isEmpty()) {
nue = new HashSet<Module>(); for (Module m: modules) { for (Dependency dep : m.getDependenciesArray()) { if (dep.getType() != Dependency.TYPE_MODULE) { continue;
}
Module other = mgr.get((String)parseCodeName(dep.getName())[0]); if (other != null && !modules.contains(other)) {
nue.add(other);
}
}
}
modules.addAll(nue);
}
}
}
¤ Dauer der Verarbeitung: 0.49 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.