Projekt

Obecné

Profil

« Předchozí | Další » 

Revize 07621624

Přidáno uživatelem Tomáš Šimandl před asi 6 roky(ů)

Updated modularization

+ removed unfunctional interface
+ added mechanism to stop watcher on modules folder changes
+ run module method execution with own class loader
+ small refactor

Zobrazit rozdíly:

sources/src/main/java/cz/zcu/kiv/offscreen/ApplicationListener.java
1
package cz.zcu.kiv.offscreen;
2

  
3
import cz.zcu.kiv.offscreen.modularization.ModuleProvider;
4

  
5
import javax.servlet.ServletContextEvent;
6
import javax.servlet.ServletContextListener;
7

  
8
public class ApplicationListener implements ServletContextListener {
9

  
10
    @Override
11
    public void contextInitialized(ServletContextEvent servletContextEvent) {
12
    }
13

  
14
    @Override
15
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
16
        ModuleProvider.getInstance().stopWatcher();
17
    }
18
}
sources/src/main/java/cz/zcu/kiv/offscreen/modularization/ModuleLoader.java
1 1
package cz.zcu.kiv.offscreen.modularization;
2 2

  
3
import com.sun.jndi.toolkit.url.Uri;
4 3
import javafx.util.Pair;
5 4
import org.apache.logging.log4j.LogManager;
6 5
import org.apache.logging.log4j.Logger;
......
8 7
import java.io.File;
9 8
import java.io.FileInputStream;
10 9
import java.io.FilenameFilter;
11
import java.net.URI;
12 10
import java.net.URISyntaxException;
13 11
import java.net.URL;
14 12
import java.net.URLClassLoader;
......
28 26
    private static final String MODULE_NAME_IDENTIFIER = "Module-Name";
29 27

  
30 28
    private final String modulesPath;
29
    private final String methodName;
30
    private final Class methodParamClass;
