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