org.eclipse.jdt.internal.compiler.env.AutomaticModuleNaming.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.jdt.internal.compiler.env.AutomaticModuleNaming.java

Source

/*******************************************************************************
 * Copyright (c) 2017 Till Brychcy and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     Till Brychcy - initial API and implementation
 *******************************************************************************/
package org.eclipse.jdt.internal.compiler.env;

import java.io.File;
import java.io.IOException;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

public class AutomaticModuleNaming {

    private static final String AUTOMATIC_MODULE_NAME = "Automatic-Module-Name"; //$NON-NLS-1$

    /**
     * Determine the automatic module name of a given jar as specified in {@link <a href=
     * "http://download.java.net/java/jdk9/docs/api/java/lang/module/ModuleFinder.html#of-java.nio.file.Path...-">
     * ModuleFinder.of</a>}
     */
    public static char[] determineAutomaticModuleName(final String jarFileName) {
        // "If the JAR file has the attribute "Automatic-Module-Name" in its main manifest then its value is the
        // module name."
        try (JarFile jar = new JarFile(jarFileName)) {
            Manifest manifest = jar.getManifest();
            if (manifest != null) {
                String automaticModuleName = manifest.getMainAttributes().getValue(AUTOMATIC_MODULE_NAME);
                if (automaticModuleName != null) {
                    return automaticModuleName.toCharArray();
                }
            }
        } catch (IOException e) {
            // ignore
        }
        // The module name is otherwise derived from the name of the JAR file.
        return determineAutomaticModuleNameFromFileName(jarFileName, true, true);
    }

    /**
     * Determine the automatic module name of a given jar or project as specified in {@link <a href=
     * "http://download.java.net/java/jdk9/docs/api/java/lang/module/ModuleFinder.html#of-java.nio.file.Path...-">
     * ModuleFinder.of</a>}
     * @param fileName names either a jar file or a java project in the workspace
     * @param isFile <code>true</code> indicates that fileName denotes a file, <code>false</code> must be used for projects
     * @param manifest representation of the META-INF/MANIFEST.MF entry within the given source (jar or project), or <code>null</code>
     * @return the derived module name or <code>null</code>
     */
    public static char[] determineAutomaticModuleName(final String fileName, boolean isFile, Manifest manifest) {
        if (manifest != null) {
            String automaticModuleName = manifest.getMainAttributes().getValue(AUTOMATIC_MODULE_NAME);
            if (automaticModuleName != null) {
                return automaticModuleName.toCharArray();
            }
        }
        return determineAutomaticModuleNameFromFileName(fileName, true, isFile);
    }

    /**
     * Determine the automatic module name of a given jar or project as defined by an Automatic-Module-Name
     * header in its manifest.
     * @param manifest representation of the META-INF/MANIFEST.MF entry within the given source (jar or project), or <code>null</code>
     * @return the derived module name or <code>null</code>
     */
    public static char[] determineAutomaticModuleNameFromManifest(Manifest manifest) {
        if (manifest != null) {
            String automaticModuleName = manifest.getMainAttributes().getValue(AUTOMATIC_MODULE_NAME);
            if (automaticModuleName != null) {
                return automaticModuleName.toCharArray();
            }
        }
        return null;
    }

    /**
     * Determine the automatic module name if no "Automatic-Module-Name" was found in the Manifest, as specified in
     * {@link <a href=
     * "http://download.java.net/java/jdk9/docs/api/java/lang/module/ModuleFinder.html#of-java.nio.file.Path...-">ModuleFinder.of</a>}
     * 
     * @param name
     *            the filename (or directory name)
     * @param skipDirectory
     *            if true, parent directory names are skipped
     * @param removeExtension
     *            if true, the ".jar" extension is removed.
     */
    public static char[] determineAutomaticModuleNameFromFileName(String name, boolean skipDirectory,
            boolean removeExtension) {
        int index;
        int start = 0;
        int end = name.length();
        if (skipDirectory) {
            index = name.lastIndexOf(File.separatorChar);
            start = index + 1;
        }

        // "The ".jar" suffix is removed"
        if (removeExtension) {
            if (name.endsWith(".jar") || name.endsWith(".JAR")) { //$NON-NLS-1$//$NON-NLS-2$
                end -= 4;
            }
        }

        // "If the name matches the regular expression "-(\\d+(\\.|$))" then the module name will be derived from the
        // subsequence preceding the hyphen of the first occurrence. [...]"
        dashLoop: for (index = start; index < end - 1; index++) {
            if (name.charAt(index) == '-' && name.charAt(index + 1) >= '0' && name.charAt(index + 1) <= '9') {
                for (int index2 = index + 2; index2 < end; index2++) {
                    final char c = name.charAt(index2);
                    if (c == '.') {
                        break;
                    }
                    if (c < '0' || c > '9') {
                        continue dashLoop;
                    }
                }
                end = index;
                break;
            }
        }

        // "All non-alphanumeric characters ([^A-Za-z0-9]) in the module name are replaced with a dot ("."), all
        // repeating dots are replaced with one dot, and all leading and trailing dots are removed."
        StringBuilder sb = new StringBuilder(end - start);
        boolean needDot = false;
        for (int i = start; i < end; i++) {
            char c = name.charAt(i);
            if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')) {
                if (needDot) {
                    sb.append('.');
                    needDot = false;
                }
                sb.append(c);
            } else {
                if (sb.length() > 0) {
                    needDot = true;
                }
            }
        }
        return sb.toString().toCharArray();
    }

}