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    /** Constructs a new instance. */
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 aboutMenuItemActionPerformed(final ActionEvent e) {
104        JOptionPane.showMessageDialog(this, Verifier.BANNER, Verifier.NAME, JOptionPane.INFORMATION_MESSAGE);
105    }
106
107    synchronized void classNamesJListValueChanged(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) getContentPane();
132        contentPane.setLayout(cardLayout1);
133        setJMenuBar(jMenuBar1);
134        this.setSize(new Dimension(708, 451));
135        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::classNamesJListValueChanged);
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::newFileMenuItemActionPerformed);
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::whatisMenuItemActionPerformed);
177        aboutMenuItem.setText("About");
178        aboutMenuItem.addActionListener(this::aboutMenuItemActionPerformed);
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 newFileMenuItemActionPerformed(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 whatisMenuItemActionPerformed(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}