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 java.io.Serializable; 022 023import org.jpos.core.Configurable; 024import org.jpos.core.Configuration; 025import org.jpos.core.ConfigurationException; 026import org.jpos.core.annotation.Config; 027import org.jpos.iso.ISOMsg; 028import org.jpos.iso.ISOSource; 029import org.jpos.space.LocalSpace; 030import org.jpos.space.SpaceSource; 031import org.jpos.transaction.Context; 032import org.jpos.transaction.AbortParticipant; 033import org.jpos.transaction.TransactionManager; 034 035import static org.jpos.transaction.ContextConstants.*; 036 037@SuppressWarnings("unused") 038public class SendResponse implements AbortParticipant, Configurable { 039 private String source; 040 private String request; 041 private String response; 042 private LocalSpace isp; 043 private long timeout = 70000L; 044 private HeaderStrategy headerStrategy; 045 046 @Config("abort-on-closed") 047 private boolean abortOnClosed = true; 048 049 public int prepare (long id, Serializable context) { 050 Context ctx = (Context) context; 051 ISOSource source = ctx.get (this.source); 052 if (abortOnClosed && (source == null || !source.isConnected())) { 053 ctx.log (this.source + " not present or not longer connected"); 054 return ABORTED | READONLY | NO_JOIN; 055 } 056 057 return PREPARED | READONLY; 058 } 059 060 public void commit (long id, Serializable context) { 061 sendResponse(id, (Context) context); 062 } 063 public void abort (long id, Serializable context) { 064 sendResponse(id, (Context) context); 065 } 066 067 private void sendResponse (long id, Context ctx) { 068 ISOSource src = ctx.get (source); 069 ISOMsg m = ctx.get(request); 070 ISOMsg resp = ctx.get (response); 071 try { 072 if (ctx.getResult().hasInhibit()) { 073 ctx.log("*** RESPONSE INHIBITED ***"); 074 } else if (ctx.get (TX.toString()) != null) { 075 ctx.log("*** PANIC - TX not null - RESPONSE OMITTED ***"); 076 } else if (resp == null) { 077 ctx.log (response + " not present"); 078 } else if (src == null) { 079 ctx.log (source + " not present"); 080 } else if (!src.isConnected()) 081 ctx.log (source + " is no longer connected"); 082 else { 083 if (src instanceof SpaceSource) 084 ((SpaceSource)src).init(isp, timeout); 085 if (src.isConnected() && resp != null) { 086 headerStrategy.handleHeader(m, resp); 087 src.send(resp); 088 } 089 } 090 } catch (Throwable t) { 091 ctx.log(t); 092 } 093 } 094 095 @Override 096 public void setConfiguration(Configuration cfg) throws ConfigurationException { 097 source = cfg.get ("source", SOURCE.toString()); 098 request = cfg.get ("request", REQUEST.toString()); 099 response = cfg.get ("response", RESPONSE.toString()); 100 timeout = cfg.getLong ("timeout", timeout); 101 try { 102 headerStrategy = HeaderStrategy.valueOf( 103 cfg.get("header-strategy", "PRESERVE_RESPONSE").toUpperCase() 104 ); 105 } catch (IllegalArgumentException e) { 106 throw new ConfigurationException (e.getMessage()); 107 } 108 } 109 public void setTransactionManager(TransactionManager tm) { 110 isp = (LocalSpace) tm.getInputSpace(); 111 } 112 113 private interface HeaderHandler { 114 void handleHeader (ISOMsg m, ISOMsg r); 115 } 116 117 @SuppressWarnings("unused") 118 public enum HeaderStrategy implements HeaderHandler { 119 PRESERVE_ORIGINAL() { 120 @Override 121 public void handleHeader(ISOMsg m, ISOMsg r) { 122 r.setHeader(m.getHeader()); 123 } 124 }, 125 PRESERVE_RESPONSE() { 126 @Override 127 public void handleHeader(ISOMsg m, ISOMsg r) { } 128 }, 129 SET_TO_NULL() { 130 @Override 131 public void handleHeader(ISOMsg m, ISOMsg r) { 132 r.setHeader((byte[]) null); 133 } 134 } 135 } 136}