Back to index...
/*
 * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package jdk.internal.module;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleDescriptor.Exports;
import java.lang.module.ModuleDescriptor.Opens;
import java.lang.module.ModuleDescriptor.Provides;
import java.lang.module.ModuleDescriptor.Requires;
import java.lang.module.ModuleDescriptor.Version;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import jdk.internal.misc.JavaLangModuleAccess;
import jdk.internal.misc.SharedSecrets;
/**
 * This builder is optimized for reconstituting the {@code ModuleDescriptor}s
 * for system modules.  The validation should be done at jlink time.
 *
 * 1. skip name validation
 * 2. ignores dependency hashes.
 * 3. ModuleDescriptor skips the defensive copy and directly uses the
 *    sets/maps created in this Builder.
 *
 * SystemModules should contain modules for the boot layer.
 */
final class Builder {
    private static final JavaLangModuleAccess JLMA =
        SharedSecrets.getJavaLangModuleAccess();
    // Static cache of the most recently seen Version to cheaply deduplicate
    // most Version objects.  JDK modules have the same version.
    static Version cachedVersion;
    /**
     * Returns a {@link Requires} for a dependence on a module with the given
     * (and possibly empty) set of modifiers, and optionally the version
     * recorded at compile time.
     */
    public static Requires newRequires(Set<Requires.Modifier> mods,
                                       String mn,
                                       String compiledVersion)
    {
        Version version = null;
        if (compiledVersion != null) {
            // use the cached version if the same version string
            Version ver = cachedVersion;
            if (ver != null && compiledVersion.equals(ver.toString())) {
                version = ver;
            } else {
                version = Version.parse(compiledVersion);
            }
        }
        return JLMA.newRequires(mods, mn, version);
    }
    /**
     * Returns a {@link Requires} for a dependence on a module with the given
     * (and possibly empty) set of modifiers, and optionally the version
     * recorded at compile time.
     */
    public static Requires newRequires(Set<Requires.Modifier> mods,
                                       String mn)
    {
        return newRequires(mods, mn, null);
    }
    /**
     * Returns a {@link Exports} for a qualified export, with
     * the given (and possibly empty) set of modifiers,
     * to a set of target modules.
     */
    public static Exports newExports(Set<Exports.Modifier> ms,
                                     String pn,
                                     Set<String> targets) {
        return JLMA.newExports(ms, pn, targets);
    }
    /**
     * Returns an {@link Opens} for an unqualified open with a given set of
     * modifiers.
     */
    public static Opens newOpens(Set<Opens.Modifier> ms, String pn) {
        return JLMA.newOpens(ms, pn);
    }
    /**
     * Returns an {@link Opens} for a qualified opens, with
     * the given (and possibly empty) set of modifiers,
     * to a set of target modules.
     */
    public static Opens newOpens(Set<Opens.Modifier> ms,
                                 String pn,
                                 Set<String> targets) {
        return JLMA.newOpens(ms, pn, targets);
    }
    /**
     * Returns a {@link Exports} for an unqualified export with a given set
     * of modifiers.
     */
    public static Exports newExports(Set<Exports.Modifier> ms, String pn) {
        return JLMA.newExports(ms, pn);
    }
    /**
     * Returns a {@link Provides} for a service with a given list of
     * implementation classes.
     */
    public static Provides newProvides(String st, List<String> pcs) {
        return JLMA.newProvides(st, pcs);
    }
    final String name;
    boolean open, synthetic, mandated;
    Set<Requires> requires;
    Set<Exports> exports;
    Set<Opens> opens;
    Set<String> packages;
    Set<String> uses;
    Set<Provides> provides;
    Version version;
    String mainClass;
    Builder(String name) {
        this.name = name;
        this.requires = Collections.emptySet();
        this.exports = Collections.emptySet();
        this.opens = Collections.emptySet();
        this.provides = Collections.emptySet();
        this.uses = Collections.emptySet();
    }
    Builder open(boolean value) {
        this.open = value;
        return this;
    }
    Builder synthetic(boolean value) {
        this.synthetic = value;
        return this;
    }
    Builder mandated(boolean value) {
        this.mandated = value;
        return this;
    }
    /**
     * Sets module exports.
     */
    public Builder exports(Exports[] exports) {
        this.exports = Set.of(exports);
        return this;
    }
    /**
     * Sets module opens.
     */
    public Builder opens(Opens[] opens) {
        this.opens = Set.of(opens);
        return this;
    }
    /**
     * Sets module requires.
     */
    public Builder requires(Requires[] requires) {
        this.requires = Set.of(requires);
        return this;
    }
    /**
     * Adds a set of (possible empty) packages.
     */
    public Builder packages(Set<String> packages) {
        this.packages = packages;
        return this;
    }
    /**
     * Sets the set of service dependences.
     */
    public Builder uses(Set<String> uses) {
        this.uses = uses;
        return this;
    }
    /**
     * Sets module provides.
     */
    public Builder provides(Provides[] provides) {
        this.provides = Set.of(provides);
        return this;
    }
    /**
     * Sets the module version.
     *
     * @throws IllegalArgumentException if {@code v} is null or cannot be
     *         parsed as a version string
     *
     * @see Version#parse(String)
     */
    public Builder version(String v) {
        Version ver = cachedVersion;
        if (ver != null && v.equals(ver.toString())) {
            version = ver;
        } else {
            cachedVersion = version = Version.parse(v);
        }
        return this;
    }
    /**
     * Sets the module main class.
     */
    public Builder mainClass(String mc) {
        mainClass = mc;
        return this;
    }
    /**
     * Returns an immutable set of the module modifiers derived from the flags.
     */
    private Set<ModuleDescriptor.Modifier> modifiers() {
        int n = 0;
        if (open) n++;
        if (synthetic) n++;
        if (mandated) n++;
        if (n == 0) {
            return Collections.emptySet();
        } else {
            ModuleDescriptor.Modifier[] mods = new ModuleDescriptor.Modifier[n];
            if (open) mods[--n] = ModuleDescriptor.Modifier.OPEN;
            if (synthetic) mods[--n] = ModuleDescriptor.Modifier.SYNTHETIC;
            if (mandated) mods[--n] = ModuleDescriptor.Modifier.MANDATED;
            return Set.of(mods);
        }
    }
    /**
     * Builds a {@code ModuleDescriptor} from the components.
     */
    public ModuleDescriptor build(int hashCode) {
        assert name != null;
        return JLMA.newModuleDescriptor(name,
                                        version,
                                        modifiers(),
                                        requires,
                                        exports,
                                        opens,
                                        uses,
                                        provides,
                                        packages,
                                        mainClass,
                                        hashCode);
    }
}
Back to index...