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

io.microsphere.lang.ClassDataRepository Maven / Gradle / Ivy

The 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 io.microsphere.lang;

import io.microsphere.collection.CollectionUtils;
import io.microsphere.util.ClassPathUtils;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarFile;

import static io.microsphere.util.ClassPathUtils.getBootstrapClassPaths;
import static io.microsphere.util.ClassPathUtils.getClassPaths;
import static io.microsphere.util.ClassUtils.findClassNamesInClassPath;
import static io.microsphere.util.ClassUtils.resolvePackageName;
import static io.microsphere.util.StringUtils.isNotBlank;
import static java.util.Collections.emptySet;
import static java.util.Collections.unmodifiableMap;
import static java.util.Collections.unmodifiableSet;

/**
 * The Class Data Repository
 *
 * @author Mercy
 * @see ClassPathUtils
 * @since 1.0.0
 */
public class ClassDataRepository {

    /**
     * Singleton instance of {@link ClassDataRepository}
     */
    public static final ClassDataRepository INSTANCE = new ClassDataRepository();

    private final Map> classPathToClassNamesMap = initClassPathToClassNamesMap();

    private final Map classNameToClassPathsMap = initClassNameToClassPathsMap();

    private final Map> packageNameToClassNamesMap = initPackageNameToClassNamesMap();

    private ClassDataRepository() {
    }

    /**
     * Get all package names in {@link ClassPathUtils#getClassPaths() class paths}
     *
     * @return all package names in class paths
     */
    @Nonnull
    public Set getAllPackageNamesInClassPaths() {
        return packageNameToClassNamesMap.keySet();
    }

    /**
     * Find class path under specified class name
     *
     * @param type class
     * @return class path
     */
    @Nullable
    public String findClassPath(Class type) {
        return findClassPath(type.getName());
    }

    /**
     * Find class path under specified class name
     *
     * @param className class name
     * @return class path
     */
    @Nullable
    public String findClassPath(String className) {
        return classNameToClassPathsMap.get(className);
    }

    /**
     * Gets class name {@link Set} under specified class path
     *
     * @param classPath class path
     * @param recursive is recursive on sub directories
     * @return non-null {@link Set}
     */
    @Nonnull
    public Set getClassNamesInClassPath(String classPath, boolean recursive) {
        Set classNames = classPathToClassNamesMap.get(classPath);
        if (CollectionUtils.isEmpty(classNames)) {
            classNames = findClassNamesInClassPath(classPath, recursive);
        }
        return classNames;
    }

    /**
     * Gets class name {@link Set} under specified package
     *
     * @param onePackage one package
     * @return non-null {@link Set}
     */
    @Nonnull
    public Set getClassNamesInPackage(Package onePackage) {
        return getClassNamesInPackage(onePackage.getName());
    }

    /**
     * Gets class name {@link Set} under specified package name
     *
     * @param packageName package name
     * @return non-null {@link Set}
     */
    @Nonnull
    public Set getClassNamesInPackage(String packageName) {
        Set classNames = packageNameToClassNamesMap.get(packageName);
        return classNames == null ? emptySet() : classNames;
    }

    /**
     * The map of all class names in {@link ClassPathUtils#getClassPaths() class path} , the class path for one {@link
     * JarFile} or classes directory as key , the class names set as value
     *
     * @return Read-only
     */
    @Nonnull
    public Map> getClassPathToClassNamesMap() {
        return classPathToClassNamesMap;
    }

    /**
     * The set of all class names in {@link ClassPathUtils#getClassPaths() class path}
     *
     * @return Read-only
     */
    @Nonnull
    public Set getAllClassNamesInClassPaths() {
        Set allClassNames = new LinkedHashSet();
        for (Set classNames : classPathToClassNamesMap.values()) {
            allClassNames.addAll(classNames);
        }
        return unmodifiableSet(allClassNames);
    }

    /**
     * Get {@link Class}'s code source location URL
     *
     * @param type
     * @return If , return null.
     * @throws NullPointerException If type is null , {@link NullPointerException} will be thrown.
     */
    public URL getCodeSourceLocation(Class type) throws NullPointerException {

        URL codeSourceLocation = null;
        ClassLoader classLoader = type.getClassLoader();

        if (classLoader == null) { // Bootstrap ClassLoader or type is primitive or void
            String path = findClassPath(type);
            if (isNotBlank(path)) {
                try {
                    codeSourceLocation = new File(path).toURI().toURL();
                } catch (MalformedURLException ignored) {
                    codeSourceLocation = null;
                }
            }
        } else {
            ProtectionDomain protectionDomain = type.getProtectionDomain();
            CodeSource codeSource = protectionDomain == null ? null : protectionDomain.getCodeSource();
            codeSourceLocation = codeSource == null ? null : codeSource.getLocation();
        }
        return codeSourceLocation;
    }

    private Map> initClassPathToClassNamesMap() {
        Map> classPathToClassNamesMap = new LinkedHashMap<>();
        Set classPaths = new LinkedHashSet<>();
        classPaths.addAll(getBootstrapClassPaths());
        classPaths.addAll(getClassPaths());
        for (String classPath : classPaths) {
            Set classNames = findClassNamesInClassPath(classPath, true);
            classPathToClassNamesMap.put(classPath, classNames);
        }
        return unmodifiableMap(classPathToClassNamesMap);
    }

    private Map initClassNameToClassPathsMap() {
        Map classNameToClassPathsMap = new LinkedHashMap<>();

        for (Map.Entry> entry : classPathToClassNamesMap.entrySet()) {
            String classPath = entry.getKey();
            Set classNames = entry.getValue();
            for (String className : classNames) {
                classNameToClassPathsMap.put(className, classPath);
            }
        }

        return unmodifiableMap(classNameToClassPathsMap);
    }

    private Map> initPackageNameToClassNamesMap() {
        Map> packageNameToClassNamesMap = new LinkedHashMap();
        for (Map.Entry entry : classNameToClassPathsMap.entrySet()) {
            String className = entry.getKey();
            String packageName = resolvePackageName(className);
            Set classNamesInPackage = packageNameToClassNamesMap.get(packageName);
            if (classNamesInPackage == null) {
                classNamesInPackage = new LinkedHashSet();
                packageNameToClassNamesMap.put(packageName, classNamesInPackage);
            }
            classNamesInPackage.add(className);
        }

        return unmodifiableMap(packageNameToClassNamesMap);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy