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 © 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 on I/O failure 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 on I/O failure 077 * @see ISOPackager 078 */ 079 public ASCIIChannel (ISOPackager p, ServerSocket serverSocket) 080 throws IOException 081 { 082 super(p, serverSocket); 083 } 084 085 086 /** Sets the number of ASCII digits used for the message length prefix. 087 * @param len number of length digits 088 */ 089 public void setLengthDigits(int len) { lengthDigits= len; } 090 /** Returns the number of ASCII digits used for the message length prefix. 091 * @return number of length digits 092 */ 093 public int getLengthDigits() { return lengthDigits; } 094 095 096 /** 097 * @param len the packed Message len 098 * @exception IOException on I/O failure 099 */ 100 protected void sendMessageLength(int len) throws IOException { 101 int maxLen= ten.pow(lengthDigits).intValue() - 1; // 10^lengthDigits - 1 102 103 if (len > maxLen) 104 throw new IOException ("len exceeded ("+len+" > "+maxLen+")"); 105 else if (len < 0) 106 throw new IOException ("invalid negative length ("+len+")"); 107 serverOut.write(ISOUtil.zeropad(len, lengthDigits).getBytes()); 108 } 109 /** 110 * @return the Message len 111 * @exception IOException on I/O failure 112 * @exception ISOException on ISO packing/unpacking failure 113 */ 114 protected int getMessageLength() throws IOException, ISOException { 115 int l = 0; 116 byte[] b = new byte[lengthDigits]; 117 while (l == 0) { 118 serverIn.readFully(b, 0, lengthDigits); 119 try { 120 if ((l=Integer.parseInt(new String(b))) == 0 && 121 isExpectKeepAlive()) { 122 123 serverOutLock.lock(); 124 try { 125 serverOut.write(b); 126 serverOut.flush(); 127 } finally { 128 serverOutLock.unlock(); 129 } 130 } 131 } catch (NumberFormatException e) { 132 throw new ISOException ("Invalid message length "+new String(b)); 133 } 134 } 135 return l; 136 } 137 138 139 /** 140 * 141 * Calls super.setConfiguration() and then reads the 'length-digits' property, 142 * defaulting to 4 143 * 144 * @param cfg Configuration 145 * @throws ConfigurationException if the configuration is invalid 146 */ 147 @Override 148 public void setConfiguration (Configuration cfg) throws ConfigurationException 149 { 150 super.setConfiguration(cfg); 151 setLengthDigits(cfg.getInt("length-digits", 4)); 152 } 153} 154