001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.tools;
023:
024: import java.io.File;
025: import java.io.FileOutputStream;
026: import java.io.ObjectOutputStream;
027: import java.io.IOException;
028: import java.util.HashSet;
029: import java.util.Iterator;
030: import java.util.Enumeration;
031: import java.util.TreeMap;
032: import java.util.Map;
033: import java.util.logging.Logger;
034: import java.util.logging.Level;
035: import java.util.jar.JarFile;
036: import java.util.jar.JarEntry;
037: import java.net.URLClassLoader;
038: import java.net.MalformedURLException;
039: import java.net.URL;
040:
041: /** A tool/service that computes all the class serialVersionUIDs under the
042: * jboss home directory.
043: *
044: * @author Scott.Stark@jboss.org
045: * @version $Revision: 57210 $
046: */
047: public class SerialVersionUID {
048: /** A jdk logger so that only this + ClassVersionInfo are needed */
049: static Logger log = Logger.getLogger("SerialVersionUID");
050:
051: static void buildJarSet(File dir, HashSet jarFiles)
052: throws MalformedURLException {
053: File[] files = dir.listFiles();
054: for (int n = 0; n < files.length; n++) {
055: File child = files[n];
056: // Ignore the server tmp directory
057: if (child.isDirectory()
058: && child.getName().equals("tmp") == false)
059: buildJarSet(child, jarFiles);
060: else if (child.getName().endsWith(".jar"))
061: jarFiles.add(child.toURL());
062: }
063: }
064:
065: /**
066: * Build a TreeMap of the class name to ClassVersionInfo
067: * @param jar
068: * @param classVersionMap TreeMap<String, ClassVersionInfo> for serializable
069: * classes
070: * @param cl - the class loader to use
071: * @throws IOException thrown if the jar cannot be opened
072: */
073: static void generateJarSerialVersionUIDs(URL jar,
074: TreeMap classVersionMap, ClassLoader cl, String pkgPrefix)
075: throws IOException {
076: String jarName = jar.getFile();
077: JarFile jf = new JarFile(jarName);
078: Enumeration entries = jf.entries();
079: while (entries.hasMoreElements()) {
080: JarEntry entry = (JarEntry) entries.nextElement();
081: String name = entry.getName();
082: if (name.endsWith(".class") && name.startsWith(pkgPrefix)) {
083: name = name.substring(0, name.length() - 6);
084: String classname = name.replace('/', '.');
085: try {
086: log.fine("Creating ClassVersionInfo for: "
087: + classname);
088: ClassVersionInfo cvi = new ClassVersionInfo(
089: classname, cl);
090: if (cvi.getSerialVersion() != 0) {
091: ClassVersionInfo prevCVI = (ClassVersionInfo) classVersionMap
092: .put(classname, cvi);
093: if (prevCVI != null) {
094: if (prevCVI.getSerialVersion() != cvi
095: .getSerialVersion()) {
096: log
097: .severe("Found inconsistent classes, "
098: + prevCVI
099: + " != "
100: + cvi
101: + ", jar: "
102: + jarName);
103: }
104: }
105: if (cvi.getHasExplicitSerialVersionUID() == false) {
106: log
107: .warning("No explicit serialVersionUID: "
108: + cvi);
109: }
110: }
111: } catch (OutOfMemoryError e) {
112: log.log(Level.SEVERE, "Check the MaxPermSize", e);
113: } catch (Throwable e) {
114: log.log(Level.FINE, "While loading: " + name, e);
115: }
116: }
117: }
118: jf.close();
119: }
120:
121: /**
122: * Create a Map<String, ClassVersionInfo> for the jboss dist jars.
123: *
124: * @param jbossHome - the jboss dist root directory
125: * @return Map<String, ClassVersionInfo>
126: * @throws IOException
127: */
128: public static Map generateJBossSerialVersionUIDReport(File jbossHome)
129: throws IOException {
130: // Obtain the jars from the /lib and /server/all locations
131: HashSet jarFiles = new HashSet();
132: File lib = new File(jbossHome, "lib");
133: buildJarSet(lib, jarFiles);
134: File all = new File(jbossHome, "server/all");
135: buildJarSet(all, jarFiles);
136: URL[] cp = new URL[jarFiles.size()];
137: jarFiles.toArray(cp);
138: ClassLoader parent = Thread.currentThread()
139: .getContextClassLoader();
140: URLClassLoader completeClasspath = new URLClassLoader(cp,
141: parent);
142:
143: TreeMap classVersionMap = new TreeMap();
144: Iterator jarIter = jarFiles.iterator();
145: while (jarIter.hasNext()) {
146: URL jar = (URL) jarIter.next();
147: try {
148: generateJarSerialVersionUIDs(jar, classVersionMap,
149: completeClasspath, "");
150: } catch (IOException e) {
151: log.info("Failed to process jar: " + jar);
152: }
153: }
154:
155: return classVersionMap;
156: }
157:
158: /**
159: * Create a Map<String, ClassVersionInfo> for the jboss dist jars.
160: * @param j2eeHome - the j2ee ri dist root directory
161: * @return Map<String, ClassVersionInfo>
162: * @throws IOException
163: */
164: public static Map generateRISerialVersionUIDReport(File j2eeHome)
165: throws IOException {
166: // Obtain the jars from the /lib
167: HashSet jarFiles = new HashSet();
168: File lib = new File(j2eeHome, "lib");
169: buildJarSet(lib, jarFiles);
170: URL[] cp = new URL[jarFiles.size()];
171: jarFiles.toArray(cp);
172: ClassLoader parent = Thread.currentThread()
173: .getContextClassLoader();
174: URLClassLoader completeClasspath = new URLClassLoader(cp,
175: parent);
176:
177: TreeMap classVersionMap = new TreeMap();
178: Iterator jarIter = jarFiles.iterator();
179: while (jarIter.hasNext()) {
180: URL jar = (URL) jarIter.next();
181: try {
182: generateJarSerialVersionUIDs(jar, classVersionMap,
183: completeClasspath, "javax");
184: } catch (IOException e) {
185: log.info("Failed to process jar: " + jar);
186: }
187: }
188:
189: return classVersionMap;
190: }
191:
192: /**
193: * Generate a mapping of the serial version UIDs for the serializable classes
194: * under the jboss dist directory
195: * @param args - [0] = jboss dist root directory
196: * @throws Exception
197: */
198: public static void main(String[] args) throws Exception {
199: if (args.length != 1) {
200: System.err.println("Usage: jboss-home");
201: System.exit(1);
202: }
203: File distHome = new File(args[0]);
204: Map classVersionMap = null;
205: if (distHome.getName().startsWith("jboss"))
206: classVersionMap = generateJBossSerialVersionUIDReport(distHome);
207: else
208: classVersionMap = generateRISerialVersionUIDReport(distHome);
209: // Write the map out the object file
210: log.info("Total classes with serialVersionUID != 0: "
211: + classVersionMap.size());
212: FileOutputStream fos = new FileOutputStream("serialuid.ser");
213: ObjectOutputStream oos = new ObjectOutputStream(fos);
214: oos.writeObject(classVersionMap);
215: fos.close();
216: }
217: }
|