0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU General
0007: * Public License Version 2 only ("GPL") or the Common Development and Distribution
0008: * License("CDDL") (collectively, the "License"). You may not use this file except in
0009: * compliance with the License. You can obtain a copy of the License at
0010: * http://www.netbeans.org/cddl-gplv2.html or nbbuild/licenses/CDDL-GPL-2-CP. See the
0011: * License for the specific language governing permissions and limitations under the
0012: * License. When distributing the software, include this License Header Notice in
0013: * each file and include the License file at nbbuild/licenses/CDDL-GPL-2-CP. Sun
0014: * designates this particular file as subject to the "Classpath" exception as
0015: * provided by Sun in the GPL Version 2 section of the License file that
0016: * accompanied this code. If applicable, add the following below the License Header,
0017: * with the fields enclosed by brackets [] replaced by your own identifying
0018: * information: "Portions Copyrighted [year] [name of copyright owner]"
0019: *
0020: * Contributor(s):
0021: *
0022: * The Original Software is NetBeans. The Initial Developer of the Original Software
0023: * is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun Microsystems, Inc. All
0024: * Rights Reserved.
0025: *
0026: * If you wish your version of this file to be governed by only the CDDL or only the
0027: * GPL Version 2, indicate your decision by adding "[Contributor] elects to include
0028: * this software in this distribution under the [CDDL or GPL Version 2] license." If
0029: * you do not indicate a single choice of license, a recipient has the option to
0030: * distribute your version of this file under either the CDDL, the GPL Version 2 or
0031: * to extend the choice of license to its licensees as provided above. However, if
0032: * you add GPL Version 2 code and therefore, elected the GPL Version 2 license, then
0033: * the option applies only if the new code is made subject to such option by the
0034: * copyright holder.
0035: */
0036:
0037: package org.netbeans.installer.utils;
0038:
0039: import java.io.BufferedReader;
0040: import java.io.File;
0041: import java.io.FileInputStream;
0042: import java.io.IOException;
0043: import java.io.InputStream;
0044: import java.io.StringReader;
0045: import java.lang.reflect.InvocationTargetException;
0046: import java.lang.reflect.Method;
0047: import java.net.InetAddress;
0048: import java.net.ServerSocket;
0049: import java.net.UnknownHostException;
0050: import java.security.CodeSigner;
0051: import java.security.GeneralSecurityException;
0052: import java.security.KeyStore;
0053: import java.security.KeyStoreException;
0054: import java.security.NoSuchAlgorithmException;
0055: import java.security.cert.Certificate;
0056: import java.security.cert.CertificateException;
0057: import java.security.cert.CertificateExpiredException;
0058: import java.security.cert.CertificateNotYetValidException;
0059: import java.security.cert.X509Certificate;
0060: import java.util.Collections;
0061: import java.util.Date;
0062: import java.util.LinkedList;
0063: import java.util.List;
0064: import java.util.Map;
0065: import java.util.Random;
0066: import java.util.jar.JarEntry;
0067: import java.util.jar.JarFile;
0068: import java.util.regex.Matcher;
0069: import java.util.regex.Pattern;
0070: import org.netbeans.installer.utils.UiUtils.CertificateAcceptanceStatus;
0071: import org.netbeans.installer.utils.exceptions.NativeException;
0072: import org.netbeans.installer.utils.helper.ApplicationDescriptor;
0073: import org.netbeans.installer.utils.helper.EnvironmentScope;
0074: import org.netbeans.installer.utils.helper.ErrorLevel;
0075: import org.netbeans.installer.utils.helper.ExecutionResults;
0076: import org.netbeans.installer.utils.helper.FilesList;
0077: import org.netbeans.installer.utils.helper.FinishHandler;
0078: import org.netbeans.installer.utils.helper.Platform;
0079: import org.netbeans.installer.utils.system.shortcut.FileShortcut;
0080: import org.netbeans.installer.utils.system.shortcut.Shortcut;
0081: import org.netbeans.installer.utils.helper.ShortcutLocationType;
0082: import org.netbeans.installer.utils.progress.Progress;
0083: import org.netbeans.installer.utils.system.NativeUtils;
0084: import org.netbeans.installer.utils.system.launchers.Launcher;
0085: import org.netbeans.installer.utils.system.launchers.LauncherFactory;
0086: import org.netbeans.installer.utils.system.launchers.LauncherProperties;
0087: import org.netbeans.installer.utils.system.shortcut.LocationType;
0088:
0089: /**
0090: *
0091: * @author Kirill Sorokin
0092: */
0093: public final class SystemUtils {
0094: /////////////////////////////////////////////////////////////////////////////////
0095: // Static
0096: private static Map<String, String> environment = new ProcessBuilder()
0097: .environment();
0098:
0099: private static NativeUtils nativeUtils;
0100:
0101: private static KeyStore caStore;
0102: private static KeyStore permanentTrustedStore;
0103: private static KeyStore sessionTrustedStore;
0104: private static KeyStore deniedStore;
0105:
0106: private static Platform currentPlatform;
0107:
0108: private static File localDirectory;
0109: private static FinishHandler finishHandler;
0110:
0111: // string resolution ////////////////////////////////////////////////////////////
0112: public static String resolveString(String string) {
0113: return resolveString(string, SystemUtils.class.getClassLoader());
0114: }
0115:
0116: public static String resolveString(String string, ClassLoader loader) {
0117: String parsed = string;
0118:
0119: if (parsed == null) {
0120: return null;
0121: }
0122: // N for Name
0123: try {
0124: parsed = parsed
0125: .replaceAll(
0126: "(?<!\\\\)\\$N\\{install\\}",
0127: StringUtils
0128: .escapeRegExp(getDefaultApplicationsLocation()
0129: .getAbsolutePath()));
0130: } catch (NativeException e) {
0131: ErrorManager.notifyError(ResourceUtils.getString(
0132: SystemUtils.class,
0133: ERROR_CANNOT_GET_DEFAULT_APPS_LOCATION_KEY), e);
0134: }
0135:
0136: parsed = parsed.replaceAll("(?<!\\\\)\\$N\\{home\\}",
0137: StringUtils.escapeRegExp(getUserHomeDirectory()
0138: .getAbsolutePath()));
0139: parsed = parsed.replaceAll("(?<!\\\\)\\$N\\{temp\\}",
0140: StringUtils.escapeRegExp(getTempDirectory()
0141: .getAbsolutePath()));
0142: parsed = parsed.replaceAll("(?<!\\\\)\\$N\\{current\\}",
0143: StringUtils.escapeRegExp(getCurrentDirectory()
0144: .getAbsolutePath()));
0145:
0146: Matcher matcher;
0147:
0148: // P for Properties
0149: matcher = Pattern.compile(
0150: "(?<!\\\\)\\$P\\{(.*?), (.*?)(?:, (.*?))?\\}").matcher(
0151: parsed);
0152: while (matcher.find()) {
0153: String basename = matcher.group(1);
0154: String key = matcher.group(2);
0155: String argumentsString = matcher.group(3);
0156:
0157: if (argumentsString == null) {
0158: parsed = parsed.replace(matcher.group(), ResourceUtils
0159: .getString(basename, key, loader));
0160: } else {
0161: Object[] arguments = (Object[]) argumentsString
0162: .split(", ?");
0163:
0164: parsed = parsed.replace(matcher.group(), ResourceUtils
0165: .getString(basename, key, loader, arguments));
0166: }
0167: }
0168:
0169: // F for Field
0170: matcher = Pattern
0171: .compile(
0172: "(?<!\\\\)\\$F\\{((?:[a-zA-Z_][a-zA-Z_0-9]*\\.)+[a-zA-Z_][a-zA-Z_0-9]*)\\.([a-zA-Z_][a-zA-Z_0-9]*)\\}")
0173: .matcher(parsed);
0174: while (matcher.find()) {
0175: String classname = matcher.group(1);
0176: String fieldname = matcher.group(2);
0177:
0178: try {
0179: Object object = loader.loadClass(classname).getField(
0180: fieldname).get(null);
0181: if (object != null) {
0182: String value = object.toString();
0183:
0184: parsed = parsed.replace(matcher.group(), value);
0185: }
0186: } catch (IllegalArgumentException e) {
0187: ErrorManager.notifyDebug(ResourceUtils
0188: .getString(SystemUtils.class,
0189: ERROR_CANNOT_PARSE_PATTERN_KEY, matcher
0190: .group()), e);
0191: } catch (SecurityException e) {
0192: ErrorManager.notifyDebug(ResourceUtils
0193: .getString(SystemUtils.class,
0194: ERROR_CANNOT_PARSE_PATTERN_KEY, matcher
0195: .group()), e);
0196: } catch (ClassNotFoundException e) {
0197: ErrorManager.notifyDebug(ResourceUtils
0198: .getString(SystemUtils.class,
0199: ERROR_CANNOT_PARSE_PATTERN_KEY, matcher
0200: .group()), e);
0201: } catch (IllegalAccessException e) {
0202: ErrorManager.notifyDebug(ResourceUtils
0203: .getString(SystemUtils.class,
0204: ERROR_CANNOT_PARSE_PATTERN_KEY, matcher
0205: .group()), e);
0206: } catch (NoSuchFieldException e) {
0207: ErrorManager.notifyDebug(ResourceUtils
0208: .getString(SystemUtils.class,
0209: ERROR_CANNOT_PARSE_PATTERN_KEY, matcher
0210: .group()), e);
0211: }
0212: }
0213:
0214: // M for Method
0215: matcher = Pattern
0216: .compile(
0217: "(?<!\\\\)\\$M\\{((?:[a-zA-Z_][a-zA-Z_0-9]*\\.)+[a-zA-Z_][a-zA-Z_0-9]*)\\.([a-zA-Z_][a-zA-Z_0-9]*)\\(\\)\\}")
0218: .matcher(parsed);
0219: while (matcher.find()) {
0220: String classname = matcher.group(1);
0221: String methodname = matcher.group(2);
0222:
0223: try {
0224: Method method = loader.loadClass(classname).getMethod(
0225: methodname);
0226: if (method != null) {
0227: Object object = method.invoke(null);
0228:
0229: if (object != null) {
0230: String value = object.toString();
0231:
0232: parsed = parsed.replace(matcher.group(), value);
0233: }
0234: }
0235: } catch (IllegalArgumentException e) {
0236: ErrorManager.notifyDebug(ResourceUtils
0237: .getString(SystemUtils.class,
0238: ERROR_CANNOT_PARSE_PATTERN_KEY, matcher
0239: .group()), e);
0240: } catch (SecurityException e) {
0241: ErrorManager.notifyDebug(ResourceUtils
0242: .getString(SystemUtils.class,
0243: ERROR_CANNOT_PARSE_PATTERN_KEY, matcher
0244: .group()), e);
0245: } catch (ClassNotFoundException e) {
0246: ErrorManager.notifyDebug(ResourceUtils
0247: .getString(SystemUtils.class,
0248: ERROR_CANNOT_PARSE_PATTERN_KEY, matcher
0249: .group()), e);
0250: } catch (IllegalAccessException e) {
0251: ErrorManager.notifyDebug(ResourceUtils
0252: .getString(SystemUtils.class,
0253: ERROR_CANNOT_PARSE_PATTERN_KEY, matcher
0254: .group()), e);
0255: } catch (NoSuchMethodException e) {
0256: ErrorManager.notifyDebug(ResourceUtils
0257: .getString(SystemUtils.class,
0258: ERROR_CANNOT_PARSE_PATTERN_KEY, matcher
0259: .group()), e);
0260: } catch (InvocationTargetException e) {
0261: ErrorManager.notifyDebug(ResourceUtils
0262: .getString(SystemUtils.class,
0263: ERROR_CANNOT_PARSE_PATTERN_KEY, matcher
0264: .group()), e);
0265: }
0266: }
0267:
0268: // R for Resource
0269: matcher = Pattern.compile("(?<!\\\\)\\$R\\{(.*?)\\}").matcher(
0270: parsed);
0271: while (matcher.find()) {
0272: String path = matcher.group(1);
0273:
0274: InputStream inputStream = null;
0275: try {
0276: inputStream = ResourceUtils.getResource(path, loader);
0277: parsed = parsed.replace(matcher.group(), StringUtils
0278: .readStream(inputStream));
0279: } catch (IOException e) {
0280: ErrorManager.notifyDebug(ResourceUtils
0281: .getString(SystemUtils.class,
0282: ERROR_CANNOT_PARSE_PATTERN_KEY, matcher
0283: .group()), e);
0284: } finally {
0285: if (inputStream != null) {
0286: try {
0287: inputStream.close();
0288: } catch (IOException e) {
0289: ErrorManager.notifyDebug(
0290: "Cannot close input stream after reading resource: "
0291: + matcher.group(), e);
0292: }
0293: }
0294: }
0295: }
0296:
0297: // S for System Property
0298: matcher = Pattern.compile("(?<!\\\\)\\$S\\{(.*?)\\}").matcher(
0299: parsed);
0300: while (matcher.find()) {
0301: String name = matcher.group(1);
0302: String value = System.getProperty(name);
0303:
0304: parsed = parsed.replace(matcher.group(), value);
0305: }
0306:
0307: // E for Environment Variable
0308: matcher = Pattern.compile("(?<!\\\\)\\$E\\{(.*?)\\}").matcher(
0309: parsed);
0310: while (matcher.find()) {
0311: try {
0312: String name = matcher.group(1);
0313: String value = getEnvironmentVariable(name);
0314:
0315: parsed = parsed.replace(matcher.group(), value);
0316: } catch (NativeException e) {
0317: ErrorManager.notifyDebug(ResourceUtils
0318: .getString(SystemUtils.class,
0319: ERROR_CANNOT_PARSE_PATTERN_KEY, matcher
0320: .group()), e);
0321: }
0322: }
0323:
0324: parsed.replace("\\$", "$");
0325: parsed.replace("\\\\", "\\");
0326:
0327: return parsed;
0328: }
0329:
0330: public static File resolvePath(String string) {
0331: return resolvePath(string, SystemUtils.class.getClassLoader());
0332: }
0333:
0334: public static File resolvePath(String path, ClassLoader loader) {
0335: final String separator = getFileSeparator();
0336:
0337: String parsed = resolveString(path, loader);
0338:
0339: parsed = parsed.replace("\\", separator);
0340: parsed = parsed.replace("/", separator);
0341:
0342: try {
0343: if (parsed.contains(separator + ".." + separator)
0344: || parsed.contains(separator + "." + separator)
0345: || parsed.endsWith(separator + "..")
0346: || parsed.endsWith(separator + ".")) {
0347: return new File(parsed).getCanonicalFile();
0348: }
0349: } catch (IOException e) {
0350: ErrorManager.notifyDebug(
0351: "Could not get the cannonical path", e);
0352: }
0353:
0354: return new File(parsed).getAbsoluteFile();
0355: }
0356:
0357: // system info //////////////////////////////////////////////////////////////////
0358: public static File getUserHomeDirectory() {
0359: return new File(USER_HOME);
0360: }
0361:
0362: public static String getUserName() {
0363: return System.getProperty("user.name");
0364: }
0365:
0366: public static boolean isCurrentUserAdmin() throws NativeException {
0367: return getNativeUtils().isCurrentUserAdmin();
0368: }
0369:
0370: public static File getCurrentDirectory() {
0371: return new File(".");
0372: }
0373:
0374: public static File getTempDirectory() {
0375: return new File(System.getProperty("java.io.tmpdir"));
0376: }
0377:
0378: public static File getDefaultApplicationsLocation()
0379: throws NativeException {
0380: return getNativeUtils().getDefaultApplicationsLocation();
0381: }
0382:
0383: public static File getCurrentJavaHome() {
0384: return new File(JAVA_HOME);
0385: }
0386:
0387: public static boolean isCurrentJava64Bit() {
0388: return System.getProperty("os.arch").equals("amd64")
0389: || System.getProperty("os.arch").equals("sparcv9");
0390: }
0391:
0392: public static File getPacker() {
0393: if (isWindows()) {
0394: return new File(getCurrentJavaHome(), "bin/pack200.exe");
0395: } else {
0396: return new File(getCurrentJavaHome(), "bin/pack200");
0397: }
0398: }
0399:
0400: public static File getUnpacker() {
0401: if (isWindows()) {
0402: return new File(getCurrentJavaHome(), "bin/unpack200.exe");
0403: } else {
0404: return new File(getCurrentJavaHome(), "bin/unpack200");
0405: }
0406: }
0407:
0408: public static String getLineSeparator() {
0409: return LINE_SEPARATOR;
0410: }
0411:
0412: public static String getFileSeparator() {
0413: return FILE_SEPARATOR;
0414: }
0415:
0416: public static String getPathSeparator() {
0417: return PATH_SEPARATOR;
0418: }
0419:
0420: public static long getFreeSpace(File file) throws NativeException {
0421: //LogManager.log("[SystemUtils] getFreeSpace");
0422: //LogManager.indent();
0423: //LogManager.log(ErrorLevel.DEBUG,
0424: // "... getting free space [requested path] : " + file.getPath());
0425: File directory = file;
0426: while (directory != null
0427: && (!directory.exists() || !directory.isDirectory())) {
0428: directory = directory.getParentFile();
0429: }
0430: //LogManager.log(ErrorLevel.DEBUG,
0431: // "... getting free space [existing parent] : " + directory.getPath());
0432: long space = getNativeUtils().getFreeSpace(directory);
0433: //LogManager.unindent();
0434: //LogManager.log(ErrorLevel.DEBUG, "... free space is : " + space);
0435: return space;
0436: }
0437:
0438: public static ExecutionResults executeCommand(String... command)
0439: throws IOException {
0440: return executeCommand(null, command);
0441: }
0442:
0443: public static ExecutionResults executeCommand(
0444: File workingDirectory, String... command)
0445: throws IOException {
0446: // construct the initial log message
0447: String commandString = StringUtils.asString(command,
0448: StringUtils.SPACE);
0449:
0450: if (workingDirectory == null) {
0451: workingDirectory = getCurrentDirectory();
0452: }
0453:
0454: LogManager
0455: .log(ErrorLevel.MESSAGE, "executing command: "
0456: + commandString + ", in directory: "
0457: + workingDirectory);
0458: LogManager.indent();
0459:
0460: StringBuilder processStdOut = new StringBuilder();
0461: StringBuilder processStdErr = new StringBuilder();
0462: int errorLevel = ExecutionResults.TIMEOUT_ERRORCODE;
0463:
0464: ProcessBuilder builder = new ProcessBuilder(command)
0465: .directory(workingDirectory);
0466:
0467: builder.environment().clear();
0468: builder.environment().putAll(environment);
0469: setDefaultEnvironment();
0470:
0471: Process process = builder.start();
0472:
0473: long startTime = System.currentTimeMillis();
0474: long endTime = startTime + MAX_EXECUTION_TIME;
0475: boolean doRun = true;
0476: long delay = INITIAL_DELAY;
0477: while (doRun && (System.currentTimeMillis() < endTime)) {
0478: try {
0479: Thread.sleep(delay);
0480: if (delay < MAX_DELAY) {
0481: delay += DELTA_DELAY;
0482: }
0483: } catch (InterruptedException e) {
0484: ErrorManager.notifyDebug("Interrupted", e);
0485: }
0486: try {
0487: errorLevel = process.exitValue();
0488: doRun = false;
0489: } catch (IllegalThreadStateException e) {
0490: ; // do nothing - the process is still running
0491: }
0492: String string;
0493:
0494: string = StringUtils.readStream(process.getInputStream());
0495: if (string.length() > 0) {
0496: BufferedReader reader = new BufferedReader(
0497: new StringReader(string));
0498: for (String line = reader.readLine(); line != null; line = reader
0499: .readLine()) {
0500: LogManager.log(ErrorLevel.MESSAGE, "[stdout]: "
0501: + line);
0502: }
0503:
0504: processStdOut.append(string);
0505: }
0506:
0507: string = StringUtils.readStream(process.getErrorStream());
0508: if (string.length() > 0) {
0509: BufferedReader reader = new BufferedReader(
0510: new StringReader(string));
0511: for (String line = reader.readLine(); line != null; line = reader
0512: .readLine()) {
0513: LogManager.log(ErrorLevel.MESSAGE, "[stderr]: "
0514: + line);
0515: }
0516:
0517: processStdErr.append(string);
0518: }
0519: }
0520:
0521: LogManager.log(ErrorLevel.MESSAGE,
0522: (doRun) ? "[return]: killed by timeout" : "[return]: "
0523: + errorLevel);
0524: process.destroy();
0525: LogManager.unindent();
0526: LogManager.log(ErrorLevel.MESSAGE,
0527: "... command execution finished");
0528:
0529: return new ExecutionResults(errorLevel, processStdOut
0530: .toString(), processStdErr.toString());
0531: }
0532:
0533: public static boolean isPathValid(String path) {
0534: return getNativeUtils().isPathValid(path);
0535: }
0536:
0537: public static boolean isPortAvailable(int port,
0538: int... forbiddenPorts) {
0539: // check whether the port is in the restricted list, if it is, there is no
0540: // sense to check whether it is physically available
0541: for (int forbidden : forbiddenPorts) {
0542: if (port == forbidden) {
0543: return false;
0544: }
0545: }
0546:
0547: // if the port is not in the allowed range - return false
0548: if ((port < 0) && (port > 65535)) {
0549: return false;
0550: }
0551:
0552: // if the port is not in the restricted list, we'll try to open a server
0553: // socket on it, if we fail, then someone is already listening on this port
0554: // and it is occupied
0555: ServerSocket socket = null;
0556: try {
0557: socket = new ServerSocket(port);
0558: return true;
0559: } catch (IOException e) {
0560: return false;
0561: } finally {
0562: if (socket != null) {
0563: try {
0564: socket.close();
0565: } catch (IOException e) {
0566: ErrorManager.notifyError(
0567: "Could not close server socket on port "
0568: + port, e);
0569: }
0570: }
0571: }
0572: }
0573:
0574: public static int getAvailablePort(int basePort,
0575: int... forbiddenPorts) {
0576: // increment the port value until we find an available port or stumble into
0577: // the upper bound
0578: int port = basePort;
0579: while ((port < 65535) && !isPortAvailable(port, forbiddenPorts)) {
0580: port++;
0581: }
0582:
0583: if (port == 65535) {
0584: port = 0;
0585: while ((port < basePort)
0586: && !isPortAvailable(port, forbiddenPorts)) {
0587: port++;
0588: }
0589:
0590: if (port == basePort) {
0591: return -1;
0592: } else {
0593: return port;
0594: }
0595: } else {
0596: return port;
0597: }
0598: }
0599:
0600: public static boolean isDeletingAllowed(File file) {
0601: return getNativeUtils().isDeletingAllowed(file);
0602: }
0603:
0604: @Deprecated
0605: private static LocationType toLocationType(ShortcutLocationType type) {
0606: LocationType tp = null;
0607: switch (type) {
0608: case CURRENT_USER_DESKTOP:
0609: tp = LocationType.CURRENT_USER_DESKTOP;
0610: break;
0611: case CURRENT_USER_START_MENU:
0612: tp = LocationType.CURRENT_USER_START_MENU;
0613: break;
0614: case ALL_USERS_DESKTOP:
0615: tp = LocationType.ALL_USERS_DESKTOP;
0616: break;
0617: case ALL_USERS_START_MENU:
0618: tp = LocationType.ALL_USERS_START_MENU;
0619: break;
0620: }
0621: return tp;
0622: }
0623:
0624: @Deprecated
0625: public static File getShortcutLocation(
0626: org.netbeans.installer.utils.helper.Shortcut shortcut,
0627: ShortcutLocationType locationType) throws NativeException {
0628: return getNativeUtils().getShortcutLocation(
0629: (FileShortcut) shortcut, toLocationType(locationType));
0630: }
0631:
0632: @Deprecated
0633: public static File createShortcut(
0634: org.netbeans.installer.utils.helper.Shortcut shortcut,
0635: ShortcutLocationType locationType) throws NativeException {
0636: return getNativeUtils().createShortcut((FileShortcut) shortcut,
0637: toLocationType(locationType));
0638: }
0639:
0640: @Deprecated
0641: public static void removeShortcut(
0642: org.netbeans.installer.utils.helper.Shortcut shortcut,
0643: ShortcutLocationType locationType,
0644: boolean deleteEmptyParents) throws NativeException {
0645: getNativeUtils().removeShortcut((FileShortcut) shortcut,
0646: toLocationType(locationType), deleteEmptyParents);
0647: }
0648:
0649: public static File getShortcutLocation(Shortcut shortcut,
0650: LocationType locationType) throws NativeException {
0651: return getNativeUtils().getShortcutLocation(shortcut,
0652: locationType);
0653: }
0654:
0655: /**
0656: * Create shortcut at the specified location that is set using <code>locationType</code>.
0657: * <br>For the current moment the following logic is implemented:
0658: * <ul>
0659: * <li> For Windows FileShortcut is created as an <i>.lnk</i> file.<br>
0660: * InternetShortcut is created as a standard <i>.url</i> file.<br></li>
0661: * <li> For Linux/Solaris FileShortcut is created as a <i>.desktop</i> entry with
0662: * type <b>Application</b> if the target is normal file.<br>
0663: * If the file is actually a directory then a symlink is created <br>
0664: * InternetShortcut is created as a <i>.desktop</i> entry with type
0665: * <b>Link</b>.</li>
0666: * <li> For MacOS FileShortcut on desktop is created as a symlink
0667: * (with, possibly, moving up-parents to the first .app).<br>
0668: * InternetShortcut on desktop is created as a standard <i>.url</i> file.<br>
0669: * "Start Menu" file shortcuts for MacOS are created at Dock.<br>
0670: * InternetShortcut creation in Dock actually does nothing since it
0671: * seems that there is no way add an internet shortcut ot the Dock
0672: * at all.</li>
0673: * </ul>
0674: *
0675: *
0676: */
0677: public static File createShortcut(final Shortcut shortcut,
0678: final LocationType locationType) throws NativeException {
0679: return getNativeUtils().createShortcut(shortcut, locationType);
0680: }
0681:
0682: public static void removeShortcut(Shortcut shortcut,
0683: LocationType locationType, boolean deleteEmptyParents)
0684: throws NativeException {
0685: getNativeUtils().removeShortcut(shortcut, locationType,
0686: deleteEmptyParents);
0687: }
0688:
0689: public static FilesList addComponentToSystemInstallManager(
0690: ApplicationDescriptor descriptor) throws NativeException {
0691: return getNativeUtils().addComponentToSystemInstallManager(
0692: descriptor);
0693: }
0694:
0695: public static void removeComponentFromSystemInstallManager(
0696: ApplicationDescriptor descriptor) throws NativeException {
0697: getNativeUtils().removeComponentFromSystemInstallManager(
0698: descriptor);
0699: }
0700:
0701: public static String getEnvironmentVariable(String name)
0702: throws NativeException {
0703: return getEnvironmentVariable(name, EnvironmentScope.PROCESS,
0704: true);
0705: }
0706:
0707: public static String getEnvironmentVariable(String name,
0708: EnvironmentScope scope, boolean expand)
0709: throws NativeException {
0710: return getNativeUtils().getEnvironmentVariable(name, scope,
0711: expand);
0712: }
0713:
0714: public static void setEnvironmentVariable(String name, String value)
0715: throws NativeException {
0716: setEnvironmentVariable(name, value, EnvironmentScope.PROCESS,
0717: true);
0718: }
0719:
0720: public static void setEnvironmentVariable(String name,
0721: String value, EnvironmentScope scope, boolean expand)
0722: throws NativeException {
0723: getNativeUtils().setEnvironmentVariable(name, value, scope,
0724: expand);
0725: }
0726:
0727: public static List<File> findIrrelevantFiles(File parent)
0728: throws IOException {
0729: return getNativeUtils().findIrrelevantFiles(parent);
0730: }
0731:
0732: public static List<File> findIrrelevantFiles(File... parents)
0733: throws IOException {
0734: List<File> list = new LinkedList<File>();
0735:
0736: for (File parent : parents) {
0737: list.addAll(findIrrelevantFiles(parent));
0738: }
0739:
0740: return list;
0741: }
0742:
0743: public static void removeIrrelevantFiles(File parent)
0744: throws IOException {
0745: FileUtils.deleteFiles(findIrrelevantFiles(parent));
0746: }
0747:
0748: public static void removeIrrelevantFiles(File... parents)
0749: throws IOException {
0750: for (File file : parents) {
0751: removeIrrelevantFiles(file);
0752: }
0753: }
0754:
0755: public static List<File> findExecutableFiles(File parent)
0756: throws IOException {
0757: return getNativeUtils().findExecutableFiles(parent);
0758: }
0759:
0760: public static List<File> findExecutableFiles(File... parents)
0761: throws IOException {
0762: List<File> list = new LinkedList<File>();
0763:
0764: for (File parent : parents) {
0765: list.addAll(findExecutableFiles(parent));
0766: }
0767:
0768: return list;
0769: }
0770:
0771: public static void correctFilesPermissions(File parent)
0772: throws IOException {
0773: getNativeUtils().correctFilesPermissions(parent);
0774: }
0775:
0776: public static void correctFilesPermissions(File... parents)
0777: throws IOException {
0778: for (File file : parents) {
0779: correctFilesPermissions(file);
0780: }
0781: }
0782:
0783: public static void setPermissions(final File file, final int mode,
0784: final int change) throws IOException {
0785: getNativeUtils().setPermissions(file, mode, change);
0786: }
0787:
0788: public static int getPermissions(final File file)
0789: throws IOException {
0790: return getNativeUtils().getPermissions(file);
0791: }
0792:
0793: public static Launcher createLauncher(LauncherProperties props,
0794: Progress progress) throws IOException {
0795: return createLauncher(props, getCurrentPlatform(), progress);
0796: }
0797:
0798: public static Launcher createLauncher(LauncherProperties props,
0799: Platform platform, Progress progress) throws IOException {
0800: Progress prg = (progress == null) ? new Progress() : progress;
0801: LogManager.log("Create native launcher for "
0802: + platform.toString());
0803: Launcher launcher = null;
0804: try {
0805: LogManager.indent();
0806: launcher = LauncherFactory.newLauncher(props, platform);
0807: long start = System.currentTimeMillis();
0808: launcher.initialize();
0809: launcher.create(progress);
0810: long seconds = System.currentTimeMillis() - start;
0811: LogManager.unindent();
0812: LogManager.log("[launcher] Time : " + (seconds / 1000)
0813: + "." + (seconds % 1000) + " seconds");
0814: } catch (IOException e) {
0815: LogManager.unindent();
0816: LogManager
0817: .log("[launcher] Build failed with the following exception :");
0818: LogManager.log(e);
0819: throw e;
0820: }
0821: return launcher;
0822: }
0823:
0824: public static void sleep(long millis) {
0825: try {
0826: Thread.sleep(millis);
0827: } catch (InterruptedException e) {
0828: ErrorManager.notify(ErrorLevel.DEBUG,
0829: "Interrupted while sleeping", e);
0830: }
0831: }
0832:
0833: public static void setDefaultEnvironment() {
0834: environment = new ProcessBuilder().environment();
0835: }
0836:
0837: public static Map<String, String> getEnvironment() {
0838: return environment;
0839: }
0840:
0841: public static Platform getCurrentPlatform() {
0842: if (currentPlatform == null) {
0843: boolean is64bit = System.getProperty("os.arch").equals(
0844: "amd64")
0845: || System.getProperty("os.arch").equals("sparcv9");
0846:
0847: if (System.getProperty("os.name").contains("Windows")) {
0848: currentPlatform = is64bit ? Platform.WINDOWS_X64
0849: : Platform.WINDOWS_X86;
0850: }
0851: if (System.getProperty("os.name").contains("Linux")) {
0852: currentPlatform = is64bit ? Platform.LINUX_X64
0853: : Platform.LINUX_X86;
0854: }
0855: if (System.getProperty("os.name").contains("Mac OS X")
0856: && System.getProperty("os.arch").contains("ppc")) {
0857: currentPlatform = Platform.MACOSX_PPC;
0858: }
0859: if (System.getProperty("os.name").contains("Mac OS X")
0860: && System.getProperty("os.arch").contains("i386")) {
0861: currentPlatform = Platform.MACOSX_X86;
0862: }
0863: if (System.getProperty("os.name").contains("SunOS")) {
0864: if (System.getProperty("os.arch").contains("sparc")) {
0865: currentPlatform = Platform.SOLARIS_SPARC;
0866: } else {
0867: currentPlatform = Platform.SOLARIS_X86;
0868: }
0869: }
0870: }
0871:
0872: return currentPlatform;
0873: }
0874:
0875: public static String getHostName() {
0876: try {
0877: String hostName = InetAddress.getLocalHost().getHostName();
0878: if (hostName != null) {
0879: return hostName;
0880: }
0881: } catch (UnknownHostException e) {
0882: LogManager.log(ErrorLevel.MESSAGE, e);
0883: }
0884:
0885: return "localhost"; //NOI18N
0886: }
0887:
0888: public static List<File> getFileSystemRoots() throws IOException {
0889: return getNativeUtils().getFileSystemRoots();
0890: }
0891:
0892: public static boolean isJarSignatureVeryfied(final File file,
0893: final String description) throws IOException,
0894: KeyStoreException, NoSuchAlgorithmException,
0895: CertificateException {
0896: if (caStore == null) {
0897: caStore = KeyStore.getInstance(KeyStore.getDefaultType());
0898: caStore.load(new FileInputStream(new File(JAVA_HOME
0899: + "/lib/security/cacerts")), null);
0900:
0901: permanentTrustedStore = KeyStore.getInstance(KeyStore
0902: .getDefaultType());
0903: permanentTrustedStore.load(null, null);
0904:
0905: sessionTrustedStore = KeyStore.getInstance(KeyStore
0906: .getDefaultType());
0907: sessionTrustedStore.load(null, null);
0908:
0909: deniedStore = KeyStore.getInstance(KeyStore
0910: .getDefaultType());
0911: deniedStore.load(null, null);
0912: }
0913:
0914: final JarFile jar = new JarFile(file);
0915: try {
0916: // first we should fetch all certificates that are present in the jar
0917: // file skipping duplicates
0918: Certificate[] certificates = null;
0919: CodeSigner[] codeSigners = null;
0920: for (JarEntry entry : Collections.list(jar.entries())) {
0921: readFully(jar.getInputStream(entry));
0922:
0923: certificates = entry.getCertificates();
0924: codeSigners = entry.getCodeSigners();
0925:
0926: if (certificates != null) {
0927: break;
0928: }
0929: }
0930:
0931: // if there are no certificates -- we should pop up the dialog warning
0932: // that the jar is not signed and ask the user whether he wants to
0933: // accept this
0934: if (certificates == null) {
0935: // todo
0936: }
0937:
0938: // check the permanent and session trusted stores
0939: int chainStart = 0;
0940: int chainEnd = 0;
0941: int chainNum = 0;
0942:
0943: // iterate over the certificate chains that are present in the
0944: // certificate arrays
0945: while (chainEnd < certificates.length) {
0946: // determine the start and end of the current certificates chain
0947: int i = chainStart;
0948: while (i < certificates.length - 1) {
0949: final boolean isIssuer = isIssuerOf(
0950: (X509Certificate) certificates[i],
0951: (X509Certificate) certificates[i + 1]);
0952:
0953: if ((certificates[i] instanceof X509Certificate)
0954: && (certificates[i + 1] instanceof X509Certificate)
0955: && isIssuer) {
0956: i++;
0957: } else {
0958: break;
0959: }
0960: }
0961: chainEnd = i + 1;
0962:
0963: // if the denied certificates store contains the
0964: if (containsCertificate(deniedStore,
0965: certificates[chainStart])) {
0966: return false;
0967: } else if (containsCertificate(permanentTrustedStore,
0968: certificates[chainStart])
0969: || containsCertificate(sessionTrustedStore,
0970: certificates[chainStart])) {
0971: return true;
0972: }
0973:
0974: chainStart = chainEnd;
0975: chainNum++;
0976: }
0977:
0978: // If we get here, no cert in chain has been stored in Session or Permanent store.
0979: // If they are not in Deny store either, we have to pop up security dialog box
0980: // for each signer's certificate one by one.
0981: boolean rootCANotValid = false;
0982: boolean timeNotValid = false;
0983:
0984: chainStart = 0;
0985: chainEnd = 0;
0986: chainNum = 0;
0987: while (chainEnd < certificates.length) {
0988: int i = chainStart;
0989:
0990: for (i = chainStart; i < certificates.length; i++) {
0991: X509Certificate currentCert = null;
0992: X509Certificate issuerCert = null;
0993:
0994: if (certificates[i] instanceof X509Certificate)
0995: currentCert = (X509Certificate) certificates[i];
0996:
0997: if ((i < certificates.length - 1)
0998: && (certificates[i + 1] instanceof X509Certificate)) {
0999: issuerCert = (X509Certificate) certificates[i + 1];
1000: } else {
1001: issuerCert = currentCert;
1002: }
1003:
1004: // check if the certificate is valid and has not expired
1005: try {
1006: currentCert.checkValidity();
1007: } catch (CertificateExpiredException e1) {
1008: timeNotValid = true;
1009: } catch (CertificateNotYetValidException e2) {
1010: timeNotValid = true;
1011: }
1012:
1013: if (isIssuerOf(currentCert, issuerCert)) {
1014: // check the current certificate's signature -- verify that
1015: // this issuer did indeed sign the certificate.
1016: try {
1017: currentCert.verify(issuerCert
1018: .getPublicKey());
1019: } catch (GeneralSecurityException e) {
1020: return false;
1021: }
1022: } else {
1023: break;
1024: }
1025: }
1026: chainEnd = (i < certificates.length) ? (i + 1) : i;
1027:
1028: // we need to verify if the certificate chain is signed by a CA
1029: rootCANotValid = !verifyCertificate(caStore,
1030: certificates[chainEnd - 1]);
1031:
1032: Date timestamp = null;
1033: if (codeSigners[chainNum].getTimestamp() != null) {
1034: timestamp = codeSigners[chainNum].getTimestamp()
1035: .getTimestamp();
1036: }
1037:
1038: CertificateAcceptanceStatus status = UiUtils
1039: .showCertificateAcceptanceDialog(certificates,
1040: chainStart, chainEnd, rootCANotValid,
1041: timeNotValid, timestamp, description);
1042:
1043: // If user Grant permission, just pass all security checks.
1044: // If user Deny first signer, pop up security box for second signer certs
1045: if (status == CertificateAcceptanceStatus.ACCEPT_PERMANENTLY) {
1046: addCertificate(permanentTrustedStore,
1047: certificates[chainStart]);
1048: return true;
1049: } else if (status == CertificateAcceptanceStatus.ACCEPT_FOR_THIS_SESSION) {
1050: addCertificate(sessionTrustedStore,
1051: certificates[chainStart]);
1052: return true;
1053: } else {
1054: addCertificate(deniedStore,
1055: certificates[chainStart]);
1056: }
1057:
1058: chainStart = chainEnd;
1059: chainNum++;
1060: }
1061:
1062: return false;
1063: } finally {
1064: jar.close();
1065: }
1066: }
1067:
1068: private static void readFully(final InputStream stream)
1069: throws IOException {
1070: final byte[] buffer = new byte[BUFFER_SIZE];
1071: while (stream.read(buffer) != -1) {
1072: ; // do this!
1073: }
1074: }
1075:
1076: private static boolean isIssuerOf(
1077: final X509Certificate certificate1,
1078: final X509Certificate certificate2) {
1079: return certificate1.getIssuerDN().equals(
1080: certificate2.getSubjectDN());
1081: }
1082:
1083: private static boolean containsCertificate(final KeyStore store,
1084: final Certificate certificate) throws KeyStoreException {
1085: return store.getCertificateAlias(certificate) != null;
1086: }
1087:
1088: private static void addCertificate(final KeyStore store,
1089: final Certificate certificate) throws KeyStoreException {
1090: if (store.getCertificateAlias(certificate) == null) {
1091: store.setCertificateEntry(
1092: "alias" + new Random().nextLong(), certificate);
1093: }
1094: }
1095:
1096: private static boolean verifyCertificate(final KeyStore store,
1097: final Certificate certificate) throws KeyStoreException {
1098: for (String alias : Collections.list(store.aliases())) {
1099: try {
1100: certificate.verify(store.getCertificate(alias)
1101: .getPublicKey());
1102: return true;
1103: } catch (GeneralSecurityException e) {
1104: // we must ignore this exception as it is VERY expected -- will
1105: // happen N-1 times at least
1106: }
1107: }
1108:
1109: return false;
1110: }
1111:
1112: // platforms probes /////////////////////////////////////////////////////////////
1113: public static boolean isWindows() {
1114: return getCurrentPlatform().isCompatibleWith(Platform.WINDOWS);
1115: }
1116:
1117: public static boolean isMacOS() {
1118: return getCurrentPlatform().isCompatibleWith(Platform.MACOSX);
1119: }
1120:
1121: public static boolean isLinux() {
1122: return getCurrentPlatform().isCompatibleWith(Platform.LINUX);
1123: }
1124:
1125: public static boolean isSolaris() {
1126: return getCurrentPlatform().isCompatibleWith(Platform.SOLARIS);
1127: }
1128:
1129: // miscellanea //////////////////////////////////////////////////////////////////
1130: public static boolean intersects(
1131: final List<? extends Object> list1,
1132: final List<? extends Object> list2) {
1133: for (int i = 0; i < list1.size(); i++) {
1134: for (int j = 0; j < list2.size(); j++) {
1135: if (list1.get(i).equals(list2.get(j))) {
1136: return true;
1137: }
1138: }
1139: }
1140:
1141: return false;
1142: }
1143:
1144: public static <T> List<T> intersect(final List<? extends T> list1,
1145: final List<? extends T> list2) {
1146: final List<T> intersection = new LinkedList<T>();
1147:
1148: for (T item : list1) {
1149: if (list2.contains(item)) {
1150: intersection.add(item);
1151: }
1152: }
1153:
1154: return intersection;
1155: }
1156:
1157: public static <T> List<T> substract(final List<? extends T> list1,
1158: final List<? extends T> list2) {
1159: final List<T> result = new LinkedList<T>();
1160:
1161: for (T item1 : list1) {
1162: boolean found = false;
1163:
1164: for (T item2 : list2) {
1165: if (item1.equals(item2)) {
1166: found = true;
1167: break;
1168: }
1169: }
1170:
1171: if (!found) {
1172: result.add(item1);
1173: }
1174: }
1175:
1176: return result;
1177: }
1178:
1179: // native accessor //////////////////////////////////////////////////////////////
1180: public static synchronized NativeUtils getNativeUtils() {
1181: if (nativeUtils == null) {
1182: nativeUtils = NativeUtils.getInstance();
1183: }
1184: return nativeUtils;
1185: }
1186:
1187: /////////////////////////////////////////////////////////////////////////////////
1188: // Constants
1189: public static final long MAX_EXECUTION_TIME = 600000;
1190:
1191: public static final int BUFFER_SIZE = 4096;
1192:
1193: public static final int MAX_DELAY = 50; // NOMAGI
1194: public static final int INITIAL_DELAY = 5; // NOMAGI
1195: public static final int DELTA_DELAY = 5; // NOMAGI
1196: public static final String LINE_SEPARATOR = System
1197: .getProperty("line.separator");//NOI18N
1198: public static final String FILE_SEPARATOR = System
1199: .getProperty("file.separator");//NOI18N
1200: public static final String PATH_SEPARATOR = System
1201: .getProperty("path.separator");//NOI18N
1202: public static final String JAVA_HOME = System
1203: .getProperty("java.home");//NOI18N
1204: public static final String USER_HOME = System
1205: .getProperty("user.home");//NOI18N
1206: public static final String NO_SPACE_CHECK_PROPERTY = "no.space.check";//NOI18N
1207: public static final String ERROR_CANNOT_PARSE_PATTERN_KEY = "SU.error.cannot.parse.pattern";//NOI18N
1208: public static final String ERROR_CANNOT_GET_DEFAULT_APPS_LOCATION_KEY = "SU.error.cannot.get.default.apps.location";//NOI18N
1209: }
|