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.iso.channel; 020 021import org.jpos.core.Configurable; 022import org.jpos.core.Configuration; 023import org.jpos.core.ConfigurationException; 024import org.jpos.iso.ISOChannel; 025import org.jpos.iso.ISOException; 026import org.jpos.iso.ISOMsg; 027import org.jpos.iso.ISOPackager; 028import org.jpos.util.LogEvent; 029import org.jpos.util.LogSource; 030import org.jpos.util.Logger; 031import org.jpos.util.NameRegistrar; 032 033import java.io.IOException; 034import java.util.List; 035import java.util.Vector; 036import java.util.concurrent.locks.Lock; 037import java.util.concurrent.locks.ReentrantLock; 038 039/** 040 * A pool of {@link ISOChannel} instances; tries each in order until one connects. 041 */ 042@SuppressWarnings("unchecked") 043public class ChannelPool implements ISOChannel, LogSource, Configurable, Cloneable { 044 /** Whether this pool is in a usable state. */ 045 boolean usable = true; 046 /** Registered name of this pool. */ 047 String name = ""; 048 /** Logger for this pool. */ 049 protected Logger logger; 050 /** Log realm for this pool. */ 051 protected String realm; 052 Configuration cfg = null; 053 List pool; 054 ISOChannel current; 055 Lock lock = new ReentrantLock(); 056 057 /** Default constructor. */ 058 public ChannelPool () { 059 super (); 060 pool = new Vector (); 061 } 062 public void setPackager(ISOPackager p) { 063 // nothing to do 064 } 065 public void connect () throws IOException { 066 lock.lock(); 067 try { 068 current = null; 069 LogEvent evt = new LogEvent (this, "connect"); 070 evt.addMessage ("pool-size=" + Integer.toString (pool.size())); 071 for (int i=0; i<pool.size(); i++) { 072 try { 073 evt.addMessage ("pool-" + Integer.toString (i)); 074 ISOChannel c = (ISOChannel) pool.get (i); 075 c.connect (); 076 if (c.isConnected()) { 077 current = c; 078 usable = true; 079 break; 080 } 081 } catch (IOException e) { 082 evt.addMessage (e); 083 } 084 } 085 if (current == null) 086 evt.addMessage ("connect failed"); 087 Logger.log (evt); 088 if (current == null) { 089 throw new IOException ("unable to connect"); 090 } 091 } finally { 092 lock.unlock(); 093 } 094 } 095 public void disconnect () throws IOException { 096 lock.lock(); 097 try { 098 current = null; 099 LogEvent evt = new LogEvent (this, "disconnect"); 100 for (Object aPool : pool) { 101 try { 102 ISOChannel c = (ISOChannel) aPool; 103 c.disconnect(); 104 } catch (IOException e) { 105 evt.addMessage(e); 106 } 107 } 108 Logger.log (evt); 109 } finally { 110 lock.unlock(); 111 } 112 113 } 114 public void reconnect() throws IOException { 115 lock.lock(); 116 try { 117 disconnect (); 118 connect (); 119 } finally { 120 lock.unlock();; 121 } 122 } 123 public boolean isConnected() { 124 lock.lock(); 125 try { 126 return getCurrent().isConnected (); 127 } catch (IOException e) { 128 return false; 129 } finally { 130 lock.unlock(); 131 } 132 } 133 public ISOMsg receive() throws IOException, ISOException { 134 return getCurrent().receive (); 135 } 136 public void send (ISOMsg m) throws IOException, ISOException { 137 getCurrent().send (m); 138 } 139 public void send (byte[] b) throws IOException, ISOException { 140 getCurrent().send (b); 141 } 142 public void setUsable(boolean b) { 143 this.usable = b; 144 } 145 public void setName (String name) { 146 this.name = name; 147 NameRegistrar.register ("channel."+name, this); 148 } 149 public String getName() { 150 return this.name; 151 } 152 public ISOPackager getPackager () { 153 return null; 154 } 155 public void setLogger (Logger logger, String realm) { 156 this.logger = logger; 157 this.realm = realm; 158 } 159 public String getRealm () { 160 return realm; 161 } 162 public Logger getLogger() { 163 return logger; 164 } 165 public void setConfiguration (Configuration cfg) 166 throws ConfigurationException 167 { 168 this.cfg = cfg; 169 String channelName[] = cfg.getAll ("channel"); 170 for (String aChannelName : channelName) { 171 try { 172 addChannel(aChannelName); 173 } catch (NameRegistrar.NotFoundException e) { 174 throw new ConfigurationException(e); 175 } 176 } 177 } 178 /** 179 * Adds a channel to the pool. 180 * @param channel the channel to add 181 */ 182 public void addChannel (ISOChannel channel) { 183 pool.add (channel); 184 } 185 /** 186 * Adds a channel to the pool by its registered name. 187 * @param name the NameRegistrar name of the channel to add 188 * @throws NameRegistrar.NotFoundException if name not found 189 */ 190 public void addChannel (String name) 191 throws NameRegistrar.NotFoundException 192 { 193 pool.add (NameRegistrar.get ("channel."+name)); 194 } 195 /** 196 * Removes a channel from the pool. 197 * @param channel the channel to remove 198 */ 199 public void removeChannel (ISOChannel channel) { 200 pool.remove (channel); 201 } 202 /** 203 * Removes a channel from the pool by its registered name. 204 * @param name the channel name to remove 205 * @throws NameRegistrar.NotFoundException if name not found 206 */ 207 public void removeChannel (String name) throws NameRegistrar.NotFoundException { 208 pool.remove (NameRegistrar.get ("channel."+name)); 209 } 210 /** 211 * Returns the number of channels in the pool. 212 * @return channel count 213 */ 214 public int size() { 215 return pool.size(); 216 } 217 /** Returns the currently active channel, trying to connect if necessary. 218 * @return the active ISOChannel 219 * @throws IOException if no channel can be connected 220 */ 221 public ISOChannel getCurrent () throws IOException { 222 lock.lock(); 223 try { 224 if (current == null) 225 connect(); 226 else if (!usable) 227 reconnect(); 228 } finally { 229 lock.unlock(); 230 } 231 return current; 232 } 233 234 public Object clone(){ 235 try { 236 return super.clone(); 237 } catch (CloneNotSupportedException e) { 238 throw new InternalError(); 239 } 240 } 241} 242