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

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

The newest version!
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2017 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 static java.security.AccessController.doPrivileged;

import java.io.IOException;
import java.lang.Module;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleFinder;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.Set;

/**
 */
public final class JDKModuleFinder implements IterableModuleFinder {
    private final ModuleLayer layer;

    private static final JDKModuleFinder INSTANCE = new JDKModuleFinder();

    private JDKModuleFinder() {
        ModuleLayer layer;
        if (JDKModuleFinder.class.getModule().isNamed()) {
            layer = JDKModuleFinder.class.getModule().getLayer();
            if (layer == null) {
                layer = ModuleLayer.boot();
            }
        } else {
            layer = ModuleLayer.boot();
        }
        this.layer = layer;
    }

    public static JDKModuleFinder getInstance() {
        return INSTANCE;
    }

    public ModuleSpec findModule(final String name, final ModuleLoader delegateLoader) {
        if ("java.se".equals(name)) {
            // The `java.se` aggregator module is not included in JDK boot layer by default.
            // It becomes available when the JVM starts with the `--add-modules java.se` command line parameter.
            // By defining it here, we ensure its availability even if the JVM was not started with this parameter.
            final ModuleSpec.Builder builder = ModuleSpec.build(name, false);
            final ModuleDescriptor javaSeDescriptor = ModuleFinder.ofSystem().find(name).get().descriptor();
            DependencySpec dependencySpec;
            for (final ModuleDescriptor.Requires dep : javaSeDescriptor.requires()) {
                dependencySpec = new ModuleDependencySpecBuilder().setName(dep.name()).setExport(true).build();
                builder.addDependency(dependencySpec);
            }
            return builder.create();
        }

        final Set packages;
        final Module module;
        final Optional moduleOptional = layer.findModule(name);
        if (moduleOptional.isEmpty()) {
            if ("org.jboss.modules".equals(name)) {
                module = getClass().getModule();
                if (module.isNamed()) {
                    packages = module.getPackages();
                } else {
                    packages = Utils.MODULES_PACKAGES;
                }
            } else {
                return null;
            }
        } else {
            module = moduleOptional.get();
            packages = module.getPackages();
        }
        final ModuleSpec.Builder builder = ModuleSpec.build(name);
        final ModuleDescriptor descriptor = module.getDescriptor();
        if (descriptor != null) {
            final Optional version = descriptor.rawVersion();
            if (version.isPresent()) builder.setVersion(Version.parse(version.get()));
            for (ModuleDescriptor.Requires require : descriptor.requires()) {
                final Set modifiers = require.modifiers();
                builder.addDependency(
                        new ModuleDependencySpecBuilder()
                                .setName(require.name())
                                .setExport(modifiers.contains(ModuleDescriptor.Requires.Modifier.TRANSITIVE))
                                .setOptional(modifiers.contains(ModuleDescriptor.Requires.Modifier.STATIC))
                                .build()
                );
            }
        }
        final Set paths = new HashSet<>(packages.size());
        for (String pkg : packages) {
            paths.add(pkg.replace('.', '/'));
        }
        final LocalDependencySpecBuilder depBuilder = new LocalDependencySpecBuilder();
        depBuilder.setLoaderPaths(paths);
        depBuilder.setExport(true);
        depBuilder.setLocalLoader(new JDKModuleLoader(module, packages));
        builder.addDependency(depBuilder.build());
        return builder.create();
    }

    public String toString() {
        return "JDK Module Finder";
    }

    public Iterator iterateModules(final String baseName, final boolean recursive, final ModuleLoader delegate) {
        final Set moduleSet = layer.modules();
        final ArrayList nameList = new ArrayList<>(moduleSet.size() + 1);
        final Module ourModule = getClass().getModule();
        boolean foundUs = false;
        for (Module module : moduleSet) {
            if (module == ourModule) {
                foundUs = true;
            }
            nameList.add(module.getName());
        }
        if (!foundUs) {
            nameList.add("org.jboss.modules");
        }
        return nameList.iterator();
    }

    static class JDKModuleLoader implements LocalLoader {
        private final Module module;
        private final ClassLoader classLoader;
        private final Set packages;

        JDKModuleLoader(final Module module, final Set packages) {
            this.module = module;
            JDKModuleLoader.class.getModule().addReads(module);
            classLoader = doPrivileged(new ModuleClassLoaderAction(module));
            this.packages = packages;
        }

        public Class loadClassLocal(String name, final boolean resolve) {
            final String nameDots = name.replace('/', '.');
            final int idx = nameDots.lastIndexOf('.');
            if (idx == -1) {
                // no empty package allowed
                return null;
            }
            if (packages.contains(nameDots.substring(0, idx))) {
                try {
                    final Class clazz = classLoader.loadClass(nameDots);
                    if (clazz.getModule() != module) {
                        return null;
                    } else {
                        return clazz;
                    }
                } catch (ClassNotFoundException e) {
                    // unlikely
                    return null;
                }
            }
            return null;
        }

        public Package loadPackageLocal(final String name) {
            return packages.contains(name) ? classLoader.getDefinedPackage(name) : null;
        }

        public List loadResourceLocal(final String name) {
            final URL url;
            try {
                url = new URL("jrt:/" + module.getName() + "/" + name);
            } catch (MalformedURLException e) {
                return Collections.emptyList();
            }
            try {
                final URLConnection connection = url.openConnection();
                connection.connect();
                return Collections.singletonList(new URLConnectionResource(connection));
            } catch (IOException e) {
                // connect failed; try the class loader
                final int idx = name.lastIndexOf('/');
                if (idx != -1) {
                    final String nameDots = name.substring(0, idx).replace('/', '.');
                    if (packages.contains(nameDots)) {
                        final URL resource = classLoader.getResource(name);
                        if (resource != null) {
                            try {
                                final URLConnection connection = resource.openConnection();
                                connection.connect();
                                return Collections.singletonList(new URLConnectionResource(connection));
                            } catch (IOException e2) {
                                return Collections.emptyList();
                            }
                        }
                    }
                }
                return Collections.emptyList();
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy