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