de.metanome.backend.algorithm_loading.AlgorithmFinder.java Source code

Java tutorial

Introduction

Here is the source code for de.metanome.backend.algorithm_loading.AlgorithmFinder.java

Source

/*
 * Copyright 2014 by the Metanome project
 *
 * 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 de.metanome.backend.algorithm_loading;

import de.metanome.algorithm_integration.Algorithm;
import org.apache.commons.lang3.ClassUtils;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLDecoder;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

/**
 * Class that provides utilities to retrieve information on the available algorithm jars.
 */
public class AlgorithmFinder {

    protected static final String bootstrapClassTagName = "Algorithm-Bootstrap-Class";

    /**
     * @param algorithmSubclass Class of algorithms to retrieve, or null if all subclasses
     * @return an array with the names of the available algorithms
     * @throws java.io.IOException if the algorithm folder could not be opened
     * @throws java.lang.ClassNotFoundException if an algorithm contains a not supported algorithm subclass
     */
    public String[] getAvailableAlgorithmFileNames(Class<?> algorithmSubclass)
            throws IOException, ClassNotFoundException {

        LinkedList<String> availableAlgorithms = new LinkedList<>();

        String pathToFolder = "";
        try {
            pathToFolder = Thread.currentThread().getContextClassLoader().getResource("algorithms").getPath();
        } catch (NullPointerException e) {
            // The algorithm folder does not exist
            return new String[] {};
        }
        File[] jarFiles = retrieveJarFiles(pathToFolder);

        for (File jarFile : jarFiles) {
            if (algorithmSubclass == null || getAlgorithmInterfaces(jarFile).contains(algorithmSubclass)) {
                availableAlgorithms.add(jarFile.getName());
            }
        }

        String[] stringArray = new String[availableAlgorithms.size()];
        return availableAlgorithms.toArray(stringArray);
    }

    /**
     * @param pathToFolder Path to search for jar files
     * @return an array of Files with ".jar" ending
     * @throws java.io.UnsupportedEncodingException if the file path could not be decoded in utf-8
     */
    private File[] retrieveJarFiles(String pathToFolder) throws UnsupportedEncodingException {
        File folder = new File(URLDecoder.decode(pathToFolder, "utf-8"));
        File[] jars = folder.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File file, String name) {
                return name.endsWith(".jar");
            }
        });

        if (jars == null) {
            jars = new File[0];
        }
        return jars;
    }

    /**
     * Finds out which subclass of Algorithm is implemented by the source code in the algorithmJarFile
     * by file name.
     *
     * @param algorithmJarFileName the algorithm's file name
     * @return the interfaces of the algorithm implementation in algorithmJarFile
     * @throws java.io.IOException if the algorithm jar file could not be opened
     * @throws java.lang.ClassNotFoundException if the algorithm contains a not supported interface
     */
    public Set<Class<?>> getAlgorithmInterfaces(String algorithmJarFileName)
            throws IOException, ClassNotFoundException {

        String jarFilePath = "";
        try {
            jarFilePath = Thread.currentThread().getContextClassLoader()
                    .getResource("algorithms" + System.getProperty("file.separator") + algorithmJarFileName)
                    .getFile();
        } catch (NullPointerException e) {
            // The algorithm folder does not exist
            return new HashSet<>();
        }

        File file = new File(URLDecoder.decode(jarFilePath, "utf-8"));

        return getAlgorithmInterfaces(file);
    }

    /**
     * Finds out which subclass of Algorithm is implemented by the source code in the
     * algorithmJarFile.
     *
     * @param algorithmJarFile the algorithm's jar file
     * @return the interfaces of the algorithm implementation in algorithmJarFile
     * @throws java.io.IOException if the algorithm jar file could not be opened
     * @throws java.lang.ClassNotFoundException if the algorithm contains a not supported interface
     */
    public Set<Class<?>> getAlgorithmInterfaces(File algorithmJarFile) throws IOException, ClassNotFoundException {
        JarFile jar = new JarFile(algorithmJarFile);

        Manifest man = jar.getManifest();
        Attributes attr = man.getMainAttributes();
        String className = attr.getValue(bootstrapClassTagName);

        URL[] url = { algorithmJarFile.toURI().toURL() };
        ClassLoader loader = new URLClassLoader(url, Algorithm.class.getClassLoader());

        Class<?> algorithmClass;
        try {
            algorithmClass = Class.forName(className, false, loader);
        } catch (ClassNotFoundException e) {
            System.out.println("Could not find class " + className);
            return new HashSet<>();
        } finally {
            jar.close();
        }

        return new HashSet<>(ClassUtils.getAllInterfaces(algorithmClass));
    }
}