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.packager; 020 021import org.jpos.iso.*; 022import org.jpos.util.LogEvent; 023import org.jpos.util.LogSource; 024import org.jpos.util.Logger; 025import org.xml.sax.Attributes; 026import org.xml.sax.InputSource; 027import org.xml.sax.SAXException; 028import org.xml.sax.XMLReader; 029import org.xml.sax.helpers.DefaultHandler; 030import org.xml.sax.helpers.XMLReaderFactory; 031 032import java.io.*; 033import java.util.Stack; 034import java.util.concurrent.locks.Lock; 035import java.util.concurrent.locks.ReentrantLock; 036 037/** 038 * packs/unpacks ISOMsgs from jPOS logs 039 * 040 * @author apr@cs.com.uy 041 * @version $Id$ 042 * @see ISOPackager 043 */ 044@SuppressWarnings("unchecked") 045public class LogPackager extends DefaultHandler 046 implements ISOPackager, LogSource 047{ 048 protected Logger logger = null; 049 protected String realm = null; 050 private ByteArrayOutputStream out; 051 private PrintStream p; 052 private XMLReader reader = null; 053 private Stack stk; 054 055 private Lock lock = new ReentrantLock(); 056 057 public static final String LOG_TAG = "log"; 058 public static final String ISOMSG_TAG = "isomsg"; 059 public static final String ISOFIELD_TAG = "field"; 060 public static final String ID_ATTR = "id"; 061 public static final String VALUE_ATTR = "value"; 062 public static final String TYPE_ATTR = "type"; 063 public static final String TYPE_BINARY = "binary"; 064 public static final String TYPE_BITMAP = "bitmap"; 065 066 public LogPackager() throws ISOException { 067 super(); 068 out = new ByteArrayOutputStream(); 069 p = new PrintStream(out); 070 stk = new Stack(); 071 try { 072 reader = XMLReaderFactory.createXMLReader( 073 System.getProperty( "sax.parser", 074 "org.apache.crimson.parser.XMLReaderImpl") 075 ); 076 reader.setFeature ("http://xml.org/sax/features/validation",false); 077 reader.setContentHandler(this); 078 reader.setErrorHandler(this); 079 } catch (Exception e) { 080 throw new ISOException (e.toString()); 081 } 082 } 083 public byte[] pack (ISOComponent c) throws ISOException { 084 LogEvent evt = new LogEvent (this, "pack"); 085 lock.lock(); 086 try { 087 if (!(c instanceof ISOMsg)) 088 throw new ISOException ("cannot pack "+c.getClass()); 089 ISOMsg m = (ISOMsg) c; 090 byte[] b; 091 p.println ("<log>"); 092 c.dump (p, " "); 093 p.println ("</log>"); 094 b = out.toByteArray(); 095 out.reset(); 096 if (logger != null) 097 evt.addMessage (m); 098 return b; 099 } catch (ISOException e) { 100 evt.addMessage (e); 101 throw e; 102 } finally { 103 Logger.log(evt); 104 lock.unlock(); 105 } 106 } 107 108 public int unpack (ISOComponent c, byte[] b) 109 throws ISOException 110 { 111 LogEvent evt = new LogEvent (this, "unpack"); 112 lock.lock(); 113 try { 114 if (!(c instanceof ISOMsg)) 115 throw new ISOException 116 ("Can't call packager on non Composite"); 117 118 while (!stk.empty()) // purge from possible previous error 119 stk.pop(); 120 121 InputSource src = new InputSource (new ByteArrayInputStream(b)); 122 reader.parse (src); 123 if (!stk.empty()) { 124 ISOMsg m = (ISOMsg) c; 125 m.merge ((ISOMsg) stk.pop()); 126 if (logger != null) 127 evt.addMessage (m); 128 } 129 } catch (ISOException e) { 130 evt.addMessage (e); 131 // throw e; 132 } catch (IOException e) { 133 evt.addMessage (e); 134 // throw new ISOException (e.toString()); 135 } catch (SAXException e) { 136 evt.addMessage (e); 137 // throw new ISOException (e.toString()); 138 } finally { 139 Logger.log (evt); 140 lock.unlock(); 141 } 142 return b.length; 143 } 144 145 public void unpack (ISOComponent c, InputStream in) 146 throws ISOException, IOException 147 { 148 LogEvent evt = new LogEvent (this, "unpack"); 149 lock.lock(); 150 try { 151 if (!(c instanceof ISOMsg)) 152 throw new ISOException 153 ("Can't call packager on non Composite"); 154 155 while (!stk.empty()) // purge from possible previous error 156 stk.pop(); 157 158 reader.parse (new InputSource (in)); 159 if (!stk.empty()) { 160 ISOMsg m = (ISOMsg) c; 161 m.merge ((ISOMsg) stk.pop()); 162 if (logger != null) 163 evt.addMessage (m); 164 } 165 } catch (ISOException e) { 166 evt.addMessage (e); 167 // throw e; 168 } catch (IOException e) { 169 evt.addMessage (e); 170 // throw new ISOException (e.toString()); 171 } catch (SAXException e) { 172 evt.addMessage (e); 173 // throw new ISOException (e.toString()); 174 } finally { 175 Logger.log (evt); 176 lock.unlock(); 177 } 178 } 179 180 public void startElement 181 (String ns, String name, String qName, Attributes atts) 182 throws SAXException 183 { 184 int fieldNumber = -1; 185 try { 186 String id = atts.getValue(ID_ATTR); 187 if (id != null) { 188 try { 189 fieldNumber = Integer.parseInt (id); 190 } catch (NumberFormatException ex) { } 191 } 192 if (name.equals (ISOMSG_TAG)) { 193 if (fieldNumber >= 0) { 194 if (stk.empty()) 195 throw new SAXException ("inner without outter"); 196 197 ISOMsg inner = new ISOMsg(fieldNumber); 198 ((ISOMsg)stk.peek()).set (inner); 199 stk.push (inner); 200 } else { 201 stk.push (new ISOMsg(0)); 202 } 203 } else if (name.equals (ISOFIELD_TAG)) { 204 ISOMsg m = (ISOMsg) stk.peek(); 205 String value = atts.getValue(VALUE_ATTR); 206 String type = atts.getValue(TYPE_ATTR); 207 if (id == null || value == null) 208 throw new SAXException ("invalid field"); 209 if (TYPE_BINARY.equals (type)) { 210 m.set (new ISOBinaryField ( 211 fieldNumber, 212 ISOUtil.hex2byte ( 213 value.getBytes(), 0, value.length()/2 214 ) 215 ) 216 ); 217 } 218 else { 219 m.set (new ISOField (fieldNumber, value)); 220 } 221 } 222 } catch (ISOException e) { 223 throw new SAXException 224 ("ISOException unpacking "+fieldNumber); 225 } 226 } 227 228 public void endElement (String ns, String name, String qname) 229 throws SAXException 230 { 231 if (name.equals (ISOMSG_TAG)) { 232 ISOMsg m = (ISOMsg) stk.pop(); 233 if (stk.empty()) 234 stk.push (m); // push outter message 235 } 236 } 237 238 public String getFieldDescription(ISOComponent m, int fldNumber) { 239 return "<notavailable/>"; 240 } 241 public String getDescription () { 242 return getClass().getName(); 243 } 244 public void setLogger (Logger logger, String realm) { 245 this.logger = logger; 246 this.realm = realm; 247 } 248 public String getRealm () { 249 return realm; 250 } 251 public Logger getLogger() { 252 return logger; 253 } 254 public ISOMsg createISOMsg() { 255 return new ISOMsg(); 256 } 257} 258