Projekt

Obecné

Profil

« Předchozí | Další » 

Revize 19f6f5c5

Přidáno uživatelem Pavel Fidranský před asi 6 roky(ů)

simplified ModuleLoader to load modules directly from classpath instead of special directory, modules are added to classpath as normal maven dependencies

Zobrazit rozdíly:

sources/imiger-core/pom.xml
58 58
    </build>
59 59

  
60 60
    <dependencies>
61
        <dependency>
62
            <groupId>cz.zcu.kiv</groupId>
63
            <artifactId>imiger-spade-converter</artifactId>
64
            <version>1.0-SNAPSHOT</version>
65
        </dependency>
66

  
61 67
        <dependency>
62 68
            <groupId>org.apache.logging.log4j</groupId>
63 69
            <artifactId>log4j-core</artifactId>
sources/imiger-core/src/main/java/cz/zcu/kiv/offscreen/modularization/ModuleLoader.java
1 1
package cz.zcu.kiv.offscreen.modularization;
2 2

  
3 3
import javafx.util.Pair;
4
import org.apache.commons.io.FileUtils;
5
import org.apache.commons.io.FilenameUtils;
4 6
import org.apache.logging.log4j.LogManager;
5 7
import org.apache.logging.log4j.Logger;
6 8

  
7
import java.io.File;
8 9
import java.io.FileInputStream;
9
import java.io.FilenameFilter;
10 10
import java.io.IOException;
11
import java.net.URISyntaxException;
12 11
import java.net.URL;
13 12
import java.net.URLClassLoader;
14 13
import java.util.Arrays;
......
25 24
class ModuleLoader {
26 25

  
27 26
    private static final Logger logger = LogManager.getLogger();
28
    /** Filter to get only jar files from modules folder. */
29
    private static final FilenameFilter MODULE_FILTER = (file, name) -> name.contains(".jar");
27
    /** Valid file extension of Java module. */
28
    private static final String VALID_MODULE_EXTENSION = "jar";
29
    /** Identification of section in manifest containing other information about the module. */
30
    private static final String MODULE_SECTION_IDENTIFIER = "cz.zcu.kiv.imiger.plugin";
30 31
    /** Identification of class name in modules manifest. */
31 32
    private static final String MODULE_CLASS_IDENTIFIER = "Module-Class";
32 33
    /** Identification of modules visible name in modules manifest. */
33 34
    private static final String MODULE_NAME_IDENTIFIER = "Module-Name";
34 35

  
35
    /** Path to folder where are modules. Path is relative to resources. */
36
    private final String modulesPath;
37 36
    /** Name of method which must contains every module. */
38 37
    private final String methodName;
39 38
    /** Class type of parameter to method which must contains every module. */
......
42 41

  
43 42
    /**
44 43
     * Only story  input parameters
45
     * @param modulesPath Path to folder where are modules. Path is relative to resources.
46 44
     * @param methodName Name of method which must contains every module.
47 45
     * @param methodParamClass Class type of parameter to method which must contains every module.
48 46
     */
49
    ModuleLoader(String modulesPath, String methodName, Class methodParamClass) {
50
        this.modulesPath = modulesPath;
47
    ModuleLoader(String methodName, Class methodParamClass) {
51 48
        this.methodName = methodName;
52 49
        this.methodParamClass = methodParamClass;
53
        logger.info("Initializing new ModuleLoader with folder path: " + modulesPath);
50
        logger.info("Initializing new ModuleLoader");
54 51
    }
55 52

  
56 53
    /**
......
59 56
     */
60 57
    Set<Pair<String, Class>> loadModules() {
61 58
        logger.info("Loading all modules from file.");
62
        final File[] modules = loadJarFiles();
63
        return Arrays.stream(modules)
59
        final URL[] resources = ((URLClassLoader) getClass().getClassLoader()).getURLs();
60
        return Arrays.stream(resources)
61
                .filter(this::isJarFile) // remove resources which are not jar files
64 62
                .map(this::loadModule) // call method loadModule for every module
65 63
                .filter(Optional::isPresent) // remove modules which were not loaded
66 64
                .map(Optional::get) // extract modules from Optional class
......
68 66
    }
69 67

  
70 68
    /**
71
     * Method open file given by modules path in constructor, check if folder exists and if it is a directory.
72
     * On success return Optional of opened folder otherwise returns empty optional.
73
     * @return Optional of opened folder otherwise returns empty optional.
74
     */
75
    Optional<File> getModulesFolder() {
76

  
77
        final URL fileURL = getClass().getClassLoader().getResource(modulesPath);
78
        if (fileURL == null) {
79
            logger.warn("Can not open modules directory.");
80
            return Optional.empty();
81
        }
82

  
83
        try {
84
            final File modulesFolder = new File(fileURL.toURI());
85

  
86
            if (!modulesFolder.exists() || !modulesFolder.isDirectory()) {
87
                logger.warn("Modules folder is not exists or it is not a directory");
88
                return Optional.empty();
89
            }
90
            return Optional.of(modulesFolder);
91

  
92
        } catch (URISyntaxException e) {
93
            logger.warn("Can not open modules directory", e);
94
            return Optional.empty();
95
        }
96
    }
97

  
98
    /**
99
     * Load all jar files from folder given by modules path in constructor.
69
     * Checks if resource is a jar file by its extension.
100 70
     *
101
     * @return array of founded jars or empty array
71
     * @param resourceUrl URL of the resource in local filesystem
72
     * @return true if the resource is a jar file, otherwise false
102 73
     */
103
    private File[] loadJarFiles() {
104

  
105
        Optional<File> folderOptional = getModulesFolder();
106
        if (folderOptional.isPresent()) {
107
            File[] files = folderOptional.get().listFiles(MODULE_FILTER);
108
            if (files == null) files = new File[0];
109
            logger.info(files.length + " modules were read from file");
110
            return files;
111
        }
112
        return new File[0];
74
    private boolean isJarFile(URL resourceUrl) {
75
        return FilenameUtils.getExtension(resourceUrl.getFile()).equals(VALID_MODULE_EXTENSION);
113 76
    }
114 77

  
115 78
    /**
116 79
     * Load one particular module given by input File containing opened jar file.
117 80
     * Method returns module in Optional in Pair where key is visible modules name and value is access Class from module.
118 81
     *
119
     * @param moduleFile opened jar file with module
82
     * @param moduleUrl URL of the module in local filesystem
120 83
     * @return opened module or empty Optional where some error occurs.
121 84
     */
122
    private Optional<Pair<String, Class>> loadModule(File moduleFile) {
85
    private Optional<Pair<String, Class>> loadModule(URL moduleUrl) {
123 86
        JarInputStream jis = null;
124 87
        try {
125
            jis = new JarInputStream(new FileInputStream(moduleFile));
88
            jis = new JarInputStream(new FileInputStream(FileUtils.toFile(moduleUrl)));
126 89
            final Manifest mf = jis.getManifest();
127
            final Attributes attributes = mf.getMainAttributes();
90
            final Attributes attributes = mf.getAttributes(MODULE_SECTION_IDENTIFIER);
91
            if (attributes == null) {
92
                throw new NotModuleException();
93
            }
94

  
128 95
            final String moduleClassName = attributes.getValue(MODULE_CLASS_IDENTIFIER);
129 96
            final String moduleVisibleName = attributes.getValue(MODULE_NAME_IDENTIFIER);
130 97

  
131
            final ClassLoader loader = URLClassLoader.newInstance(new URL[]{moduleFile.toURI().toURL()});
132
            final Class<?> clazz = Class.forName(moduleClassName, true, loader);
98
            final Class<?> clazz = Class.forName(moduleClassName, true, getClass().getClassLoader());
133 99
            // checking if method exists, if not throw exception
134 100
            clazz.getMethod(methodName, methodParamClass);
135 101

  
136 102
            return Optional.of(new Pair<>(moduleVisibleName, clazz));
137 103

  
104
        } catch (NotModuleException e) {
105
            return Optional.empty();
138 106
        } catch (Exception e) {
139 107
            logger.debug("Invalid module throw exception: ", e);
140 108
            return Optional.empty();
sources/imiger-core/src/main/java/cz/zcu/kiv/offscreen/modularization/ModuleProvider.java
4 4
import org.apache.logging.log4j.LogManager;
5 5
import org.apache.logging.log4j.Logger;
6 6

  
7
import java.io.File;
8 7
import java.io.IOException;
8
import java.net.URISyntaxException;
9 9
import java.nio.file.*;
10 10
import java.util.HashMap;
11 11
import java.util.Map;
12
import java.util.Optional;
13 12
import java.util.Set;
14 13
import java.util.concurrent.*;
15 14

  
......
24 23
    public static final Class METHOD_PARAMETER_CLASS = String.class;
25 24

  
26 25
    private static final Logger logger = LogManager.getLogger();
27
    /** Path to folder with modules relative to resources */
28
    private static final String MODULES_PATH = "modules";
29 26
    /** Instance of this class used for singleton pattern. */
30 27
    private static ModuleProvider instance = null;
31 28

  
......
63 60
     * When watcher fails than is automatically starts new watcher after 5 minutes timeout.
64 61
     */
65 62
    private ModuleProvider() {
66
        this.loader = new ModuleLoader(MODULES_PATH, METHOD_NAME, METHOD_PARAMETER_CLASS);
63
        this.loader = new ModuleLoader(METHOD_NAME, METHOD_PARAMETER_CLASS);
67 64

  
68 65
        processModules(loader.loadModules());
69 66

  
......
104 101
        try {
105 102
            logger.debug("Initializing new WatcherService for modules directory");
106 103

  
107
            Optional<File> folderFileOptional = loader.getModulesFolder();
108
            if (!folderFileOptional.isPresent()) {
109
                return;
110
            }
111

  
112
            Path path = folderFileOptional.get().toPath();
104
            Path path = Paths.get(getClass().getClassLoader().getResource("/../lib/").toURI());
113 105
            watcher = FileSystems.getDefault().newWatchService();
114 106
            path.register(watcher,
115 107
                    StandardWatchEventKinds.ENTRY_CREATE,
......
138 130
                }
139 131
            }
140 132

  
141
        } catch (IOException | InterruptedException e) {
133
        } catch (URISyntaxException | IOException | InterruptedException e) {
142 134
            logger.error("Modules directory watcher throw an exception: ", e);
143 135
        }
144 136
    }
sources/imiger-core/src/main/java/cz/zcu/kiv/offscreen/modularization/NotModuleException.java
1
package cz.zcu.kiv.offscreen.modularization;
2

  
3
/**
4
 * Exception thrown when a jar file which is not a valid IMiGEr plugin is loaded.
5
 */
6
class NotModuleException extends Exception {
7
    NotModuleException() {
8
        super("Jar file is not a valid IMiGEr plugin!");
9
    }
10
}
sources/imiger-spade-converter/pom.xml
19 19
        <plugins>
20 20
            <plugin>
21 21
                <groupId>org.apache.maven.plugins</groupId>
22
                <artifactId>maven-assembly-plugin</artifactId>
22
                <artifactId>maven-jar-plugin</artifactId>
23
                <version>3.1.1</version>
23 24
                <configuration>
24 25
                    <archive>
25
                        <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
26
                        <manifestSections>
27
                            <manifestSection>
28
                                <name>cz.zcu.kiv.imiger.plugin</name>
29
                                <manifestEntries>
30
                                    <Module-Class>cz.zcu.kiv.imiger.plugin.spade.Spade</Module-Class>
31
                                    <Module-Name>Spade JSON</Module-Name>
32
                                </manifestEntries>
33
                            </manifestSection>
34
                        </manifestSections>
26 35
                    </archive>
27
                    <descriptorRefs>
28
                        <descriptorRef>jar-with-dependencies</descriptorRef>
29
                    </descriptorRefs>
30 36
                </configuration>
31
                <executions>
32
                    <execution>
33
                        <id>make-assembly</id> <!-- this is used for inheritance merges -->
34
                        <phase>package</phase> <!-- bind to the packaging phase -->
35
                        <goals>
36
                            <goal>single</goal>
37
                        </goals>
38
                    </execution>
39
                </executions>
40 37
            </plugin>
41 38
        </plugins>
42 39
    </build>
sources/imiger-spade-converter/src/main/resources/META-INF/MANIFEST.MF
1
Manifest-Version: 1.0
2
Created-By: Apache Maven ${maven.version}
3
Built-By: ${user.name}
4
Build-Jdk: ${java.version}
5
Module-Class: cz.zcu.kiv.imiger.plugin.spade.Spade
6
Module-Name: Spade JSON

Také k dispozici: Unified diff