    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 *  Unless required by applicable law or agreed to in writing, software
    012 *  distributed under the License is distributed on an "AS IS" BASIS,
    013 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 *  See the License for the specific language governing permissions and
    015 *  limitations under the License.
    016 *
    017 */
    018package org.apache.bcel.verifier;
    019
    020import java.awt.AWTEvent;
    021import java.awt.CardLayout;
    022import java.awt.Color;
    023import java.awt.Dimension;
    024import java.awt.GridLayout;
    025import java.awt.event.ActionEvent;
    026import java.awt.event.InputEvent;
    027import java.awt.event.WindowEvent;
    028import java.util.Arrays;
    029
    030import javax.swing.BorderFactory;
    031import javax.swing.JFrame;
    032import javax.swing.JList;
    033import javax.swing.JMenu;
    034import javax.swing.JMenuBar;
    035import javax.swing.JMenuItem;
    036import javax.swing.JOptionPane;
    037import javax.swing.JPanel;
    038import javax.swing.JScrollPane;
    039import javax.swing.JSplitPane;
    040import javax.swing.JTextPane;
    041import javax.swing.ListSelectionModel;
    042import javax.swing.event.ListSelectionEvent;
    043
    044import org.apache.bcel.Repository;
    045import org.apache.bcel.classfile.JavaClass;
    046import org.apache.commons.lang3.ArrayUtils;
    047
    048/**
    049 * This class implements a machine-generated frame for use with the GraphicalVerfifier.
    050 *
    051 * @see GraphicalVerifier
    052 */
    053public class VerifierAppFrame extends JFrame {
    054
    055    private static final long serialVersionUID = -542458133073307640L;
    056    private static final String JUSTICE_VERSION = "JustIce by Enver Haase";
    057
    058    private JPanel contentPane;
    059    private final JSplitPane jSplitPane1 = new JSplitPane();
    060    private final JPanel jPanel1 = new JPanel();
    061    private final JPanel jPanel2 = new JPanel();
    062    private final JSplitPane jSplitPane2 = new JSplitPane();
    063    private final JPanel jPanel3 = new JPanel();
    064    private final JList<String> classNamesJList = new JList<>();
    065    private final GridLayout gridLayout1 = new GridLayout();
    066    private final JPanel messagesPanel = new JPanel();
    067    private final GridLayout gridLayout2 = new GridLayout();
    068    private final JMenuBar jMenuBar1 = new JMenuBar();
    069    private final JMenu jMenu1 = new JMenu();
    070    private final JScrollPane jScrollPane1 = new JScrollPane();
    071    private final JScrollPane messagesScrollPane = new JScrollPane();
    072    private final JScrollPane jScrollPane3 = new JScrollPane();
    073    private final GridLayout gridLayout4 = new GridLayout();
    074    private final JScrollPane jScrollPane4 = new JScrollPane();
    075    private final CardLayout cardLayout1 = new CardLayout();
    076    private String current_class;
    077    private final GridLayout gridLayout3 = new GridLayout();
    078    private final JTextPane pass1TextPane = new JTextPane();
    079    private final JTextPane pass2TextPane = new JTextPane();
    080    private final JTextPane messagesTextPane = new JTextPane();
    081    private final JMenuItem newFileMenuItem = new JMenuItem();
    082    private final JSplitPane jSplitPane3 = new JSplitPane();
    083    private final JSplitPane jSplitPane4 = new JSplitPane();
    084    private final JScrollPane jScrollPane2 = new JScrollPane();
    085    private final JScrollPane jScrollPane5 = new JScrollPane();
    086    private final JScrollPane jScrollPane6 = new JScrollPane();
    087    private final JScrollPane jScrollPane7 = new JScrollPane();
    088    private final JList<String> pass3aJList = new JList<>();
    089    private final JList<String> pass3bJList = new JList<>();
    090    private final JTextPane pass3aTextPane = new JTextPane();
    091    private final JTextPane pass3bTextPane = new JTextPane();
    092    private final JMenu jMenu2 = new JMenu();
    093    private final JMenuItem whatisMenuItem = new JMenuItem();
    094    private final JMenuItem aboutMenuItem = new JMenuItem();
    095
    096    /** Constructor. */
    097    public VerifierAppFrame() {
    098        enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    099        try {
    100            jbInit();
    101        } catch (final Exception e) {
    102            e.printStackTrace();
    103        }
    104    }
    105
    106    void aboutMenuItem_actionPerformed(final ActionEvent e) {
    107        JOptionPane.showMessageDialog(this,
    108            "JustIce is a Java class file verifier.\n" + "It was implemented by Enver Haase in 2001, 2002.\n<https://commons.apache.org/bcel/>",
    109            JUSTICE_VERSION, JOptionPane.INFORMATION_MESSAGE);
    110    }
    111
    112    synchronized void classNamesJList_valueChanged(final ListSelectionEvent e) {
    113        if (e.getValueIsAdjusting()) {
    114            return;
    115        }
    116        current_class = classNamesJList.getSelectedValue();
    117        try {
    118            verify();
    119        } catch (final ClassNotFoundException ex) {
    120            // FIXME: report the error using the GUI
    121            ex.printStackTrace();
    122        }
    123        classNamesJList.setSelectedValue(current_class, true);
    124    }
    125
    126    /**
    127     * @return the classNamesJList
    128     */
    129    JList<String> getClassNamesJList() {
    130        return classNamesJList;
    131    }
    132
    133    /** Initizalization of the components. */
    134    private void jbInit() {
    135        // setIconImage(Toolkit.getDefaultToolkit().createImage(Frame1.class.getResource("[Ihr Symbol]")));
    136        contentPane = (JPanel) this.getContentPane();
    137        contentPane.setLayout(cardLayout1);
    138        this.setJMenuBar(jMenuBar1);
    139        this.setSize(new Dimension(708, 451));
    140        this.setTitle("JustIce");
    141        jPanel1.setMinimumSize(new Dimension(100, 100));
    142        jPanel1.setPreferredSize(new Dimension(100, 100));
    143        jPanel1.setLayout(gridLayout1);
    144        jSplitPane2.setOrientation(JSplitPane.VERTICAL_SPLIT);
    145        jPanel2.setLayout(gridLayout2);
    146        jPanel3.setMinimumSize(new Dimension(200, 100));
    147        jPanel3.setPreferredSize(new Dimension(400, 400));
    148        jPanel3.setLayout(gridLayout4);
    149        messagesPanel.setMinimumSize(new Dimension(100, 100));
    150        messagesPanel.setLayout(gridLayout3);
    151        jPanel2.setMinimumSize(new Dimension(200, 100));
    152        jMenu1.setText("File");
    153        jScrollPane1.getViewport().setBackground(Color.red);
    154        messagesScrollPane.getViewport().setBackground(Color.red);
    155        messagesScrollPane.setPreferredSize(new Dimension(10, 10));
    156        classNamesJList.addListSelectionListener(this::classNamesJList_valueChanged);
    157        classNamesJList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    158        jScrollPane3.setBorder(BorderFactory.createLineBorder(Color.black));
    159        jScrollPane3.setPreferredSize(new Dimension(100, 100));
    160        gridLayout4.setRows(4);
    161        gridLayout4.setColumns(1);
    162        gridLayout4.setHgap(1);
    163        jScrollPane4.setBorder(BorderFactory.createLineBorder(Color.black));
    164        jScrollPane4.setPreferredSize(new Dimension(100, 100));
    165        pass1TextPane.setBorder(BorderFactory.createRaisedBevelBorder());
    166        pass1TextPane.setToolTipText("");
    167        pass1TextPane.setEditable(false);
    168        pass2TextPane.setBorder(BorderFactory.createRaisedBevelBorder());
    169        pass2TextPane.setEditable(false);
    170        messagesTextPane.setBorder(BorderFactory.createRaisedBevelBorder());
    171        messagesTextPane.setEditable(false);
    172        newFileMenuItem.setText("New...");
    173        newFileMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(78, InputEvent.CTRL_MASK, true));
    174        newFileMenuItem.addActionListener(this::newFileMenuItem_actionPerformed);
    175        pass3aTextPane.setEditable(false);
    176        pass3bTextPane.setEditable(false);
    177        pass3aJList.addListSelectionListener(this::pass3aJList_valueChanged);
    178        pass3bJList.addListSelectionListener(this::pass3bJList_valueChanged);
    179        jMenu2.setText("Help");
    180        whatisMenuItem.setText("What is...");
    181        whatisMenuItem.addActionListener(this::whatisMenuItem_actionPerformed);
    182        aboutMenuItem.setText("About");
    183        aboutMenuItem.addActionListener(this::aboutMenuItem_actionPerformed);
    184        jSplitPane2.add(messagesPanel, JSplitPane.BOTTOM);
    185        messagesPanel.add(messagesScrollPane, null);
    186        messagesScrollPane.getViewport().add(messagesTextPane, null);
    187        jSplitPane2.add(jPanel3, JSplitPane.TOP);
    188        jPanel3.add(jScrollPane3, null);
    189        jScrollPane3.getViewport().add(pass1TextPane, null);
    190        jPanel3.add(jScrollPane4, null);
    191        jPanel3.add(jSplitPane3, null);
    192        jSplitPane3.add(jScrollPane2, JSplitPane.LEFT);
    193        jScrollPane2.getViewport().add(pass3aJList, null);
    194        jSplitPane3.add(jScrollPane5, JSplitPane.RIGHT);
    195        jScrollPane5.getViewport().add(pass3aTextPane, null);
    196        jPanel3.add(jSplitPane4, null);
    197        jSplitPane4.add(jScrollPane6, JSplitPane.LEFT);
    198        jScrollPane6.getViewport().add(pass3bJList, null);
    199        jSplitPane4.add(jScrollPane7, JSplitPane.RIGHT);
    200        jScrollPane7.getViewport().add(pass3bTextPane, null);
    201        jScrollPane4.getViewport().add(pass2TextPane, null);
    202        jSplitPane1.add(jPanel2, JSplitPane.TOP);
    203        jPanel2.add(jScrollPane1, null);
    204        jSplitPane1.add(jPanel1, JSplitPane.BOTTOM);
    205        jPanel1.add(jSplitPane2, null);
    206        jScrollPane1.getViewport().add(classNamesJList, null);
    207        jMenuBar1.add(jMenu1);
    208        jMenuBar1.add(jMenu2);
    209        contentPane.add(jSplitPane1, "jSplitPane1");
    210        jMenu1.add(newFileMenuItem);
    211        jMenu2.add(whatisMenuItem);
    212        jMenu2.add(aboutMenuItem);
    213        jSplitPane2.setDividerLocation(300);
    214        jSplitPane3.setDividerLocation(150);
    215        jSplitPane4.setDividerLocation(150);
    216    }
    217
    218    void newFileMenuItem_actionPerformed(final ActionEvent e) {
    219        final String classname = JOptionPane.showInputDialog("Please enter the fully qualified name of a class or interface to verify:");
    220        if (classname == null || classname.isEmpty()) {
    221            return;
    222        }
    223        VerifierFactory.getVerifier(classname); // let observers do the rest.
    224        classNamesJList.setSelectedValue(classname, true);
    225    }
    226
    227    synchronized void pass3aJList_valueChanged(final ListSelectionEvent e) {
    228        if (e.getValueIsAdjusting()) {
    229            return;
    230        }
    231        final Verifier v = VerifierFactory.getVerifier(current_class);
    232        final StringBuilder all3amsg = new StringBuilder();
    233        boolean all3aok = true;
    234        boolean rejected = false;
    235        for (int i = 0; i < pass3aJList.getModel().getSize(); i++) {
    236            if (pass3aJList.isSelectedIndex(i)) {
    237                final VerificationResult vr = v.doPass3a(i);
    238                if (vr.getStatus() == VerificationResult.VERIFIED_REJECTED) {
    239                    all3aok = false;
    240                    rejected = true;
    241                }
    242                JavaClass jc = null;
    243                try {
    244                    jc = Repository.lookupClass(v.getClassName());
    245                    all3amsg.append("Method '").append(jc.getMethods()[i]).append("': ").append(vr.getMessage().replace('\n', ' ')).append("\n\n");
    246                } catch (final ClassNotFoundException ex) {
    247                    // FIXME: handle the error
    248                    ex.printStackTrace();
    249                }
    250            }
    251        }
    252        pass3aTextPane.setText(all3amsg.toString());
    253        pass3aTextPane.setBackground(all3aok ? Color.green : rejected ? Color.red : Color.yellow);
    254    }
    255
    256    synchronized void pass3bJList_valueChanged(final ListSelectionEvent e) {
    257        if (e.getValueIsAdjusting()) {
    258            return;
    259        }
    260        final Verifier v = VerifierFactory.getVerifier(current_class);
    261        final StringBuilder all3bmsg = new StringBuilder();
    262        boolean all3bok = true;
    263        boolean rejected = false;
    264        for (int i = 0; i < pass3bJList.getModel().getSize(); i++) {
    265            if (pass3bJList.isSelectedIndex(i)) {
    266                final VerificationResult vr = v.doPass3b(i);
    267                if (vr.getStatus() == VerificationResult.VERIFIED_REJECTED) {
    268                    all3bok = false;
    269                    rejected = true;
    270                }
    271                JavaClass jc = null;
    272                try {
    273                    jc = Repository.lookupClass(v.getClassName());
    274                    all3bmsg.append("Method '").append(jc.getMethods()[i]).append("': ").append(vr.getMessage().replace('\n', ' ')).append("\n\n");
    275                } catch (final ClassNotFoundException ex) {
    276                    // FIXME: handle the error
    277                    ex.printStackTrace();
    278                }
    279            }
    280        }
    281        pass3bTextPane.setText(all3bmsg.toString());
    282        pass3bTextPane.setBackground(all3bok ? Color.green : rejected ? Color.red : Color.yellow);
    283    }
    284
    285    /** Overridden to stop the application on a closing window. */
    286    @Override
    287    protected void processWindowEvent(final WindowEvent e) {
    288        super.processWindowEvent(e);
    289        if (e.getID() == WindowEvent.WINDOW_CLOSING) {
    290            System.exit(0);
    291        }
    292    }
    293
    294    private void verify() throws ClassNotFoundException {
    295        setTitle("PLEASE WAIT");
    296        final Verifier v = VerifierFactory.getVerifier(current_class);
    297        v.flush(); // Don't cache the verification result for this class.
    298        VerificationResult vr;
    299        vr = v.doPass1();
    300        if (vr.getStatus() == VerificationResult.VERIFIED_REJECTED) {
    301            pass1TextPane.setText(vr.getMessage());
    302            pass1TextPane.setBackground(Color.red);
    303            pass2TextPane.setText("");
    304            pass2TextPane.setBackground(Color.yellow);
    305            pass3aTextPane.setText("");
    306            pass3aJList.setListData(ArrayUtils.EMPTY_STRING_ARRAY);
    307            pass3aTextPane.setBackground(Color.yellow);
    308            pass3bTextPane.setText("");
    309            pass3bJList.setListData(ArrayUtils.EMPTY_STRING_ARRAY);
    310            pass3bTextPane.setBackground(Color.yellow);
    311        } else { // Must be VERIFIED_OK, Pass 1 does not know VERIFIED_NOTYET
    312            pass1TextPane.setBackground(Color.green);
    313            pass1TextPane.setText(vr.getMessage());
    314            vr = v.doPass2();
    315            if (vr.getStatus() == VerificationResult.VERIFIED_REJECTED) {
    316                pass2TextPane.setText(vr.getMessage());
    317                pass2TextPane.setBackground(Color.red);
    318                pass3aTextPane.setText("");
    319                pass3aTextPane.setBackground(Color.yellow);
    320                pass3aJList.setListData(ArrayUtils.EMPTY_STRING_ARRAY);
    321                pass3bTextPane.setText("");
    322                pass3bTextPane.setBackground(Color.yellow);
    323                pass3bJList.setListData(ArrayUtils.EMPTY_STRING_ARRAY);
    324            } else { // must be Verified_OK, because Pass1 was OK (cannot be Verified_NOTYET).
    325                pass2TextPane.setText(vr.getMessage());
    326                pass2TextPane.setBackground(Color.green);
    327                final JavaClass jc = Repository.lookupClass(current_class);
    328                /*
    329                 * boolean all3aok = true; boolean all3bok = true; String all3amsg = ""; String all3bmsg = "";
    330                 */
    331                final String[] methodNames = new String[jc.getMethods().length];
    332                Arrays.setAll(methodNames, i -> jc.getMethods()[i].toString().replace('\n', ' ').replace('\t', ' '));
    333                pass3aJList.setListData(methodNames);
    334                pass3aJList.setSelectionInterval(0, jc.getMethods().length - 1);
    335                pass3bJList.setListData(methodNames);
    336                pass3bJList.setSelectionInterval(0, jc.getMethods().length - 1);
    337            }
    338        }
    339        final String[] msgs = v.getMessages();
    340        messagesTextPane.setBackground(msgs.length == 0 ? Color.green : Color.yellow);
    341        final StringBuilder allmsgs = new StringBuilder();
    342        for (int i = 0; i < msgs.length; i++) {
    343            msgs[i] = msgs[i].replace('\n', ' ');
    344            allmsgs.append(msgs[i]).append("\n\n");
    345        }
    346        messagesTextPane.setText(allmsgs.toString());
    347        setTitle(current_class + " - " + JUSTICE_VERSION);
    348    }
    349
    350    void whatisMenuItem_actionPerformed(final ActionEvent e) {
    351        JOptionPane.showMessageDialog(this,
    352            "The upper four boxes to the right reflect verification passes according to"
    353                + " The Java Virtual Machine Specification.\nThese are (in that order):"
    354                + " Pass one, Pass two, Pass three (before data flow analysis), Pass three (data flow analysis).\n"
    355                + "The bottom box to the right shows (warning) messages; warnings do not cause a class to be rejected.",
    356            JUSTICE_VERSION, JOptionPane.INFORMATION_MESSAGE);
    357    }
    358
    359}