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.transaction.participant;
020
021import bsh.EvalError;
022import bsh.Interpreter;
023import org.jdom2.Element;
024import org.jpos.q2.QFactory;
025
026import java.io.FileReader;
027import java.io.IOException;
028import java.util.Collection;
029import java.util.HashMap;
030import java.util.Map;
031
032/** This is a utility class that makes it a bit easier to work with beanshell 
033 *  scripts.
034 *  Check out the execute methods.
035 *
036 * @author  AMarques
037 */
038@SuppressWarnings("unchecked")
039public class BSHMethod {
040    
041    private String bshData;
042    private boolean source;
043    
044    
045    /** Creates a BSHMethod from a JDom Element.
046     *
047     *  The element is not requiered to have a specific name. 
048     *  
049     *  If the given element defines an attribute named 'file' the file 
050     *  specified as its value will be sourced by the created BSHMethod.
051     *
052     *  If the 'file' attribute is specified, a 'cache'
053     *  attribute may be specified as well which can take the values true|false
054     *  and indicates wether to load the script to memory or to read from the 
055     *  file for every script evaluation.
056     *
057     *  If the 'file' attibute is not specified then the text contained by the 
058     *  element is set to be evaluated by the new BSHMethod. 
059     *  <pre>
060     *  Example 1 : 
061     *          &lt;prepare>
062     *                  import org.jpos.iso.*;
063     *                  import org.jpos.transaction.*;
064     *
065     *                  msg = context.get("txnRequest");
066     *                  BaseChannel.getChannel("loop-channel").send(msg);
067     *                  result=TransactionConstants.PREPARED | TransactionConstants.READONLY;
068     *          &lt;/prepare>
069     *
070     *  Example 2 :
071     *          &lt;routing file='cfg\files\routing1.bsh' cache='false'/>
072     *  </pre>
073     */ 
074    public static BSHMethod createBshMethod(Element e) throws IOException {
075        if (e == null) {
076            return null;
077        }
078        String file = QFactory.getAttributeValue(e, "file");
079        String bsh;
080        if (file != null) {
081            boolean cache = false;
082            String cacheAtt = QFactory.getAttributeValue(e, "cache");
083            if (cacheAtt != null) {
084                cache = cacheAtt.equalsIgnoreCase("true"); 
085            }
086            if (!cache) {
087                return new BSHMethod(file, true);
088            } else {
089                bsh = "";
090                FileReader f = new FileReader(file);
091                int c;
092                while ( (c = f.read()) != -1) {
093                    bsh += (char) c; 
094                }
095                f.close();
096                return new BSHMethod(bsh, false);
097            }
098        } else {
099            bsh = e.getTextTrim();
100            if (bsh == null || bsh.equals("")) {
101                return null;
102            }
103            return new BSHMethod(bsh, false);
104        }
105    }
106        
107    /** Creates a BSHMethod.
108     *  @param bshData - May either be the file to source or the script itself to
109     *                  evaluate.
110     *  @param source - If true indicates that the bshData passed is a file to 
111     *                  source. Otherwise the string itself is evaluated.
112     */
113    public BSHMethod(String bshData, boolean source) {
114        this.bshData = bshData;
115        this.source = source; 
116    }
117
118    /** Sets the given arguments to the Interpreter, evaluates the script and 
119     *  returns the object stored on the variable named resultName.
120     *
121     *  @param arguments    Parameters to set to the Interpreter. For every 
122     *                      Map.Entry (key, value), interpreter.set(key, value)
123     *                      is called. All keys must be Strings.
124     */
125    public Object execute(Map arguments, String resultName) throws EvalError, IOException {
126        Interpreter i = initInterpreter(arguments);
127        return i.get(resultName);
128    }
129    
130    /** Sets the given arguments to the Interpreter, evaluates the script and 
131     *  returns a map that has the Strings of the returnNames collection as keys
132     *  and the objects stored in the variables thus named as values.
133     *  
134     *  @param arguments    Parameters to set to the Interpreter. For every 
135     *                      Map.Entry (key, value), interpreter.set(key, value)
136     *                      is called. All keys must be Strings.
137     *  @param returnNames  Collection of Strings. The names of the variables 
138     *                      wich`s contents are to be returned.
139     */
140    public Map execute(Map arguments, Collection returnNames) throws EvalError, IOException {
141        Interpreter i = initInterpreter(arguments);
142        Map result = new HashMap();
143        String rName;
144        for (Object returnName : returnNames) {
145            rName = (String) returnName;
146            result.put(rName, i.get(rName));
147        }
148        return result;
149    }
150    
151    protected Interpreter initInterpreter(Map arguments) throws EvalError, IOException {
152        Interpreter i = new Interpreter();
153        Map.Entry entry;
154        for (Object o : arguments.entrySet()) {
155            entry = (Map.Entry) o;
156            i.set((String) entry.getKey(), entry.getValue());
157        }
158        if (source) {
159            i.source(bshData);
160        } else {
161            i.eval(bshData);
162        }
163        return i;
164    }
165
166    public String toString() {
167        return bshData;
168    }
169}