org.jpos.q2.iso.MultiSessionChannelAdaptor.java Source code

Java tutorial

Introduction

Here is the source code for org.jpos.q2.iso.MultiSessionChannelAdaptor.java

Source

/*
 * jPOS Project [http://jpos.org]
 * Copyright (C) 2000-2016 Alejandro P. Revilla
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.jpos.q2.iso;

import org.jdom2.Element;
import org.jpos.core.ConfigurationException;
import org.jpos.iso.*;
import org.jpos.space.SpaceUtil;
import org.jpos.util.LogSource;
import org.jpos.util.Loggeable;
import org.jpos.util.NameRegistrar;

import java.io.IOException;
import java.util.Date;

/**
 * @author apr
 * @since 1.8.5
 */
@SuppressWarnings({ "unused", "unchecked" })
public class MultiSessionChannelAdaptor extends ChannelAdaptor
        implements MultiSessionChannelAdaptorMBean, Channel, Loggeable {
    int sessions = 1;
    ISOChannel[] channels;
    int roundRobinCounter = 0;

    public MultiSessionChannelAdaptor() {
        super();
        resetCounters();
    }

    public void initService() throws ConfigurationException {
        initSpaceAndQueues();
        NameRegistrar.register(getName(), this);
    }

    public void startService() {
        try {
            channels = new ISOChannel[sessions];
            for (int i = 0; i < sessions; i++) {
                ISOChannel c = initChannel();
                if (c instanceof LogSource) {
                    LogSource ls = (LogSource) c;
                    ls.setLogger(ls.getLogger(), ls.getRealm() + "-" + i);

                }
                channels[i] = c;
                if (!writeOnly)
                    new Thread(new Receiver(i), "channel-receiver-" + in + "-" + i).start();
            }
            new Thread(new Sender(), "channel-sender-" + in).start();
        } catch (Exception e) {
            getLog().warn("error starting service", e);
        }
    }

    public int getSessions() {
        return sessions;
    }

    public void setSessions(int sessions) {
        this.sessions = sessions;
    }

    @SuppressWarnings("unchecked")
    public class Sender implements Runnable {
        public Sender() {
            super();
        }

        public void run() {
            while (running()) {
                ISOChannel channel = null;
                try {
                    if (!running())
                        break;
                    if (sp.rd(ready, delay) == null)
                        continue;
                    Object o = sp.in(in, delay);
                    channel = getNextChannel(); // we want to call getNextChannel even if o is null so that
                                                // it can pull the 'ready' indicator.
                    if (o instanceof ISOMsg && channel != null) {
                        channel.send((ISOMsg) o);
                        tx++;
                    }
                } catch (ISOFilter.VetoException e) {
                    getLog().warn("channel-sender-" + in, e.getMessage());
                } catch (ISOException e) {
                    getLog().warn("channel-sender-" + in, e.getMessage());
                    if (!ignoreISOExceptions) {
                        disconnect(channel);
                    }
                    ISOUtil.sleep(1000); // slow down on errors
                } catch (Exception e) {
                    getLog().warn("channel-sender-" + in, e.getMessage());
                    disconnect(channel);
                    ISOUtil.sleep(1000);
                }
            }
            disconnectAll();
        }
    }

    @SuppressWarnings("unchecked")
    public class Receiver implements Runnable {
        int slot;
        ISOChannel channel;

        public Receiver(int slot) {
            super();
            this.channel = channels[slot];
            this.slot = slot;
        }

        public void run() {
            ISOUtil.sleep(slot * 10); // we don't want to blast a server at startup
            while (running()) {
                try {
                    if (!channel.isConnected()) {
                        connect(slot);
                        if (!channel.isConnected()) {
                            ISOUtil.sleep(delay);
                            continue;
                        }
                    }
                    ISOMsg m = channel.receive();
                    rx++;
                    lastTxn = System.currentTimeMillis();
                    if (timeout > 0)
                        sp.out(out, m, timeout);
                    else
                        sp.out(out, m);
                } catch (ISOException e) {
                    if (running()) {
                        getLog().warn("channel-receiver-" + out, e);
                        if (!ignoreISOExceptions) {
                            disconnect(channel);
                        }
                        ISOUtil.sleep(1000);
                    }
                } catch (Exception e) {
                    if (running()) {
                        getLog().warn("channel-receiver-" + out, e);
                        disconnect(channel);
                        ISOUtil.sleep(1000);
                    }
                }
            }
        }
    }

    @Override
    protected void initSpaceAndQueues() throws ConfigurationException {
        super.initSpaceAndQueues();
        Element persist = getPersist();
        String s = persist.getChildTextTrim("sessions");
        setSessions(s != null && s.length() > 0 ? Integer.parseInt(s) : 1);
    }

    private void connect(int slot) {
        ISOChannel c = channels[slot];
        if (c != null && !c.isConnected()) {
            try {
                c.connect();
                sp.put(ready, new Date());
            } catch (IOException e) {
                getLog().warn("check-connection(" + slot + ") " + c.toString(), e.getMessage());
            }
        }
    }

    private void disconnect(ISOChannel channel) {
        try {
            if (getConnectedCount() <= 1)
                SpaceUtil.wipe(sp, ready);
            channel.disconnect();
        } catch (IOException e) {
            getLog().warn("disconnect", e);
        }
    }

    private void disconnectAll() {
        for (ISOChannel channel : channels)
            disconnect(channel);
    }

    private ISOChannel getNextChannel() {
        ISOChannel c = null;
        for (int size = channels.length; size > 0; size--) {
            c = channels[roundRobinCounter++ % channels.length];
            if (c != null && c.isConnected())
                break;
        }
        if (c == null)
            SpaceUtil.wipe(sp, ready);
        return c;
    }

    private int getConnectedCount() {
        int connected = 0;
        for (ISOChannel c : channels) {
            if (c != null && c.isConnected()) {
                connected++;
            }
        }
        return connected;
    }
}