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