1 /* 2 * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.tools.serialver; 27 28 import java.io.*; 29 import java.awt.*; 30 import java.applet.*; 31 import java.io.ObjectStreamClass; 32 import java.util.Properties; 33 import java.text.MessageFormat; 34 import java.util.ResourceBundle; 35 import java.util.MissingResourceException; 36 import java.net.URLClassLoader; 37 import java.net.URL; 38 import java.net.MalformedURLException; 39 import java.util.StringTokenizer; 40 import sun.net.www.ParseUtil; 41 42 public class SerialVer extends Applet { 43 GridBagLayout gb; 44 TextField classname_t; 45 Button show_b; 46 TextField serialversion_t; 47 Label footer_l; 48 49 private static final long serialVersionUID = 7666909783837760853L; 50 51 public synchronized void init() { 52 gb = new GridBagLayout(); 53 setLayout(gb); 54 55 GridBagConstraints c = new GridBagConstraints(); 56 c.fill = GridBagConstraints.BOTH; 57 58 Label l1 = new Label(Res.getText("FullClassName")); 59 l1.setAlignment(Label.RIGHT); 60 gb.setConstraints(l1, c); 61 add(l1); 62 63 classname_t = new TextField(20); 64 c.gridwidth = GridBagConstraints.RELATIVE; 65 c.weightx = 1.0; 66 gb.setConstraints(classname_t, c); 67 add(classname_t); 68 69 show_b = new Button(Res.getText("Show")); 70 c.gridwidth = GridBagConstraints.REMAINDER; 71 c.weightx = 0.0; /* Don't grow the button */ 72 gb.setConstraints(show_b, c); 73 add(show_b); 74 75 Label l2 = new Label(Res.getText("SerialVersion")); 76 l2.setAlignment(Label.RIGHT); 77 c.gridwidth = 1; 78 gb.setConstraints(l2, c); 79 add(l2); 80 81 serialversion_t = new TextField(50); 82 serialversion_t.setEditable(false); 83 c.gridwidth = GridBagConstraints.REMAINDER; 84 gb.setConstraints(serialversion_t, c); 85 add(serialversion_t); 86 87 footer_l = new Label(); 88 c.gridwidth = GridBagConstraints.REMAINDER; 89 gb.setConstraints(footer_l, c); 90 add(footer_l); 91 92 /* Give the focus to the type-in area */ 93 classname_t.requestFocus(); 94 } 95 96 public void start() { 97 /* Give the focus to the type-in area */ 98 classname_t.requestFocus(); 99 } 100 101 @SuppressWarnings("deprecation") 102 public boolean action(Event ev, Object obj) { 103 if (ev.target == classname_t) { 104 show((String)ev.arg); 105 return true; 106 } else if (ev.target == show_b) { 107 show(classname_t.getText()); 108 return true; 109 } 110 return false; 111 } 112 113 114 @SuppressWarnings("deprecation") 115 public boolean handleEvent(Event ev) { 116 boolean rc = super.handleEvent(ev); 117 return rc; 118 } 119 120 /** 121 * Lookup the specified classname and display it. 122 */ 123 void show(String classname) { 124 try { 125 footer_l.setText(""); // Clear the message 126 serialversion_t.setText(""); // clear the last value 127 128 if (classname.equals("")) { 129 return; 130 } 131 132 String s = serialSyntax(classname); 133 if (s != null) { 134 serialversion_t.setText(s); 135 } else { 136 footer_l.setText(Res.getText("NotSerializable", classname)); 137 } 138 } catch (ClassNotFoundException cnf) { 139 footer_l.setText(Res.getText("ClassNotFound", classname)); 140 } 141 } 142 143 /* 144 * A class loader that will load from the CLASSPATH environment 145 * variable set by the user. 146 */ 147 static URLClassLoader loader = null; 148 149 /* 150 * Create a URL class loader that will load classes from the 151 * specified classpath. 152 */ 153 static void initializeLoader(String cp) 154 throws MalformedURLException, IOException { 155 URL[] urls; 156 StringTokenizer st = new StringTokenizer(cp, File.pathSeparator); 157 int count = st.countTokens(); 158 urls = new URL[count]; 159 for (int i = 0; i < count; i++) { 160 urls[i] = ParseUtil.fileToEncodedURL( 161 new File(new File(st.nextToken()).getCanonicalPath())); 162 } 163 loader = new URLClassLoader(urls); 164 } 165 166 /* 167 * From the classname find the serialVersionUID string formatted 168 * for to be copied to a java class. 169 */ 170 static String serialSyntax(String classname) throws ClassNotFoundException { 171 String ret = null; 172 boolean classFound = false; 173 174 // If using old style of qualifyling inner classes with '$'s. 175 if (classname.indexOf('$') != -1) { 176 ret = resolveClass(classname); 177 } else { 178 /* Try to resolve the fully qualified name and if that fails, start 179 * replacing the '.'s with '$'s starting from the last '.', until 180 * the class is resolved. 181 */ 182 try { 183 ret = resolveClass(classname); 184 classFound = true; 185 } catch (ClassNotFoundException e) { 186 /* Class not found so far */ 187 } 188 if (!classFound) { 189 StringBuffer workBuffer = new StringBuffer(classname); 190 String workName = workBuffer.toString(); 191 int i; 192 while ((i = workName.lastIndexOf('.')) != -1 && !classFound) { 193 workBuffer.setCharAt(i, '$'); 194 try { 195 workName = workBuffer.toString(); 196 ret = resolveClass(workName); 197 classFound = true; 198 } catch (ClassNotFoundException e) { 199 /* Continue searching */ 200 } 201 } 202 } 203 if (!classFound) { 204 throw new ClassNotFoundException(); 205 } 206 } 207 return ret; 208 } 209 210 static String resolveClass(String classname) throws ClassNotFoundException { 211 Class<?> cl = Class.forName(classname, false, loader); 212 ObjectStreamClass desc = ObjectStreamClass.lookup(cl); 213 if (desc != null) { 214 return " private static final long serialVersionUID = " + 215 desc.getSerialVersionUID() + "L;"; 216 } else { 217 return null; 218 } 219 } 220 221 @SuppressWarnings("deprecation") 222 private static void showWindow(Window w) { 223 w.show(); 224 } 225 226 public static void main(String[] args) { 227 boolean show = false; 228 String envcp = null; 229 int i = 0; 230 231 if (args.length == 0) { 232 usage(); 233 System.exit(1); 234 } 235 236 for (i = 0; i < args.length; i++) { 237 if (args[i].equals("-show")) { 238 show = true; 239 } else if (args[i].equals("-classpath")) { 240 if ((i+1 == args.length) || args[i+1].startsWith("-")) { 241 System.err.println(Res.getText("error.missing.classpath")); 242 usage(); 243 System.exit(1); 244 } 245 envcp = new String(args[i+1]); 246 i++; 247 } else if (args[i].startsWith("-")) { 248 System.err.println(Res.getText("invalid.flag", args[i])); 249 usage(); 250 System.exit(1); 251 } else { 252 break; // drop into processing class names 253 } 254 } 255 256 257 /* 258 * Get user's CLASSPATH environment variable, if the -classpath option 259 * is not defined, and make a loader that can read from that path. 260 */ 261 if (envcp == null) { 262 envcp = System.getProperty("env.class.path"); 263 /* 264 * If environment variable not set, add current directory to path. 265 */ 266 if (envcp == null) { 267 envcp = "."; 268 } 269 } 270 271 try { 272 initializeLoader(envcp); 273 } catch (MalformedURLException mue) { 274 System.err.println(Res.getText("error.parsing.classpath", envcp)); 275 System.exit(2); 276 } catch (IOException ioe) { 277 System.err.println(Res.getText("error.parsing.classpath", envcp)); 278 System.exit(3); 279 } 280 281 if (!show) { 282 /* 283 * Check if there are any class names specified, if it is not a 284 * invocation with the -show option. 285 */ 286 if (i == args.length) { 287 usage(); 288 System.exit(1); 289 } 290 291 /* 292 * The rest of the parameters are classnames. 293 */ 294 boolean exitFlag = false; 295 for (i = i; i < args.length; i++ ) { 296 try { 297 String syntax = serialSyntax(args[i]); 298 if (syntax != null) 299 System.out.println(args[i] + ":" + syntax); 300 else { 301 System.err.println(Res.getText("NotSerializable", 302 args[i])); 303 exitFlag = true; 304 } 305 } catch (ClassNotFoundException cnf) { 306 System.err.println(Res.getText("ClassNotFound", args[i])); 307 exitFlag = true; 308 } 309 } 310 if (exitFlag) { 311 System.exit(1); 312 } 313 } else { 314 if (i < args.length) { 315 System.err.println(Res.getText("ignoring.classes")); 316 System.exit(1); 317 } 318 Frame f = new SerialVerFrame(); 319 // f.setLayout(new FlowLayout()); 320 SerialVer sv = new SerialVer(); 321 sv.init(); 322 323 f.add("Center", sv); 324 f.pack(); 325 showWindow(f); 326 } 327 } 328 329 330 /** 331 * Usage 332 */ 333 public static void usage() { 334 System.err.println(Res.getText("usage")); 335 } 336 337 } 338 339 /** 340 * Top level frame so serialVer can be run as an main program 341 * and have an exit menu item. 342 */ 343 class SerialVerFrame extends Frame { 344 MenuBar menu_mb; 345 Menu file_m; 346 MenuItem exit_i; 347 348 private static final long serialVersionUID = -7248105987187532533L; 349 350 /* 351 * Construct a new Frame with title and menu. 352 */ 353 SerialVerFrame() { 354 super(Res.getText("SerialVersionInspector")); 355 356 /* Create the file menu */ 357 file_m = new Menu(Res.getText("File")); 358 file_m.add(exit_i = new MenuItem(Res.getText("Exit"))); 359 360 /* Now add the file menu to the menu bar */ 361 menu_mb = new MenuBar(); 362 menu_mb.add(file_m); 363 364 /* Add the menubar to the frame */ 365 // Bug in JDK1.1 setMenuBar(menu_mb); 366 } 367 368 /* 369 * Handle a window destroy event by exiting. 370 */ 371 @SuppressWarnings("deprecation") 372 public boolean handleEvent(Event e) { 373 if (e.id == Event.WINDOW_DESTROY) { 374 exit(0); 375 } 376 return super.handleEvent(e); 377 } 378 /* 379 * Handle an Exit event by exiting. 380 */ 381 @SuppressWarnings("deprecation") 382 public boolean action(Event ev, Object obj) { 383 if (ev.target == exit_i) { 384 exit(0); 385 } 386 return false; 387 } 388 389 /* 390 * Cleanup and exit. 391 */ 392 void exit(int ret) { 393 System.exit(ret); 394 } 395 396 } 397 398 /** 399 * Utility for integrating with serialver and for localization. 400 * Handle Resources. Access to error and warning counts. 401 * Message formatting. 402 * 403 * @see java.util.ResourceBundle 404 * @see java.text.MessageFormat 405 */ 406 class Res { 407 408 private static ResourceBundle messageRB; 409 410 /** 411 * Initialize ResourceBundle 412 */ 413 static void initResource() { 414 try { 415 messageRB = 416 ResourceBundle.getBundle("sun.tools.serialver.resources.serialver"); 417 } catch (MissingResourceException e) { 418 throw new Error("Fatal: Resource for serialver is missing"); 419 } 420 } 421 422 /** 423 * get and format message string from resource 424 * 425 * @param key selects message from resource 426 */ 427 static String getText(String key) { 428 return getText(key, (String)null); 429 } 430 431 /** 432 * get and format message string from resource 433 * 434 * @param key selects message from resource 435 * @param a1 first argument 436 */ 437 static String getText(String key, String a1) { 438 return getText(key, a1, null); 439 } 440 441 /** 442 * get and format message string from resource 443 * 444 * @param key selects message from resource 445 * @param a1 first argument 446 * @param a2 second argument 447 */ 448 static String getText(String key, String a1, String a2) { 449 return getText(key, a1, a2, null); 450 } 451 452 /** 453 * get and format message string from resource 454 * 455 * @param key selects message from resource 456 * @param a1 first argument 457 * @param a2 second argument 458 * @param a3 third argument 459 */ 460 static String getText(String key, String a1, String a2, String a3) { 461 if (messageRB == null) { 462 initResource(); 463 } 464 try { 465 String message = messageRB.getString(key); 466 return MessageFormat.format(message, a1, a2, a3); 467 } catch (MissingResourceException e) { 468 throw new Error("Fatal: Resource for serialver is broken. There is no " + key + " key in resource."); 469 } 470 } 471 }