All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.modules.LocalModuleFinder Maven / Gradle / Ivy

There is a newer version: 1.3.3
Show newest version
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2014 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * Licensed 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.jboss.modules;

import java.io.File;
import java.io.FilePermission;
import java.io.IOException;
import java.lang.reflect.UndeclaredThrowableException;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import org.jboss.modules.filter.PathFilter;
import org.jboss.modules.filter.PathFilters;

import static java.security.AccessController.doPrivileged;
import static java.security.AccessController.getContext;

/**
 * A module finder which locates module specifications which are stored in a local module
 * repository on the filesystem, which uses {@code module.xml} descriptors.
 *
 * @author David M. Lloyd
 */
public final class LocalModuleFinder implements ModuleFinder {

    private static final File[] NO_FILES = new File[0];

    private final File[] repoRoots;
    private final PathFilter pathFilter;
    private final AccessControlContext accessControlContext;

    private LocalModuleFinder(final File[] repoRoots, final PathFilter pathFilter, final boolean cloneRoots) {
        this.repoRoots = cloneRoots && repoRoots.length > 0 ? repoRoots.clone() : repoRoots;
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            for (File repoRoot : this.repoRoots) {
                if (repoRoot == null) sm.checkPermission(new FilePermission(new File(repoRoot, "-").getPath(), "read"));
            }
        }
        this.pathFilter = pathFilter;
        this.accessControlContext = AccessController.getContext();
    }

    /**
     * Construct a new instance.
     *
     * @param repoRoots the repository roots to use
     * @param pathFilter the path filter to use
     */
    public LocalModuleFinder(final File[] repoRoots, final PathFilter pathFilter) {
        this(repoRoots, pathFilter, true);
    }

    /**
     * Construct a new instance.
     *
     * @param repoRoots the repository roots to use
     */
    public LocalModuleFinder(final File[] repoRoots) {
        this(repoRoots, PathFilters.acceptAll());
    }

    /**
     * Construct a new instance, using the {@code module.path} system property or the {@code JAVA_MODULEPATH} environment variable
     * to get the list of module repository roots.
     * 

* This is equivalent to a call to {@link LocalModuleFinder#LocalModuleFinder(boolean) LocalModuleFinder(true)}. *

*/ public LocalModuleFinder() { this(true); } /** * Construct a new instance, using the {@code module.path} system property or the {@code JAVA_MODULEPATH} environment variable * to get the list of module repository roots. * * @param supportLayersAndAddOns {@code true} if the identified module repository roots should be checked for * an internal structure of child "layer" and "add-on" directories that may also * be treated as module roots lower in precedence than the parent root. Any "layers" * subdirectories whose names are specified in a {@code layers.conf} file found in * the module repository root will be added in the precedence of order specified * in the {@code layers.conf} file; all "add-on" subdirectories will be added at * a lower precedence than all "layers" and with no guaranteed precedence order * between them. If {@code false} no check for "layer" and "add-on" directories * will be performed. * */ public LocalModuleFinder(boolean supportLayersAndAddOns) { this(getRepoRoots(supportLayersAndAddOns), PathFilters.acceptAll(), false); } static File[] getRepoRoots(final boolean supportLayersAndAddOns) { return supportLayersAndAddOns ? LayeredModulePathFactory.resolveLayeredModulePath(getModulePathFiles()) : getModulePathFiles(); } private static File[] getModulePathFiles() { return getFiles(System.getProperty("module.path", System.getenv("JAVA_MODULEPATH")), 0, 0); } private static File[] getFiles(final String modulePath, final int stringIdx, final int arrayIdx) { if (modulePath == null) return NO_FILES; final int i = modulePath.indexOf(File.pathSeparatorChar, stringIdx); final File[] files; if (i == -1) { files = new File[arrayIdx + 1]; files[arrayIdx] = new File(modulePath.substring(stringIdx)).getAbsoluteFile(); } else { files = getFiles(modulePath, i + 1, arrayIdx + 1); files[arrayIdx] = new File(modulePath.substring(stringIdx, i)).getAbsoluteFile(); } return files; } private static String toPathString(ModuleIdentifier moduleIdentifier) { final StringBuilder builder = new StringBuilder(40); builder.append(moduleIdentifier.getName().replace('.', File.separatorChar)); builder.append(File.separatorChar).append(moduleIdentifier.getSlot()); builder.append(File.separatorChar); return builder.toString(); } public ModuleSpec findModule(final ModuleIdentifier identifier, final ModuleLoader delegateLoader) throws ModuleLoadException { final String child = toPathString(identifier); if (pathFilter.accept(child)) { try { return doPrivileged(new PrivilegedExceptionAction() { public ModuleSpec run() throws Exception { for (File root : repoRoots) { final File file = new File(root, child); final File moduleXml = new File(file, "module.xml"); if (moduleXml.exists()) { final ModuleSpec spec = ModuleXmlParser.parseModuleXml(delegateLoader, identifier, file, moduleXml, accessControlContext); if (spec == null) break; return spec; } } return null; } }, accessControlContext); } catch (PrivilegedActionException e) { try { throw e.getException(); } catch (RuntimeException e1) { throw e1; } catch (ModuleLoadException e1) { throw e1; } catch (Error e1) { throw e1; } catch (Exception e1) { throw new UndeclaredThrowableException(e1); } } } return null; } /** * Parse a {@code module.xml} file and return the corresponding module specification. * * @param identifier the identifier to load * @param delegateLoader the delegate module loader to use for module specifications * @param roots the repository root paths to search * @return the module specification * @throws IOException if reading the module file failed * @throws ModuleLoadException if creating the module specification failed (e.g. due to a parse error) */ public static ModuleSpec parseModuleXmlFile(final ModuleIdentifier identifier, final ModuleLoader delegateLoader, final File... roots) throws IOException, ModuleLoadException { final String child = toPathString(identifier); for (File root : roots) { final File file = new File(root, child); final File moduleXml = new File(file, "module.xml"); if (moduleXml.exists()) { final ModuleSpec spec = ModuleXmlParser.parseModuleXml(delegateLoader, identifier, file, moduleXml, getContext()); if (spec == null) break; return spec; } } return null; } public String toString() { final StringBuilder b = new StringBuilder(); b.append("local module finder @").append(Integer.toHexString(hashCode())).append(" (roots: "); final int repoRootsLength = repoRoots.length; for (int i = 0; i < repoRootsLength; i++) { final File root = repoRoots[i]; b.append(root); if (i != repoRootsLength - 1) { b.append(','); } } b.append(')'); return b.toString(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy