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