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}