Revize 19f6f5c5
Přidáno uživatelem Pavel Fidranský před asi 6 roky(ů)
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
simplified ModuleLoader to load modules directly from classpath instead of special directory, modules are added to classpath as normal maven dependencies