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.iso.*;
022import org.jpos.iso.packager.XMLPackager;
023
024import java.io.BufferedReader;
025import java.io.EOFException;
026import java.io.IOException;
027import java.io.InputStreamReader;
028import java.net.ServerSocket;
029import java.net.Socket;
030
031/**
032 * Implements an ISOChannel able to exchange <b>jPOS generated</b> (or
033 * compliant) XML based ISO-8583 messages through a Telnet session the telnet
034 * commands are simply ignored.
035 * 
036 * @author <a href="mailto:apr@cs.com.uy">Alejandro P. Revilla</a>
037 * @author <a href="mailto:marksalter@talktalk.net">Mark Salter</a>
038 * @version $Id: TelnetXMLChannel.java 2594 2008-01-22 16:41:31Z apr $
039 * 
040 * @see ISOMsg
041 * @see ISOException
042 * @see ISOChannel
043 */
044public class TelnetXMLChannel extends BaseChannel {
045    BufferedReader reader = null;
046
047    static final String isomsgStartTag = "<" + XMLPackager.ISOMSG_TAG + ">";
048    static final String isomsgEndTag = "</" + XMLPackager.ISOMSG_TAG + ">";
049
050    /**
051     * Public constructor (used by Class.forName("...").newInstance())
052     */
053    public TelnetXMLChannel() {
054        super();
055    }
056
057    /**
058     * Constructs client ISOChannel
059     * 
060     * @param host
061     *            server TCP Address
062     * @param port
063     *            server port number
064     * @param p
065     *            an ISOPackager
066     * @see ISOPackager
067     */
068    public TelnetXMLChannel(String host, int port, ISOPackager p) {
069        super(host, port, p);
070    }
071
072    /**
073     * Construct server ISOChannel
074     * 
075     * @param p
076     *            an ISOPackager
077     * @see ISOPackager
078     * @exception IOException
079     */
080    public TelnetXMLChannel(ISOPackager p) throws IOException {
081        super(p);
082    }
083
084    /**
085     * constructs a server ISOChannel associated with a Server Socket
086     * 
087     * @param p
088     *            an ISOPackager
089     * @param serverSocket
090     *            where to accept a connection
091     * @exception IOException
092     * @see ISOPackager
093     */
094    public TelnetXMLChannel(ISOPackager p, ServerSocket serverSocket)
095            throws IOException {
096        super(p, serverSocket);
097    }
098
099    /**
100     * @return a byte array with the received message
101     * @exception IOException
102     */
103    protected byte[] streamReceive() throws IOException {
104        int sp = 0;
105        StringBuilder sb = new StringBuilder();
106        while (reader != null) {
107            /*
108             * Throw away any telnet commands - each is 3 bytes first being
109             * x'FF'...
110             */
111            reader.mark(3); // Mark the current position in case there are no
112                            // telnet commands (FFnnmm)
113            while (reader.read() == 255) {
114                reader.skip(2);
115                reader.mark(3);
116            }
117            reader.reset(); // Return to the first byte that was *not* a telnet
118                            // command (IAC).
119
120            // Now the commands are out of the way continue with the xml stream
121            // until it closes with </isomsg>.
122            String s = reader.readLine();
123            if (s == null)
124                throw new EOFException();
125            int isomsgStart = s.indexOf(isomsgStartTag);
126            if (isomsgStart >= 0) {
127                sp++;
128                sb.append(s, isomsgStart, s.length() - isomsgStart);
129            } else {
130                int isomsgEnd = s.indexOf(isomsgEndTag);
131                if (isomsgEnd >= 0) {
132                    sb.append(s,0,isomsgEnd + isomsgEndTag.length());
133                    if (--sp <= 0)
134                        break;
135                } else {
136                    if (sp > 0)
137                        sb.append(s);
138                }
139            }
140
141        }
142        return sb.toString().getBytes();
143    }
144
145    protected int getHeaderLength() {
146        // XML Channel does not support header
147        return 0;
148    }
149
150    protected void sendMessageHeader(ISOMsg m, int len) {
151        // XML Channel does not support header
152    }
153
154    protected void connect(Socket socket) throws IOException {
155        super.connect(socket);
156        reader = new BufferedReader(new InputStreamReader(serverIn));
157    }
158
159    public void disconnect() throws IOException {
160        super.disconnect();
161        if (reader != null)
162            reader.close();
163        reader = null;
164    }
165}