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

com.alipay.sofa.ark.loader.jar.JarUtils Maven / Gradle / Ivy

There is a newer version: 3.1.8
Show newest version
/*
 * 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 com.alipay.sofa.ark.loader.jar;

import com.alipay.sofa.ark.common.util.FileUtils;
import com.alipay.sofa.ark.common.util.StringUtils;
import com.alipay.sofa.ark.loader.archive.JarFileArchive;
import com.alipay.sofa.ark.loader.util.ModifyPathUtils;
import com.alipay.sofa.ark.spi.archive.Archive;
import com.alipay.sofa.common.utils.StringUtil;
import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.JarEntry;

public class JarUtils {
    private static final String                        CLASSPATH_ROOT_IDENTITY          = "/target/classes";

    private static final String                        TEST_CLASSPATH_ROOT_IDENTITY     = "/target/test-classes";
    private static final String                        TARGET_ROOT_IDENTITY             = "/target/";

    private static final String                        JAR_POM_PROPERTIES_RELATIVE_PATH = "maven-archiver/pom.properties";
    private static final String                        JAR_ARTIFACT_ID                  = "artifactId";

    private static final String                        JAR_POM_PROPERTIES               = "pom.properties";

    private static final String                        POM_FILE                         = "/pom.xml";

    private static final String                        VERSION_REGEX                    = "^([0-9]+\\.)+.+";

    private static final MavenXpp3Reader               READER                           = new MavenXpp3Reader();

    public static final String                         JAR_SEPARATOR                    = "!/";

    public static final String                         JAR_SUFFIX                       = ".jar";

    private static final Map> artifactIdCacheMap               = new ConcurrentHashMap<>();

    static File searchPomProperties(File dirOrFile) {
        if (dirOrFile == null || !dirOrFile.exists()) {
            return null;
        }
        if (dirOrFile.isFile() && JAR_POM_PROPERTIES.equals(dirOrFile.getName())) {
            return dirOrFile;
        }
        if (dirOrFile.isDirectory()) {
            File[] files = dirOrFile.listFiles();

            if (files != null) {
                for (File file : files) {
                    File result = searchPomProperties(file);
                    if (result != null) {
                        return result;
                    }
                }
            }
        }
        return null;
    }

    static String getArtifactIdFromLocalClassPath(String fileClassPath) {

        String libraryFile = fileClassPath.replace("file:", "");
        // 1. search pom.properties
        int classesRootIndex = libraryFile.endsWith(CLASSPATH_ROOT_IDENTITY) ? libraryFile
            .indexOf(CLASSPATH_ROOT_IDENTITY) : libraryFile.indexOf(CLASSPATH_ROOT_IDENTITY + "/");
        int testClassesRootIndex = libraryFile.endsWith(TEST_CLASSPATH_ROOT_IDENTITY) ? libraryFile
            .indexOf(TEST_CLASSPATH_ROOT_IDENTITY) : libraryFile
            .indexOf(TEST_CLASSPATH_ROOT_IDENTITY + "/");
        String pomPropertiesPath;
        String pomXmlPath = null;
        if (classesRootIndex != -1) {
            pomPropertiesPath = libraryFile.substring(0,
                classesRootIndex + TARGET_ROOT_IDENTITY.length())
                                + JAR_POM_PROPERTIES_RELATIVE_PATH;
            pomXmlPath = libraryFile.substring(0, classesRootIndex) + POM_FILE;
        } else if (testClassesRootIndex != -1) {
            pomPropertiesPath = libraryFile.substring(0, testClassesRootIndex
                                                         + TARGET_ROOT_IDENTITY.length())
                                + JAR_POM_PROPERTIES_RELATIVE_PATH;
            pomXmlPath = libraryFile.substring(0, testClassesRootIndex) + POM_FILE;
        } else {
            // is not from test classpath, for example install uncompressed modules, just return null
            // search for pom.properties
            File pomPropertiesFile = searchPomProperties(FileUtils.file(libraryFile));
            if (pomPropertiesFile != null && pomPropertiesFile.exists()) {
                pomPropertiesPath = pomPropertiesFile.getAbsolutePath();
            } else {
                // not found pom.properties
                pomPropertiesPath = null;
            }
        }

        String artifactId = null;
        if (!StringUtils.isEmpty(pomPropertiesPath)) {
            try (InputStream inputStream = Files.newInputStream(FileUtils.file(pomPropertiesPath)
                .toPath())) {
                Properties properties = new Properties();
                properties.load(inputStream);
                artifactId = properties.getProperty(JAR_ARTIFACT_ID);
            } catch (IOException e) {
                // ignore
            }
        }

        if (StringUtils.isEmpty(artifactId) && !StringUtils.isEmpty(pomXmlPath)) {
            try (FileReader fileReader = new FileReader(pomXmlPath)) {
                Model model = READER.read(fileReader);
                return model.getArtifactId();
            } catch (Exception e) {
                // ignore
            }
        }
        return artifactId;
    }

    public static String parseArtifactId(String jarLocation) {
        // 1. /xxx/xxx/xx.jar!/
        // 2. /xxx/xxx/xx.jar!/xxxx.class
        // 3. /xxx/xxx/xx.jar
        // 4. /xxx/xxx/xxx-bootstrap-1.0.0-ark-biz.jar!/BOOT-INF/lib/spring-boot-2.4.13.jar!/
        // 5. /xxx/xxx-bootstrap-1.0.0-ark-biz.jar!/BOOT-INF/lib/sofa-ark-springboot-starter-2.1.1.jar!/META-INF/spring.factories
        // 6. /xxx/xxx/target/classes/xxxx.jar
        // 7. /xxx/xxx/target/test-classes/yyy/yyy/
        // 8. /xxx/xxx/xxx-starter-1.0.0-SNAPSHOT.jar!/BOOT-INF/lib/xxx2-starter-1.1.4-SNAPSHOT-ark-biz.jar!/lib/xxx3-230605-sofa.jar!/
        // 9. if is ark plugin, then return null to set declared default

        // clean the jar location prefix and suffix
        if (jarLocation.contains(JAR_SUFFIX)) {
            jarLocation = jarLocation.substring(0, jarLocation.lastIndexOf(JAR_SUFFIX) + JAR_SUFFIX.length());
        }
        if (jarLocation.startsWith("file:")) {
            jarLocation = jarLocation.substring("file:".length());
        }

        // modify the path to suit WindowsOS
        jarLocation = ModifyPathUtils.modifyPath(jarLocation);
        String finalJarLocation = jarLocation;
        artifactIdCacheMap.computeIfAbsent(jarLocation, a -> {
            try {
                String artifactId;
                String[] as = a.split(JAR_SEPARATOR, -1);
                if (as.length == 1) {
                    // no '!/'
                    if (a.endsWith(".jar")) {
                        artifactId = parseArtifactIdFromJar(a);
                        if (StringUtils.isEmpty(artifactId)) {
                            artifactId = doGetArtifactIdFromFileName(a);
                        }
                    } else {
                        artifactId = getArtifactIdFromLocalClassPath(a);
                    }
                } else {
                    // contains one '!/' or more
                    artifactId = parseArtifactIdFromJar(a);
                    if (StringUtils.isEmpty(artifactId)) {
                        artifactId = doGetArtifactIdFromFileName(a);
                    }
                }
                return Optional.ofNullable(artifactId);
            } catch (IOException e) {
                throw new RuntimeException(String.format("Failed to parse artifact id from jar %s.",
                        finalJarLocation), e);
            }

        });
        return artifactIdCacheMap.get(jarLocation).orElse(null);
    }

    private static String doGetArtifactIdFromFileName(String jarLocation) {
        String[] jarInfos = jarLocation.split("/");
        if (jarInfos.length == 0) {
            return null;
        }
        String artifactVersion = jarInfos[jarInfos.length - 1];
        String[] artifactVersionInfos = artifactVersion.split("-");
        List artifactInfos = new ArrayList<>();
        boolean getVersion = false;
        for (String info : artifactVersionInfos) {
            if (!StringUtils.isEmpty(info) && info.matches(VERSION_REGEX)) {
                getVersion = true;
                break;
            }
            artifactInfos.add(info);
        }
        if (getVersion) {
            return String.join("-", artifactInfos);
        }
        // if can't find any version from jar name, then we just return null to paas the declared check
        return null;
    }

    private static String parseArtifactIdFromJar(String jarLocation) throws IOException {
        try (com.alipay.sofa.ark.loader.jar.JarFile jarFile = getNestedRootJarFromJarLocation(jarLocation)) {
            JarFileArchive jarFileArchive = new JarFileArchive(jarFile);
            return jarFileArchive.getPomProperties().getProperty(JAR_ARTIFACT_ID);
        }
    }

    public static com.alipay.sofa.ark.loader.jar.JarFile getNestedRootJarFromJarLocation(String jarLocation)
                                                                                                            throws IOException {
        //  /xxx/xxx/xxx-starter-1.0.0-SNAPSHOT.jar!/BOOT-INF/lib/xxx2-starter-1.1.4-SNAPSHOT-ark-biz.jar!/lib/xxx3-230605-sofa.jar
        String[] js = jarLocation.split(JAR_SEPARATOR, -1);
        com.alipay.sofa.ark.loader.jar.JarFile rJarFile = new com.alipay.sofa.ark.loader.jar.JarFile(
            FileUtils.file(js[0]));
        for (int i = 1; i < js.length; i++) {
            String jPath = js[i];
            if (StringUtils.isEmpty(jPath) || !jPath.endsWith(".jar")) {
                break;
            }
            try {
                JarEntry jarEntry = rJarFile.getJarEntry(jPath);
                rJarFile = rJarFile.getNestedJarFile(jarEntry);
            } catch (NullPointerException e) {
                throw new IOException(
                    String.format("Failed to parse artifact id, jPath: %s", jPath), e);
            }
        }
        return rJarFile;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy