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: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.visualweb.complib;
043:
044: import java.io.BufferedInputStream;
045: import java.io.File;
046: import java.io.FileInputStream;
047: import java.io.FileOutputStream;
048: import java.io.IOException;
049: import java.io.OutputStream;
050: import java.nio.channels.FileChannel;
051: import java.util.Properties;
052: import java.util.logging.Logger;
053: import java.util.zip.ZipEntry;
054: import java.util.zip.ZipInputStream;
055:
056: import org.apache.tools.ant.module.api.support.ActionUtils;
057: import org.netbeans.api.project.FileOwnerQuery;
058: import org.netbeans.api.project.Project;
059: import org.netbeans.api.project.ProjectManager;
060: import org.netbeans.modules.visualweb.api.designerapi.DesignerServiceHack;
061: import org.netbeans.modules.visualweb.project.jsf.api.JsfProjectConstants;
062: import org.openide.ErrorManager;
063: import org.openide.execution.ExecutorTask;
064: import org.openide.filesystems.FileObject;
065: import org.openide.filesystems.FileUtil;
066: import org.openide.filesystems.Repository;
067: import org.openide.modules.InstalledFileLocator;
068:
069: /**
070: * Misc methods to simplify interface to IDE
071: *
072: * @author Edwin Goei
073: */
074: public class IdeUtil {
075: private static final Logger logger = Logger.getLogger(IdeUtil.class
076: .getPackage().getName());
077:
078: private static File raveClusterDir;
079:
080: /**
081: * Returns the Logger for this NB module. Use Java logging instead of the older NB ErrorManager APIs.
082: *
083: * @return
084: */
085: public static Logger getLogger() {
086: return logger;
087: }
088:
089: /**
090: * @deprecated Use the newer Java logging API.
091: * @param th
092: */
093: public static void logWarning(Throwable th) {
094: ErrorManager.getDefault()
095: .notify(ErrorManager.INFORMATIONAL, th);
096: }
097:
098: public static void logWarning(String msg) {
099: logWarning(new Throwable(msg));
100: }
101:
102: public static void logWarning(String msg, Throwable cause) {
103: logWarning(new Throwable(msg, cause));
104: }
105:
106: /**
107: * @deprecated Use the newer Java logging API.
108: * @param th
109: */
110: public static void logError(Throwable th) {
111: ErrorManager.getDefault().notify(ErrorManager.ERROR, th);
112: }
113:
114: public static void logError(String msg) {
115: logError(new Throwable(msg));
116: }
117:
118: public static void logError(String msg, Throwable cause) {
119: logError(new Throwable(msg, cause));
120: }
121:
122: public static void printDebug(String msg) {
123: System.err.println(msg);
124: }
125:
126: /**
127: * Return the Project that is currently active according to the Designer.
128: *
129: * @return currently active project or null, if none.
130: */
131: public static Project getActiveProject() {
132: FileObject fileObject = DesignerServiceHack.getDefault()
133: .getCurrentFile();
134: if (fileObject == null) {
135: return null;
136: }
137: return FileOwnerQuery.getOwner(fileObject);
138: }
139:
140: /**
141: * Returns a NB Project for a project directory or else null if not a project.
142: *
143: * @param projectDir
144: * @return NB Project object or null if not a project
145: */
146: public static Project fileToProject(File projectDir) {
147: try {
148: FileObject fo = FileUtil.toFileObject(projectDir);
149: if (fo != null && /* #60518 */fo.isFolder()) {
150: return ProjectManager.getDefault().findProject(fo);
151: } else {
152: return null;
153: }
154: } catch (IOException e) {
155: ErrorManager.getDefault().notify(
156: ErrorManager.INFORMATIONAL, e);
157: return null;
158: }
159: }
160:
161: /**
162: * Remove whitespace in a String and replace with underscores
163: *
164: * @param str
165: * @return new String with whitespace replaced with underscores
166: */
167: public static String removeWhiteSpace(String str) {
168: String[] parts = str.split("\\s+"); // NOI18N
169: if (parts.length <= 1) {
170: return str;
171: }
172:
173: StringBuffer buf = new StringBuffer();
174: buf.append(parts[0]);
175: for (int i = 1; i < parts.length; i++) {
176: buf.append('_');
177: buf.append(parts[i]);
178: }
179: return buf.toString();
180: }
181:
182: /**
183: * Unzip a zip or jar file into a dest directory. Derived from jar command in JDK.
184: *
185: * @param zipFile
186: * a zip or jar file
187: * @param dest
188: * destination directory to contain expanded contents
189: * @throws IOException
190: */
191: public static void unzip(File zipFile, File dest)
192: throws IOException {
193: ZipInputStream zis = new ZipInputStream(
194: new BufferedInputStream(new FileInputStream(zipFile)));
195: ZipEntry e;
196: while ((e = zis.getNextEntry()) != null) {
197: File f = new File(dest, e.getName().replace('/',
198: File.separatorChar));
199: if (e.isDirectory()) {
200: if (!f.exists() && !f.mkdirs() || !f.isDirectory()) {
201: throw new IOException("Unable to create dir: "
202: + f.getPath());
203: }
204: } else {
205: if (f.getParent() != null) {
206: File d = new File(f.getParent());
207: if (!d.exists() && !d.mkdirs() || !d.isDirectory()) {
208: throw new IOException("Unable to create dir: "
209: + d.getPath());
210: }
211: }
212: OutputStream os = new FileOutputStream(f);
213: byte[] b = new byte[512];
214: int len;
215: while ((len = zis.read(b, 0, b.length)) != -1) {
216: os.write(b, 0, len);
217: }
218: zis.closeEntry();
219: os.close();
220: }
221: }
222: zis.close();
223: }
224:
225: /**
226: * @param antScript
227: * Ant build file
228: * @param target
229: * target to build
230: * @param props
231: * properties to set
232: * @throws IOException
233: */
234: public static void runAntTask(File antScript, String target,
235: Properties props) throws IOException {
236: ExecutorTask executorTask = ActionUtils.runTarget(FileUtil
237: .toFileObject(antScript), new String[] { target },
238: props);
239:
240: int result = executorTask.result();
241: if (result != 0) {
242: throw new IOException("Ant task execution failed");
243: }
244: }
245:
246: /**
247: * Return the non-extension part of a filename. eg. foo.txt -> "foo"
248: *
249: * @param name
250: * @return
251: */
252: public static String removeExtension(String name) {
253: int i = name.lastIndexOf('.');
254: if (i < 0) {
255: return name;
256: }
257: return name.substring(0, i);
258: }
259:
260: /**
261: * Find unique file name within a directory which can either be a plain file or a directory.
262: *
263: * @param dir
264: * eg. an absoluteLibDir
265: * @param baseFileName
266: * eg. "sample-date-dt"
267: * @param suffix
268: * Can be empty string to mean no suffix. eg. ".jar", ""
269: * @return
270: */
271: public static File findUniqueFile(File dir, String baseFileName,
272: String suffix) {
273: assert dir.isDirectory();
274:
275: String testName = baseFileName + suffix;
276: File testFile = new File(dir, testName);
277: int i = 0;
278: while (testFile.exists()) {
279: i++;
280: testName = baseFileName + "_" + i + suffix;
281: testFile = new File(dir, testName);
282: }
283: return testFile;
284: }
285:
286: /**
287: * Get the top level netbeans install directory
288: *
289: * @return
290: */
291: public static File getNetBeansInstallDirectory() {
292: File dir = getRaveClusterDirectory();
293: if (dir != null) {
294: return dir.getParentFile();
295: }
296: return null;
297: // return getRaveClusterDirectory().getParentFile();
298: }
299:
300: /**
301: * Get the rave samples directory
302: *
303: * @return
304: */
305: public static File getRaveSamplesDirectory() {
306: return new File(IdeUtil.getRaveClusterDirectory(), "samples"); // NOI18N
307: }
308:
309: /**
310: * Get the rave cluster directory
311: *
312: * @return
313: */
314: private static File getRaveClusterDirectory() {
315: // Isn't there a better way to find the top level rave directory??
316: if (raveClusterDir == null) {
317: File file = InstalledFileLocator
318: .getDefault()
319: .locate(
320: "modules/org-netbeans-modules-visualweb-complib.jar",
321: null, false); // NOI18N
322: if (file != null) {
323: raveClusterDir = file.getParentFile().getParentFile();
324: }
325: }
326: return raveClusterDir;
327: }
328:
329: public static void copyFileRecursive(File source, File dest)
330: throws IOException {
331: File newItem = null;
332: if (dest.isDirectory()) {
333: newItem = new File(dest, source.getName());
334: } else {
335: newItem = dest;
336: }
337:
338: if (source.isDirectory()) {
339: newItem.mkdir();
340: File[] contents = source.listFiles();
341:
342: for (int i = 0; i < contents.length; i++) {
343: copyFileRecursive(contents[i], newItem);
344: }
345: } else {
346: copyFile(source, newItem);
347: }
348: }
349:
350: /**
351: * Deletes all files and subdirectories under dir. Returns true if all deletions were
352: * successful. If a deletion fails, the method stops attempting to delete and returns false.
353: *
354: * @param dir
355: * @return
356: */
357: public static boolean deleteRecursive(File dir) {
358: if (dir.isDirectory()) {
359: String[] children = dir.list();
360: for (int i = 0; i < children.length; i++) {
361: boolean success = deleteRecursive(new File(dir,
362: children[i]));
363: if (!success) {
364: return false;
365: }
366: }
367: }
368:
369: // The directory is now empty so delete it
370: return dir.delete();
371: }
372:
373: /**
374: * Possibly make a copy of a file to workaround a problem on Windows where a jar file can be
375: * locked and not allow the user to remove it. The tradeoff is that the file will be copied
376: * which may take time for large files. A System property can be set to override the default
377: * behavior.
378: *
379: * @param origFile
380: * original file eg. jar or complib file
381: * @return
382: * @throws IOException
383: */
384: public static File freeJarFile(File origFile) throws IOException {
385: boolean isWindows = System.getProperty("os.name").toLowerCase() // NOI18N
386: .indexOf("windows") != -1;// NOI18N
387:
388: // Escape hatch to allow user to override default copying behavior
389: String doTempCopy = System.getProperty("toolbox.makeTempCopy",
390: Boolean // NOI18N
391: .toString(isWindows));
392:
393: // In JDK 1.5 we can use Boolean.parseBoolean() instead
394: if (!Boolean.valueOf(doTempCopy).booleanValue()) {
395: return origFile;
396: }
397:
398: // Create a temporary file that will be deleted on exit. Figure out a
399: // user-friendly prefix and suffix if possible.
400: String prefix;
401: String suffix;
402: String baseName = origFile.getName();
403: int dotIndex = baseName.lastIndexOf('.');
404: if (dotIndex != -1 && (dotIndex + 1) < baseName.length()) {
405: prefix = baseName.substring(0, dotIndex) + "_";
406: suffix = baseName.substring(dotIndex);
407: } else {
408: prefix = baseName;
409: suffix = null;
410: }
411: File temp = File.createTempFile(prefix, suffix);
412: temp.deleteOnExit();
413: copyFile(origFile, temp);
414: return temp;
415: }
416:
417: /**
418: * Copy files using nio
419: *
420: * @param src
421: * source file
422: * @param dst
423: * destination file
424: * @throws IOException
425: */
426: public static void copyFile(File src, File dst) throws IOException {
427: FileChannel srcChannel = new FileInputStream(src).getChannel();
428: FileChannel dstChannel = new FileOutputStream(dst).getChannel();
429: dstChannel.transferFrom(srcChannel, 0, srcChannel.size());
430: srcChannel.close();
431: dstChannel.close();
432: }
433:
434: /**
435: * Return base class name using "." as a separator
436: *
437: * @param name
438: * @return
439: */
440: public static String baseClassName(String name) {
441: int i = name.lastIndexOf('.');
442: if (i < 0) {
443: return name;
444: }
445: if (name.length() > 0) {
446: return name.substring(i + 1);
447: }
448: return name;
449: }
450:
451: /**
452: * Return basename of a string similar to unix basename command. Uses platform file separator
453: * char. Basename of root dir is itself.
454: *
455: * @param name
456: * @return
457: */
458: public static String baseName(String name) {
459: int i = name.lastIndexOf(File.separatorChar);
460: if (i < 0) {
461: return name;
462: }
463: if (name.length() > 0) {
464: return name.substring(i + 1);
465: }
466: return name;
467: }
468:
469: /**
470: * Returns a directory under the project root under which library resources such as jar files
471: * can be managed by the IDE.
472: *
473: * @param project
474: * Target project
475: * @return File of the library directory or null if it does not exist
476: */
477: public static File getProjectLibraryDirectory(Project project) {
478: FileObject projRoot = project.getProjectDirectory();
479: File projRootFile = FileUtil.toFile(projRoot);
480: return new File(projRootFile,
481: JsfProjectConstants.PATH_LIBRARIES);
482: }
483:
484: /** ********* Begin module-specifc methods ****************************** */
485:
486: /** Root directory in userDir where complib state is stored */
487: private static File complibStateDir;
488:
489: /**
490: * Returns the NetBeans module code name base.
491: *
492: * @return
493: */
494: public static String getCodeNameBase() {
495: // Code name base should be the same as the package name of this class
496: return IdeUtil.class.getPackage().getName();
497: }
498:
499: /**
500: * Get the directory where state of this module is kept. This will be in the userdir and also
501: * part of the NetBeans filesystem so that it will make it easier to migrate to future IDE
502: * versions.
503: *
504: * @return
505: * @throws IOException
506: */
507: public static File getComplibStateDir() {
508: if (complibStateDir == null) {
509: File root = FileUtil.toFile(Repository.getDefault()
510: .getDefaultFileSystem().getRoot());
511: // Follow NetBeans convention of replacing dots with dashes
512: String stateDirName = getCodeNameBase().replace('.', '-');
513: complibStateDir = new File(root, stateDirName);
514: if (!complibStateDir.exists() && !complibStateDir.mkdirs()) {
515: IllegalStateException ex = new IllegalStateException(
516: "Unable to create dir: " + complibStateDir);
517: logError(ex);
518: throw ex;
519: }
520: }
521: return complibStateDir;
522: }
523:
524: /** *********** End module-specifc methods ****************************** */
525: }
|