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.gui;
020
021import org.jpos.iso.ISOException;
022import org.jpos.iso.ISOMsg;
023import org.jpos.iso.ISOPackager;
024import org.jpos.iso.ISOUtil;
025
026import javax.swing.*;
027import javax.swing.event.ListSelectionEvent;
028import javax.swing.event.ListSelectionListener;
029import javax.swing.table.AbstractTableModel;
030import javax.swing.table.TableModel;
031import java.awt.*;
032import java.util.Vector;
033
034/**
035 * Called from ISOChannelPanel when you click on it's ISOMeter.
036 * It enable field and header visualization by means of visual
037 * components such as JTable
038 *
039 * @see ISOChannelPanel
040 * @see ISORequestListenerPanel
041 */
042@SuppressWarnings({"unchecked", "deprecation"})
043public class ISOMsgPanel extends JPanel {
044
045    private static final long serialVersionUID = 7779880613544725704L;
046    /**
047     * Message currently displayed by the panel.
048     *
049     * @serial serialized message snapshot
050     */
051    ISOMsg m;
052    /**
053     * Ordered collection of populated field numbers.
054     *
055     * @serial field-number list used by the table model
056     */
057    Vector validFields;
058    /** Constructs a panel for the given message.
059     * @param m        the ISO message to display
060     * @param withDump if true, include a hex dump
061     */
062    public ISOMsgPanel(ISOMsg m, boolean withDump) {
063        super();
064        this.m = m;
065        setLayout(new BorderLayout());
066        setBorder(BorderFactory.createRaisedBevelBorder());
067        setValidFields();
068        add(createISOMsgTable(), BorderLayout.CENTER);
069        if (withDump)
070            add(createISOMsgDumpPanel(), BorderLayout.SOUTH);
071    }
072    /** Constructs a panel for the given message.
073     * @param m the ISO message to display
074     */
075    public ISOMsgPanel(ISOMsg m) {
076        this(m, false);
077    }
078    private void setValidFields() {
079        validFields = new Vector();
080        for (int i=0; i<=m.getMaxField(); i++)
081            if (m.hasField(i))
082                validFields.addElement(i);
083    }
084    private JComponent createISOMsgTable() {
085        TableModel dataModel = new AbstractTableModel() {
086
087            private static final long serialVersionUID = 8917029825751856951L;
088
089            @Override
090            public int getColumnCount() {
091                return 3;
092            }
093
094            @Override
095            public int getRowCount() {
096                return validFields.size();
097            }
098
099            @Override
100            public String getColumnName(int columnIndex) {
101                switch (columnIndex) {
102                    case 0 :
103                        return "#";
104                    case 1 :
105                        return "Content";
106                    case 2 :
107                        return "Description";
108                    default:
109                        return "";
110                }
111            }
112
113            @Override
114            public Object getValueAt(int row, int col) {
115                switch (col) {
116                    case 0 :
117                        return validFields.elementAt(row);
118                    case 1 :
119                        int index = (Integer) validFields.elementAt(row);
120
121                        Object obj = m.getValue(index);
122                        if (obj instanceof String) {
123                            String s = obj.toString();
124                            switch (index) {
125                                case 2 :
126                                case 35:
127                                case 45:
128                                    s = ISOUtil.protect(s);
129                                    break;
130                                case 14:
131                                    s = "----";
132                            }
133                            return s;
134                        }
135                        else if (obj instanceof byte[])
136                            return ISOUtil.hexString((byte[]) obj);
137                        else if (obj instanceof ISOMsg)
138                            return "<ISOMsg>";
139                        break;
140                    case 2 :
141                        int i = (Integer) validFields.elementAt(row);
142                        ISOPackager p = m.getPackager();
143                        return p.getFieldDescription(m,i);
144                }
145                return "<???>";
146            }
147        };
148        JTable table = new JTable(dataModel);
149        table.getColumnModel().getColumn(0).setPreferredWidth(10);
150        table.setPreferredScrollableViewportSize(
151            new Dimension (500,table.getRowCount()*table.getRowHeight()));
152        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
153
154        ListSelectionModel rowSM = table.getSelectionModel();
155        rowSM.addListSelectionListener(new ListSelectionListener() {
156            public void valueChanged(ListSelectionEvent e) {
157                if (e.getValueIsAdjusting())
158                    return;
159
160                ListSelectionModel lsm =
161                    (ListSelectionModel)e.getSource();
162                if (!lsm.isSelectionEmpty()) {
163                    int selectedRow = lsm.getMinSelectionIndex();
164                    int index = (Integer)
165                            validFields.elementAt(selectedRow);
166
167                    Object obj = m.getValue(index);
168                    if (obj instanceof ISOMsg) {
169                        ISOMsg sm = (ISOMsg) obj;
170                        JFrame f = new JFrame("ISOMsg field "+index);
171                        ISOMsgPanel p = new ISOMsgPanel(sm, false);
172                        f.getContentPane().add(p);
173                        f.pack();
174                        f.show();
175                    }
176                }
177            }
178        });
179
180        return new JScrollPane(table);
181    }
182    JComponent createISOMsgDumpPanel() {
183        JPanel p = new JPanel();
184        JTextArea t = new JTextArea(3,20);
185
186        p.setLayout(new BorderLayout());
187        p.setBackground(Color.white);
188        p.setBorder(BorderFactory.createLoweredBevelBorder());
189        p.add(new JLabel("Dump", SwingConstants.LEFT),
190            BorderLayout.NORTH);
191        t.setFont(new Font ("Helvetica", Font.PLAIN, 8));
192        t.setLineWrap(true);
193        try {
194            StringBuilder buf = new StringBuilder();
195            if (m.getHeader() != null) {
196                buf.append("--[Header]--\n");
197                buf.append(ISOUtil.hexString(m.getHeader()));
198                buf.append("\n--[Msg]--\n");
199            }
200            byte[] b = m.pack();
201            buf.append (ISOUtil.hexString(b));
202            t.setText(buf.toString());
203        } catch (ISOException e) {
204            t.setText(e.toString());
205            t.setForeground(Color.red);
206        }
207        p.add(t, BorderLayout.CENTER);
208        return p;
209    }
210}