001: /*
002: * The contents of this file are subject to the terms of the Common Development
003: * and Distribution License (the License). You may not use this file except in
004: * compliance with the License.
005: *
006: * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
007: * or http://www.netbeans.org/cddl.txt.
008: *
009: * When distributing Covered Code, include this CDDL Header Notice in each file
010: * and include the License file at http://www.netbeans.org/cddl.txt.
011: * If applicable, add the following below the CDDL Header, with the fields
012: * enclosed by brackets [] replaced by your own identifying information:
013: * "Portions Copyrighted [year] [name of copyright owner]"
014: *
015: * The Original Software is NetBeans. The Initial Developer of the Original
016: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
017: * Microsystems, Inc. All Rights Reserved.
018: */
019:
020: package org.netbeans.installer;
021:
022: import com.installshield.product.ProductAction;
023: import com.installshield.product.ProductActionSupport;
024: import com.installshield.product.ProductBuilderSupport;
025: import com.installshield.product.ProductException;
026: import com.installshield.product.RequiredBytesTable;
027: import com.installshield.util.Log;
028: import com.installshield.wizard.service.MutableOperationState;
029: import com.installshield.wizard.service.exitcode.ExitCodeService;
030: import com.installshield.wizard.service.file.FileService;
031:
032: import java.io.BufferedReader;
033: import java.io.File;
034: import java.lang.reflect.InvocationTargetException;
035: import java.lang.reflect.Method;
036: import java.net.MalformedURLException;
037: import java.net.URL;
038: import java.net.URLClassLoader;
039:
040: public class StorageBuilderAction extends ProductAction {
041:
042: //return code incase an error returns
043: public static final int STORAGE_BUILDER_UNHANDLED_ERROR = -200;
044: public static final String STORAGE_BUILDER_TEMP_DIR = "mdrtmpdir";
045: public static final String STORAGE_BUILDER_TEMP_FILE = "mdrtmpfile";
046:
047: private int installMode = 0;
048: private static final int INSTALL = 0;
049: private static final int UNINSTALL = 1;
050:
051: private String ideClusterDir;
052: private String platformClusterDir;
053: private String sbDestDir;
054:
055: private String statusDesc = "";
056: private String nbInstallDir = "";
057: private String uninstDir = "";
058: private String tempPath = "";
059:
060: private File mdrTempDir;
061:
062: private boolean success = false;
063:
064: private ProgressThread progressThread;
065: private MutableOperationState mutableOperationState;
066:
067: public StorageBuilderAction() {
068: }
069:
070: public void build(ProductBuilderSupport support) {
071: try {
072: support.putClass(RunCommand.class.getName());
073: support
074: .putClass("org.netbeans.installer.RunCommand$StreamAccumulator");
075: support.putClass(Util.class.getName());
076: support
077: .putClass("org.netbeans.installer.StorageBuilderAction$ProgressThread");
078: } catch (Exception ex) {
079: System.out.println(ex.getLocalizedMessage());
080: ex.printStackTrace();
081: }
082: }
083:
084: private void init(ProductActionSupport support) {
085: /*
086: ProductService pservice = (ProductService)getService(ProductService.NAME);
087: String productURL = ProductService.DEFAULT_PRODUCT_SOURCE;
088: instDirPath = resolveString((String)pservice.getProductBeanProperty(productURL,null,"absoluteInstallLocation")); */
089: nbInstallDir = resolveString("$P(absoluteInstallLocation)");
090: logEvent(this , Log.DBG, "nbInstallDir: " + nbInstallDir);
091: uninstDir = nbInstallDir + File.separator + "_uninst";
092: logEvent(this , Log.DBG, "uninstDir: " + uninstDir);
093: logEvent(this , Log.DBG, "jdkHome: " + Util.getJdkHome());
094: tempPath = Util.getTmpDir();
095: logEvent(this , Log.DBG, "TempPath: " + tempPath);
096:
097: ideClusterDir = resolveString("$L(org.netbeans.installer.Bundle,NetBeans.ideClusterDir)");
098: platformClusterDir = resolveString("$L(org.netbeans.installer.Bundle,NetBeans.platformClusterDir)");
099: sbDestDir = ideClusterDir + File.separator + "mdrstorage";
100:
101: mutableOperationState = support.getOperationState();
102: }
103:
104: public void install(ProductActionSupport support) {
105: long currtime = System.currentTimeMillis();
106: statusDesc = resolveString("$L(org.netbeans.installer.Bundle,ProgressPanel.storageBuilderMessage)")
107: + " "
108: + resolveString("$L(org.netbeans.installer.Bundle,ProgressPanel.waitMessage)");
109:
110: support.getOperationState().setStatusDescription(statusDesc);
111:
112: try {
113: init(support);
114: installMode = INSTALL;
115:
116: //Create new temp dir for storage builder
117: mdrTempDir = new File(tempPath + File.separator
118: + STORAGE_BUILDER_TEMP_DIR);
119: int i = 1;
120: while (mdrTempDir.exists()) {
121: mdrTempDir = new File(tempPath + File.separator
122: + STORAGE_BUILDER_TEMP_DIR + i);
123: i++;
124: }
125: if (!mdrTempDir.mkdir()) {
126: logEvent(this , Log.ERROR, "# # # # # # # #");
127: logEvent(this , Log.ERROR,
128: "Fatal error: Cannot create temporary directory for Storage Builder.");
129: try {
130: ExitCodeService ecservice = (ExitCodeService) getService(ExitCodeService.NAME);
131: ecservice
132: .setExitCode(STORAGE_BUILDER_UNHANDLED_ERROR);
133: } catch (Exception ex) {
134: logEvent(this , Log.ERROR,
135: "Couldn't set exit code. ");
136: }
137: return;
138: }
139: logEvent(this , Log.DBG, "Created temporary dir for SB: "
140: + mdrTempDir.getAbsolutePath());
141:
142: //Create destination dir for storage builder
143: File mdrDestDir = new File(nbInstallDir + File.separator
144: + sbDestDir);
145: if (mdrDestDir.exists()) {
146: logEvent(this , Log.ERROR, "# # # # # # # #");
147: logEvent(this , Log.ERROR,
148: "Fatal error: Storage Builder destination directory already exists.");
149: try {
150: ExitCodeService ecservice = (ExitCodeService) getService(ExitCodeService.NAME);
151: ecservice
152: .setExitCode(STORAGE_BUILDER_UNHANDLED_ERROR);
153: } catch (Exception ex) {
154: logEvent(this , Log.ERROR,
155: "Could not set exit code. ");
156: }
157: return;
158: }
159: if (!mdrDestDir.mkdir()) {
160: logEvent(this , Log.ERROR, "# # # # # # # #");
161: logEvent(this , Log.ERROR,
162: "Fatal error: Cannot create destination directory for Storage Builder.");
163: try {
164: ExitCodeService ecservice = (ExitCodeService) getService(ExitCodeService.NAME);
165: ecservice
166: .setExitCode(STORAGE_BUILDER_UNHANDLED_ERROR);
167: } catch (Exception ex) {
168: logEvent(this , Log.ERROR,
169: "Could not set exit code. ");
170: }
171: return;
172: }
173: logEvent(this , Log.DBG, "Created destination dir for SB: "
174: + mdrDestDir.getAbsolutePath());
175:
176: long startTime = System.currentTimeMillis();
177:
178: //Set system proeprties for sb
179: System.getProperties().put(
180: "gjast.location",
181: nbInstallDir + File.separator + ideClusterDir
182: + File.separator + "modules"
183: + File.separator + "ext" + File.separator
184: + "gjast.jar");
185:
186: System.getProperties().put(
187: "mdr.filename",
188: mdrTempDir.getAbsolutePath() + File.separator
189: + STORAGE_BUILDER_TEMP_FILE);
190:
191: System.getProperties().put(
192: "preparse.files",
193: nbInstallDir + File.separator + "_uninst"
194: + File.separator + "storagebuilder"
195: + File.separator + "preparse-files.txt");
196:
197: ClassLoader parent = this .getClass().getClassLoader()
198: .getParent();
199: URL[] classPath = getClassPath();
200: URLClassLoader urlClassLoader = new URLClassLoader(
201: classPath, parent);
202: Class clazz = Class.forName(
203: "org.netbeans.lib.java.storagebuilder.Main", true,
204: urlClassLoader);
205:
206: //Must be called so that Lookup finds org.netbeans.modules.masterfs.MasterURLMapper
207: Thread.currentThread()
208: .setContextClassLoader(urlClassLoader);
209:
210: Method method = null;
211: Class[] params = new Class[] { String[].class, String.class };
212:
213: try {
214: method = clazz.getMethod("prebuildJDKStorages", params);
215: } catch (NoSuchMethodException exc) {
216: logEvent(this , Log.ERROR, "Could not find SB method.");
217: logEvent(this , Log.ERROR, exc);
218: return;
219: }
220:
221: startProgress();
222:
223: Object oResult = null;
224: String destDir = nbInstallDir + File.separator
225: + ideClusterDir + File.separator + "mdrstorage";
226: String jdkHome;
227: if (Util.isJDKAlreadyInstalled() && Util.isWindowsOS()) {
228: jdkHome = Util.getInstalledJdk();
229: } else {
230: jdkHome = Util.getJdkHome();
231: }
232: Object[] args = new Object[] { new String[] { jdkHome },
233: destDir };
234: try {
235: oResult = method.invoke(null, args);
236: } catch (IllegalAccessException exc) {
237: logEvent(this , Log.ERROR, exc);
238: return;
239: } catch (IllegalArgumentException exc) {
240: logEvent(this , Log.ERROR, exc);
241: return;
242: } catch (InvocationTargetException exc) {
243: logEvent(this , Log.ERROR, exc);
244: return;
245: }
246:
247: logEvent(this , Log.DBG, "Storage Builder returned: "
248: + oResult);
249:
250: long endTime = System.currentTimeMillis();
251: logEvent(this , Log.DBG, "Storage builder took: "
252: + (endTime - startTime) + "ms");
253: } catch (Exception ex) {
254: logEvent(this , Log.ERROR, ex);
255: } finally {
256: stopProgress();
257:
258: //Delete temporary dir
259: Util.deleteCompletely(mdrTempDir, support);
260: logEvent(this , Log.DBG, "Deleted temporary dir for SB: "
261: + mdrTempDir.getAbsolutePath());
262: }
263: logEvent(this , Log.DBG, "Running Storage Builder took: (ms) "
264: + (System.currentTimeMillis() - currtime));
265: }
266:
267: /** Create array of URLs filed with classpath elements for running
268: * storage builder.
269: */
270: private URL[] getClassPath() throws MalformedURLException {
271: URL[] classPath;
272: String s;
273: //For Windows replace "\" in path by "/" to get correct URL.
274: if (Util.isWindowsOS()) {
275: s = nbInstallDir.replace('\\', '/');
276: } else {
277: s = nbInstallDir;
278: }
279: logEvent(this , Log.DBG, "getClassPath Path prefix1: " + s);
280: //Replace spaces in URL
281: if (Util.isWindowsOS()) {
282: //On Windows path starts with disk like C: so we must add additional slash
283: s = "file:///" + s.replaceAll(" ", "%20") + "/";
284: } else {
285: s = "file://" + s.replaceAll(" ", "%20") + "/";
286: }
287: logEvent(this , Log.DBG, "getClassPath Path prefix2: " + s);
288: try {
289: classPath = new URL[] {
290: new URL(s + ideClusterDir
291: + "/modules/org-netbeans-jmi-javamodel.jar"),
292: new URL(
293: s
294: + ideClusterDir
295: + "/modules/org-netbeans-modules-javacore.jar"),
296: new URL(
297: s
298: + platformClusterDir
299: + "/modules/org-netbeans-modules-masterfs.jar"),
300:
301: new URL(
302: s
303: + "_uninst/storagebuilder/storagebuilder.jar"),
304:
305: new URL(s + platformClusterDir
306: + "/core/org-openide-filesystems.jar"),
307: new URL(s + platformClusterDir
308: + "/lib/org-openide-util.jar"),
309: new URL(s + platformClusterDir
310: + "/lib/org-openide-modules.jar"),
311:
312: new URL(s + platformClusterDir
313: + "/modules/org-openide-actions.jar"),
314: new URL(s + platformClusterDir
315: + "/modules/org-openide-awt.jar"),
316: new URL(s + platformClusterDir
317: + "/modules/org-openide-dialogs.jar"),
318: new URL(s + platformClusterDir
319: + "/modules/org-openide-execution.jar"),
320: new URL(s + platformClusterDir
321: + "/modules/org-openide-explorer.jar"),
322: new URL(s + platformClusterDir
323: + "/modules/org-openide-io.jar"),
324: new URL(s + platformClusterDir
325: + "/modules/org-openide-loaders.jar"),
326: new URL(s + platformClusterDir
327: + "/modules/org-openide-nodes.jar"),
328: new URL(s + platformClusterDir
329: + "/modules/org-openide-options.jar"),
330: new URL(s + platformClusterDir
331: + "/modules/org-openide-text.jar"),
332: new URL(s + platformClusterDir
333: + "/modules/org-openide-windows.jar"),
334:
335: new URL(s + ideClusterDir
336: + "/modules/org-netbeans-api-java.jar"),
337: new URL(s + ideClusterDir
338: + "/modules/javax-jmi-model.jar"),
339: new URL(s + ideClusterDir
340: + "/modules/javax-jmi-reflect.jar"),
341: new URL(s + ideClusterDir
342: + "/modules/org-netbeans-api-mdr.jar"),
343: new URL(s + ideClusterDir
344: + "/modules/org-netbeans-modules-mdr.jar"),
345: new URL(
346: s
347: + ideClusterDir
348: + "/modules/org-netbeans-modules-jmiutils.jar"),
349: new URL(
350: s
351: + ideClusterDir
352: + "/modules/org-netbeans-modules-projectapi.jar"),
353: new URL(
354: s
355: + ideClusterDir
356: + "/modules/org-netbeans-modules-classfile.jar"),
357: new URL(s + ideClusterDir
358: + "/modules/ext/java-parser.jar") };
359: } catch (MalformedURLException exc) {
360: throw exc;
361: }
362: //Dump class path
363: for (int i = 0; i < classPath.length; i++) {
364: logEvent(this , Log.DBG, "cl[" + i + "]: "
365: + classPath[i].toString());
366: }
367: return classPath;
368: }
369:
370: /** Does cleaning. */
371: public void uninstall(ProductActionSupport support) {
372: init(support);
373: installMode = UNINSTALL;
374:
375: String fileName;
376: //Delete directory created by storage builder during install
377: fileName = nbInstallDir + File.separator + sbDestDir;
378: logEvent(this , Log.DBG, "Deleting: " + fileName);
379: Util.deleteCompletely(new File(fileName), support);
380:
381: fileName = uninstDir + File.separator + "storagebuilder"
382: + File.separator + "storagebuilder.log";
383: logEvent(this , Log.DBG, "Deleting: " + fileName);
384: Util.deleteCompletely(new File(fileName), support);
385: }
386:
387: /** Returns checksum for Storage directory in bytes. */
388: public long getCheckSum() {
389: //Need to set according to JDK version for 1.5.0 it is 64MB
390: //for 1.4.2_06 42MB
391: //return 67000000L;
392: //just indexing src.zip no deep parsing
393: return 16000000L;
394: //return 44000000L;
395: }
396:
397: /* Returns the required bytes table information.
398: * @return required bytes table.
399: * @see com.installshield.product.RequiredBytesTable
400: */
401: public RequiredBytesTable getRequiredBytes()
402: throws ProductException {
403: RequiredBytesTable req = new RequiredBytesTable();
404:
405: nbInstallDir = resolveString("$P(absoluteInstallLocation)");
406: logEvent(this , Log.DBG, "getRequiredBytes nbInstallDir: "
407: + nbInstallDir);
408: req.addBytes(nbInstallDir, getCheckSum());
409:
410: //#48948: We must set dirs here because init() is not run yet when getRequiredBytes
411: //is called.
412: tempPath = Util.getTmpDir();
413: logEvent(this , Log.DBG, "getRequiredBytes tempPath: "
414: + tempPath);
415:
416: //Storage is first built to temp dir then it is copied to destination
417: req.addBytes(tempPath, getCheckSum());
418: logEvent(this , Log.DBG,
419: "Total (not necessarily on one disk when tempdir is redirected) Mbytes = "
420: + (req.getTotalBytes() >> 20));
421: logEvent(this , Log.DBG, "RequiredBytesTable: " + req);
422: return req;
423: }
424:
425: private char getWinSystemDrive() {
426: char sysDrive = 'C';
427: try {
428: String sysLib = resolveString("$D(lib)"); // Resolve system library directory
429: logEvent(this , Log.DBG, "System Library directory is "
430: + sysLib);
431: sysDrive = sysLib.charAt(0); // Resolve system drive letter
432: logEvent(this , Log.DBG, "Found system drive is: "
433: + String.valueOf(sysDrive));
434: } catch (Exception ex) {
435: Util.logStackTrace(this , ex);
436: return 'C';
437: }
438: return sysDrive;
439: }
440:
441: private static int ESTIMATED_TIME = 3500; // tenths of seconds
442:
443: public int getEstimatedTimeToInstall() {
444: return ESTIMATED_TIME;
445: }
446:
447: public void startProgress() {
448: progressThread = new ProgressThread();
449: progressThread.start();
450: }
451:
452: public void stopProgress() {
453: //Method startProgress() must be called first
454: if (progressThread == null) {
455: return;
456: }
457: logEvent(this , Log.DBG, "in progress stop");
458: progressThread.finish();
459: logEvent(this , Log.DBG, "Finishing ProgressThread");
460: //wait until progressThread is interrupted
461: while (progressThread.isAlive()) {
462: logEvent(this , Log.DBG,
463: "Waiting for progressThread to die...");
464: try {
465: Thread.currentThread().sleep(1000);
466: } catch (Exception ex) {
467: }
468: }
469: logEvent(this , Log.DBG, "ProgressThread finished");
470: progressThread = null;
471: logEvent(this , Log.DBG, "active Threads -> "
472: + Thread.currentThread().activeCount());
473: }
474:
475: private boolean setExecutable(String filename) {
476: try {
477: FileService fileService = (FileService) getService(FileService.NAME);
478: if (fileService == null) {
479: logEvent(this , Log.DBG,
480: "FileService is null. Cannot set file as executable: "
481: + filename);
482: return false;
483: }
484: fileService.setFileExecutable(filename);
485: } catch (Exception ex) {
486: logEvent(this , Log.DBG, "Cannot set file as executable: "
487: + filename + "\nException: " + ex);
488: return false;
489: }
490: return true;
491: }
492:
493: /** inner class to update the progress pane while installation */
494: class ProgressThread extends Thread {
495: private boolean loop = true;
496: private MutableOperationState mos;
497:
498: //progress bar related variables
499: private long percentageCompleted = 0L;
500: private long percentageStart = 0L;
501: private long checksum = 0L;
502:
503: //status detail related variables
504: //progress dots (...) after the path if it is being shown since s while
505: private final int MIN_DOTS = 3;
506: private int fileCounter = 0;
507: private String lastPathShown;
508:
509: //status description related variables
510: private File logFile;
511: private boolean doStatusDescUpdate = true;
512:
513: //variables related to pkg unzipping before installation. Only for Solaris
514: private boolean isUnzipping = false;
515: private File unzipLog;
516: private BufferedReader unzipLogReader = null;
517: private long startTime = 0L;
518:
519: public ProgressThread() {
520: this .mos = mutableOperationState;
521: checksum = getCheckSum();
522: }
523:
524: public void run() {
525: long sleepTime = 1000L;
526: percentageStart = mos.getProgress().getPercentComplete();
527: logEvent(this , Log.DBG, "Starting percentageStart: "
528: + percentageStart);
529: while (loop) {
530: //logEvent(this, Log.DBG,"looping");
531: try {
532: //logEvent(this, Log.DBG,"going 2 updateProgressBar");
533: updateProgressBar();
534: Thread.currentThread().sleep(sleepTime);
535: if (isCanceled()) {
536: return;
537: }
538: } catch (InterruptedException ex) {
539: //ex.printStackTrace();
540: loop = false;
541: return;
542: } catch (Exception ex) {
543: loop = false;
544: String trace = Util.getStackTrace(ex);
545: logEvent(this , Log.DBG, trace);
546: logEvent(this , Log.ERROR, trace);
547: return;
548: }
549: }
550: logEvent(this , Log.DBG, "Finished loop loop:" + loop);
551: }
552:
553: public void finish() {
554: loop = false;
555: mos.setStatusDetail("");
556: logEvent(this , Log.DBG, "Finishing");
557: ;
558: if (!mos.isCanceled()) {
559: mos.setStatusDescription("");
560: percentageCompleted = mos.getProgress()
561: .getPercentComplete();
562: for (; percentageCompleted <= 100; percentageCompleted++) {
563: logEvent(this , Log.DBG, "percentageCompleted = "
564: + percentageCompleted + " updateCounter "
565: + mos.getUpdateCounter());
566: mos.updatePercentComplete(ESTIMATED_TIME, 1L, 100L);
567: }
568: } else {
569: String statusDesc = resolveString("$L(org.netbeans.installer.Bundle, ProgressPanel.installationCancelled)");
570: mos.setStatusDescription(statusDesc);
571: mos.getProgress().setPercentComplete(0);
572: }
573:
574: }
575:
576: /** Check if the operation is canceled. */
577: private boolean isCanceled() {
578: if (mos.isCanceled() && loop) {
579: logEvent(this , Log.DBG, "MOS is cancelled");
580: loop = false;
581: }
582:
583: return mos.isCanceled();
584: }
585:
586: /** Updates the progress bar. */
587: private void updateProgressBar() {
588: if (isCanceled()) {
589: return;
590: }
591: long size = Util.getFileSize(mdrTempDir);
592: long perc = (size * (100 - percentageStart)) / checksum;
593: logEvent(this , Log.DBG, "installed size = " + size
594: + " perc = " + perc);
595: if (perc <= percentageCompleted) {
596: return;
597: }
598: long increment = perc - percentageCompleted;
599: mos.updatePercentComplete(ESTIMATED_TIME, increment, 100L);
600: percentageCompleted = perc;
601: }
602:
603: }
604:
605: }
|