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@SuppressWarnings("unchecked")
040public class ChannelPool implements ISOChannel, LogSource, Configurable, Cloneable {
041    boolean usable = true;
042    String name = "";
043    protected Logger logger;
044    protected String realm;
045    Configuration cfg = null;
046    List pool;
047    ISOChannel current;
048    Lock lock = new ReentrantLock();
049
050    public ChannelPool () {
051        super ();
052        pool = new Vector ();
053    }
054    public void setPackager(ISOPackager p) {
055        // nothing to do
056    }
057    public void connect () throws IOException {
058        lock.lock();
059        try {
060            current = null;
061            LogEvent evt = new LogEvent (this, "connect");
062            evt.addMessage ("pool-size=" + Integer.toString (pool.size()));
063            for (int i=0; i<pool.size(); i++) {
064                try {
065                    evt.addMessage ("pool-" + Integer.toString (i));
066                    ISOChannel c = (ISOChannel) pool.get (i);
067                    c.connect ();
068                    if (c.isConnected()) {
069                        current = c;
070                        usable = true;
071                        break;
072                    }
073                } catch (IOException e) {
074                    evt.addMessage (e);
075                }
076            }
077            if (current == null)
078                evt.addMessage ("connect failed");
079            Logger.log (evt);
080            if (current == null) {
081                throw new IOException ("unable to connect");
082            }
083        } finally {
084            lock.unlock();
085        }
086    }
087    public void disconnect () throws IOException {
088        lock.lock();
089        try {
090            current = null;
091            LogEvent evt = new LogEvent (this, "disconnect");
092            for (Object aPool : pool) {
093                try {
094                    ISOChannel c = (ISOChannel) aPool;
095                    c.disconnect();
096                } catch (IOException e) {
097                    evt.addMessage(e);
098                }
099            }
100            Logger.log (evt);
101        } finally {
102            lock.unlock();
103        }
104
105    }
106    public void reconnect() throws IOException {
107        lock.lock();
108        try {
109            disconnect ();
110            connect ();
111        } finally {
112            lock.unlock();;
113        }
114    }
115    public boolean isConnected() {
116        lock.lock();
117        try {
118            return getCurrent().isConnected ();
119        } catch (IOException e) {
120            return false;
121        } finally {
122            lock.unlock();
123        }
124    }
125    public ISOMsg receive() throws IOException, ISOException {
126        return getCurrent().receive ();
127    }
128    public void send (ISOMsg m) throws IOException, ISOException {
129        getCurrent().send (m);
130    }
131    public void send (byte[] b) throws IOException, ISOException {
132        getCurrent().send (b);
133    }
134    public void setUsable(boolean b) {
135        this.usable = b;
136    }
137    public void setName (String name) {
138        this.name = name;
139        NameRegistrar.register ("channel."+name, this);
140    }
141    public String getName() {
142        return this.name;
143    }
144    public ISOPackager getPackager () {
145        return null;
146    }
147    public void setLogger (Logger logger, String realm) {
148        this.logger = logger;
149        this.realm  = realm;
150    }
151    public String getRealm () {
152        return realm;
153    }
154    public Logger getLogger() {
155        return logger;
156    }
157    public void setConfiguration (Configuration cfg)
158        throws ConfigurationException
159    {
160        this.cfg = cfg;
161        String channelName[] = cfg.getAll ("channel");
162        for (String aChannelName : channelName) {
163            try {
164                addChannel(aChannelName);
165            } catch (NameRegistrar.NotFoundException e) {
166                throw new ConfigurationException(e);
167            }
168        }
169    }
170    public void addChannel (ISOChannel channel) {
171        pool.add (channel);
172    }
173    public void addChannel (String name) 
174        throws NameRegistrar.NotFoundException
175    {
176        pool.add (NameRegistrar.get ("channel."+name));
177    }
178    public void removeChannel (ISOChannel channel) {
179        pool.remove (channel);
180    }
181    public void removeChannel (String name) throws NameRegistrar.NotFoundException {
182        pool.remove (NameRegistrar.get ("channel."+name));
183    }
184    public int size() {
185        return pool.size();
186    }
187    public ISOChannel getCurrent () throws IOException {
188        lock.lock();
189        try {
190            if (current == null)
191                connect();
192            else if (!usable)
193                reconnect();
194        } finally {
195            lock.unlock();
196        }
197        return current;
198    }
199    
200    public Object clone(){
201      try {
202        return super.clone();
203      } catch (CloneNotSupportedException e) {
204        throw new InternalError();
205      }
206    }
207}
208