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.iso.*; 027import org.jpos.rc.CMF; 028import org.jpos.rc.Result; 029import org.jpos.transaction.ContextConstants; 030import org.jpos.transaction.TransactionParticipant; 031import org.jpos.util.Caller; 032import org.jpos.util.Chronometer; 033import org.jpos.util.NameRegistrar; 034import org.jpos.transaction.Context; 035 036public class QueryHost implements TransactionParticipant, Configurable { 037 public static final String TIMEOUT_NAME = "QUERYHOST_TIMEOUT"; 038 039 private static final long DEFAULT_TIMEOUT = 30000L; 040 private static final long DEFAULT_WAIT_TIMEOUT = 1000L; 041 042 private long timeout; 043 private long waitTimeout; 044 private String timeoutName = TIMEOUT_NAME; // default ctx name 045 private String requestName; 046 private String responseName; 047 private String destination; 048 private boolean continuations; 049 private Configuration cfg; 050 private boolean ignoreUnreachable; 051 private boolean checkConnected= true; 052 053 public QueryHost () { 054 super(); 055 } 056 public int prepare (long id, Serializable ser) { 057 Context ctx = (Context) ser; 058 059 Result result = ctx.getResult(); 060 String ds = ctx.getString(destination); 061 if (ds == null) { 062 return result.fail( 063 CMF.MISCONFIGURED_ENDPOINT, Caller.info(), "'%s' not present in Context", destination 064 ).FAIL(); 065 } 066 String muxName = cfg.get ("mux." + ds , "mux." + ds); 067 MUX mux = NameRegistrar.getIfExists (muxName); 068 if (mux == null) 069 return result.fail(CMF.MISCONFIGURED_ENDPOINT, Caller.info(), "MUX '%s' not found", muxName).FAIL(); 070 071 ISOMsg m = ctx.get (requestName); 072 if (m == null) 073 return result.fail(CMF.INVALID_REQUEST, Caller.info(), "'%s' is null", requestName).FAIL(); 074 075 Chronometer chronometer = new Chronometer(); 076 if (isConnected(mux)) { 077 long t = Math.max(resolveTimeout(ctx) - chronometer.elapsed(), 1000L); // give at least a second to catch a response 078 try { 079 ISOMsg resp = mux.request(m, t); 080 if (resp != null) { 081 ctx.put(responseName, resp); 082 return PREPARED | READONLY | NO_JOIN; 083 } else if (ignoreUnreachable) { 084 ctx.log(String.format ("MUX '%s' no response", muxName)); 085 } else { 086 return result.fail(CMF.HOST_UNREACHABLE, Caller.info(), "'%s' does not respond", muxName).FAIL(); 087 } 088 } catch (ISOException e) { 089 return result.fail(CMF.SYSTEM_ERROR, Caller.info(), e.getMessage()).FAIL(); 090 } 091 } else if (ignoreUnreachable) { 092 ctx.log(String.format ("MUX '%s' not connected", muxName)); 093 } else { 094 return result.fail(CMF.HOST_UNREACHABLE, Caller.info(), "'%s' is not connected", muxName).FAIL(); 095 } 096 return PREPARED | NO_JOIN | READONLY; 097 } 098 099 public void setConfiguration (Configuration cfg) throws ConfigurationException { 100 this.cfg = cfg; 101 timeout = cfg.getLong ("timeout", DEFAULT_TIMEOUT); 102 waitTimeout = cfg.getLong ("wait-timeout", DEFAULT_WAIT_TIMEOUT); 103 timeoutName = cfg.get("timeout-name", timeoutName); 104 requestName = cfg.get ("request", ContextConstants.REQUEST.toString()); 105 responseName = cfg.get ("response", ContextConstants.RESPONSE.toString()); 106 destination = cfg.get ("destination", ContextConstants.DESTINATION.toString()); 107 ignoreUnreachable = cfg.getBoolean("ignore-host-unreachable", false); 108 checkConnected = cfg.getBoolean("check-connected", checkConnected); 109 } 110 111 protected long resolveTimeout(Context ctx) { 112 Object o = ctx.get(timeoutName); 113 if (o == null) 114 return timeout; 115 else if (o instanceof Number) 116 return ((Number)o).longValue(); 117 else 118 return Long.parseLong(o.toString()); 119 } 120 121 protected boolean isConnected (MUX mux) { 122 if (!checkConnected || mux.isConnected()) 123 return true; 124 long timeout = System.currentTimeMillis() + waitTimeout; 125 while (System.currentTimeMillis() < timeout) { 126 if (mux.isConnected()) 127 return true; 128 ISOUtil.sleep (500); 129 } 130 return false; 131 } 132}