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 org.jdom2.Element; 023import org.jpos.core.ConfigurationException; 024import org.jpos.core.XmlConfigurable; 025import org.jpos.q2.QFactory; 026import org.jpos.transaction.AbortParticipant; 027import org.jpos.transaction.TransactionParticipant; 028import org.jpos.util.LogEvent; 029import org.jpos.util.Logger; 030import org.jpos.util.SimpleLogSource; 031 032import java.io.IOException; 033import java.io.Serializable; 034import java.util.HashMap; 035import java.util.Map; 036 037/** A TransactionParticipant whose prepare, commit and abort methods can be 038 * specified through beanshell scripts. <BR> 039 * 040 * To indicate what code to execute for any of the methods just add an element 041 * named 'prepare', 'commit' or 'abort' contained in that of the participant. <BR> 042 * 043 * See BSHMethod for details on the syntax of these elements. The value to return 044 * in the prepare method should be stored in the script variable named "result". 045 * None of these tags are mandatory. <BR> 046 * 047 * You can subclass BSHTransactionParticipant and override the default... 048 * methods. That way you can provide default behaviour for a participant and 049 * override it at deploy time through scripts. 050 * 051 * @see BSHMethod 052 * @author AMarques 053 */ 054@SuppressWarnings("unchecked") 055public class BSHTransactionParticipant extends SimpleLogSource 056 implements TransactionParticipant, AbortParticipant, XmlConfigurable 057{ 058 059 protected BSHMethod prepareMethod; 060 protected BSHMethod prepareForAbortMethod; 061 protected BSHMethod commitMethod; 062 protected BSHMethod abortMethod; 063 064 boolean trace; 065 066 /** Creates a new instance of BSHTransactionParticipant */ 067 public BSHTransactionParticipant() { 068 super(); 069 } 070 071 public void abort(long id, java.io.Serializable context) { 072 LogEvent ev = new LogEvent(this, "abort"); 073 if (abortMethod != null) { 074 try { 075 executeMethod(abortMethod, id, context, ev, ""); 076 } catch (Exception ex) { 077 ev.addMessage(ex); 078 } 079 } else { 080 defaultAbort(id, context, ev); 081 } 082 if (trace) 083 Logger.log(ev); 084 } 085 086 protected void defaultAbort(long id, Serializable context, LogEvent ev) {} 087 088 public void commit(long id, java.io.Serializable context) { 089 LogEvent ev = new LogEvent(this, "commit"); 090 if (commitMethod != null) { 091 try { 092 executeMethod(commitMethod, id, context, ev, ""); 093 } catch (Exception ex) { 094 ev.addMessage(ex); 095 } 096 } else { 097 defaultCommit(id, context, ev); 098 } 099 if (trace) 100 Logger.log(ev); 101 } 102 103 protected void defaultCommit(long id, Serializable context, LogEvent ev) {} 104 105 public int prepare(long id, java.io.Serializable context) { 106 LogEvent ev = new LogEvent(this, "prepare"); 107 int result = ABORTED | READONLY; 108 if (prepareMethod != null) { 109 try { 110 result = (Integer) executeMethod(prepareMethod, id, context, ev, "result"); 111 } catch (Exception ex) { 112 ev.addMessage(ex); 113 } 114 } else { 115 result = defaultPrepare(id, context, ev); 116 } 117 ev.addMessage("result", Integer.toBinaryString(result)); 118 if (trace) 119 Logger.log(ev); 120 return result; 121 } 122 123 public int prepareForAbort(long id, java.io.Serializable context) { 124 LogEvent ev = new LogEvent(this, "prepare-for-abort"); 125 int result = ABORTED | READONLY; 126 if (prepareForAbortMethod != null) { 127 try { 128 result = (Integer) executeMethod(prepareForAbortMethod, id, context, ev, "result"); 129 } catch (Exception ex) { 130 ev.addMessage(ex); 131 } 132 } 133 ev.addMessage("result", Integer.toBinaryString(result)); 134 if (trace) 135 Logger.log(ev); 136 return result; 137 } 138 139 protected int defaultPrepare(long id, Serializable context, LogEvent ev) { 140 return PREPARED | READONLY; 141 } 142 143 public void setConfiguration(Element e) throws ConfigurationException { 144 try { 145 prepareMethod = BSHMethod.createBshMethod(e.getChild("prepare")); 146 prepareForAbortMethod = BSHMethod.createBshMethod(e.getChild("prepare-for-abort")); 147 commitMethod = BSHMethod.createBshMethod(e.getChild("commit")); 148 abortMethod = BSHMethod.createBshMethod(e.getChild("abort")); 149 trace = "yes".equals (QFactory.getAttributeValue (e, "trace")); 150 } catch (Exception ex) { 151 throw new ConfigurationException(ex.getMessage(), ex); 152 } 153 } 154 155 protected Object executeMethod(BSHMethod m, long id, Serializable context, LogEvent evt, String resultName) 156 throws EvalError, IOException { 157 Map params = new HashMap(); 158 params.put("context", context); 159 params.put("id", id); 160 params.put("evt", evt); 161 params.put("self", this); 162 return m.execute(params, resultName); 163 } 164} 165