| /* |
| * 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. |
| */ |
| |
| package org.netbeans; |
| |
| // THIS CLASS OUGHT NOT USE NbBundle NOR org.openide CLASSES |
| // OUTSIDE OF openide-util.jar! UI AND FILESYSTEM/DATASYSTEM |
| // INTERACTIONS SHOULD GO ELSEWHERE. |
| // (NbBundle.getLocalizedValue is OK here.) |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.ObjectInput; |
| import java.security.AllPermission; |
| import java.security.CodeSource; |
| import java.security.PermissionCollection; |
| import java.security.Permissions; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.MissingResourceException; |
| import java.util.Properties; |
| import java.util.ResourceBundle; |
| import java.util.Set; |
| import java.util.StringTokenizer; |
| import java.util.jar.Attributes; |
| import java.util.jar.JarFile; |
| import java.util.jar.Manifest; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| import java.util.zip.ZipEntry; |
| import org.netbeans.LocaleVariants.FileWithSuffix; |
| import org.openide.modules.Dependency; |
| import org.openide.modules.InstalledFileLocator; |
| import org.openide.util.Exceptions; |
| import org.openide.util.NbBundle; |
| import org.openide.util.BaseUtilities; |
| |
| /** Object representing one module, possibly installed. |
| * Responsible for opening of module JAR file; reading |
| * manifest; parsing basic information such as dependencies; |
| * and creating a classloader for use by the installer. |
| * Methods not defined in ModuleInfo must be called from within |
| * the module manager's read mutex as a rule. |
| * @author Jesse Glick, Allan Gregersen |
| */ |
| class StandardModule extends Module { |
| |
| /** JAR file holding the module */ |
| private final File jar; |
| /** if reloadable, temporary JAR file actually loaded from */ |
| private File physicalJar; |
| private Manifest manifest; |
| |
| /** Simple registry of JAR files used as modules. |
| * Used only for debugging purposes, so that we can be sure |
| * that no one is using Class-Path to refer to other modules. |
| */ |
| private static final Set<File> moduleJARs = new HashSet<File>(); |
| |
| /** Patches added at the front of the classloader (or null). |
| * Files are assumed to be JARs; directories are themselves. |
| */ |
| private Set<File> patches; |
| |
| /** localized properties, only non-null if requested from disabled module */ |
| private Properties localizedProps; |
| |
| /** Use ModuleManager.create as a factory. */ |
| public StandardModule(ModuleManager mgr, Events ev, File jar, Object history, boolean reloadable, boolean autoload, boolean eager) throws IOException { |
| super(mgr, ev, history, JaveleonModule.isJaveleonPresent || reloadable, autoload, eager); |
| this.jar = jar; |
| moduleJARs.add(jar); |
| } |
| |
| @Override |
| ModuleData createData(ObjectInput in, Manifest mf) throws IOException { |
| if (in != null) { |
| return new StandardModuleData(in); |
| } else { |
| return new StandardModuleData(mf, this); |
| } |
| } |
| |
| public @Override Manifest getManifest() { |
| if (manifest == null) { |
| try { |
| loadManifest(); |
| } catch (IOException x) { |
| Util.err.log(Level.WARNING, "While loading manifest for " + getJarFile(), x); |
| manifest = new Manifest(); |
| } |
| } |
| return manifest; |
| } |
| |
| public @Override void releaseManifest() { |
| manifest = null; |
| } |
| |
| /** Get a localized attribute. |
| * First, if OpenIDE-Module-Localizing-Bundle was given, the specified |
| * bundle file (in all locale JARs as well as base JAR) is searched for |
| * a key of the specified name. |
| * Otherwise, the manifest's main attributes are searched for an attribute |
| * with the specified name, possibly with a locale suffix. |
| * If the attribute name contains a slash, and there is a manifest section |
| * named according to the part before the last slash, then this section's attributes |
| * are searched instead of the main attributes, and for the attribute listed |
| * after the slash. Currently this would only be useful for localized filesystem |
| * names. E.g. you may request the attribute org/foo/MyFileSystem.class/Display-Name. |
| * In the future certain attributes known to be dangerous could be |
| * explicitly suppressed from this list; should only be used for |
| * documented localizable attributes such as OpenIDE-Module-Name etc. |
| */ |
| public Object getLocalizedAttribute(String attr) { |
| String locb = getManifest().getMainAttributes().getValue("OpenIDE-Module-Localizing-Bundle"); // NOI18N |
| boolean usingLoader = false; |
| if (locb != null) { |
| if (classloader != null) { |
| if (locb.endsWith(".properties")) { // NOI18N |
| usingLoader = true; |
| String basename = locb.substring(0, locb.length() - 11).replace('/', '.'); |
| try { |
| ResourceBundle bundle = NbBundle.getBundle(basename, Locale.getDefault(), classloader); |
| try { |
| return bundle.getString(attr); |
| } catch (MissingResourceException mre) { |
| // Fine, ignore. |
| } |
| } catch (MissingResourceException mre) { |
| String resource = basename.replace('.', '/') + ".properties"; |
| Exceptions.attachMessage(mre, "#149833: failed to find " + basename + |
| " in locale " + Locale.getDefault() + " in " + classloader + " for " + jar + |
| "; resource lookup of " + resource + " -> " + classloader.getResource(resource)); |
| Exceptions.printStackTrace(mre); |
| } |
| } else { |
| Util.err.warning("cannot efficiently load non-*.properties OpenIDE-Module-Localizing-Bundle: " + locb); |
| } |
| } |
| if (!usingLoader) { |
| if (localizedProps == null) { |
| Util.err.log(Level.FINE, "Trying to get localized attr {0} from disabled module {1}", new Object[] {attr, getCodeNameBase()}); |
| try { |
| // check if the jar file still exists (see issue 82480) |
| if (jar != null && jar.isFile ()) { |
| JarFile jarFile = new JarFile(jar, false); |
| try { |
| loadLocalizedProps(jarFile, getManifest()); |
| } finally { |
| jarFile.close(); |
| } |
| } else { |
| Util.err.log(Level.FINE, "Cannot get localized attr {0} from module {1} (missing or deleted JAR file: {2})", new Object[] {attr, getCodeNameBase(), jar}); |
| } |
| } catch (IOException ioe) { |
| Util.err.log(Level.WARNING, jar.getAbsolutePath(), ioe); |
| } |
| } |
| if (localizedProps != null) { |
| String val = localizedProps.getProperty(attr); |
| if (val != null) { |
| return val; |
| } |
| } |
| } |
| } |
| // Try in the manifest now. |
| int idx = attr.lastIndexOf('/'); // NOI18N |
| if (idx == -1) { |
| // Simple main attribute. |
| return NbBundle.getLocalizedValue(getManifest().getMainAttributes(), new Attributes.Name(attr)); |
| } else { |
| // Attribute of a manifest section. |
| String section = attr.substring(0, idx); |
| String realAttr = attr.substring(idx + 1); |
| Attributes attrs = getManifest().getAttributes(section); |
| if (attrs != null) { |
| return NbBundle.getLocalizedValue(attrs, new Attributes.Name(realAttr)); |
| } else { |
| return null; |
| } |
| } |
| } |
| |
| public boolean isFixed() { |
| return false; |
| } |
| |
| /** Get the JAR this module is packaged in. |
| * May be null for modules installed specially, e.g. |
| * automatically from the classpath. |
| * @see #isFixed |
| */ |
| public @Override File getJarFile() { |
| return jar; |
| } |
| |
| /** Create a temporary test JAR if necessary. |
| * This is primarily necessary to work around a Java bug, |
| * #4405789, which is marked as fixed so might be obsolete. |
| */ |
| private void ensurePhysicalJar() throws IOException { |
| if (reloadable && physicalJar == null) { |
| physicalJar = Util.makeTempJar(jar); |
| } |
| } |
| private void destroyPhysicalJar() { |
| if (physicalJar != null) { |
| if (physicalJar.isFile()) { |
| if (! physicalJar.delete()) { |
| Util.err.warning("temporary JAR " + physicalJar + " not currently deletable."); |
| } else { |
| Util.err.fine("deleted: " + physicalJar); |
| } |
| } |
| physicalJar = null; |
| } else { |
| Util.err.fine("no physicalJar to delete for " + this); |
| } |
| } |
| |
| /** Open the JAR, load its manifest, and do related things. */ |
| private void loadManifest() throws IOException { |
| if (Util.err.isLoggable(Level.FINE)) { |
| Util.err.fine("loading manifest of " + jar); |
| } |
| File jarBeingOpened = null; // for annotation purposes |
| try { |
| if (reloadable) { |
| // Never try to cache reloadable JARs. |
| jarBeingOpened = physicalJar; // might be null |
| ensurePhysicalJar(); |
| jarBeingOpened = physicalJar; // might have changed |
| JarFile jarFile = new JarFile(physicalJar, false); |
| try { |
| Manifest m = jarFile.getManifest(); |
| if (m == null) throw new IOException("No manifest found in " + physicalJar); // NOI18N |
| manifest = m; |
| } finally { |
| jarFile.close(); |
| } |
| } else { |
| jarBeingOpened = jar; |
| manifest = getManager().loadManifest(jar); |
| } |
| } catch (IOException e) { |
| if (jarBeingOpened != null) { |
| Exceptions.attachMessage(e, |
| "While loading manifest from: " + |
| jarBeingOpened); // NOI18N |
| } |
| throw e; |
| } |
| } |
| |
| private Set<File> findPatches() { |
| if (patches == null) { |
| // #9273: load any modules/patches/this-code-name/*.jar files first: |
| File patchdir = new File(new File(jar.getParentFile(), "patches"), // NOI18N |
| getCodeNameBase().replace('.', '-')); // NOI18N |
| if (patchdir.isDirectory()) { |
| File[] jars = patchdir.listFiles(Util.jarFilter()); |
| if (jars != null) { |
| for (File patchJar : jars) { |
| if (patches == null) { |
| patches = new HashSet<File>(5); |
| } |
| patches.add(patchJar); |
| } |
| } else { |
| Util.err.warning("Could not search for patches in " + patchdir); |
| } |
| } |
| // The following system property is used |
| // by XTest, Maven Compile On Save & co. |
| // to influence installed modules without changing the build. |
| // Format is -Dnetbeans.patches.org.nb.mods.foo=/path/to.file.jar:/path/to/dir |
| String patchesClassPath = System.getProperty("netbeans.patches." + getCodeNameBase()); // NOI18N |
| if (patchesClassPath != null) { |
| StringTokenizer tokenizer = new StringTokenizer(patchesClassPath, File.pathSeparator); |
| while (tokenizer.hasMoreTokens()) { |
| String element = tokenizer.nextToken(); |
| File fileElement = new File(element); |
| if (fileElement.exists()) { |
| if (patches == null) { |
| patches = new HashSet<File>(15); |
| } |
| patches.add(fileElement); |
| } |
| } |
| } |
| if (Util.err.isLoggable(Level.FINE)) { |
| Util.err.log(Level.FINE, "patches of {0}: {1}", new Object[]{jar, patches}); |
| } |
| if (patches != null) { |
| for (File patch : patches) { |
| events.log(Events.PATCH, patch); |
| } |
| } |
| if (patches == null) { |
| patches = Collections.emptySet(); |
| } |
| } |
| |
| return patches; |
| } |
| |
| |
| /** Check if there is any need to load localized properties. |
| * If so, try to load them. Throw an exception if they cannot |
| * be loaded for some reason. Uses an open JAR file for the |
| * base module at least, though may also open locale variants |
| * as needed. |
| * Note: due to #19698, this cache is not usually used; only if you |
| * specifically go to look at the display properties of a disabled module. |
| * @see <a href="http://www.netbeans.org/issues/show_bug.cgi?id=12549">#12549</a> |
| */ |
| private void loadLocalizedProps(JarFile jarFile, Manifest m) throws IOException { |
| String locbundle = m.getMainAttributes().getValue("OpenIDE-Module-Localizing-Bundle"); // NOI18N |
| if (locbundle != null) { |
| // Something requested, read it in. |
| // locbundle is a resource path. |
| { |
| ZipEntry bundleFile = jarFile.getEntry(locbundle); |
| // May not be present in base JAR: might only be in e.g. default locale variant. |
| if (bundleFile != null) { |
| localizedProps = new Properties(); |
| InputStream is = jarFile.getInputStream(bundleFile); |
| try { |
| localizedProps.load(is); |
| } finally { |
| is.close(); |
| } |
| } |
| } |
| { |
| // Check also for localized variant JARs and load in anything from them as needed. |
| // Note we need to go in the reverse of the usual search order, so as to |
| // overwrite less specific bundles with more specific. |
| int idx = locbundle.lastIndexOf('.'); // NOI18N |
| String name, ext; |
| if (idx == -1) { |
| name = locbundle; |
| ext = ""; // NOI18N |
| } else { |
| name = locbundle.substring(0, idx); |
| ext = locbundle.substring(idx); |
| } |
| List<FileWithSuffix> pairs = LocaleVariants.findLocaleVariantsWithSuffixesOf(jar, getCodeNameBase()); |
| Collections.reverse(pairs); |
| for (FileWithSuffix pair : pairs) { |
| File localeJar = pair.file; |
| String suffix = pair.suffix; |
| String rsrc = name + suffix + ext; |
| JarFile localeJarFile = new JarFile(localeJar, false); |
| try { |
| ZipEntry bundleFile = localeJarFile.getEntry(rsrc); |
| // Need not exist in all locale variants. |
| if (bundleFile != null) { |
| if (localizedProps == null) { |
| localizedProps = new Properties(); |
| } // else append and overwrite base-locale values |
| InputStream is = localeJarFile.getInputStream(bundleFile); |
| try { |
| localizedProps.load(is); |
| } finally { |
| is.close(); |
| } |
| } |
| } finally { |
| localeJarFile.close(); |
| } |
| } |
| } |
| if (localizedProps == null) { |
| // We should have loaded from at least some bundle in there... |
| throw new IOException("Could not find localizing bundle: " + locbundle); // NOI18N |
| } |
| /* Don't log; too large and annoying: |
| if (Util.err.isLoggable(ErrorManager.INFORMATIONAL)) { |
| Util.err.fine("localizedProps=" + localizedProps); |
| } |
| */ |
| } |
| } |
| |
| /** Get all JARs loaded by this module. |
| * Includes the module itself, any locale variants of the module, |
| * any extensions specified with Class-Path, any locale variants |
| * of those extensions. |
| * The list will be in classpath order (patches first). |
| * Currently the temp JAR is provided in the case of test modules, to prevent |
| * sporadic ZIP file exceptions when background threads (like Java parsing) tries |
| * to open libraries found in the library path. |
| * JARs already present in the classpath are <em>not</em> listed. |
| * @return a <code>List<File></code> of JARs |
| */ |
| @Override |
| public List<File> getAllJars() { |
| List<File> l = new ArrayList<File>(); |
| Set<File> ptchs = findPatches(); |
| if (ptchs != null) l.addAll(ptchs); |
| if (physicalJar != null) { |
| l.add(physicalJar); |
| } else if (jar != null) { |
| l.add(jar); |
| } |
| ((StandardModuleData)data()).addCp(l); |
| return l; |
| } |
| |
| /** Set whether this module is supposed to be reloadable. |
| * Has no immediate effect, only impacts what happens the |
| * next time it is enabled (after having been disabled if |
| * necessary). |
| * Must be called from within a write mutex. |
| * @param r whether the module should be considered reloadable |
| */ |
| public void setReloadable(boolean r) { |
| getManager().assertWritable(); |
| if (reloadable != r) { |
| reloadable = r; |
| getManager().fireReloadable(this); |
| } |
| } |
| |
| /** Reload this module. Access from ModuleManager. |
| * If an exception is thrown, the module is considered |
| * to be in an invalid state. |
| */ |
| public void reload() throws IOException { |
| // Probably unnecessary but just in case: |
| destroyPhysicalJar(); |
| String codeNameBase1 = getCodeNameBase(); |
| localizedProps = null; |
| loadManifest(); |
| parseManifest(); |
| // JST: reload not solved yet |
| // JST findExtensionsAndVariants(manifest); |
| String codeNameBase2 = getCodeNameBase(); |
| if (! codeNameBase1.equals(codeNameBase2)) { |
| throw new InvalidException("Code name base changed during reload: " + codeNameBase1 + " -> " + codeNameBase2); // NOI18N |
| } |
| } |
| |
| // Access from ModuleManager: |
| /** Turn on the classloader. Passed a list of parent modules to use. |
| * The parents should already have had their classloaders initialized. |
| */ |
| protected void classLoaderUp(Set<Module> parents) throws IOException { |
| if (Util.err.isLoggable(Level.FINE)) { |
| Util.err.fine("classLoaderUp on " + this + " with parents " + parents); |
| } |
| // Find classloaders for dependent modules and parent to them. |
| List<ClassLoader> loaders = new ArrayList<ClassLoader>(parents.size() + 1); |
| // This should really be the base loader created by org.nb.Main for loading openide etc.: |
| loaders.add(Module.class.getClassLoader()); |
| for (Module parent: parents) { |
| PackageExport[] exports = parent.getPublicPackages(); |
| if (exports != null && exports.length == 0) { |
| // Check if there is an impl dep here. |
| boolean implDep = false; |
| for (Dependency dep : getDependenciesArray()) { |
| if (dep.getType() == Dependency.TYPE_MODULE && |
| dep.getComparison() == Dependency.COMPARE_IMPL && |
| dep.getName().equals(parent.getCodeName())) { |
| implDep = true; |
| break; |
| } |
| } |
| if (!implDep) { |
| // Nothing exported from here at all, no sense even adding it. |
| // Shortcut; would not harm anything to add it now, but we would |
| // never use it anyway. |
| // Cf. #27853. |
| continue; |
| } |
| } |
| ClassLoader l = getParentLoader(parent); |
| if (parent.isFixed() && loaders.contains(l)) { |
| Util.err.log(Level.FINE, "#24996: skipping duplicate classloader from {0}", parent); |
| continue; |
| } |
| loaders.add(l); |
| } |
| List<File> classp = new ArrayList<File>(3); |
| Set<File> ptchs = findPatches(); |
| if (ptchs != null) classp.addAll(ptchs); |
| |
| if (reloadable) { |
| ensurePhysicalJar(); |
| // Using OPEN_DELETE does not work well with test modules under 1.4. |
| // Random code (URL handler?) still expects the JAR to be there and |
| // it is not. |
| classp.add(physicalJar); |
| } else { |
| classp.add(jar); |
| } |
| |
| ((StandardModuleData)data()).addCp(classp); |
| |
| // possibly inject some patches |
| getManager().refineModulePath(this, classp); |
| |
| // #27853 |
| ClassLoader cld = getManager().refineClassLoader(this, loaders); |
| // the classloader may be shared, if this module is a fragment |
| if (cld != null) { |
| classloader = cld; |
| } else { |
| try { |
| classloader = createNewClassLoader(classp, loaders); |
| } catch (IllegalArgumentException iae) { |
| // Should not happen, but just in case. |
| throw (IOException) new IOException(iae.toString()).initCause(iae); |
| } |
| } |
| } |
| |
| /** Setup a new module with the given class path and the set of parent |
| * class loaders. |
| */ |
| protected ClassLoader createNewClassLoader(List<File> classp, List<ClassLoader> parents) { |
| return new OneModuleClassLoader(classp, parents.toArray(new ClassLoader[parents.size()])); |
| } |
| |
| /** Get the class loader of a particular parent module. */ |
| protected ClassLoader getParentLoader(Module parent) { |
| return parent.getClassLoader(); |
| } |
| |
| /** Turn off the classloader and release all resources. */ |
| protected void classLoaderDown() { |
| if (classloader instanceof ProxyClassLoader) { |
| ((ProxyClassLoader)classloader).destroy(); |
| } |
| classloader = null; |
| } |
| /** Should be called after turning off the classloader of one or more modules & GC'ing. */ |
| protected void cleanup() { |
| if (isEnabled()) throw new IllegalStateException("cleanup on enabled module: " + this); // NOI18N |
| if (classloader != null) throw new IllegalStateException("cleanup on module with classloader: " + this); // NOI18N |
| // XXX should this rather be done when the classloader is collected? |
| destroyPhysicalJar(); |
| } |
| |
| /** Notify the module that it is being deleted. */ |
| public void destroy() { |
| moduleJARs.remove(jar); |
| } |
| |
| /** String representation for debugging. */ |
| public @Override String toString() { |
| String s = "StandardModule:" + getCodeNameBase() + " jarFile: " + jar.getAbsolutePath(); // NOI18N |
| if (!isValid()) s += "[invalid]"; // NOI18N |
| return s; |
| } |
| |
| /** PermissionCollection with an instance of AllPermission. */ |
| private static PermissionCollection modulePermissions; |
| /** @return initialized @see #modulePermission */ |
| private static synchronized PermissionCollection getAllPermission() { |
| if (modulePermissions == null) { |
| modulePermissions = new Permissions(); |
| modulePermissions.add(new AllPermission()); |
| modulePermissions.setReadOnly(); |
| } |
| return modulePermissions; |
| } |
| |
| static boolean isModuleJar(File f) { |
| return moduleJARs.contains(f); |
| } |
| |
| private static final Logger CL_LOG = Logger.getLogger(OneModuleClassLoader.class.getName()); |
| /** Class loader to load a single module. |
| * Auto-localizing, multi-parented, permission-granting, the works. |
| */ |
| class OneModuleClassLoader extends JarClassLoader implements Util.ModuleProvider { |
| /** Create a new loader for a module. |
| * @param classp the List of all module jars of code directories; |
| * includes the module itself, its locale variants, |
| * variants of extensions and Class-Path items from Manifest. |
| * The items are JarFiles for jars and Files for directories |
| * @param parents a set of parent classloaders (from other modules) |
| */ |
| public OneModuleClassLoader(List<File> classp, ClassLoader[] parents) throws IllegalArgumentException { |
| super(classp, parents, false, StandardModule.this); |
| JaveleonModule.registerClassLoader(this, getCodeNameBase()); |
| } |
| |
| public Module getModule() { |
| return StandardModule.this; |
| } |
| |
| /** Inherited. |
| * @param cs is ignored |
| * @return PermissionCollection with an AllPermission instance |
| */ |
| protected @Override PermissionCollection getPermissions(CodeSource cs) { |
| return getAllPermission(); |
| } |
| |
| /** |
| * Look up a native library as described in modules documentation. |
| * @see http://bits.netbeans.org/dev/javadoc/org-openide-modules/org/openide/modules/doc-files/api.html#jni |
| */ |
| protected @Override String findLibrary(String libname) { |
| InstalledFileLocator ifl = InstalledFileLocator.getDefault(); |
| String arch = System.getProperty("os.arch"); // NOI18N |
| String system = System.getProperty("os.name").toLowerCase(Locale.ENGLISH); // NOI18N |
| String mapped = System.mapLibraryName(libname); |
| File lib; |
| |
| lib = ifl.locate("modules/lib/" + mapped, getCodeNameBase(), false); // NOI18N |
| if (lib != null) { |
| CL_LOG.log(Level.FINE, "found {0}", lib); |
| return lib.getAbsolutePath(); |
| } |
| |
| lib = ifl.locate("modules/lib/" + arch + "/" + mapped, getCodeNameBase(), false); // NOI18N |
| if (lib != null) { |
| CL_LOG.log(Level.FINE, "found {0}", lib); |
| return lib.getAbsolutePath(); |
| } |
| |
| lib = ifl.locate("modules/lib/" + arch + "/" + system + "/" + mapped, getCodeNameBase(), false); // NOI18N |
| if (lib != null) { |
| CL_LOG.log(Level.FINE, "found {0}", lib); |
| return lib.getAbsolutePath(); |
| } |
| |
| if( BaseUtilities.isMac() ) { |
| String jniMapped = mapped.replaceFirst("\\.dylib$",".jnilib"); |
| lib = ifl.locate("modules/lib/" + jniMapped, getCodeNameBase(), false); // NOI18N |
| if (lib != null) { |
| CL_LOG.log(Level.FINE, "found {0}", lib); |
| return lib.getAbsolutePath(); |
| } |
| |
| lib = ifl.locate("modules/lib/" + arch + "/" + jniMapped, getCodeNameBase(), false); // NOI18N |
| if (lib != null) { |
| CL_LOG.log(Level.FINE, "found {0}", lib); |
| return lib.getAbsolutePath(); |
| } |
| |
| lib = ifl.locate("modules/lib/" + arch + "/" + system + "/" + jniMapped, getCodeNameBase(), false); // NOI18N |
| if (lib != null) { |
| CL_LOG.log(Level.FINE, "found {0}", lib); |
| return lib.getAbsolutePath(); |
| } |
| CL_LOG.log(Level.FINE, "found nothing like modules/lib/{0}/{1}/{2}", new Object[] {arch, system, jniMapped}); |
| } |
| |
| CL_LOG.log(Level.FINE, "found nothing like modules/lib/{0}/{1}/{2}", new Object[] {arch, system, mapped}); |
| return null; |
| } |
| |
| protected @Override boolean shouldDelegateResource(String pkg, ClassLoader parent) { |
| if (!super.shouldDelegateResource(pkg, parent)) { |
| return false; |
| } |
| Module other; |
| if (parent instanceof Util.ModuleProvider) { |
| other = ((Util.ModuleProvider)parent).getModule(); |
| } else { |
| other = null; |
| } |
| return getManager().shouldDelegateResource(StandardModule.this, other, pkg, parent); |
| } |
| |
| public @Override String toString() { |
| return "ModuleCL@" + Integer.toHexString(System.identityHashCode(this)) + "[" + getCodeNameBase() + "]"; // NOI18N |
| } |
| } |
| } |