]> git.basschouten.com Git - openhab-addons.git/blob
7be64da4b8f0a3415ec9970fcbf26ced7b7ed3ac
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.automation.jrubyscripting.internal;
14
15 import java.io.Reader;
16 import java.util.Objects;
17
18 import javax.script.Bindings;
19 import javax.script.Compilable;
20 import javax.script.CompiledScript;
21 import javax.script.Invocable;
22 import javax.script.ScriptContext;
23 import javax.script.ScriptEngine;
24 import javax.script.ScriptEngineFactory;
25 import javax.script.ScriptException;
26
27 import org.eclipse.jdt.annotation.NonNullByDefault;
28 import org.eclipse.jdt.annotation.Nullable;
29 import org.jruby.embed.jsr223.JRubyEngine;
30
31 /**
32  * This is a wrapper for {@link JRubyEngine}.
33  * 
34  * The purpose of this class is to intercept the call to eval and save the context into
35  * a global variable for use in the helper library.
36  *
37  * @author Jimmy Tanagra - Initial contribution
38  */
39 @NonNullByDefault
40 public class JRubyEngineWrapper implements Compilable, Invocable, ScriptEngine {
41
42     private final JRubyEngine engine;
43
44     private static final String CONTEXT_VAR_NAME = "ctx";
45     private static final String GLOBAL_VAR_NAME = "$" + CONTEXT_VAR_NAME;
46
47     JRubyEngineWrapper(JRubyEngine engine) {
48         this.engine = Objects.requireNonNull(engine);
49     }
50
51     @Override
52     public CompiledScript compile(@Nullable String script) throws ScriptException {
53         return engine.compile(script);
54     }
55
56     @Override
57     public CompiledScript compile(@Nullable Reader reader) throws ScriptException {
58         return engine.compile(reader);
59     }
60
61     @Override
62     public Object eval(@Nullable String script, @Nullable ScriptContext context) throws ScriptException {
63         Object ctx = Objects.requireNonNull(context).getBindings(ScriptContext.ENGINE_SCOPE).get(CONTEXT_VAR_NAME);
64
65         if (ctx == null) {
66             return engine.eval(script, context);
67         }
68
69         context.setAttribute(GLOBAL_VAR_NAME, ctx, ScriptContext.ENGINE_SCOPE);
70         try {
71             return engine.eval(script, context);
72         } finally {
73             context.removeAttribute(GLOBAL_VAR_NAME, ScriptContext.ENGINE_SCOPE);
74         }
75     }
76
77     @Override
78     public Object eval(@Nullable Reader reader, @Nullable ScriptContext context) throws ScriptException {
79         Object ctx = Objects.requireNonNull(context).getBindings(ScriptContext.ENGINE_SCOPE).get(CONTEXT_VAR_NAME);
80
81         if (ctx == null) {
82             return engine.eval(reader, context);
83         }
84
85         context.setAttribute(GLOBAL_VAR_NAME, ctx, ScriptContext.ENGINE_SCOPE);
86         try {
87             return engine.eval(reader, context);
88         } finally {
89             context.removeAttribute(GLOBAL_VAR_NAME, ScriptContext.ENGINE_SCOPE);
90         }
91     }
92
93     @Override
94     public Object eval(@Nullable String script, @Nullable Bindings bindings) throws ScriptException {
95         Object ctx = Objects.requireNonNull(bindings).get(CONTEXT_VAR_NAME);
96
97         if (ctx == null) {
98             return engine.eval(script, bindings);
99         }
100
101         bindings.put(GLOBAL_VAR_NAME, ctx);
102         try {
103             return engine.eval(script, bindings);
104         } finally {
105             bindings.remove(GLOBAL_VAR_NAME);
106         }
107     }
108
109     @Override
110     public Object eval(@Nullable Reader reader, @Nullable Bindings bindings) throws ScriptException {
111         Object ctx = Objects.requireNonNull(bindings).get(CONTEXT_VAR_NAME);
112
113         if (ctx == null) {
114             return engine.eval(reader, bindings);
115         }
116
117         bindings.put(GLOBAL_VAR_NAME, ctx);
118         try {
119             return engine.eval(reader, bindings);
120         } finally {
121             bindings.remove(GLOBAL_VAR_NAME);
122         }
123     }
124
125     @Override
126     public Object eval(@Nullable String script) throws ScriptException {
127         Object ctx = getBindings(ScriptContext.ENGINE_SCOPE).get(CONTEXT_VAR_NAME);
128
129         if (ctx == null) {
130             return engine.eval(script);
131         }
132
133         getContext().setAttribute(GLOBAL_VAR_NAME, ctx, ScriptContext.ENGINE_SCOPE);
134         try {
135             return engine.eval(script);
136         } finally {
137             getContext().removeAttribute(GLOBAL_VAR_NAME, ScriptContext.ENGINE_SCOPE);
138         }
139     }
140
141     @Override
142     public Object eval(@Nullable Reader reader) throws ScriptException {
143         Object ctx = getBindings(ScriptContext.ENGINE_SCOPE).get(CONTEXT_VAR_NAME);
144
145         if (ctx == null) {
146             return engine.eval(reader);
147         }
148
149         getContext().setAttribute(GLOBAL_VAR_NAME, ctx, ScriptContext.ENGINE_SCOPE);
150         try {
151             return engine.eval(reader);
152         } finally {
153             getContext().removeAttribute(GLOBAL_VAR_NAME, ScriptContext.ENGINE_SCOPE);
154         }
155     }
156
157     @Override
158     public Object get(@Nullable String key) {
159         return engine.get(key);
160     }
161
162     @Override
163     public void put(@Nullable String key, @Nullable Object value) {
164         engine.put(key, value);
165     }
166
167     @Override
168     public Bindings getBindings(int scope) {
169         return engine.getBindings(scope);
170     }
171
172     @Override
173     public void setBindings(@Nullable Bindings bindings, int scope) {
174         engine.setBindings(bindings, scope);
175     }
176
177     @Override
178     public Bindings createBindings() {
179         return engine.createBindings();
180     }
181
182     @Override
183     public ScriptContext getContext() {
184         return engine.getContext();
185     }
186
187     @Override
188     public void setContext(@Nullable ScriptContext context) {
189         engine.setContext(context);
190     }
191
192     @Override
193     public ScriptEngineFactory getFactory() {
194         return engine.getFactory();
195     }
196
197     @Override
198     public Object invokeMethod(@Nullable Object receiver, @Nullable String method, Object @Nullable... args)
199             throws ScriptException, NoSuchMethodException {
200         return engine.invokeMethod(receiver, method, args);
201     }
202
203     @Override
204     public Object invokeFunction(@Nullable String method, Object @Nullable... args)
205             throws ScriptException, NoSuchMethodException {
206         return engine.invokeFunction(method, args);
207     }
208
209     @Override
210     public <T> T getInterface(@Nullable Class<T> returnType) {
211         return engine.getInterface(returnType);
212     }
213
214     @Override
215     public <T> T getInterface(@Nullable Object receiver, @Nullable Class<T> returnType) {
216         return engine.getInterface(receiver, returnType);
217     }
218 }