📄 isomsg.java
字号:
/* * jPOS Project [http://jpos.org] * Copyright (C) 2000-2008 Alejandro P. Revilla * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */package org.jpos.iso;import java.io.Externalizable;import java.io.IOException;import java.io.InputStream;import java.io.ObjectInput;import java.io.ObjectOutput;import java.io.PrintStream;import java.lang.ref.WeakReference;import java.util.BitSet;import java.util.Enumeration;import java.util.Hashtable;import java.util.StringTokenizer;import org.jpos.iso.header.BaseHeader;import org.jpos.iso.packager.XMLPackager;import org.jpos.util.Loggeable;/** * implements <b>Composite</b> * whithin a <b>Composite pattern</b> * * @author apr@cs.com.uy * @version $Id: ISOMsg.java 2599 2008-01-28 03:38:34Z apr $ * @see ISOComponent * @see ISOField */public class ISOMsg extends ISOComponent implements Cloneable, Loggeable, Externalizable{ protected Hashtable fields; protected int maxField; protected ISOPackager packager; protected boolean dirty, maxFieldDirty; protected int direction; protected ISOHeader header; protected int fieldNumber = -1; public static final int INCOMING = 1; public static final int OUTGOING = 2; private static final long serialVersionUID = 4306251831901413975L; private WeakReference sourceRef; /** * Creates an ISOMsg */ public ISOMsg () { fields = new Hashtable (); maxField = -1; dirty = true; maxFieldDirty=true; direction = 0; header = null; } /** * Creates a nested ISOMsg */ public ISOMsg (int fieldNumber) { this(); setFieldNumber (fieldNumber); } /** * changes this Component field number<br> * Use with care, this method does not change * any reference held by a Composite. * @param fieldNumber new field number */ public void setFieldNumber (int fieldNumber) { this.fieldNumber = fieldNumber; } /** * Creates an ISOMsg with given mti * @param mti Msg's MTI */ public ISOMsg (String mti) { this(); try { setMTI (mti); } catch (ISOException e) { // should never happen } } /** * Sets the direction information related to this message * @param direction can be either ISOMsg.INCOMING or ISOMsg.OUTGOING */ public void setDirection(int direction) { this.direction = direction; } /** * Sets an optional message header image * @param b header image */ public void setHeader(byte[] b) { header = new BaseHeader (b); } public void setHeader (ISOHeader header) { this.header = header; } /** * get optional message header image * @return message header image (may be null) */ public byte[] getHeader() { return (header != null) ? header.pack() : null; } /** * Return this messages ISOHeader */ public ISOHeader getISOHeader() { return header; } /** * @return the direction (ISOMsg.INCOMING or ISOMsg.OUTGOING) * @see ISOChannel */ public int getDirection() { return direction; } /** * @return true if this message is an incoming message * @see ISOChannel */ public boolean isIncoming() { return direction == INCOMING; } /** * @return true if this message is an outgoing message * @see ISOChannel */ public boolean isOutgoing() { return direction == OUTGOING; } /** * @return the max field number associated with this message */ public int getMaxField() { if (maxFieldDirty) recalcMaxField(); return maxField; } private void recalcMaxField() { maxField = 0; for (Enumeration e = fields.keys(); e.hasMoreElements(); ) { Object obj = e.nextElement(); if (obj instanceof Integer) maxField = Math.max (maxField, ((Integer)obj).intValue()); } maxFieldDirty = false; } /** * @param p - a peer packager */ public void setPackager (ISOPackager p) { packager = p; } /** * @return the peer packager */ public ISOPackager getPackager () { return packager; } /** * Set a field within this message * @param c - a component */ public void set (ISOComponent c) throws ISOException { Integer i = (Integer) c.getKey(); fields.put (i, c); if (i.intValue() > maxField) maxField = i.intValue(); dirty = true; } /** * Creates an ISOField associated with fldno within this ISOMsg * @param fldno field number * @param value field value */ public void set(int fldno, String value) throws ISOException { if (value != null) { if (!(packager instanceof ISOBasePackager)) { // No packager is available, we can't tell what the field // might be, so treat as a String! set(new ISOField(fldno, value)); } else { // This ISOMsg has a packager, so use it Object obj = ((ISOBasePackager) packager).getFieldPackager(fldno); if (obj instanceof ISOBinaryFieldPackager) { set(new ISOBinaryField(fldno, ISOUtil.hex2byte(value))); } else { set(new ISOField(fldno, value)); } } } else unset(fldno); } /** * Creates an ISOField associated with fldno within this ISOMsg * @param fpath dot-separated field path (i.e. 63.2) * @param value field value */ public void set (String fpath, String value) throws ISOException { StringTokenizer st = new StringTokenizer (fpath, "."); ISOMsg m = this; for (;;) { int fldno = Integer.parseInt(st.nextToken()); if (st.hasMoreTokens()) { Object obj = m.getValue(fldno); if (obj instanceof ISOMsg) m = (ISOMsg) obj; else m.set (m = new ISOMsg (fldno)); } else { m.set (fldno, value); break; } } } /** * Creates an ISOField associated with fldno within this ISOMsg * @param fpath dot-separated field path (i.e. 63.2) * @param value binary field value */ public void set (String fpath, byte[] value) throws ISOException { StringTokenizer st = new StringTokenizer (fpath, "."); ISOMsg m = this; for (;;) { int fldno = Integer.parseInt(st.nextToken()); if (st.hasMoreTokens()) { Object obj = m.getValue(fldno); if (obj instanceof ISOMsg) m = (ISOMsg) obj; else m.set (m = new ISOMsg (fldno)); } else { m.set (fldno, value); break; } } } /** * Creates an ISOBinaryField associated with fldno within this ISOMsg * @param fldno field number * @param value field value */ public void set (int fldno, byte[] value) throws ISOException { if (value != null) set (new ISOBinaryField (fldno, value)); else unset (fldno); } /** * Unset a field if it exists, otherwise ignore. * @param fldno - the field number */ public void unset (int fldno) { if (fields.remove (new Integer (fldno)) != null) dirty = maxFieldDirty = true; } /** * Unsets several fields at once * @param flds - array of fields to be unset from this ISOMsg */ public void unset (int[] flds) { for (int i=0; i<flds.length; i++) unset (flds[i]); } /** * In order to interchange <b>Composites</b> and <b>Leafs</b> we use * getComposite(). A <b>Composite component</b> returns itself and * a Leaf returns null. * * @return ISOComponent */ public ISOComponent getComposite() { return this; } /** * setup BitMap * @exception ISOException */ public void recalcBitMap () throws ISOException { if (!dirty) return; BitSet bmap = new BitSet (((getMaxField()+62)>>6)<<6); for (int i=1; i<=maxField; i++) if (((ISOComponent) fields.get (new Integer (i))) != null) bmap.set (i); set (new ISOBitMap (-1, bmap)); dirty = false; } /** * clone fields */ public Hashtable getChildren() { return (Hashtable) fields.clone(); } /** * pack the message with the current packager * @return the packed message * @exception ISOException */ public byte[] pack() throws ISOException { synchronized (this) { recalcBitMap(); return packager.pack(this); } } /** * unpack a message * @param b - raw message * @return consumed bytes * @exception ISOException */ public int unpack(byte[] b) throws ISOException { synchronized (this) { return packager.unpack(this, b); } } public void unpack (InputStream in) throws IOException, ISOException { synchronized (this) { packager.unpack(this, in); } } /** * dump the message to a PrintStream. The output is sorta * XML, intended to be easily parsed. * <br> * Each component is responsible for its own dump function, * ISOMsg just calls dump on every valid field. * @param p - print stream * @param indent - optional indent string */ public void dump (PrintStream p, String indent) { ISOComponent c; p.print (indent + "<" + XMLPackager.ISOMSG_TAG); switch (direction) { case INCOMING: p.print (" direction=\"incoming\""); break; case OUTGOING: p.print (" direction=\"outgoing\""); break; } if (fieldNumber != -1) p.print (" "+XMLPackager.ID_ATTR +"=\""+fieldNumber +"\""); p.println (">"); String newIndent = indent + " "; if (header instanceof Loggeable) ((Loggeable) header).dump (p, newIndent); for (int i=0; i<=maxField; i++) { if ((c = (ISOComponent) fields.get (new Integer (i))) != null) c.dump (p, newIndent); // // Uncomment to include bitmaps within logs // // if (i == 0) { // if ((c = (ISOComponent) fields.get (new Integer (-1))) != null) // c.dump (p, newIndent); // } // } p.println (indent + "</" + XMLPackager.ISOMSG_TAG+">"); } /** * get the component associated with the given field number * @param fldno the Field Number * @return the Component */ public ISOComponent getComponent(int fldno) { return (ISOComponent) fields.get(new Integer(fldno)); } /** * Return the object value associated with the given field number * @param fldno the Field Number * @return the field Object */ public Object getValue(int fldno) throws ISOException { ISOComponent c = getComponent(fldno); return c != null ? c.getValue() : null; } /** * Return the object value associated with the given field path * @param fpath field path * @return the field Object (may be null) */ public Object getValue (String fpath) throws ISOException { StringTokenizer st = new StringTokenizer (fpath, "."); ISOMsg m = this; Object obj = null; for (;;) { int fldno = Integer.parseInt(st.nextToken()); obj = m.getValue (fldno); if (st.hasMoreTokens()) { if (obj instanceof ISOMsg) { m = (ISOMsg) obj; } else throw new ISOException ("Invalid path '" + fpath + "'"); } else break; } return obj; } /** * Return the String value associated with the given ISOField number
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -