001/*
002 * jPOS Project [http://jpos.org]
003 * Copyright (C) 2000-2026 jPOS Software SRL
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jpos.q2.qbean;
020
021import bsh.EvalError;
022import bsh.Interpreter;
023import org.jdom2.Element;
024import org.jpos.core.ConfigurationException;
025import org.jpos.q2.QBeanSupport;
026import org.jpos.space.Space;
027import org.jpos.space.SpaceError;
028import org.jpos.space.SpaceFactory;
029import org.jpos.util.NameRegistrar;
030
031import java.io.IOException;
032import java.util.Iterator;
033
034/**
035 * QBean that adapts a {@link Space} for scripted access via BeanShell, allowing
036 * incoming/outgoing operations to be intercepted by configured BSH snippets.
037 */
038@SuppressWarnings("unchecked")
039public class SpaceLet extends QBeanSupport implements Space {
040    /** Default constructor; no instance state to initialise. */
041    public SpaceLet() {}
042    Space sp;
043    String uri;
044    String outScript, outSource;
045    String pushScript, pushSource;
046    String inScript, inSource;
047    String rdScript, rdSource;
048    String putScript, putSource;
049
050    public void initService() throws ConfigurationException {
051        Element config = getPersist ();
052        grabSpace (config.getChild ("space"));
053        initSpace (config.getChild ("init"));
054
055        String name = getName();
056        if ("spacelet".equals (name))
057            name = "default";
058        uri = "spacelet:" + name;
059
060        Element e = config.getChild ("out");
061        outScript = getScript (e);
062        if (e != null)
063            outSource = e.getAttributeValue ("source");
064
065        e = config.getChild ("push");
066        pushScript = getScript (e);
067        if (e != null)
068            pushSource = e.getAttributeValue ("source");
069
070        e = config.getChild ("in");
071        inScript = getScript (e);
072        if (e != null)
073            inSource = e.getAttributeValue ("source");
074
075        e = config.getChild ("rd");
076        rdScript = getScript (e);
077        if (e != null)
078            rdSource = e.getAttributeValue ("source");
079
080        e = config.getChild ("put");
081        putScript = getScript (e);
082        if (e != null)
083            putSource = e.getAttributeValue ("source");
084
085    }
086    public void startService() {
087        NameRegistrar.register (uri, this);
088
089        Iterator iter = getPersist().getChildren("run").iterator();
090        while (iter.hasNext ()) 
091            launch ((Element) iter.next ());
092    }
093    public void stopService() {
094        NameRegistrar.unregister (uri);
095    }
096    public void out (Object key, Object value) {
097        try {
098            Interpreter bsh = initInterpreter (key, value);
099            synchronized (sp) {
100                if (!eval (bsh, outScript, outSource))
101                    sp.out (key, value);
102            }
103        } catch (Throwable t) {
104            throw new SpaceError (t);
105        }
106    }
107    public void out (Object key, Object value, long timeout) {
108        try {
109            Interpreter bsh = initInterpreter (key, value, timeout);
110            synchronized (sp) {
111                if (!eval (bsh, outScript, outSource))
112                    sp.out (key, value, timeout);
113            }
114        } catch (Throwable t) {
115            throw new SpaceError (t);
116        }
117    }
118    public void push (Object key, Object value) {
119        try {
120            Interpreter bsh = initInterpreter (key, value);
121            synchronized (sp) {
122                if (!eval (bsh, pushScript, pushSource))
123                    sp.out (key, value);
124            }
125        } catch (Throwable t) {
126            throw new SpaceError (t);
127        }
128    }
129    public void push (Object key, Object value, long timeout) {
130        try {
131            Interpreter bsh = initInterpreter (key, value, timeout);
132            synchronized (sp) {
133                if (!eval (bsh, pushScript, pushSource))
134                    sp.out (key, value, timeout);
135            }
136        } catch (Throwable t) {
137            throw new SpaceError (t);
138        }
139    }
140    public void put (Object key, Object value) {
141        try {
142            Interpreter bsh = initInterpreter (key, value);
143            synchronized (sp) {
144                if (!eval (bsh, putScript, putSource))
145                    sp.put (key, value);
146            }
147        } catch (Throwable t) {
148            throw new SpaceError (t);
149        }
150    }
151    public void put (Object key, Object value, long timeout) {
152        try {
153            Interpreter bsh = initInterpreter (key, value, timeout);
154            synchronized (sp) {
155                if (!eval (bsh, putScript, putSource))
156                    sp.out (key, value, timeout);
157            }
158        } catch (Throwable t) {
159            throw new SpaceError (t);
160        }
161    }
162
163
164    public Object in  (Object key) {
165        try {
166            Interpreter bsh = initInterpreter (key);
167            synchronized (sp) {
168                if (eval (bsh, inScript, inSource)) {
169                    return bsh.get ("value");
170                } else {
171                    return sp.in (key);
172                }
173            }
174        } catch (Throwable t) {
175            throw new SpaceError (t);
176        }
177    }
178    public Object rd  (Object key) {
179        try {
180            Interpreter bsh = initInterpreter (key);
181            synchronized (sp) {
182                if (eval (bsh, rdScript, rdSource)) {
183                    return bsh.get ("value");
184                } else {
185                    return sp.rd (key);
186                }
187            }
188        } catch (Throwable t) {
189            throw new SpaceError (t);
190        }
191    }
192    public Object in  (Object key, long timeout) {
193        try {
194            Interpreter bsh = initInterpreter (key, timeout);
195            synchronized (sp) {
196                if (eval (bsh, inScript, inSource)) {
197                    return bsh.get ("value");
198                } else {
199                    return sp.in (key, timeout);
200                }
201            }
202        } catch (Throwable t) {
203            throw new SpaceError (t);
204        }
205    }
206    public Object rd  (Object key, long timeout) {
207        try {
208            Interpreter bsh = initInterpreter (key, timeout);
209            synchronized (sp) {
210                if (eval (bsh, rdScript, rdSource)) {
211                    return bsh.get ("value");
212                } else {
213                    return sp.rd (key, timeout);
214                }
215            }
216        } catch (Throwable t) {
217            throw new SpaceError (t);
218        }
219    }
220    public Object inp (Object key) {
221        try {
222            Interpreter bsh = initInterpreter (key);
223            bsh.set ("probe", true);
224            synchronized (sp) {
225                if (eval (bsh, inScript, inSource)) {
226                    return bsh.get ("value");
227                } else {
228                    return sp.inp (key);
229                }
230            }
231        } catch (Throwable t) {
232            throw new SpaceError (t);
233        }
234    }
235    public Object rdp (Object key) {
236        try {
237            Interpreter bsh = initInterpreter (key);
238            bsh.set ("probe", true);
239            synchronized (sp) {
240                if (eval (bsh, rdScript, rdSource)) {
241                    return bsh.get ("value");
242                } else {
243                    return sp.rdp (key);
244                }
245            }
246        } catch (Throwable t) {
247            throw new SpaceError (t);
248        }
249    }
250    public boolean existAny (Object[] keys) {
251        return sp.existAny (keys);
252    }
253    public boolean existAny (Object[] keys, long timeout) {
254        return sp.existAny (keys, timeout);
255    }
256    private void grabSpace (Element e) {
257        sp = SpaceFactory.getSpace (e != null ? e.getText() : "");
258    }
259    private String getScript (Element e) {
260        return e == null ? null : e.getText();
261    }
262    public void nrd (Object key) {
263         sp.nrd(key);
264    }
265    public Object nrd (Object key, long timeout) {
266        return sp.nrd(key, timeout);
267    }
268    private void launch (Element e) {
269        // final Interpreter bsh = initInterpreter ();
270        final String script = e.getText();
271        final String source = e.getAttributeValue ("source");
272
273        new Thread ("SpaceLet-launch") {
274            public void run () {
275                try {
276                    eval (initInterpreter(), script, source);
277                } catch (Throwable t) {
278                    getLog().warn (t);
279                }
280            }
281        }.start ();
282    }
283    private void initSpace (Element e) throws ConfigurationException {
284        if (e == null)
285            return;
286
287        try {
288            eval (
289                initInterpreter(), 
290                e.getText(), 
291                e.getAttributeValue ("source")
292            );
293        } catch (Throwable t) {
294            throw new ConfigurationException (t);
295        }
296    }
297    private Interpreter initInterpreter () throws EvalError {
298        Interpreter bsh = new Interpreter ();
299        bsh.set ("sp", sp);
300        bsh.set ("spacelet", this); 
301        bsh.set ("log", getLog());
302        return bsh;
303    }
304    private Interpreter initInterpreter (Object key) throws EvalError {
305        Interpreter bsh = initInterpreter ();
306        bsh.set ("key", key);
307        return bsh;
308    }
309    private Interpreter initInterpreter (Object key, Object value) 
310        throws EvalError
311    {
312        Interpreter bsh = initInterpreter (key);
313        bsh.set ("value", value);
314        return bsh;
315    }
316    private Interpreter initInterpreter 
317        (Object key, Object value, long timeout) 
318        throws EvalError 
319    {
320        Interpreter bsh = initInterpreter (key, value);
321        bsh.set ("timeout", timeout);
322        return bsh;
323    }
324    private Interpreter initInterpreter (Object key, long timeout) 
325        throws EvalError
326    {
327        Interpreter bsh = initInterpreter (key);
328        bsh.set ("timeout", timeout);
329        return bsh;
330    }
331    private boolean eval (Interpreter bsh, String script, String source)
332        throws EvalError, IOException
333    {
334        boolean rc = false;
335        if (script != null) {
336            Object retValue = bsh.eval (script);
337            if (source != null)
338                retValue = bsh.source (source);
339            if (retValue instanceof Boolean) {
340                rc = (Boolean) retValue;
341            }
342        }
343        return rc;
344    }
345}
346