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     * @return The classNamesJList.
163     */
164    JList<String> getClassNamesJList() {
165        return classNamesJList;
166    }
167
168    /** Initizalization of the components. */
169    private void jbInit() {
170        // setIconImage(Toolkit.getDefaultToolkit().createImage(Frame1.class.getResource("[Ihr Symbol]")));
171        contentPane = (JPanel) getContentPane();
172        contentPane.setLayout(cardLayout1);
173        setJMenuBar(jMenuBar1);
174        this.setSize(new Dimension(708, 451));
175        setTitle("JustIce");
176        jPanel1.setMinimumSize(new Dimension(100, 100));
177        jPanel1.setPreferredSize(new Dimension(100, 100));
178        jPanel1.setLayout(gridLayout1);
179        jSplitPane2.setOrientation(JSplitPane.VERTICAL_SPLIT);
180        jPanel2.setLayout(gridLayout2);
181        jPanel3.setMinimumSize(new Dimension(200, 100));
182        jPanel3.setPreferredSize(new Dimension(400, 400));
183        jPanel3.setLayout(gridLayout4);
184        messagesPanel.setMinimumSize(new Dimension(100, 100));
185        messagesPanel.setLayout(gridLayout3);
186        jPanel2.setMinimumSize(new Dimension(200, 100));
187        jMenu1.setText("File");
188        jScrollPane1.getViewport().setBackground(Color.red);
189        messagesScrollPane.getViewport().setBackground(Color.red);
190        messagesScrollPane.setPreferredSize(new Dimension(10, 10));
191        classNamesJList.addListSelectionListener(this::classNamesJListValueChanged);
192        classNamesJList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
193        jScrollPane3.setBorder(BorderFactory.createLineBorder(Color.black));
194        jScrollPane3.setPreferredSize(new Dimension(100, 100));
195        gridLayout4.setRows(4);
196        gridLayout4.setColumns(1);
197        gridLayout4.setHgap(1);
198        jScrollPane4.setBorder(BorderFactory.createLineBorder(Color.black));
199        jScrollPane4.setPreferredSize(new Dimension(100, 100));
200        pass1TextPane.setBorder(BorderFactory.createRaisedBevelBorder());
201        pass1TextPane.setToolTipText("");
202        pass1TextPane.setEditable(false);
203        pass2TextPane.setBorder(BorderFactory.createRaisedBevelBorder());
204        pass2TextPane.setEditable(false);
205        messagesTextPane.setBorder(BorderFactory.createRaisedBevelBorder());
206        messagesTextPane.setEditable(false);
207        newFileMenuItem.setText("New...");
208        newFileMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(78, InputEvent.CTRL_MASK, true));
209        newFileMenuItem.addActionListener(this::newFileMenuItemActionPerformed);
210        pass3aTextPane.setEditable(false);
211        pass3bTextPane.setEditable(false);
212        pass3aJList.addListSelectionListener(this::pass3aJList_valueChanged);
213        pass3bJList.addListSelectionListener(this::pass3bJList_valueChanged);
214        jMenu2.setText("Help");
215        whatisMenuItem.setText("What is...");
216        whatisMenuItem.addActionListener(this::whatisMenuItemActionPerformed);
217        aboutMenuItem.setText("About");
218        aboutMenuItem.addActionListener(this::aboutMenuItemActionPerformed);
219        jSplitPane2.add(messagesPanel, JSplitPane.BOTTOM);
220        messagesPanel.add(messagesScrollPane, null);
221        messagesScrollPane.getViewport().add(messagesTextPane, null);
222        jSplitPane2.add(jPanel3, JSplitPane.TOP);
223        jPanel3.add(jScrollPane3, null);
224        jScrollPane3.getViewport().add(pass1TextPane, null);
225        jPanel3.add(jScrollPane4, null);
226        jPanel3.add(jSplitPane3, null);
227        jSplitPane3.add(jScrollPane2, JSplitPane.LEFT);
228        jScrollPane2.getViewport().add(pass3aJList, null);
229        jSplitPane3.add(jScrollPane5, JSplitPane.RIGHT);
230        jScrollPane5.getViewport().add(pass3aTextPane, null);
231        jPanel3.add(jSplitPane4, null);
232        jSplitPane4.add(jScrollPane6, JSplitPane.LEFT);
233        jScrollPane6.getViewport().add(pass3bJList, null);
234        jSplitPane4.add(jScrollPane7, JSplitPane.RIGHT);
235        jScrollPane7.getViewport().add(pass3bTextPane, null);
236        jScrollPane4.getViewport().add(pass2TextPane, null);
237        jSplitPane1.add(jPanel2, JSplitPane.TOP);
238        jPanel2.add(jScrollPane1, null);
239        jSplitPane1.add(jPanel1, JSplitPane.BOTTOM);
240        jPanel1.add(jSplitPane2, null);
241        jScrollPane1.getViewport().add(classNamesJList, null);
242        jMenuBar1.add(jMenu1);
243        jMenuBar1.add(jMenu2);
244        contentPane.add(jSplitPane1, "jSplitPane1");
245        jMenu1.add(newFileMenuItem);
246        jMenu2.add(whatisMenuItem);
247        jMenu2.add(aboutMenuItem);
248        jSplitPane2.setDividerLocation(300);
249        jSplitPane3.setDividerLocation(150);
250        jSplitPane4.setDividerLocation(150);
251    }
252
253    void newFileMenuItemActionPerformed(final ActionEvent e) {
254        final String className = JOptionPane.showInputDialog("Please enter the fully qualified name of a class or interface to verify:");
255        if (className == null || className.isEmpty()) {
256            return;
257        }
258        VerifierFactory.getVerifier(className); // let observers do the rest.
259        classNamesJList.setSelectedValue(className, true);
260    }
261
262    synchronized void pass3aJList_valueChanged(final ListSelectionEvent e) {
263        if (e.getValueIsAdjusting()) {
264            return;
265        }
266        final Verifier v = VerifierFactory.getVerifier(currentClass);
267        final StringBuilder all3amsg = new StringBuilder();
268        boolean all3aok = true;
269        boolean rejected = false;
270        for (int i = 0; i < pass3aJList.getModel().getSize(); i++) {
271            if (pass3aJList.isSelectedIndex(i)) {
272                final VerificationResult vr = v.doPass3a(i);
273                if (vr.getStatus() == VerificationResult.VERIFIED_REJECTED) {
274                    all3aok = false;
275                    rejected = true;
276                }
277                JavaClass jc = null;
278                try {
279                    jc = Repository.lookupClass(v.getClassName());
280                    all3amsg.append("Method '").append(jc.getMethods()[i]).append("': ").append(vr.getMessage().replace('\n', ' ')).append("\n\n");
281                } catch (final ClassNotFoundException ex) {
282                    // FIXME: handle the error
283                    ex.printStackTrace();
284                }
285            }
286        }
287        pass3aTextPane.setText(all3amsg.toString());
288        pass3aTextPane.setBackground(all3aok ? Color.green : rejected ? Color.red : Color.yellow);
289    }
290
291    synchronized void pass3bJList_valueChanged(final ListSelectionEvent e) {
292        if (e.getValueIsAdjusting()) {
293            return;
294        }
295        final Verifier v = VerifierFactory.getVerifier(currentClass);
296        final StringBuilder all3bmsg = new StringBuilder();
297        boolean all3bok = true;
298        boolean rejected = false;
299        for (int i = 0; i < pass3bJList.getModel().getSize(); i++) {
300            if (pass3bJList.isSelectedIndex(i)) {
301                final VerificationResult vr = v.doPass3b(i);
302                if (vr.getStatus() == VerificationResult.VERIFIED_REJECTED) {
303                    all3bok = false;
304                    rejected = true;
305                }
306                JavaClass jc = null;
307                try {
308                    jc = Repository.lookupClass(v.getClassName());
309                    all3bmsg.append("Method '").append(jc.getMethods()[i]).append("': ").append(vr.getMessage().replace('\n', ' ')).append("\n\n");
310                } catch (final ClassNotFoundException ex) {
311                    // FIXME: handle the error
312                    ex.printStackTrace();
313                }
314            }
315        }
316        pass3bTextPane.setText(all3bmsg.toString());
317        pass3bTextPane.setBackground(all3bok ? Color.green : rejected ? Color.red : Color.yellow);
318    }
319
320    /** Overridden to stop the application on a closing window. */
321    @Override
322    protected void processWindowEvent(final WindowEvent e) {
323        super.processWindowEvent(e);
324        if (e.getID() == WindowEvent.WINDOW_CLOSING) {
325            System.exit(0);
326        }
327    }
328
329    private void verify() throws ClassNotFoundException {
330        setTitle("PLEASE WAIT");
331        final Verifier v = VerifierFactory.getVerifier(currentClass);
332        v.flush(); // Don't cache the verification result for this class.
333        VerificationResult vr;
334        vr = v.doPass1();
335        if (vr.getStatus() == VerificationResult.VERIFIED_REJECTED) {
336            pass1TextPane.setText(vr.getMessage());
337            pass1TextPane.setBackground(Color.red);
338            pass2TextPane.setText("");
339            pass2TextPane.setBackground(Color.yellow);
340            pass3aTextPane.setText("");
341            pass3aJList.setListData(ArrayUtils.EMPTY_STRING_ARRAY);
342            pass3aTextPane.setBackground(Color.yellow);
343            pass3bTextPane.setText("");
344            pass3bJList.setListData(ArrayUtils.EMPTY_STRING_ARRAY);
345            pass3bTextPane.setBackground(Color.yellow);
346        } else { // Must be VERIFIED_OK, Pass 1 does not know VERIFIED_NOTYET
347            pass1TextPane.setBackground(Color.green);
348            pass1TextPane.setText(vr.getMessage());
349            vr = v.doPass2();
350            if (vr.getStatus() == VerificationResult.VERIFIED_REJECTED) {
351                pass2TextPane.setText(vr.getMessage());
352                pass2TextPane.setBackground(Color.red);
353                pass3aTextPane.setText("");
354                pass3aTextPane.setBackground(Color.yellow);
355                pass3aJList.setListData(ArrayUtils.EMPTY_STRING_ARRAY);
356                pass3bTextPane.setText("");
357                pass3bTextPane.setBackground(Color.yellow);
358                pass3bJList.setListData(ArrayUtils.EMPTY_STRING_ARRAY);
359            } else { // must be Verified_OK, because Pass1 was OK (cannot be Verified_NOTYET).
360                pass2TextPane.setText(vr.getMessage());
361                pass2TextPane.setBackground(Color.green);
362                final JavaClass jc = Repository.lookupClass(currentClass);
363                /*
364                 * boolean all3aok = true; boolean all3bok = true; String all3amsg = ""; String all3bmsg = "";
365                 */
366                final String[] methodNames = new String[jc.getMethods().length];
367                Arrays.setAll(methodNames, i -> jc.getMethods()[i].toString().replace('\n', ' ').replace('\t', ' '));
368                pass3aJList.setListData(methodNames);
369                pass3aJList.setSelectionInterval(0, jc.getMethods().length - 1);
370                pass3bJList.setListData(methodNames);
371                pass3bJList.setSelectionInterval(0, jc.getMethods().length - 1);
372            }
373        }
374        final String[] msgs = v.getMessages();
375        messagesTextPane.setBackground(msgs.length == 0 ? Color.green : Color.yellow);
376        final StringBuilder allmsgs = new StringBuilder();
377        for (int i = 0; i < msgs.length; i++) {
378            msgs[i] = msgs[i].replace('\n', ' ');
379            allmsgs.append(msgs[i]).append("\n\n");
380        }
381        messagesTextPane.setText(allmsgs.toString());
382        setTitle(currentClass + " - " + Verifier.NAME);
383    }
384
385    void whatisMenuItemActionPerformed(final ActionEvent e) {
386        JOptionPane.showMessageDialog(this,
387            "The upper four boxes to the right reflect verification passes according to"
388                + " The Java Virtual Machine Specification.\nThese are (in that order):"
389                + " Pass one, Pass two, Pass three (before data flow analysis), Pass three (data flow analysis).\n"
390                + "The bottom box to the right shows (warning) messages; warnings do not cause a class to be rejected.",
391            Verifier.NAME, JOptionPane.INFORMATION_MESSAGE);
392    }
393
394}