001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: * The Original Software is NetBeans. The Initial Developer of the Original
026: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
027: * Microsystems, Inc. All Rights Reserved.
028: *
029: * If you wish your version of this file to be governed by only the CDDL
030: * or only the GPL Version 2, indicate your decision by adding
031: * "[Contributor] elects to include this software in this distribution
032: * under the [CDDL or GPL Version 2] license." If you do not indicate a
033: * single choice of license, a recipient has the option to distribute
034: * your version of this file under either the CDDL, the GPL Version 2 or
035: * to extend the choice of license to its licensees as provided above.
036: * However, if you add GPL Version 2 code and therefore, elected the GPL
037: * Version 2 license, then the option applies only if the new code is
038: * made subject to such option by the copyright holder.
039: */
040:
041: package org.netbeans.lib.profiler.utils;
042:
043: import org.netbeans.lib.profiler.global.CommonConstants;
044: import org.netbeans.lib.profiler.global.Platform;
045: import java.io.File;
046: import java.io.IOException;
047: import java.io.InputStream;
048: import java.text.MessageFormat;
049: import java.util.*;
050: import java.util.zip.ZipEntry;
051: import java.util.zip.ZipFile;
052:
053: /**
054: * Miscellaneous utilities for class names/path management, file management, and printing/logging.
055: *
056: * @author Tomas Hurka
057: * @author Misha Dmitriev
058: * @author Ian Formanek
059: */
060: public class MiscUtils implements CommonConstants {
061: //~ Static fields/initializers -----------------------------------------------------------------------------------------------
062:
063: // -----
064: // I18N String constants
065: private static final ResourceBundle messages = ResourceBundle
066: .getBundle("org.netbeans.lib.profiler.utils.Bundle"); // NOI18N
067: private static final String NOT_DIRECTORY_MSG = messages
068: .getString("MiscUtils_NotDirectoryMsg"); // NOI18N
069: private static final String NOT_FILE_MSG = messages
070: .getString("MiscUtils_NotFileMsg"); // NOI18N
071: private static final String FILE_NOT_READABLE_MSG = messages
072: .getString("MiscUtils_FileNotReadableMsg"); // NOI18N
073: private static final String FILE_NOT_EXIST_MSG = messages
074: .getString("MiscUtils_FileNotExistMsg"); // NOI18N
075: private static final String VM_VERSION_MSG = messages
076: .getString("MiscUtils_VmVersionMsg"); // NOI18N
077: private static final String VM_UNKNOWN_MSG = messages
078: .getString("MiscUtils_VmUnknownMsg"); // NOI18N
079: private static final String VM_INCOMPATIBLE_MSG = messages
080: .getString("MiscUtils_VmIncompatibleMsg"); // NOI18N
081:
082: // ------------------------------------------------------------------------------------------------
083: // Printing/logging management
084: // ------------------------------------------------------------------------------------------------
085: private static boolean verbosePrint = false;
086: private static boolean printInfo = true;
087:
088: //~ Methods ------------------------------------------------------------------------------------------------------------------
089:
090: public static String getAbsoluteFilePath(String fileName,
091: String baseDir) {
092: boolean local = false;
093:
094: // If the name is in the local form, convert it into an absolute form
095: if (fileName.startsWith(".")) {
096: local = true; // NOI18N
097: } else {
098: if (Platform.isWindows()) {
099: if (!((fileName.charAt(0) == '\\')
100: || (fileName.charAt(0) == '/') || ((fileName
101: .length() > 1) && (fileName.charAt(1) == ':')))) {
102: local = true; // NOI18N
103: }
104: } else {
105: if (!((fileName.charAt(0) == '/') || (fileName
106: .charAt(0) == '~'))) {
107: local = true; // NOI18N
108: }
109: }
110: }
111:
112: if (local) {
113: fileName = baseDir + "/" + fileName; // NOI18N
114: }
115:
116: return fileName;
117: }
118:
119: public static void getAllClassesInDir(String dirName,
120: String packageName, boolean removeClassExt, Collection res) {
121: File dir = new File(dirName);
122: String[] fileNames = dir.list();
123:
124: if (fileNames == null) {
125: return;
126: }
127:
128: for (int i = 0; i < fileNames.length; i++) {
129: if (fileNames[i].endsWith(".class")) { // NOI18N
130:
131: String className = packageName
132: + (removeClassExt ? fileNames[i].substring(0,
133: fileNames[i].length() - 6)
134: : fileNames[i]);
135: res.add(className.intern());
136: } else {
137: String subDirName = dirName + File.separator
138: + fileNames[i];
139: File subDir = new File(subDirName);
140:
141: if (subDir.exists() && subDir.isDirectory()) {
142: String subPackage = packageName + fileNames[i]
143: + "/"; // NOI18N
144: getAllClassesInDir(subDirName, subPackage,
145: removeClassExt, res);
146: }
147: }
148: }
149: }
150:
151: public static void getAllClassesInJar(String jarName,
152: boolean removeClassExt, Collection res) {
153: ZipFile zip = null;
154:
155: try {
156: zip = new ZipFile(jarName);
157: } catch (Exception ex) {
158: System.err.println("Warning: could not open archive "
159: + jarName); // NOI18N
160:
161: return;
162: }
163:
164: for (Enumeration entries = zip.entries(); entries
165: .hasMoreElements();) {
166: ZipEntry entry = (ZipEntry) entries.nextElement();
167: String className = entry.getName();
168:
169: if (className.endsWith(".class")) { // NOI18N
170:
171: if (removeClassExt) {
172: className = className.substring(0, className
173: .length() - 6);
174: }
175:
176: res.add(className.intern());
177: }
178: }
179: }
180:
181: // ------------------------------------------------------------------------------------------------
182: // File management
183: // ------------------------------------------------------------------------------------------------
184: public static String getCanonicalPath(File file) {
185: try {
186: if (!file.exists()) {
187: return null;
188: }
189:
190: return file.getCanonicalPath();
191: } catch (IOException e) {
192: return null;
193: }
194: }
195:
196: // -----
197:
198: // ------------------------------------------------------------------------------------------------
199: // Class name and class path management
200: // ------------------------------------------------------------------------------------------------
201:
202: /** Determine the outermost class name for the given source file, based on the available source path
203: * @param sourceFileName the name of the source file
204: * @param mainSourcePath the main source path to search within
205: * @param secondarySourcePath the secondary source path to search within
206: */
207: public static String getClassNameForSource(String sourceFileName,
208: String mainSourcePath, String secondarySourcePath,
209: String workingDir) {
210: if ((sourceFileName.charAt(1) == ':')
211: && !Character.isLowerCase(sourceFileName.charAt(0))) { // NOI18N
212: sourceFileName = sourceFileName.substring(0, 1)
213: .toLowerCase()
214: + sourceFileName.substring(1);
215: }
216:
217: for (int i = 0; i < 2; i++) {
218: String sourcePath = ((i == 0) ? mainSourcePath
219: : secondarySourcePath);
220:
221: if (sourcePath == null) {
222: continue;
223: }
224:
225: ArrayList paths = getPathComponents(sourcePath, true,
226: workingDir);
227:
228: for (int j = 0; j < paths.size(); j++) {
229: String path = (String) paths.get(j);
230:
231: if ((path.charAt(1) == ':')
232: && !Character.isLowerCase(path.charAt(0))) { // NOI18N
233: path = path.substring(0, 1).toLowerCase()
234: + path.substring(1);
235: }
236:
237: if (!path.endsWith(File.separator)) {
238: path += File.separator;
239: }
240:
241: if (sourceFileName.startsWith(path)) {
242: String className = sourceFileName.substring(path
243: .length(), sourceFileName.length() - 5);
244:
245: return className.replace(File.separatorChar, '.'); // NOI18N
246: }
247: }
248: }
249:
250: return null;
251: }
252:
253: public static String getFirstPathComponent(String path) {
254: int pos = path.indexOf(File.pathSeparatorChar);
255:
256: if (pos == -1) {
257: return path;
258: } else {
259: return path.substring(0, pos);
260: }
261: }
262:
263: // ------------------------------------------------------------------------------------------------
264: // JDK version determination for a given executable file
265: // ------------------------------------------------------------------------------------------------
266: public static String getJDKVersionForJVMExeFile(File exeFile)
267: throws IOException {
268: String[] cmdLine = new String[] { exeFile.getAbsolutePath(),
269: "-version" }; // NOI18N
270: Process javaProcess = Runtime.getRuntime().exec(cmdLine);
271:
272: //javaProcess.waitFor(); // this should probably be here
273: InputStream bis = javaProcess.getErrorStream();
274:
275: int maxLen = 500;
276: int availBytes;
277: int readBytes;
278: int ofs = 0;
279: byte[] bytes = new byte[maxLen];
280:
281: do {
282: availBytes = bis.available();
283:
284: if (availBytes == 0) {
285: availBytes = 1;
286: }
287:
288: if ((ofs + availBytes) >= maxLen) {
289: availBytes = maxLen - ofs;
290: }
291:
292: readBytes = bis.read(bytes, ofs, availBytes);
293:
294: if (readBytes != -1) {
295: ofs += readBytes;
296: }
297: } while ((readBytes != -1) && (ofs < maxLen));
298:
299: bis.close();
300:
301: String outString = new String(bytes, 0, ofs);
302: String printOutString = "\n" + VM_VERSION_MSG + "\n"
303: + outString; // NOI18N
304:
305: // The string should start with something like 'java version "1.5.0"' (note the quotes). Let's remove the stuff before the quote
306: int pos = outString.indexOf('\"'); // NOI18N
307:
308: if (pos == -1) {
309: throw new IOException(VM_UNKNOWN_MSG + printOutString);
310: }
311:
312: outString = outString.substring(pos + 1);
313:
314: if (outString.startsWith("1.5")) { // NOI18N
315:
316: return JDK_15_STRING;
317: } else if (outString.startsWith("1.6")) { // NOI18N
318:
319: return JDK_16_STRING;
320: } else if (outString.startsWith("1.7")) { // NOI18N
321:
322: return JDK_17_STRING;
323: } else {
324: throw new IOException(VM_INCOMPATIBLE_MSG + printOutString);
325: }
326: }
327:
328: /** For a string representing a class path, remove all entries that don't correspond to existing files, and return the remaining ones. */
329: public static String getLiveClassPathSubset(String path,
330: String workingDir) {
331: ArrayList liveComponents = getPathComponents(path, true,
332: workingDir);
333: StringBuffer buf = new StringBuffer(liveComponents.size() * 10);
334:
335: if (liveComponents.size() > 0) {
336: buf.append((String) liveComponents.get(0));
337:
338: for (int i = 1; i < liveComponents.size(); i++) {
339: buf.append(File.pathSeparator);
340: buf.append((String) liveComponents.get(i));
341: }
342: }
343:
344: return buf.toString();
345: }
346:
347: /**
348: * Returns the components of the compound path, such as CLASSPATH. If doCheck is true,
349: * checks if each of the components really exists, i.e. is an existing directory or file,
350: * and returns only existing components. workingDir is needed in case the passed path has
351: * a local form.
352: */
353: public static ArrayList getPathComponents(String path,
354: boolean doCheck, String workingDir) {
355: ArrayList list = new ArrayList();
356:
357: if (path != null) {
358: StringTokenizer tok = new StringTokenizer(path,
359: File.pathSeparator);
360:
361: while (tok.hasMoreTokens()) {
362: String name = tok.nextToken();
363:
364: if ((name == null) || (name.length() == 0)) {
365: continue; // Essentially sanity check, but who knows?
366: }
367:
368: if (doCheck) {
369: name = getAbsoluteFilePath(name, workingDir);
370: name = getCanonicalPath(new File(name)); // clean up the name into a canonical path
371:
372: if (name != null) {
373: list.add(name);
374: }
375: } else {
376: list.add(name);
377: }
378: }
379: }
380:
381: return list;
382: }
383:
384: public static void setSilent(boolean silent) {
385: printInfo = !silent;
386: }
387:
388: public static boolean isSlashedJavaCoreClassName(String name) {
389: return (name.startsWith("java/") || name.startsWith("sun/") || name
390: .startsWith("javax/")); // NOI18N
391: }
392:
393: public static boolean isSupportedJVM(Map jdkProperties) {
394: String jdkVersionString = (String) jdkProperties
395: .get("java.version"); // NOI18N
396: String vmNameString = (String) jdkProperties
397: .get("java.vm.name"); // NOI18N
398:
399: if ((jdkVersionString == null) || (vmNameString == null)) { // probably not a platform for JDK
400:
401: return false;
402: }
403:
404: return isSupported15or16or17(jdkVersionString);
405: }
406:
407: // This method is used for checking running JVM if supported.
408: // jvmVersionString should be enough to decide that
409: public static boolean isSupportedRunningJVMVersion(
410: String jdkVersionString) {
411: return isSupported15or16or17(jdkVersionString);
412: }
413:
414: public static void setVerbosePrint() {
415: verbosePrint = true;
416: }
417:
418: public static File checkDirForName(String name) throws IOException {
419: File file = new File(name);
420:
421: return checkFile(file, true);
422: }
423:
424: public static File checkFile(File file, boolean isDir)
425: throws IOException {
426: if (file.exists()) {
427: if (isDir) {
428: if (!file.isDirectory()) {
429: throw new IOException(MessageFormat.format(
430: NOT_DIRECTORY_MSG, new Object[] { file }));
431: }
432: } else {
433: if (!file.isFile()) {
434: throw new IOException(MessageFormat.format(
435: NOT_FILE_MSG, new Object[] { file }));
436: }
437: }
438:
439: if (!file.canRead()) {
440: throw new IOException(MessageFormat.format(
441: FILE_NOT_READABLE_MSG, new Object[] { file }));
442: }
443:
444: return file;
445: } else {
446: throw new IOException(FILE_NOT_EXIST_MSG);
447: }
448: }
449:
450: public static File checkFileForName(String name) throws IOException {
451: File file = new File(name);
452:
453: return checkFile(file, false);
454: }
455:
456: /** Checks if given directory is already listed on path */
457: public static boolean containsDirectoryOnPath(String directory,
458: String path) {
459: String normalizedDirectory = new File(directory)
460: .getAbsolutePath().toLowerCase();
461: String normalizedPath = new File(path).getAbsolutePath()
462: .toLowerCase();
463: ArrayList pathComponents = getPathComponents(normalizedPath,
464: false, null);
465:
466: for (int i = 0; i < pathComponents.size(); i++) {
467: if (normalizedDirectory.equals(pathComponents.get(i))) {
468: return true;
469: }
470: }
471:
472: return false;
473: }
474:
475: public static void deleteHeapTempFiles() {
476: if (Platform.isWindows()) { // this is workaroud for JDK bug #6359560
477:
478: File tempDir = new File(System
479: .getProperty("java.io.tmpdir")); // NOI18N
480: File[] files = tempDir.listFiles();
481:
482: for (int i = 0; i < files.length; i++) {
483: File f = files[i];
484: String fname = f.getName();
485:
486: if (fname.startsWith("NBProfiler")
487: && fname.endsWith(".map")) { // NOI18N
488: f.delete();
489: }
490: }
491: }
492: }
493:
494: public static boolean fileForNameOk(String name) {
495: try {
496: checkFileForName(name);
497:
498: return true;
499: } catch (IOException ex) {
500: return false;
501: }
502: }
503:
504: public static boolean inSamePackage(String className1,
505: String className2) {
506: int ldi1 = className1.lastIndexOf('.'); // NOI18N
507: int ldi2 = className2.lastIndexOf('.'); // NOI18N
508:
509: if (ldi1 != ldi2) {
510: return false;
511: }
512:
513: if (ldi1 == -1) {
514: return true;
515: }
516:
517: return (className1.substring(0, ldi1).equals(className2
518: .substring(0, ldi2)));
519: }
520:
521: /**
522: * Method to handle internal error condition.
523: *
524: * @param message The message describing the error
525: */
526: public static void internalError(String message) {
527: throw new InternalError(message);
528: }
529:
530: public static void printErrorMessage(String message) {
531: System.err.println("*** Profiler error (" + getDate() + "): "
532: + message); // NOI18N
533: }
534:
535: public static void printInfoMessage(String message) {
536: if (printInfo) {
537: System.err.println("*** Profiler message (" + getDate()
538: + "): " + message); // NOI18N
539: }
540: }
541:
542: public static void printVerboseInfoMessage(String message) {
543: if (verbosePrint) {
544: System.err.println("Profiler Engine: " + message); // NOI18N
545: }
546: }
547:
548: public static void printVerboseInfoMessage(String[] elements) {
549: if (!verbosePrint) {
550: return;
551: }
552:
553: int i;
554:
555: for (i = 0; i < (elements.length - 1); i++) {
556: System.err.print(elements[i]);
557: System.err.print(" "); // NOI18N
558: }
559:
560: System.err.println(elements[i]);
561: }
562:
563: public static void printWarningMessage(String message) {
564: System.err.println("*** Profiler warning (" + getDate() + "): "
565: + message); // NOI18N
566: }
567:
568: public static byte[] readFileIntoBuffer(FileOrZipEntry fileOrZip)
569: throws IOException {
570: if (fileOrZip.isFile()) {
571: checkFile(fileOrZip.getFile(), false);
572: }
573:
574: InputStream in = fileOrZip.getInputStream();
575: int len = (int) fileOrZip.getLength();
576: byte[] buf = new byte[len];
577: int readBytes;
578: int ofs = 0;
579: int remBytes = len;
580:
581: do {
582: readBytes = in.read(buf, ofs, remBytes);
583: ofs += readBytes;
584: remBytes -= readBytes;
585: } while (ofs < len);
586:
587: in.close();
588:
589: return buf;
590: }
591:
592: private static String getDate() {
593: return (new Date()).toString();
594: }
595:
596: private static boolean isSupported15or16or17(String jdkVersionString) {
597: if (jdkVersionString.startsWith("1.7")) { // NOI18N
598:
599: return true;
600: } else if (jdkVersionString.startsWith("1.6")) { // NOI18N
601:
602: return true;
603: } else if (jdkVersionString.startsWith("1.5")) { // NOI18N
604:
605: if (jdkVersionString.equals("1.5.0")
606: || jdkVersionString.startsWith("1.5.0_01")
607: || jdkVersionString.startsWith("1.5.0_02")
608: || jdkVersionString.startsWith("1.5.0_03")) { // NOI18N
609:
610: return false;
611: } else {
612: return true;
613: }
614: } else {
615: return false;
616: }
617: }
618: }
|