0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2008 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2008 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: package org.netbeans.updater;
0043:
0044: import java.io.*;
0045: import java.util.*;
0046: import java.util.jar.*;
0047:
0048: //import org.openide.util.NbBundle;
0049: import javax.swing.SwingUtilities;
0050:
0051: /** Class used by autoupdate module for the work with module files and
0052: * for installing / uninstalling modules
0053: *
0054: * @author Petr Hrebejk, Ales Kemr, Jiri Rechtacek
0055: * @version
0056: */
0057: public final class ModuleUpdater extends Thread {
0058:
0059: public ModuleUpdater(Collection<File> forInstall) {
0060: this .forInstall = forInstall;
0061: }
0062:
0063: /** Relative name of update directory */
0064: private static final String DOWNLOAD_DIR_NAME = "download"; // NOI18N
0065:
0066: /** Relative name of directory where the .NBM files are downloaded */
0067: static final String DOWNLOAD_DIR = UpdaterDispatcher.UPDATE_DIR
0068: + UpdateTracking.FILE_SEPARATOR + DOWNLOAD_DIR_NAME; // NOI18N
0069:
0070: /** Relative name of backup directory */
0071: private static final String BACKUP_DIR = UpdaterDispatcher.UPDATE_DIR
0072: + UpdateTracking.FILE_SEPARATOR + "backup"; // NOI18N
0073:
0074: /** The name of zip entry containing netbeans files */
0075: public static final String UPDATE_NETBEANS_DIR = "netbeans"; // NOI18N
0076:
0077: /** The name of zip entry containing java_extension files */
0078: public static final String UPDATE_JAVA_EXT_DIR = "java_ext"; // NOI18N
0079:
0080: /** The name of zip entry containing files for external installer */
0081: public static final String UPDATE_MAIN_DIR = "main"; // NOI18N
0082:
0083: /** Name of external installer parameters file*/
0084: private static final String JVM_PARAMS_FILE = "main.properties"; // NOI18N
0085:
0086: /** Extension of the distribution files */
0087: public static final String NBM_EXTENSION = "nbm"; // NOI18N
0088:
0089: /** The name of the log file */
0090: public static final String LOG_FILE_NAME = "update.log"; // NOI18N
0091:
0092: /** The name of the install_later file */
0093: public static final String LATER_FILE_NAME = "install_later.xml"; // NOI18N
0094:
0095: public static final char SPACE = ' ';
0096: public static final char QUOTE = '\"';
0097:
0098: private static final String TEMP_FILE_NAME = "temporary";
0099:
0100: public static final String UPDATER_JAR = "updater.jar"; // NOI18N
0101: public static final String AUTOUPDATE_UPDATER_JAR_PATH = "netbeans/modules/ext/"
0102: + UPDATER_JAR; // NOI18N
0103:
0104: /** files that are supposed to be installed (when running inside the ide) */
0105: private Collection<File> forInstall;
0106: private Map<File, Collection<File>> files2clustersForInstall;
0107:
0108: /** Should the thread stop */
0109: private volatile boolean stop = false;
0110:
0111: private volatile boolean suspend = false;
0112:
0113: /** Total length of unpacked files */
0114: private long totalLength;
0115:
0116: /** Creates new ModuleUpdater */
0117: @Override
0118: public void run() {
0119: assert !SwingUtilities.isEventDispatchThread() : "Cannot run in EQ";
0120: try {
0121:
0122: checkStop();
0123:
0124: if (getClustersForInstall().isEmpty()) {
0125: endRun();
0126: }
0127:
0128: checkStop();
0129:
0130: totalLength();
0131:
0132: checkStop();
0133:
0134: unpack();
0135:
0136: for (File cluster : UpdateTracking.clusters(true)) {
0137: deleteAdditionalInfo(cluster);
0138: }
0139:
0140: } catch (Exception x) {
0141: x.printStackTrace();
0142: } finally {
0143: if (UpdaterFrame.isFromIDE()) {
0144: UpdaterFrame.getUpdaterFrame().runningFinished();
0145: }
0146: }
0147: }
0148:
0149: private void deleteInstallLater(File cluster) {
0150: File later = new File(cluster, UpdateTracking.FILE_SEPARATOR
0151: + DOWNLOAD_DIR + UpdateTracking.FILE_SEPARATOR
0152: + LATER_FILE_NAME);
0153: if (later.exists()) {
0154: later.delete();
0155: }
0156: File f = later.getParentFile();
0157: while (f != null && f.delete()) { // remove empty dirs too
0158: f = f.getParentFile();
0159: }
0160: }
0161:
0162: private void deleteAdditionalInfo(File cluster) {
0163: File additional = new File(cluster,
0164: UpdateTracking.FILE_SEPARATOR + DOWNLOAD_DIR
0165: + UpdateTracking.FILE_SEPARATOR
0166: + UpdateTracking.ADDITIONAL_INFO_FILE_NAME);
0167: if (additional != null && additional.exists()) {
0168: additional.delete();
0169: }
0170: File f = additional == null ? null : additional.getParentFile();
0171: while (f != null && f.delete()) { // remove empty dirs too
0172: f = f.getParentFile();
0173: }
0174: }
0175:
0176: /** ends the run of update */
0177: void endRun() {
0178: stop = true;
0179: }
0180:
0181: /** checks wheter ends the run of update */
0182: private void checkStop() {
0183:
0184: if (suspend)
0185: while (suspend)
0186: ;
0187:
0188: if (stop) {
0189: if (UpdaterFrame.isFromIDE()) {
0190: UpdaterFrame.getUpdaterFrame().unpackingFinished();
0191: } else {
0192: System.exit(0);
0193: }
0194: }
0195: }
0196:
0197: private void processFilesForInstall() {
0198: // if installOnly are null then generate all NBMs around all clusters
0199: if (forInstall == null) {
0200: files2clustersForInstall = new HashMap<File, Collection<File>>();
0201: for (File cluster : UpdateTracking.clusters(true)) {
0202: Collection<File> tmp = getModulesToInstall(cluster);
0203: files2clustersForInstall.put(cluster, tmp);
0204: // if ModuleUpdater runs 'offline' then delete install_later files
0205: if (!UpdaterFrame.isFromIDE()) {
0206: deleteInstallLater(cluster);
0207: }
0208: }
0209: } else {
0210: files2clustersForInstall = new HashMap<File, Collection<File>>();
0211: for (File nbm : forInstall) {
0212: File cluster = getCluster(nbm);
0213: if (files2clustersForInstall.get(cluster) == null) {
0214: files2clustersForInstall.put(cluster,
0215: new HashSet<File>());
0216: }
0217: files2clustersForInstall.get(cluster).add(nbm);
0218: }
0219: }
0220: }
0221:
0222: private static File getCluster(File nbm) {
0223: File cluster = null;
0224: try {
0225: // nbms are in <cluster>/update/download dir
0226: // but try to check it
0227: assert nbm.exists() : nbm + " for install exists.";
0228: assert nbm.getParentFile() != null : nbm + " has parent.";
0229: assert DOWNLOAD_DIR_NAME.equalsIgnoreCase(nbm
0230: .getParentFile().getName()) : nbm
0231: + " is in directory " + DOWNLOAD_DIR_NAME;
0232: assert nbm.getParentFile().getParentFile() != null : nbm
0233: .getParentFile()
0234: + " has parent.";
0235: assert UpdaterDispatcher.UPDATE_DIR.equalsIgnoreCase(nbm
0236: .getParentFile().getParentFile().getName()) : nbm
0237: + " is in directory "
0238: + UpdaterDispatcher.UPDATE_DIR;
0239: assert nbm.getParentFile().getParentFile().getParentFile() != null : nbm
0240: .getParentFile().getParentFile()
0241: + " has parent.";
0242:
0243: cluster = nbm.getParentFile().getParentFile()
0244: .getParentFile();
0245: } catch (NullPointerException npe) {
0246: System.out.println("Error: getCluster (" + nbm
0247: + ") throws " + npe);
0248: }
0249: return cluster;
0250: }
0251:
0252: private Collection<File> getFilesForInstallInCluster(File cluster) {
0253: if (files2clustersForInstall == null) {
0254: processFilesForInstall();
0255: }
0256: return files2clustersForInstall.get(cluster);
0257: }
0258:
0259: private Collection<File> getClustersForInstall() {
0260: if (files2clustersForInstall == null) {
0261: processFilesForInstall();
0262: }
0263: return files2clustersForInstall.keySet();
0264: }
0265:
0266: /** Determines size of unpacked modules */
0267: private void totalLength() {
0268: totalLength = 0L;
0269:
0270: UpdaterFrame.setLabel(Localization
0271: .getBrandedString("CTL_PreparingUnpack"));
0272: Collection<File> allFiles = new HashSet<File>();
0273: for (File c : getClustersForInstall()) {
0274: allFiles.addAll(getFilesForInstallInCluster(c));
0275: }
0276: UpdaterFrame.setProgressRange(0, allFiles.size());
0277:
0278: int i = 0;
0279: for (File f : allFiles) {
0280:
0281: JarFile jarFile = null;
0282:
0283: try {
0284: jarFile = new JarFile(f);
0285: Enumeration<JarEntry> entries = jarFile.entries();
0286: while (entries.hasMoreElements()) {
0287: JarEntry entry = entries.nextElement();
0288:
0289: checkStop();
0290:
0291: if ((entry.getName()
0292: .startsWith(UPDATE_NETBEANS_DIR)
0293: || entry.getName().startsWith(
0294: ModuleUpdater.UPDATE_JAVA_EXT_DIR) || entry
0295: .getName().startsWith(UPDATE_MAIN_DIR))
0296: && !entry.isDirectory()) {
0297: totalLength += entry.getSize();
0298: }
0299: }
0300: UpdaterFrame.setProgressValue(i++);
0301: } catch (java.io.IOException e) {
0302: System.out
0303: .println("Error: Counting size of entries in "
0304: + f + " throws " + e);
0305: } finally {
0306: try {
0307: if (jarFile != null) {
0308: jarFile.close();
0309: }
0310: } catch (java.io.IOException e) {
0311: // We can't close the file do nothing
0312: System.out.println("Error: Closing " + jarFile
0313: + " input stream throws " + e); // NOI18N
0314: }
0315: }
0316: }
0317: }
0318:
0319: /** Unpack the distribution files into update directory */
0320:
0321: private void unpack() {
0322: long bytesRead = 0L;
0323: boolean hasMainClass;
0324:
0325: UpdaterFrame.setLabel(""); // NOI18N
0326: UpdaterFrame.setProgressRange(0, totalLength);
0327:
0328: ArrayList<UpdateTracking> allTrackings = new ArrayList<UpdateTracking>();
0329: Map<ModuleUpdate, UpdateTracking.Version> l10ns = new HashMap<ModuleUpdate, UpdateTracking.Version>();
0330:
0331: for (File cluster : getClustersForInstall()) {
0332: UpdateTracking tracking = UpdateTracking.getTracking(
0333: cluster, true);
0334: if (tracking == null) {
0335: throw new RuntimeException(
0336: "No update_tracking file in cluster " + cluster);
0337: }
0338: allTrackings.add(tracking);
0339:
0340: int installedNBMs = 0;
0341: for (File nbm : getFilesForInstallInCluster(cluster)) {
0342: installedNBMs++;
0343:
0344: UpdateTracking.Version version;
0345: UpdateTracking.Module modtrack;
0346:
0347: UpdaterFrame.getUpdaterFrame().unpackingIsRunning();
0348:
0349: ModuleUpdate mu = null;
0350: try {
0351: mu = new ModuleUpdate(nbm);
0352: } catch (RuntimeException re) {
0353: if (nbm.exists()) {
0354: if (!nbm.delete()) {
0355: System.out
0356: .println("Error: File "
0357: + nbm
0358: + " cannot be deleted. Propably file lock on the file."); // NOI18N
0359: assert false : "Error: File "
0360: + nbm
0361: + " cannot be deleted. Propably file lock on the file.";
0362: nbm.deleteOnExit();
0363: }
0364: }
0365: continue;
0366: }
0367: assert mu != null : "Module update is not null for file: "
0368: + nbm; // NOI18N
0369: if (mu.isL10n()) {
0370: modtrack = null;
0371: version = tracking.createVersion("0"); // NOI18N
0372: l10ns.put(mu, version);
0373: } else {
0374: modtrack = tracking.readModuleTracking(mu
0375: .getCodenamebase(), true);
0376: // find origin for file
0377: UpdateTracking.AdditionalInfo info = UpdateTracking
0378: .getAdditionalInformation(cluster);
0379: String origin = info != null
0380: && info.getSource(nbm.getName()) != null ? info
0381: .getSource(nbm.getName())
0382: : UpdateTracking.UPDATER_ORIGIN;
0383: version = modtrack.addNewVersion(mu
0384: .getSpecification_version(), origin);
0385: }
0386: // input streams should be released, but following is needed
0387: //System.gc();
0388:
0389: hasMainClass = false;
0390: UpdaterFrame.setLabel(Localization
0391: .getBrandedString("CTL_UnpackingFile")
0392: + " " + nbm.getName()); //NOI18N
0393: UpdaterFrame.setProgressValue(bytesRead);
0394: JarFile jarFile = null;
0395:
0396: try {
0397: jarFile = new JarFile(nbm);
0398: Enumeration entries = jarFile.entries();
0399: while (entries.hasMoreElements()) {
0400: JarEntry entry = (JarEntry) entries
0401: .nextElement();
0402: checkStop();
0403: if (entry.getName().startsWith(
0404: UPDATE_NETBEANS_DIR)) {
0405: if (!entry.isDirectory()) {
0406: if (AUTOUPDATE_UPDATER_JAR_PATH
0407: .equals(entry.getName())) {
0408: // skip updater.jar
0409: continue;
0410: }
0411: String pathTo = entry.getName()
0412: .substring(
0413: UPDATE_NETBEANS_DIR
0414: .length() + 1);
0415: // path without netbeans prefix
0416: if (mu.isL10n())
0417: version
0418: .addL10NFileWithCrc(
0419: pathTo,
0420: Long.toString(entry
0421: .getCrc()),
0422: mu
0423: .getSpecification_version());
0424: else
0425: version.addFileWithCrc(pathTo, Long
0426: .toString(entry.getCrc()));
0427:
0428: File destFile = new File(cluster, entry
0429: .getName().substring(
0430: UPDATE_NETBEANS_DIR
0431: .length()));
0432: if (destFile.exists()) {
0433: File bckFile = new File(
0434: getBackupDirectory(cluster),
0435: entry.getName());
0436: bckFile.getParentFile().mkdirs();
0437: // System.out.println("Backing up" ); // NOI18N
0438: copyStreams(new FileInputStream(
0439: destFile),
0440: new FileOutputStream(
0441: bckFile), -1);
0442: if (!destFile.delete()
0443: && isWindows()) {
0444: trickyDeleteOnWindows(destFile);
0445: }
0446: } else {
0447: destFile.getParentFile().mkdirs();
0448: }
0449: bytesRead = copyStreams(jarFile
0450: .getInputStream(entry),
0451: new FileOutputStream(destFile),
0452: bytesRead);
0453: UpdaterFrame
0454: .setProgressValue(bytesRead);
0455: }
0456: } else if (entry.getName().startsWith(
0457: UPDATE_MAIN_DIR)
0458: && !entry.isDirectory()) {
0459: // run main
0460: File destFile = new File(
0461: getMainDirectory(cluster),
0462: entry
0463: .getName()
0464: .substring(
0465: UPDATE_MAIN_DIR
0466: .length() + 1));
0467: destFile.getParentFile().mkdirs();
0468: hasMainClass = true;
0469: bytesRead = copyStreams(jarFile
0470: .getInputStream(entry),
0471: new FileOutputStream(destFile),
0472: bytesRead);
0473: UpdaterFrame.setProgressValue(bytesRead);
0474: }
0475: }
0476: if (hasMainClass) {
0477: MainConfig mconfig = new MainConfig(
0478: getMainDirString(cluster)
0479: + UpdateTracking.FILE_SEPARATOR
0480: + JVM_PARAMS_FILE, cluster);
0481: if (mconfig.isValid()) {
0482: String java_path = System
0483: .getProperty("java.home")
0484: + UpdateTracking.FILE_SEPARATOR
0485: + "bin"
0486: + UpdateTracking.FILE_SEPARATOR
0487: + "java"; // NOI18N
0488: java_path = quoteString(java_path);
0489: String torun = java_path
0490: + " -cp "
0491: + quoteString(getMainDirString(cluster)
0492: + mconfig.getClasspath())
0493: + mconfig.getCommand(); // NOI18N
0494: startCommand(torun);
0495:
0496: deleteDir(getMainDirectory(cluster));
0497: }
0498: }
0499: } catch (java.io.IOException e) {
0500: // Ignore non readable files
0501: e.printStackTrace();
0502: } finally {
0503: try {
0504: if (jarFile != null)
0505: jarFile.close();
0506: } catch (java.io.IOException e) {
0507: // We can't close the file do nothing
0508: // System.out.println("Can't close : " + e ); // NOI18N
0509: }
0510: //System.out.println("Dleting :" + nbmFiles[i].getName() + ":" + nbmFiles[i].delete() ); // NOI18N
0511:
0512: if (!nbm.delete()) {
0513: System.out.println("Error: Cannot delete "
0514: + nbm); // NOI18N
0515: nbm.deleteOnExit();
0516: }
0517: }
0518: if (!mu.isL10n()) {
0519: modtrack.write();
0520: modtrack.writeConfigModuleXMLIfMissing();
0521: }
0522: }
0523:
0524: if (installedNBMs > 0) {
0525: UpdaterDispatcher.touchLastModified(cluster);
0526: }
0527: }
0528:
0529: for (UpdateTracking t : allTrackings) {
0530: // update_tracking of l10n's
0531: for (Map.Entry<ModuleUpdate, UpdateTracking.Version> entry : l10ns
0532: .entrySet()) {
0533: ModuleUpdate mod = entry.getKey();
0534: UpdateTracking.Version version = entry.getValue();
0535: UpdateTracking.Module modtrack = t.readModuleTracking(
0536: mod.getCodenamebase(), true);
0537: modtrack.addL10NVersion(version);
0538: modtrack.write();
0539: }
0540: t.deleteUnusedFiles();
0541: }
0542: }
0543:
0544: private static boolean trickyDeleteOnWindows(File destFile) {
0545: assert isWindows() : "Call it only on Windows but system is "
0546: + System.getProperty("os.name");
0547: File f = new File(destFile.getParentFile(), destFile.getName());
0548: assert f.exists() : "The file " + f + " must exists.";
0549: try {
0550: File tmpFile = File.createTempFile(TEMP_FILE_NAME, null, f
0551: .getParentFile());
0552: if (tmpFile.delete()) {
0553: f.renameTo(tmpFile);
0554: }
0555: } catch (IOException ex) {
0556: //no special handling needed
0557: }
0558: return !f.exists();
0559: }
0560:
0561: private static boolean isWindows() {
0562: String os = System.getProperty("os.name"); // NOI18N
0563: return (os != null && os.toLowerCase().startsWith("windows"));//NOI18N
0564: }
0565:
0566: private void startCommand(String torun) {
0567: Runtime runtime = Runtime.getRuntime();
0568: Process proces;
0569: try {
0570: proces = runtime.exec(parseParameters(torun));
0571: final Process proc2 = proces;
0572: new Thread() {
0573: @Override
0574: public void run() {
0575: try {
0576: InputStreamReader stream = new InputStreamReader(
0577: proc2.getErrorStream());
0578: BufferedReader reader = new BufferedReader(
0579: stream);
0580: String vystup;
0581: do {
0582: vystup = reader.readLine();
0583: if (vystup != null)
0584: System.out.println(vystup);
0585: } while (vystup != null);
0586: } catch (Exception e) {
0587: e.printStackTrace();
0588: }
0589: }
0590: }.start();
0591: int x = proces.waitFor();
0592: } catch (Exception e) {
0593: e.printStackTrace();
0594: }
0595: }
0596:
0597: /** The directory where to backup old versions of modules */
0598: public File getBackupDirectory(File activeCluster) {
0599: // #72960: Backup file created in wrong cluster
0600: File backupDirectory = new File(activeCluster, BACKUP_DIR);
0601: if (!backupDirectory.isDirectory()) {
0602: backupDirectory.mkdirs();
0603: }
0604:
0605: return backupDirectory;
0606: }
0607:
0608: /** Gets the netbeans directory */
0609: private File getMainDirectory(File activeCluster) {
0610: // #72918: Post-install cannot write into platform cluster
0611: File mainDirectory = new File(activeCluster,
0612: UpdateTracking.FILE_SEPARATOR
0613: + UpdaterDispatcher.UPDATE_DIR
0614: + UpdateTracking.FILE_SEPARATOR
0615: + UPDATE_MAIN_DIR);
0616: if (!mainDirectory.isDirectory()) {
0617: mainDirectory.mkdirs();
0618: }
0619:
0620: return mainDirectory;
0621: }
0622:
0623: private String getMainDirString(File activeCluster) {
0624: return getMainDirectory(activeCluster).getPath();
0625: }
0626:
0627: /** Quotes string correctly, eg. removes all quotes from the string and adds
0628: * just one at the start and
0629: * second one at the end.
0630: * @param s string to be quoted
0631: * @return correctly quoted string
0632: */
0633: public static final String quoteString(String s) {
0634: if (s.indexOf(SPACE) > -1) {
0635: StringBuffer sb = new StringBuffer(s);
0636: int i = 0;
0637: while (i < sb.length()) {
0638: if (sb.charAt(i) == QUOTE)
0639: sb.deleteCharAt(i);
0640: else
0641: i++;
0642: }
0643: sb.insert(0, QUOTE);
0644: sb.append(QUOTE);
0645: return sb.toString();
0646: }
0647: return s;
0648: }
0649:
0650: /**
0651: * It takes the current progress value so it can update progress
0652: * properly, and also return the new progress value after the
0653: * copy is done.
0654: *
0655: * @param progressVal The current progress bar value. If this is
0656: * negative, we don't want to update the progress bar.
0657: */
0658: private long copyStreams(InputStream src, OutputStream dest,
0659: long progressVal) throws java.io.IOException {
0660:
0661: BufferedInputStream bsrc = new BufferedInputStream(src);
0662: BufferedOutputStream bdest = new BufferedOutputStream(dest);
0663:
0664: int count = 0;
0665:
0666: int c;
0667:
0668: try {
0669: while ((c = bsrc.read()) != -1) {
0670: bdest.write(c);
0671: count++;
0672: if (count > 8500) {
0673: if (progressVal >= 0) {
0674: progressVal += count;
0675: UpdaterFrame.setProgressValue(progressVal);
0676: }
0677:
0678: count = 0;
0679: checkStop();
0680: }
0681: }
0682: // Just update the value, no need to update the
0683: // GUI yet. Caller can do that.
0684: if (progressVal >= 0) {
0685: progressVal += count;
0686: }
0687: } finally {
0688: bsrc.close();
0689: bdest.close();
0690: src.close();
0691: dest.close();
0692: }
0693: return progressVal;
0694:
0695: }
0696:
0697: private void deleteDir(File dir) {
0698: File[] files = dir.listFiles();
0699: for (int j = 0; j < files.length; j++) {
0700: if (files[j].isDirectory()) {
0701: deleteDir(files[j]);
0702: if (!files[j].delete()) {
0703: System.out.println("Error: Cannot delete "
0704: + files[j]); //NOI18N
0705: assert false : "Cannot delete " + files[j];
0706: }
0707: }
0708: }
0709: }
0710:
0711: /** [Copied from org.openide.util.Utilities]
0712: * Parses parameters from a given string in shell-like manner.
0713: * Users of the Bourne shell (e.g. on Unix) will already be familiar
0714: * with the behavior.
0715: * For example, when using {@link org.openide.execution.NbProcessDescriptor}
0716: * you should be able to:
0717: * <ul>
0718: * <li>Include command names with embedded spaces, such as
0719: * <code>c:\Program Files\jdk\bin\javac</code>.
0720: * <li>Include extra command arguments, such as <code>-Dname=value</code>.
0721: * <li>Do anything else which might require unusual characters or
0722: * processing. For example:
0723: * <p><code><pre>
0724: * "c:\program files\jdk\bin\java" -Dmessage="Hello /\\/\\ there!" -Xmx128m
0725: * </pre></code>
0726: * <p>This example would create the following executable name and arguments:
0727: * <ol>
0728: * <li> <code>c:\program files\jdk\bin\java</code>
0729: * <li> <code>-Dmessage=Hello /\/\ there!</code>
0730: * <li> <code>-Xmx128m</code>
0731: * </ol>
0732: * Note that the command string does not escape its backslashes--under the assumption
0733: * that Windows users will not think to do this, meaningless escapes are just left
0734: * as backslashes plus following character.
0735: * </ul>
0736: * <em>Caveat</em>: even after parsing, Windows programs (such as
0737: * the Java launcher)
0738: * may not fully honor certain
0739: * characters, such as quotes, in command names or arguments. This is because programs
0740: * under Windows frequently perform their own parsing and unescaping (since the shell
0741: * cannot be relied on to do this). On Unix, this problem should not occur.
0742: * @param s a string to parse
0743: * @return an array of parameters
0744: */
0745: private static String[] parseParameters(String s) {
0746: int NULL = 0x0; // STICK + whitespace or NULL + non_"
0747: int INPARAM = 0x1; // NULL + " or STICK + " or INPARAMPENDING + "\ // NOI18N
0748: int INPARAMPENDING = 0x2; // INPARAM + \
0749: int STICK = 0x4; // INPARAM + " or STICK + non_" // NOI18N
0750: int STICKPENDING = 0x8; // STICK + \
0751: Vector<String> params = new Vector<String>(5, 5);
0752: char c;
0753:
0754: int state = NULL;
0755: StringBuilder buff = new StringBuilder(20);
0756: int slength = s.length();
0757: for (int i = 0; i < slength; i++) {
0758: c = s.charAt(i);
0759: if (Character.isWhitespace(c)) {
0760: if (state == NULL) {
0761: if (buff.length() > 0) {
0762: params.addElement(buff.toString());
0763: buff.setLength(0);
0764: }
0765: } else if (state == STICK) {
0766: params.addElement(buff.toString());
0767: buff.setLength(0);
0768: state = NULL;
0769: } else if (state == STICKPENDING) {
0770: buff.append('\\');
0771: params.addElement(buff.toString());
0772: buff.setLength(0);
0773: state = NULL;
0774: } else if (state == INPARAMPENDING) {
0775: state = INPARAM;
0776: buff.append('\\');
0777: buff.append(c);
0778: } else { // INPARAM
0779: buff.append(c);
0780: }
0781: continue;
0782: }
0783:
0784: if (c == '\\') {
0785: if (state == NULL) {
0786: ++i;
0787: if (i < slength) {
0788: char cc = s.charAt(i);
0789: if (cc == '"' || cc == '\\') {
0790: buff.append(cc);
0791: } else if (Character.isWhitespace(cc)) {
0792: buff.append(c);
0793: --i;
0794: } else {
0795: buff.append(c);
0796: buff.append(cc);
0797: }
0798: } else {
0799: buff.append('\\');
0800: break;
0801: }
0802: continue;
0803: } else if (state == INPARAM) {
0804: state = INPARAMPENDING;
0805: } else if (state == INPARAMPENDING) {
0806: buff.append('\\');
0807: state = INPARAM;
0808: } else if (state == STICK) {
0809: state = STICKPENDING;
0810: } else if (state == STICKPENDING) {
0811: buff.append('\\');
0812: state = STICK;
0813: }
0814: continue;
0815: }
0816:
0817: if (c == '"') {
0818: if (state == NULL) {
0819: state = INPARAM;
0820: } else if (state == INPARAM) {
0821: state = STICK;
0822: } else if (state == STICK) {
0823: state = INPARAM;
0824: } else if (state == STICKPENDING) {
0825: buff.append('"');
0826: state = STICK;
0827: } else { // INPARAMPENDING
0828: buff.append('"');
0829: state = INPARAM;
0830: }
0831: continue;
0832: }
0833:
0834: if (state == INPARAMPENDING) {
0835: buff.append('\\');
0836: state = INPARAM;
0837: } else if (state == STICKPENDING) {
0838: buff.append('\\');
0839: state = STICK;
0840: }
0841: buff.append(c);
0842: }
0843: // collect
0844: if (state == INPARAM) {
0845: params.addElement(buff.toString());
0846: } else if ((state & (INPARAMPENDING | STICKPENDING)) != 0) {
0847: buff.append('\\');
0848: params.addElement(buff.toString());
0849: } else { // NULL or STICK
0850: if (buff.length() != 0) {
0851: params.addElement(buff.toString());
0852: }
0853: }
0854: String[] ret = new String[params.size()];
0855: params.copyInto(ret);
0856: return ret;
0857: }
0858:
0859: /** read jvm parameters from jvm parameters file */
0860: class MainConfig extends Object {
0861:
0862: /** The names of properties from jvm parameters file */
0863: private final String PAR_MAIN = "mainClass"; // NOI18N
0864: private final String PAR_RELCP = "relativeClassPath"; // NOI18N
0865: private final String PAR_JVMPAR = "jvm.parameters"; // NOI18N
0866: private final String PAR_MAINARGS = "mainClass.arguments"; // NOI18N
0867:
0868: /** The names of variables allow to use in jvm parameters file */
0869: private final String VAR_IDE_HOME = "%IDE_HOME%"; // NOI18N
0870: private final String VAR_IDE_USER = "%IDE_USER%"; // NOI18N
0871: private final String VAR_FILE_SEPARATOR = "%FS%"; // NOI18N
0872: private final String VAR_JAVA_HOME = "%JAVA_HOME%"; // NOI18N
0873:
0874: /** joined all parameters of jvm java command */
0875: private String parameters = ""; // NOI18N
0876: private String classpath = ""; // NOI18N
0877:
0878: /** is jvm parameters file in valid stucture */
0879: private boolean valid = false;
0880: private final File activeCluster;
0881:
0882: public MainConfig(String spath, File activeCluster) {
0883: valid = readParms(spath);
0884: this .activeCluster = activeCluster;
0885: }
0886:
0887: /** returns all parameters needed by jvm java command */
0888: public String getCommand() {
0889: return parameters;
0890: }
0891:
0892: /** returns all parameters needed by jvm java command */
0893: public String getClasspath() {
0894: return classpath;
0895: }
0896:
0897: /** is jvm parameters file in valid stucture */
0898: public boolean isValid() {
0899: return valid;
0900: }
0901:
0902: /** read jvm parameters from jvm parameters file */
0903: private boolean readParms(String spath) {
0904: Properties details = new Properties();
0905: FileInputStream fis = null;
0906: try {
0907: details.load(fis = new FileInputStream(spath)); // NOI18N
0908: } catch (IOException e) {
0909: return false;
0910: } finally {
0911: if (fis != null)
0912: try {
0913: fis.close();
0914: } catch (IOException e) { /* ignore */
0915: }
0916: ;
0917: }
0918:
0919: String mainclass;
0920: String relpath;
0921: String jvmparms;
0922: String mainargs;
0923:
0924: relpath = details.getProperty(PAR_RELCP, null);
0925: if (relpath != null) {
0926: relpath = replaceVars(relpath);
0927: StringTokenizer token = new StringTokenizer(relpath,
0928: UpdateTracking.PATH_SEPARATOR, false);
0929: while (token.hasMoreTokens()) {
0930: classpath = classpath
0931: + UpdateTracking.PATH_SEPARATOR
0932: + changeRelative(token.nextToken());
0933: }
0934: }
0935:
0936: parameters = "";
0937: jvmparms = details.getProperty(PAR_JVMPAR, null);
0938: if (jvmparms != null)
0939: parameters = parameters + " " + jvmparms; // NOI18N
0940:
0941: mainclass = details.getProperty(PAR_MAIN, null);
0942: if (mainclass == null)
0943: return false;
0944: else
0945: parameters = parameters + " " + mainclass; // NOI18N
0946:
0947: mainargs = details.getProperty(PAR_MAINARGS, null);
0948: if (mainargs != null)
0949: parameters = parameters + " " + mainargs; // NOI18N
0950:
0951: parameters = replaceVars(parameters);
0952: return true;
0953: }
0954:
0955: private String replaceVars(String original) {
0956: original = replaceAll(original, VAR_IDE_HOME,
0957: UpdateTracking.getPlatformDir() == null ? ""
0958: : UpdateTracking.getPlatformDir().getPath());
0959: original = replaceAll(original, VAR_IDE_USER,
0960: UpdateTracking.getPlatformDir() == null ? ""
0961: : UpdateTracking.getPlatformDir().getPath());
0962: original = replaceAll(original, VAR_FILE_SEPARATOR,
0963: UpdateTracking.FILE_SEPARATOR);
0964: original = replaceAll(original, VAR_JAVA_HOME, System
0965: .getProperty("java.home"));
0966: return original;
0967: }
0968:
0969: private String changeRelative(String path) {
0970: if (new File(path).isAbsolute())
0971: return path;
0972: else
0973: return getMainDirString(this .activeCluster)
0974: + UpdateTracking.FILE_SEPARATOR + path;
0975: }
0976:
0977: /** replace all occurences of String what by String repl in the String sin */
0978: private String replaceAll(String sin, String what, String repl) {
0979: StringBuffer sb = new StringBuffer(sin);
0980: int i = sb.toString().indexOf(what);
0981: int len = what.length();
0982: while (i > -1) {
0983: sb.replace(i, i + len, repl);
0984: i = sb.toString().indexOf(what, i + 1);
0985: }
0986:
0987: return sb.toString();
0988: }
0989: }
0990:
0991: /** Compute the list of modules that should be installed into this
0992: * cluster.
0993: * @param File root of cluster
0994: * @return List<File> of nbm files
0995: */
0996: public static Set<File> getModulesToInstall(File cluster) {
0997:
0998: class NbmFilter implements java.io.FilenameFilter {
0999: public boolean accept(File dir, String name) {
1000: return name.endsWith(ModuleUpdater.NBM_EXTENSION);
1001: }
1002: }
1003:
1004: File idir = new File(cluster, ModuleUpdater.DOWNLOAD_DIR);
1005: File[] arr = idir.listFiles(new NbmFilter());
1006:
1007: if (arr == null) {
1008: return Collections.emptySet();
1009: } else {
1010: return new HashSet<File>(Arrays.asList(arr));
1011: }
1012: }
1013:
1014: }
|