31 31

  
32
    public ModuleLoader(String modulesPath) {
32
    public ModuleLoader(String modulesPath, String methodName, Class methodParamClass) {
33 33
        this.modulesPath = modulesPath;
34
        this.methodName = methodName;
35
        this.methodParamClass = methodParamClass;
34 36
        logger.info("Initializing new ModuleLoader with folder path: " + modulesPath);
35 37
    }
36 38

  
37
    public Set<Pair<String, IModule>> loadModules() {
39
    public Set<Pair<String, Class>> loadModules() {
38 40
        logger.info("Loading all modules from file.");
39 41
        final File[] modules = loadJarFiles();
40 42
        return Arrays.stream(modules)
......
44 46
                .collect(Collectors.toSet());
45 47
    }
46 48

  
47
    public Optional<File> getModulesFolder(){
49
    public Optional<File> getModulesFolder() {
48 50

  
49 51
        final URL fileURL = getClass().getClassLoader().getResource(modulesPath);
50
        if (fileURL == null){
52
        if (fileURL == null) {
51 53
            logger.warn("Can not open modules directory.");
52 54
            return Optional.empty();
53 55
        }
......
70 72
    private File[] loadJarFiles() {
71 73

  
72 74
        Optional<File> folderOptional = getModulesFolder();
73
        if(folderOptional.isPresent()){
74
            logger.info(folderOptional.get().length() + " modules were read from file");
75
            return folderOptional.get().listFiles(MODULE_FILTER);
75
        if (folderOptional.isPresent()) {
76
            File[] files = folderOptional.get().listFiles(MODULE_FILTER);
77
            logger.info(files == null ? 0 : files.length + " modules were read from file");
78
            return files;
76 79
        }
77 80
        return new File[0];
78 81
    }
79 82

  
80
    private Optional<Pair<String, IModule>> loadModule(File moduleFile) {
83
    private Optional<Pair<String, Class>> loadModule(File moduleFile) {
81 84
        try {
82 85
            final JarInputStream jis = new JarInputStream(new FileInputStream(moduleFile));
83 86
            final Manifest mf = jis.getManifest();
......
86 89
            final String moduleVisibleName = attributes.getValue(MODULE_NAME_IDENTIFIER);
87 90

  
88 91
            final ClassLoader loader = URLClassLoader.newInstance(new URL[]{moduleFile.toURI().toURL()});
89
            final Class clazz = Class.forName(moduleClassName, true, loader);
90
            final IModule module = (IModule) clazz.asSubclass(IModule.class).newInstance();
92
            final Class<?> clazz = Class.forName(moduleClassName, true, loader);
93
            // checking if method exists, if not throw exception
94
            clazz.getMethod(methodName, methodParamClass);
91 95

  
92
            return Optional.of(new Pair<>(moduleVisibleName, module));
96
            return Optional.of(new Pair<>(moduleVisibleName, clazz));
93 97

  
94 98
        } catch (Exception e) {
95 99
            logger.debug("Invalid module throw exception: ", e);
sources/src/main/java/cz/zcu/kiv/offscreen/modularization/ModuleProvider.java
6 6

  
7 7
import java.io.File;
8 8
import java.io.IOException;
9
import java.net.URISyntaxException;
10
import java.net.URL;
11 9
import java.nio.file.*;
12 10
import java.util.HashMap;
13 11
import java.util.Map;
......
17 15

  
18 16
public class ModuleProvider {
19 17

  
18
    public static final String METHOD_NAME = "getRawJson";
19
    public static final Class METHOD_PARAMETER_CLASS = String.class;
20

  
20 21
    private static final Logger logger = LogManager.getLogger();
21 22
    private static final String MODULES_PATH = "modules";
22 23
    private static ModuleProvider instance = null;
23 24

  
24
    private ConcurrentMap<String, Pair<String, IModule>> modules = new ConcurrentHashMap<>();
25
    private ConcurrentMap<String, Pair<String, Class>> modules = new ConcurrentHashMap<>();
25 26
    private final ModuleLoader loader;
26 27
    private boolean watch = true;
27 28

  
29
    private ScheduledExecutorService executor;
30
    private ScheduledFuture scheduledFuture;
31
    private WatchService watcher = null;
32

  
28 33

  
29 34
    public static ModuleProvider getInstance() {
30 35
        if (instance == null) {
......
34 39
    }
35 40

  
36 41
    private ModuleProvider() {
37
        this.loader = new ModuleLoader(MODULES_PATH);
42
        this.loader = new ModuleLoader(MODULES_PATH, METHOD_NAME, METHOD_PARAMETER_CLASS);
38 43

  
39 44
        processModules(loader.loadModules());
40 45

  
41
        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
46
        executor = Executors.newSingleThreadScheduledExecutor();
42 47
        Runnable task = this::initModulesWatcher;
43 48
        logger.debug("Scheduling Modules Watcher thread.");
44 49
        // task will be scheduled after 1 minute
45 50
        // When task ends (on failure) after one minute will be planed again
46
        executor.scheduleWithFixedDelay(task, 1, 1, TimeUnit.MINUTES);
51
        scheduledFuture = executor.scheduleWithFixedDelay(task, 1, 1, TimeUnit.MINUTES);
52
    }
53

  
54
    public void stopWatcher() {
55
        logger.debug("Stopping WatcherProvider");
56
        watch = false;
57

  
58
        try {
59
            logger.info("Closing WatcherService");
60
            if (watcher != null) watcher.close();
61
        } catch (IOException e) {
62
            logger.debug("Closing watcher throw exception: ", e);
63
        }
64

  
65
        logger.info("Canceling scheduler");
66
        if (scheduledFuture != null) scheduledFuture.cancel(true);
67

  
68
        logger.info("Shutting down an ScheduledExecutorService");
69
        if (executor != null) executor.shutdown();
47 70
    }
48 71

  
49 72
    private void initModulesWatcher() {
......
56 79
            }
57 80

  
58 81
            Path path = folderFileOptional.get().toPath();
59
            WatchService watcher = FileSystems.getDefault().newWatchService();
82
            watcher = FileSystems.getDefault().newWatchService();
60 83
            path.register(watcher,
61 84
                    StandardWatchEventKinds.ENTRY_CREATE,
62 85
                    StandardWatchEventKinds.ENTRY_DELETE,
......
89 112
        }
90 113
    }
91 114

  
92
    private void processModules(Set<Pair<String, IModule>> unprocessedModules) {
93
        Map<String, Pair<String, IModule>> localModules = new HashMap<>();
115
    private void processModules(Set<Pair<String, Class>> unprocessedModules) {
116
        long startTime = System.nanoTime();
117
        Map<String, Pair<String, Class>> localModules = new HashMap<>();
94 118

  
95
        logger.info("Processing " + localModules.size() + " modules.");
119
        logger.info("Processing " + unprocessedModules.size() + " modules.");
96 120

  
97
        for (Pair<String, IModule> pair : unprocessedModules) {
121
        for (Pair<String, Class> pair : unprocessedModules) {
98 122
            localModules.put(String.valueOf(pair.getKey().hashCode()), pair);
99 123
        }
100 124

  
101 125
        modules.clear();
102 126
        modules.putAll(localModules);
103
        logger.debug("Modules were processed");
127
        logger.debug("Modules were loaded and processed in " + (System.nanoTime() - startTime) / 1000000d + " milliseconds");
104 128
    }
105 129

  
106
    public Map<String, Pair<String, IModule>> getModules() {
130
    public Map<String, Pair<String, Class>> getModules() {
107 131
        return modules;
108 132
    }
109 133
}
sources/src/main/java/cz/zcu/kiv/offscreen/servlets/UploadFiles.java
52 52
    @Override
53 53
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
54 54
        logger.debug("Processing request");
55
        Map<String, String> jsonData = new FileLoader().loadFile(request);
55
        Map<String, String> data = new FileLoader().loadFile(request);
56 56

  
57
        if(!jsonData.containsKey("file") || !jsonData.containsKey("jsonFileFormat")) {
57
        if(!data.containsKey("file") || !data.containsKey("fileFormat")) {
58 58
            request.setAttribute("errorMessage", "<strong>Invalid request!</strong><br/>");
59 59
            logger.debug("Invalid request");
60 60
            doGet(request, response);
61 61

  
62
        } else if (Strings.isNullOrEmpty(jsonData.get("file"))) {
62
        } else if (Strings.isNullOrEmpty(data.get("file"))) {
63 63
            request.setAttribute("errorMessage", "<strong>Unsupported file</strong><br/>");
64
            logger.debug("Empty diagram json");
64
            logger.debug("Empty diagram string");
65 65
            doGet(request, response);
66 66
        } else {
67
            request.getSession().setAttribute("json_graph", jsonData.get("file"));
68
            request.getSession().setAttribute("json_graph_type", jsonData.get("jsonFileFormat"));
69
            request.getSession().setAttribute("graph_filename", jsonData.get("filename"));
67
            request.getSession().setAttribute("diagram_string", data.get("file"));
68
            request.getSession().setAttribute("diagram_type", data.get("fileFormat"));
69
            request.getSession().setAttribute("diagram_filename", data.get("filename"));
70 70
            response.sendRedirect(getServletContext().getInitParameter("APP_HOME_URL") + "graph");
71 71
            logger.debug("send redirect to /graph");
72 72
        }
sources/src/main/java/cz/zcu/kiv/offscreen/servlets/api/GetSessionDiagram.java
2 2

  
3 3
import com.google.common.base.Strings;
4 4
import com.google.gson.JsonObject;
5
import cz.zcu.kiv.offscreen.api.Graph;
6
import cz.zcu.kiv.offscreen.graph.GraphManager;
7
import cz.zcu.kiv.offscreen.graph.loader.GraphJSONDataLoader;
8
import cz.zcu.kiv.offscreen.graph.loader.JSONConfigLoader;
9
import cz.zcu.kiv.offscreen.modularization.IModule;
10 5
import cz.zcu.kiv.offscreen.modularization.ModuleProvider;
11 6
import cz.zcu.kiv.offscreen.servlets.BaseServlet;
12 7
import javafx.util.Pair;
13
import net.sf.json.JSONObject;
8
import org.apache.commons.lang.StringUtils;
14 9
import org.apache.logging.log4j.LogManager;
15 10
import org.apache.logging.log4j.Logger;
16 11

  
17 12
import javax.servlet.http.HttpServletRequest;
18 13
import javax.servlet.http.HttpServletResponse;
19 14
import java.io.IOException;
15
import java.lang.reflect.Method;
16
import java.util.Optional;
20 17

  
21 18
/**
22 19
 * This class is used for loading diagrams from session.
......
42 39
     * Add file which was uploaded and is stored in session to response or set http status code to BAD_REQUEST.
43 40
     */
44 41
    private void getDiagramFromSession(HttpServletRequest request, HttpServletResponse response) throws IOException {
45
        String jsonToDisplay = (String) request.getSession().getAttribute("json_graph");
46
        String jsonType = (String) request.getSession().getAttribute("json_graph_type");
47
        String filename = (String) request.getSession().getAttribute("graph_filename");
42
        String diagramToDisplay = (String) request.getSession().getAttribute("diagram_string");
43
        String diagramType = (String) request.getSession().getAttribute("diagram_type");
44
        String filename = (String) request.getSession().getAttribute("diagram_filename");
48 45

  
49
        if (!Strings.isNullOrEmpty(jsonToDisplay) && jsonType != null) {
46
        if (!Strings.isNullOrEmpty(diagramToDisplay) && diagramType != null) {
50 47

  
51 48
            String rawJson;
52 49

  
53
            if (jsonType.equals("raw")) {
50
            if (diagramType.equals("raw")) {
54 51
                logger.debug("Processing Raw json");
55
                rawJson = jsonToDisplay;
52
                rawJson = diagramToDisplay;
56 53
            } else {
57
                logger.debug("Processing json with module");
58

  
59
                Pair<String, IModule> module = ModuleProvider.getInstance().getModules().get(jsonType);
60
                if (module == null){
54
                Optional<String> optional = callModuleConverter(diagramType, diagramToDisplay);
55
                if(optional.isPresent()){
56
                    rawJson = optional.get();
57
                } else {
61 58
                    response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
62
                    logger.debug("No loader available for type: " + jsonType + ". Response BAD REQUEST");
63 59
                    return;
64 60
                }
65
                rawJson = module.getValue().getRawJson(jsonToDisplay);
66 61
            }
67 62

  
68 63
            JsonObject jsonObject = new JsonObject();
......
81 76
    }
82 77

  
83 78
    /**
84
     * Convert input spade JSON to frontend backend JSON and return it.
79
     * Method find module by type and call method for getting RAW JSON from module. If result is null, empty or
80
     * blank, method returns empty Optional.
81
     *
82
     * @param type type of converter which is key to map of modules
83
     * @param stringToConvert string which will be converted
84
     * @return Optional of RAW JSON or empty Optional
85 85
     */
86
    private String convertSpadeToRawJson(String spadeJson) {
87
        GraphManager graphManager = new GraphJSONDataLoader(spadeJson).loadData();
88
        JSONConfigLoader configLoader = new JSONConfigLoader(graphManager);
86
    private Optional<String> callModuleConverter(String type, String stringToConvert){
87
        logger.debug("Processing json with module");
88

  
89
        Pair<String, Class> module = ModuleProvider.getInstance().getModules().get(type);
90
        if (module == null){
91
            logger.debug("No loader available for type: " + type + ". Response BAD REQUEST");
92
            return Optional.empty();
93
        }
94

  
95
        try {
96
            final Class<?> moduleClass = module.getValue();
97
            // switching to class loader of module
98
            final ClassLoader appClassLoader = Thread.currentThread().getContextClassLoader();
99
            Thread.currentThread().setContextClassLoader(moduleClass.getClassLoader());
100

  
101
            final Method moduleMethod = moduleClass.getMethod(ModuleProvider.METHOD_NAME, ModuleProvider.METHOD_PARAMETER_CLASS);
102
            String rawJson = String.valueOf(moduleMethod.invoke(moduleClass.newInstance(), stringToConvert));
89 103

  
90
        Graph graph = graphManager.createGraph(configLoader);
91
        JSONObject json = JSONObject.fromObject(graph);
104
            // switching back to application class loader
105
            Thread.currentThread().setContextClassLoader(appClassLoader);
92 106

  
93
        return json.toString();
107
            if(StringUtils.isBlank(rawJson)){
108
                return Optional.empty();
109
            } else {
110
                return Optional.of(rawJson);
111
            }
112

  
113
        } catch (Exception e) {
114
            logger.error("Can not call convert method in module. Module name: " + module.getKey(), e);
115
            return Optional.empty();
116
        }
94 117
    }
95 118
}
sources/src/main/webapp/WEB-INF/web.xml
131 131
	<listener>
132 132
		<listener-class>cz.zcu.kiv.offscreen.session.SessionManager</listener-class>
133 133
	</listener>
134
	<listener>
135
		<listener-class>cz.zcu.kiv.offscreen.ApplicationListener</listener-class>
136
	</listener>
134 137

  
135 138
	<!-- Tomcat CORS filter; https://tomcat.apache.org/tomcat-8.0-doc/config/filter.html#CORS_Filter -->
136 139
	<filter>
sources/src/main/webapp/uploadFiles.jsp
72 72

  
73 73
					<div class="form-field">
74 74
						Select type of data file:<br>
75
						<label for="raw"><input type="radio" name="jsonFileFormat" value="raw" id="raw" checked> Raw JSON</label><br>
75
						<label for="raw"><input type="radio" name="fileFormat" value="raw" id="raw" checked> Raw JSON</label><br>
76 76
						<c:forEach items="${processingModules}" var="module">
77
							<label for="${module.key}"><input type="radio" name="jsonFileFormat" value="${module.key}" id="${module.key}">${module.value.key}</label><br>
77
							<label for="${module.key}"><input type="radio" name="fileFormat" value="${module.key}" id="${module.key}"> ${module.value.key}</label><br>
78 78
						</c:forEach>
79 79
					</div>
80 80

  

Také k dispozici: Unified diff