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

com.github.jsr330.scanning.DefaultClassScanner Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2012 the contributors
 *
 *    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 com.github.jsr330.scanning;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Map;
import java.util.TreeMap;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.github.jsr330.GenericFilter;
import com.github.jsr330.spi.ClassScanner;

/**
 * A ClassScanner that used a classname and a source filter to optimize scanning.
 * This ClassScanner can be based on another ClassScanner to avoid the rescanning of base classes.
 */
public class DefaultClassScanner implements ClassScanner {
    
    private static final Pattern FILE_SEPARATOR_REGEX = Pattern.compile("\\" + System.getProperty("file.separator"));
    private static final Pattern ENTRY_SEPARATOR_REGEX = Pattern.compile("/");
    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultClassScanner.class);
    
    protected ClassScanner parent;
    protected GenericFilter sourceDirFilter;
    protected GenericFilter classNameFilter;
    protected Map> classes;
    protected Object monitor = new Object();
    
    public DefaultClassScanner() {
        this(null, null, null);
    }
    
    public DefaultClassScanner(ClassScanner parent) {
        this(parent, null, null);
    }
    
    public DefaultClassScanner(GenericFilter sourceDirFilter, GenericFilter classNameFilter) {
        this(null, sourceDirFilter, classNameFilter);
    }
    
    public DefaultClassScanner(ClassScanner parent, GenericFilter sourceDirFilter, GenericFilter classNameFilter) {
        this.parent = parent;
        this.sourceDirFilter = sourceDirFilter;
        this.classNameFilter = classNameFilter;
    }
    
    @Override
    public Map> scan(ClassLoader loader) {
        Enumeration urls;
        URL url;
        String tmp;
        Map> parentClasses;
        File file;
        URI uri;
        
        synchronized (monitor) {
            if (classes == null) {
                classes = new TreeMap>();
                
                if (parent != null) {
                    if ((parentClasses = parent.scan(loader)) != null) {
                        classes.putAll(parentClasses);
                    }
                }
                
                try {
                    urls = loader.getResources("META-INF");
                    while (urls.hasMoreElements()) {
                        url = urls.nextElement();
                        tmp = url.toExternalForm();
                        tmp = tmp.substring(0, tmp.length() - 8);
                        LOGGER.debug("listClasses - source={}", tmp);
                        
                        try {
                            if (tmp.startsWith("file:")) {
                                uri = new URI(tmp);
                                if (sourceDirFilter == null || sourceDirFilter != null && sourceDirFilter.filter(uri)) {
                                    file = new File(uri);
                                    traverseFile(file.getAbsolutePath(), file, loader, classes);
                                }
                            } else if (tmp.startsWith("jar:")) {
                                uri = new URI(tmp.substring(4, tmp.length() - 2));
                                if (sourceDirFilter == null || sourceDirFilter != null && sourceDirFilter.filter(uri)) {
                                    file = new File(uri);
                                    traverseJar(file.getAbsolutePath(), file.toURI().toURL(), loader, classes);
                                }
                            }
                        } catch (URISyntaxException exception) {
                            LOGGER.debug("error while generating URI", exception);
                        }
                    }
                } catch (IOException exception) {
                    LOGGER.debug("error while traversing jar", exception);
                }
            }
        }
        
        return classes;
    }
    
    protected void traverseJar(String base, URL url, ClassLoader loader, Map> classes) {
        JarInputStream stream = null;
        JarEntry entry;
        String name;
        
        try {
            stream = new JarInputStream(url.openStream());
            while ((entry = stream.getNextJarEntry()) != null) {
                if ((name = entry.getName()).endsWith(".class")) {
                    name = ENTRY_SEPARATOR_REGEX.matcher(name).replaceAll(".");
                    name = name.substring(0, name.length() - 6);
                    LOGGER.debug("traverseJar - name={}", name);
                    
                    createClass(loader, classes, name);
                }
            }
        } catch (Exception exception) {
            LOGGER.debug("error while traversing jar", exception);
        } finally {
            if (stream != null) {
                try {
                    stream.close();
                } catch (IOException exception) {
                    LOGGER.debug("error while closing stream", exception);
                }
            }
        }
    }
    
    protected void traverseFile(String base, File file, ClassLoader loader, Map> classes) {
        String name;
        
        if (file.isDirectory()) {
            for (File tmp : file.listFiles()) {
                traverseFile(base, tmp, loader, classes);
            }
        } else if ((name = file.getAbsolutePath()).endsWith(".class")) {
            name = name.substring(base.length() + 1);
            name = FILE_SEPARATOR_REGEX.matcher(name).replaceAll(".");
            name = name.substring(0, name.length() - 6);
            LOGGER.debug("traverseFile - name={}", name);
            
            createClass(loader, classes, name);
        }
    }
    
    protected void createClass(ClassLoader loader, Map> classes, String name) {
        if (classNameFilter == null || classNameFilter != null && classNameFilter.filter(name)) {
            try {
                classes.put(name, Class.forName(name, false, loader));
            } catch (Throwable exception) {
                LOGGER.debug("error while loading class", exception);
            }
        }
    }
    
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy