001: /*
002:
003: Derby - Class org.apache.derby.iapi.services.cache.ClassSizeCrawler
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to You under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derbyBuild;
023:
024: import org.apache.derby.iapi.services.cache.ClassSize;
025:
026: import java.io.File;
027: import java.io.FileWriter;
028: import java.io.PrintWriter;
029: import java.io.IOException;
030: import java.io.FileOutputStream;
031: import java.io.ObjectOutput;
032: import java.io.ObjectOutputStream;
033: import java.lang.SecurityException;
034: import java.lang.ClassNotFoundException;
035: import java.util.Hashtable;
036: import java.util.Enumeration;
037: import java.util.Calendar;
038: import java.util.Date;
039:
040: /**
041: * This class implements a program that catalogs the size estimate coefficients of various classes.
042: * @see ClassSize#getSizeCoefficients.
043: *<p>
044: * The program is invoked as:
045: *<p>
046: * java -DWS=<i>work-space</i> [-DclassDir=<i>class-dir</i>] [-Dout=<i>out-file</i> [-Dprefix[.<i>x</i>=<i>package-prefix</i>]] [-Dverbose=true] org.apache.derby.iapi.services.cache.ClassSizeCrawler <i>class-or-interface</i> ...<br>
047: *<p>
048: * This program gets the size coefficients for each class in the <i>class-or-interface</i> list,
049: * and for each class that implements an interface in the list. If there is an interface in the list
050: * this program crawls through the classes hierarcy, starting at points specified by the prefix
051: * properties, looking for classes that implement the interfaces.
052: *<p>
053: * If the <i>class-or-interface</i> list is empty then this program searches for implementations
054: * of org.apache.derby.iapi.types.DataValueDescriptor, and at least one prefix property
055: * must be specified
056: *<p>
057: * The catalog is written as a java source file
058: * into <i>out-file</i>, by default
059: * <i>work-space</i>/java/org.apache.derby.iapi.services.cache.ClassSizeCatalog.java.
060: *<p>
061: * <i>work-space</i> is the directory containing the java and classes directories. $WS in the
062: * standard development environment. This property is required.
063: *<p>
064: * <i>class-dir</i> is the directory containing the compiled classes. By default it is <i>work-space</i>/classes.
065: *<p>
066: * <i>package-prefix</i> is the first part of a package name. e.g. "com.ibm.db2j.impl". At least
067: * one prefix property must be specified if there is an interface in the list.
068: *<p>
069: * For example:<br>
070: * <pre>
071: * <code>
072: * java -DWS=$WS \
073: * -Dprefix.1=org.apache.derby.iapi.types \
074: * org.apache.derby.iapi.services.cache.ClassSizeCrawler \
075: * org.apache.derby.iapi.types.DataValueDescriptor \
076: * java.math.BigDecimal \
077: * org.apache.derby.impl.services.cache.Generic.CachedItem
078: *</code>
079: *</pre>
080: */
081: public class ClassSizeCrawler {
082: public static void main(String[] arg) {
083: String[] classAndInterfaceList = { "org.apache.derby.iapi.types.DataValueDescriptor" };
084: if (arg.length > 0)
085: classAndInterfaceList = arg;
086: Class[] interfaceList = new Class[classAndInterfaceList.length];
087: int interfaceCount = 0;
088: Class[] classList = new Class[classAndInterfaceList.length];
089: int classCount = 0;
090:
091: Class classSizeClass = ClassSize.class; // Make sure that the garbage collector does not unload it
092: ClassSize.setDummyCatalog();
093: /* Most of the classes we will catalog invoke ClassSize.estimateBaseFromCatalog in
094: * their static initializer. This dummy the catalog out so that this will not generate
095: * errors. We will not actually use the classes, just examine their fields.
096: */
097:
098: for (int i = 0; i < classAndInterfaceList.length; i++) {
099: Class cls = null;
100: try {
101: cls = Class.forName(classAndInterfaceList[i]);
102: } catch (ClassNotFoundException cnfe) {
103: System.err.println("*** Could not find class "
104: + classAndInterfaceList[i]);
105: System.exit(1);
106: }
107: if (cls.isInterface())
108: interfaceList[interfaceCount++] = cls;
109: else
110: classList[classCount++] = cls;
111: }
112:
113: String WS = System.getProperty("WS");
114: if (WS == null) {
115: System.err.println("*** WS is not set.");
116: System.exit(1);
117: }
118:
119: StringBuffer baseDir = new StringBuffer(System.getProperty(
120: "classDir", ""));
121: if (baseDir.length() == 0) {
122: baseDir.append(WS);
123: baseDir.append('/');
124: baseDir.append("classes");
125: }
126: int baseDirLength = baseDir.length();
127:
128: StringBuffer packagePrefix = new StringBuffer();
129:
130: Hashtable classSizes = new Hashtable();
131:
132: ClassSizeCrawler crawler = new ClassSizeCrawler(interfaceList,
133: interfaceCount, classSizes);
134:
135: if (interfaceCount > 0) {
136: boolean gotPrefix = false;
137: // Crawl through the class hierarchies for classes implementing the interfaces
138: for (Enumeration e = System.getProperties().propertyNames(); e
139: .hasMoreElements();) {
140: String propertyName = (String) e.nextElement();
141: if (propertyName.equals("prefix")
142: || propertyName.startsWith("prefix.")) {
143: gotPrefix = true;
144: packagePrefix.setLength(0);
145: packagePrefix.append(System
146: .getProperty(propertyName));
147: baseDir.setLength(baseDirLength);
148: if (packagePrefix.length() > 0) {
149: baseDir.append('/');
150: for (int offset = 0; offset < packagePrefix
151: .length(); offset++) {
152: char c = packagePrefix.charAt(offset);
153: if (c == '.')
154: baseDir.append('/');
155: else
156: baseDir.append(c);
157: }
158: }
159: crawler.crawl(new File(baseDir.toString()),
160: packagePrefix);
161: }
162: }
163: if (!gotPrefix) {
164: System.err
165: .println("*** Could not search the class hierarchy because no starting");
166: System.err.println(" prefixes where specified.");
167: System.exit(1);
168: }
169: }
170: for (int i = 0; i < classCount; i++)
171: crawler.addClass(classList[i]);
172:
173: baseDir.setLength(baseDirLength);
174: String outputFileName = System
175: .getProperty(
176: "out",
177: WS
178: + "/java/org.apache.derby.iapi.services.cache.ClassSizeCatalog.java");
179: try {
180: Calendar cal = Calendar.getInstance();
181: cal.setTime(new Date());
182: int year = cal.get(Calendar.YEAR);
183: PrintWriter out = new PrintWriter(new FileWriter(
184: outputFileName));
185: out
186: .print("/*\n\n"
187: +
188:
189: " Licensed to the Apache Software Foundation (ASF) under one or more\n"
190: + " contributor license agreements. See the NOTICE file distributed with\n"
191: + " this work for additional information regarding copyright ownership.\n"
192: + " The ASF licenses this file to You under the Apache License, Version 2.0\n"
193: + " (the \"License\"); you may not use this file except in compliance with\n"
194: + " the License. You may obtain a copy of the License at\n"
195: + "\n"
196: + " http://www.apache.org/licenses/LICENSE-2.0\n"
197: + "\n"
198: + " Unless required by applicable law or agreed to in writing, software\n"
199: + " distributed under the License is distributed on an \"AS IS\" BASIS,\n"
200: + " WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
201: + " See the License for the specific language governing permissions and\n"
202: + " limitations under the License.\n"
203: + " */\n");
204: out
205: .print("package org.apache.derby.iapi.services.cache;\n"
206: + "import java.util.Hashtable;\n"
207: + "class ClassSizeCatalog extends java.util.Hashtable\n"
208: + "{\n"
209: + " ClassSizeCatalog()\n"
210: + " {\n");
211: for (Enumeration e = classSizes.keys(); e.hasMoreElements();) {
212: String className = (String) e.nextElement();
213: int[] coeff = (int[]) classSizes.get(className);
214: out.print(" put( \"" + className
215: + "\", new int[]{" + coeff[0] + "," + coeff[1]
216: + "});\n");
217: }
218: out.print(" }\n" + "}\n");
219: out.flush();
220: out.close();
221: } catch (IOException ioe) {
222: System.err.println("*** Cannot write to " + outputFileName);
223: System.err.println(" " + ioe.getMessage());
224: System.exit(1);
225: }
226: } // end of main
227:
228: private Class[] interfaceList; // Search for classes that implement these interfaces
229: private int interfaceCount;
230: private Hashtable classSizes;
231: private boolean verbose = false;
232:
233: private ClassSizeCrawler(Class[] interfaceList, int interfaceCount,
234: Hashtable classSizes) {
235: this .interfaceList = interfaceList;
236: this .classSizes = classSizes;
237: this .interfaceCount = interfaceCount;
238: verbose = new Boolean(System.getProperty("verbose", "false"))
239: .booleanValue();
240: }
241:
242: private void crawl(File curDir, StringBuffer className) {
243: if (verbose)
244: System.out.println("Searching directory "
245: + curDir.getPath());
246:
247: try {
248: if (!curDir.isDirectory()) {
249: System.err.println("*** " + curDir.getPath()
250: + " is not a directory.");
251: System.exit(1);
252: }
253: } catch (SecurityException se) {
254: System.err.println("Cannot access " + curDir.getPath());
255: System.exit(1);
256: }
257: String[] filenames = curDir.list();
258: if (className.length() != 0)
259: className.append(".");
260:
261: int classNameLength = className.length();
262: for (int fileIdx = 0; fileIdx < filenames.length; fileIdx++) {
263: if (filenames[fileIdx].endsWith(".class")) {
264: // Strip off the ".class" suffix
265: String s = filenames[fileIdx].substring(0,
266: filenames[fileIdx].length() - 6);
267: className.append(s);
268: Class targetClass = null;
269: String targetClassName = className.toString();
270: try {
271: targetClass = Class.forName(targetClassName);
272: if (!targetClass.isInterface()) {
273: for (int interfaceIdx = 0; interfaceIdx < interfaceCount; interfaceIdx++) {
274: if (interfaceList[interfaceIdx]
275: .isAssignableFrom(targetClass))
276: addClass(targetClass);
277: }
278: }
279: } catch (ClassNotFoundException cnfe) {
280: System.err.println("Could not find class "
281: + targetClassName);
282: System.exit(1);
283: } catch (Throwable t) {
284: }
285: className.setLength(classNameLength);
286: } else {
287: File nextDir = new File(curDir, filenames[fileIdx]);
288: if (nextDir.isDirectory()) {
289: className.append(filenames[fileIdx]);
290: crawl(nextDir, className);
291: className.setLength(classNameLength);
292: }
293: }
294: }
295: } // end of crawl
296:
297: private void addClass(Class targetClass) {
298: int[] coefficients = ClassSize.getSizeCoefficients(targetClass);
299: if (verbose)
300: System.out.println(targetClass.getName() + " "
301: + coefficients[0] + ", " + coefficients[1]);
302: classSizes.put(targetClass.getName(), coefficients);
303: } // end of addClass
304: } // end of ClassSizeCrawler
|