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