]> git.basschouten.com Git - openhab-addons.git/blob
97ec03dad3ab461dbeedee4ba4cf20486deacbc0
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.transform.javascript.internal;
14
15 import java.io.File;
16 import java.io.FileInputStream;
17 import java.io.IOException;
18 import java.io.InputStreamReader;
19 import java.io.Reader;
20 import java.util.Map;
21 import java.util.concurrent.ConcurrentHashMap;
22
23 import javax.script.Compilable;
24 import javax.script.CompiledScript;
25 import javax.script.ScriptEngine;
26 import javax.script.ScriptEngineManager;
27 import javax.script.ScriptException;
28
29 import org.eclipse.jdt.annotation.NonNullByDefault;
30 import org.openhab.core.transform.TransformationException;
31 import org.osgi.service.component.annotations.Component;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 /**
36  * Simple cache for compiled JavaScript files.
37  *
38  * @author Thomas Kordelle - Initial contribution
39  * @author Thomas Kordelle - pre compiled scripts
40  */
41 @NonNullByDefault
42 @Component(service = JavaScriptEngineManager.class)
43 public class JavaScriptEngineManager {
44
45     private final Logger logger = LoggerFactory.getLogger(JavaScriptEngineManager.class);
46     private final ScriptEngineManager manager = new ScriptEngineManager();
47     /* keep memory foot print low. max 2 concurrent threads are estimated */
48     private final Map<String, CompiledScript> compiledScriptMap = new ConcurrentHashMap<>(4, 0.5f, 2);
49
50     /**
51      * Get a pre compiled script {@link CompiledScript} from cache. If it is not in the cache, then load it from
52      * storage and put a pre compiled version into the cache.
53      *
54      * @param filename name of the JavaScript file to load
55      * @return a pre compiled script {@link CompiledScript}
56      * @throws TransformationException if compile of JavaScript failed
57      */
58     protected CompiledScript getScript(final String filename) throws TransformationException {
59         synchronized (compiledScriptMap) {
60             CompiledScript compiledScript = compiledScriptMap.get(filename);
61             if (compiledScript != null) {
62                 logger.debug("Loading JavaScript {} from cache.", filename);
63                 return compiledScript;
64             } else {
65                 final String path = TransformationScriptWatcher.TRANSFORM_FOLDER + File.separator + filename;
66                 logger.debug("Loading script {} from storage ", path);
67                 try (final Reader reader = new InputStreamReader(new FileInputStream(path))) {
68                     final ScriptEngine engine = manager.getEngineByName("javascript");
69                     final CompiledScript cScript = ((Compilable) engine).compile(reader);
70                     logger.debug("Putting compiled JavaScript {} to cache.", cScript);
71                     compiledScriptMap.put(filename, cScript);
72                     return cScript;
73                 } catch (IOException | ScriptException e) {
74                     throw new TransformationException("An error occurred while loading JavaScript. " + e.getMessage(),
75                             e);
76                 }
77             }
78         }
79     }
80
81     /**
82      * remove a pre compiled script from cache.
83      *
84      * @param fileName name of the script file to remove
85      */
86     protected void removeFromCache(String fileName) {
87         logger.debug("Removing JavaScript {} from cache.", fileName);
88         compiledScriptMap.remove(fileName);
89     }
90 }