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; 020 021import java.io.EOFException; 022import java.io.IOException; 023import java.io.InputStream; 024import java.io.ObjectOutput; 025 026/** 027 * base class for the various IF*.java Field Packagers 028 * Implements "FlyWeight" pattern 029 * 030 * @author apr@cs.com.uy 031 * @version $Id$ 032 * 033 * @see IFA_AMOUNT 034 * @see IFA_BINARY 035 * @see IFA_BITMAP 036 * @see IFA_FLLCHAR 037 * @see IFA_FLLNUM 038 * @see IFA_LLCHAR 039 * @see IFA_LLLBINARY 040 * @see IFA_LLLCHAR 041 * @see IFA_LLLNUM 042 * @see IFA_LLNUM 043 * @see IFA_NUMERIC 044 * @see IFB_AMOUNT 045 * @see IFB_BINARY 046 * @see IFB_BITMAP 047 * @see IFB_LLBINARY 048 * @see IFB_LLCHAR 049 * @see IFB_LLHBINARY 050 * @see IFB_LLHCHAR 051 * @see IFB_LLHECHAR 052 * @see IFB_LLHNUM 053 * @see IFB_LLLBINARY 054 * @see IFB_LLLCHAR 055 * @see IFB_LLLNUM 056 * @see IFB_LLNUM 057 * @see IFB_NUMERIC 058 * @see IF_CHAR 059 */ 060public abstract class ISOFieldPackager { 061 private int len; 062 private String description; 063 /** When {@code true}, values are padded to the field length. */ 064 protected boolean pad; 065 /** When {@code true}, values are trimmed before packing. */ 066 protected boolean trim; 067 068 /** 069 * Default Constructor 070 */ 071 public ISOFieldPackager() 072 { 073 this.len = -1; 074 this.description = null; 075 } 076 077 /** 078 * Creates an ISOFieldPackager with the given length and description. 079 * @param len - field Len 080 * @param description - details 081 */ 082 public ISOFieldPackager(int len, String description) { 083 this.len = len; 084 this.description = description; 085 } 086 /** 087 * Returns the field description. 088 * @return field description 089 */ 090 public String getDescription() { 091 return description; 092 } 093 /** 094 * Sets the field description. 095 * @param description the description text 096 */ 097 public void setDescription(String description) { 098 this.description = description; 099 } 100 /** 101 * Returns the maximum field length. 102 * @return max field length 103 */ 104 public int getLength() { 105 return len; 106 } 107 /** 108 * Sets the maximum field length. 109 * @param len the maximum length 110 */ 111 public void setLength(int len) { 112 this.len = len; 113 } 114 115 /** 116 * Enables or disables padding for this field. 117 * @param pad true to enable padding 118 */ 119 public void setPad(boolean pad) { 120 this.pad = pad; 121 } 122 123 /** 124 * Enables or disables trimming for this field. 125 * @param trim true to enable trimming 126 */ 127 public void setTrim(boolean trim) { 128 this.trim = trim; 129 } 130 131 /** 132 * Returns the maximum number of bytes this packager can produce. 133 * @return maximum packed length in bytes 134 */ 135 public abstract int getMaxPackedLength(); 136 137 /** 138 * Creates an {@link ISOComponent} instance appropriate for this packager. 139 * @param fieldNumber the field number to assign to the new component 140 * @return a new ISOComponent 141 */ 142 public ISOComponent createComponent(int fieldNumber) { 143 return new ISOField (fieldNumber); 144 } 145 /** 146 * Packs the given component into a byte array. 147 * @param c - a component 148 * @return packed component 149 * @exception ISOException on packing error 150 */ 151 public abstract byte[] pack (ISOComponent c) throws ISOException; 152 153 /** 154 * Unpacks a field from the binary image into the given component. 155 * @param c - the Component to unpack 156 * @param b - binary image 157 * @param offset - starting offset within the binary image 158 * @return consumed bytes 159 * @exception ISOException on unpacking error 160 */ 161 public abstract int unpack (ISOComponent c, byte[] b, int offset) 162 throws ISOException; 163 164 /** 165 * Unpacks a field from an input stream into the given component. 166 * @param c - the Component to unpack 167 * @param in - input stream 168 * @throws IOException on I/O failure 169 * @throws ISOException on unpacking error 170 */ 171 public void unpack (ISOComponent c, InputStream in) 172 throws IOException, ISOException 173 { 174 unpack (c, readBytes (in, getMaxPackedLength ()), 0); 175 } 176 /** 177 * Packs the component to an ObjectOutput stream. 178 * @param c - the Component to pack 179 * @param out - output stream 180 * @throws ISOException on packing error 181 * @throws IOException on I/O failure 182 */ 183 public void pack (ISOComponent c, ObjectOutput out) 184 throws IOException, ISOException 185 { 186 out.write (pack (c)); 187 } 188 189 /** 190 * Reads exactly {@code l} bytes from the input stream. 191 * @param in the input stream 192 * @param l the number of bytes to read 193 * @return byte array of length {@code l} 194 * @throws IOException on I/O failure or premature end of stream 195 */ 196 protected byte[] readBytes (InputStream in, int l) throws IOException { 197 byte[] b = new byte [l]; 198 int n = 0; 199 while (n < l) { 200 int count = in.read(b, n, l - n); 201 if (count < 0) 202 throw new EOFException(); 203 n += count; 204 } 205 return b; 206 } 207} 208