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.core.Configuration;
023import org.jpos.core.ConfigurationException;
024
025import java.io.IOException;
026import java.net.ServerSocket;
027import java.math.BigInteger;
028
029/**
030 * ISOChannel implementation suitable for OASIS Ltd &copy; hosts<br>
031 * Message length header: n ASCII digits, configurable by setLengthDigits() (default: 4)
032 * or the 'length-digits' Configuration property.
033 *
034 * @author apr@cs.com.uy
035 * @version $Id$
036 * @see ISOMsg
037 * @see ISOException
038 * @see ISOChannel
039 */
040public class ASCIIChannel extends BaseChannel {
041
042    /** Number of digits for the message length header */
043    protected int lengthDigits= 4;                                      // 4 is default
044
045    private static final BigInteger ten= BigInteger.valueOf(10L);     // just a static 10
046
047    /**
048     * Public constructor (used by Class.forName("...").newInstance())
049     */
050    public ASCIIChannel () {
051        super();
052    }
053    /**
054     * Construct client ISOChannel
055     * @param host  server TCP Address
056     * @param port  server port number
057     * @param p     an ISOPackager
058     * @see ISOPackager
059     */
060    public ASCIIChannel (String host, int port, ISOPackager p) {
061        super(host, port, p);
062    }
063    /**
064     * Construct server ISOChannel
065     * @param p     an ISOPackager
066     * @exception IOException
067     * @see ISOPackager
068     */
069    public ASCIIChannel (ISOPackager p) throws IOException {
070        super(p);
071    }
072    /**
073     * constructs a server ISOChannel associated with a Server Socket
074     * @param p     an ISOPackager
075     * @param serverSocket where to accept a connection
076     * @exception IOException
077     * @see ISOPackager
078     */
079    public ASCIIChannel (ISOPackager p, ServerSocket serverSocket)
080        throws IOException
081    {
082        super(p, serverSocket);
083    }
084
085
086    public void setLengthDigits(int len) { lengthDigits= len; }
087    public int getLengthDigits() { return lengthDigits; }
088
089
090    /**
091     * @param len the packed Message len
092     * @exception IOException
093     */
094    protected void sendMessageLength(int len) throws IOException {
095        int maxLen= ten.pow(lengthDigits).intValue() - 1;       // 10^lengthDigits - 1
096
097        if (len > maxLen)
098            throw new IOException ("len exceeded ("+len+" > "+maxLen+")");
099        else if (len < 0)
100            throw new IOException ("invalid negative length ("+len+")");
101        serverOut.write(ISOUtil.zeropad(len, lengthDigits).getBytes());
102    }
103    /**
104     * @return the Message len
105     * @exception IOException, ISOException
106     */
107    protected int getMessageLength() throws IOException, ISOException {
108        int l = 0;
109        byte[] b = new byte[lengthDigits];
110        while (l == 0) {
111            serverIn.readFully(b, 0, lengthDigits);
112            try {
113                if ((l=Integer.parseInt(new String(b))) == 0 &&
114                    isExpectKeepAlive()) {
115
116                    serverOutLock.lock();
117                    try {
118                        serverOut.write(b);
119                        serverOut.flush();
120                    } finally {
121                        serverOutLock.unlock();
122                    }
123                }
124            } catch (NumberFormatException e) {
125                throw new ISOException ("Invalid message length "+new String(b));
126            }
127        }
128        return l;
129    }
130
131
132    /**
133     *
134     * Calls super.setConfiguration() and then reads the 'length-digits' property,
135     * defaulting to 4
136     *
137     * @param cfg Configuration
138     * @throws ConfigurationException
139     */
140    @Override
141    public void setConfiguration (Configuration cfg) throws ConfigurationException
142    {
143        super.setConfiguration(cfg);
144        setLengthDigits(cfg.getInt("length-digits", 4));
145    }
146}
147