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.infra.build.ant.utils;
0038:
0039: import java.io.ByteArrayOutputStream;
0040: import java.io.File;
0041: import java.io.FileInputStream;
0042: import java.io.FileOutputStream;
0043: import java.io.IOException;
0044: import java.io.InputStream;
0045: import java.io.OutputStream;
0046: import java.io.OutputStreamWriter;
0047: import java.net.HttpURLConnection;
0048: import java.net.URL;
0049: import java.security.MessageDigest;
0050: import java.security.NoSuchAlgorithmException;
0051: import java.util.ArrayList;
0052: import java.util.Arrays;
0053: import java.util.Enumeration;
0054: import java.util.Iterator;
0055: import java.util.List;
0056: import java.util.Map;
0057: import java.util.Properties;
0058: import java.util.jar.JarFile;
0059: import java.util.jar.JarOutputStream;
0060: import java.util.jar.Pack200;
0061: import java.util.jar.Pack200.Packer;
0062: import java.util.jar.Pack200.Unpacker;
0063: import java.util.regex.Matcher;
0064: import java.util.regex.Pattern;
0065: import java.util.zip.ZipEntry;
0066: import java.util.zip.ZipFile;
0067: import org.apache.tools.ant.Project;
0068:
0069: /**
0070: * A collection of utility methods used throughout the custom tasks classes.
0071: *
0072: * @author Kirill Sorokin
0073: */
0074: public final class Utils {
0075: /////////////////////////////////////////////////////////////////////////////////
0076: // Static
0077: private final static Packer packer = Pack200.newPacker();
0078: private final static Unpacker unpacker = Pack200.newUnpacker();
0079: /**
0080: * The current ant project. Some of its methods will get called in process of
0081: * the executions of some of the utility procedures. Thus the ant tasks using the
0082: * class are streongly encouraged to call the {@link #setProject(Project)}
0083: * method prior to suing any other functionality.
0084: */
0085: private static byte[] buffer = new byte[102400];
0086:
0087: private static Project project = null;
0088:
0089: /**
0090: * Setter for the 'project' property.
0091: *
0092: * @param project New value for the 'project' property.
0093: */
0094: public static void setProject(final Project project) {
0095: Utils.project = project;
0096: }
0097:
0098: /**
0099: * Calculates the MD5 checksum for the given file.
0100: *
0101: * @param file File for which the checksum should be calculated.
0102: * @return The MD5 checksum of the file.
0103: * @throws java.io.IOException if an I/O error occurs.
0104: */
0105: public static String getMd5(final File file) throws IOException {
0106: return getDigest(file, MD5);
0107: }
0108:
0109: /**
0110: * Checks whether the given file is a directory.
0111: *
0112: * @param file File to check for being a directory.
0113: * @return <code>true</code> if the file is a directory, <code>false</code>
0114: * otherwise.
0115: */
0116: public static boolean isEmpty(final File file) {
0117: if (file.listFiles().length == 0) {
0118: return true;
0119: } else {
0120: return false;
0121: }
0122: }
0123:
0124: /**
0125: * Checks whether the given file is a jar archive.
0126: *
0127: * @param file File to check for being a jar archive.
0128: * @return <code>true</code> if the file is a jar archive, <code>false</code>
0129: * otherwise.
0130: */
0131: public static boolean isJarFile(final File file) {
0132: if (file.getName().endsWith(JAR_EXTENSION)) {
0133: JarFile jar = null;
0134: try {
0135: jar = new JarFile(file);
0136: return true;
0137: } catch (IOException e) {
0138: e.printStackTrace();
0139: return false;
0140: } finally {
0141: if (jar != null) {
0142: try {
0143: jar.close();
0144: } catch (IOException e) {
0145: e.printStackTrace();
0146: }
0147: }
0148: }
0149: } else {
0150: return false;
0151: }
0152: }
0153:
0154: /**
0155: * Checks whether the given file is a signed jar archive.
0156: *
0157: * @param file File to check for being a signed jar archive.
0158: * @return <code>true</code> if the file is a signedjar archive,
0159: * <code>false</code> otherwise.
0160: * @throws java.io.IOException if an I/O error occurs.
0161: */
0162: public static boolean isSigned(final File file) throws IOException {
0163: JarFile jar = new JarFile(file);
0164:
0165: try {
0166: if (jar.getEntry(SUN_MICR_RSA) == null) {
0167: return false;
0168: }
0169: if (jar.getEntry(SUN_MICR_SF) == null) {
0170: return false;
0171: }
0172: return true;
0173: } finally {
0174: jar.close();
0175: }
0176: }
0177:
0178: /**
0179: * Packs the given jar archive using the pack200 utility.
0180: *
0181: * @param source Jar archive to pack.
0182: * @param target File which should become the packed jar archive.
0183: * @return The target file, i.e. the packed jar archive.
0184: * @throws java.io.IOException if an I/O error occurs.
0185: */
0186: public static boolean pack(final File source, final File target)
0187: throws IOException {
0188: return ("true".equals(project
0189: .getProperty("use.internal.packer"))) ? packInternally(
0190: source, target) : packExternally(source, target);
0191: }
0192:
0193: private static boolean packExternally(final File source,
0194: final File target) throws IOException {
0195: boolean result = false;
0196:
0197: final String xmx = ARG_PREFIX + XMX_ARG
0198: + project.getProperty("pack200.xmx");
0199: final String permSize = ARG_PREFIX + PERM_SIZE_ARG
0200: + project.getProperty("pack200.perm.size");
0201: final String maxPermSize = ARG_PREFIX + MAX_PERM_SIZE_ARG
0202: + project.getProperty("pack200.max.perm.size");
0203:
0204: Results results = run(PACKER_EXECUTABLE, xmx, permSize,
0205: maxPermSize, target.getAbsolutePath(), source
0206: .getAbsolutePath());
0207:
0208: if (results.getExitcode() == 0) {
0209: result = true;
0210: } else {
0211: System.out.println(results.getStdout());
0212: System.out.println(results.getStderr());
0213: System.out.println(results.getExitcode());
0214: result = false;
0215: }
0216:
0217: if (result == true) {
0218: target.setLastModified(source.lastModified());
0219: }
0220:
0221: return result;
0222: }
0223:
0224: public static boolean packInternally(final File source,
0225: final File target) throws IOException {
0226: try {
0227: JarFile jarFile = new JarFile(source);
0228: FileOutputStream outputStream = new FileOutputStream(target);
0229:
0230: packer.pack(jarFile, outputStream);
0231:
0232: jarFile.close();
0233: outputStream.close();
0234: target.setLastModified(source.lastModified());
0235: } catch (IOException exc) {
0236: exc.printStackTrace();
0237: return false;
0238: }
0239: return true;
0240: }
0241:
0242: /**
0243: * Unpacks the given packed jar archive using the unpack200 utility.
0244: *
0245: * @param source Packe jar archive to unpack.
0246: * @param target File to which the unpacked archive should be saved.
0247: * @return The target file, i.e. the unpacked jar archive.
0248: * @throws java.io.IOException if an I/O errors occurs.
0249: */
0250:
0251: public static boolean unpack(final File source, final File target)
0252: throws IOException {
0253: return ("true".equals(project
0254: .getProperty("use.internal.unpacker"))) ? unpackInternally(
0255: source, target)
0256: : unpackExternally(source, target);
0257: }
0258:
0259: private static boolean unpackExternally(final File source,
0260: final File target) throws IOException {
0261: boolean result = false;
0262:
0263: Results results = run(UNPACKER_EXECUTABLE, ARG_PREFIX + XMX_ARG
0264: + project.getProperty("pack200.xmx"), ARG_PREFIX
0265: + PERM_SIZE_ARG
0266: + project.getProperty("pack200.perm.size"), ARG_PREFIX
0267: + MAX_PERM_SIZE_ARG
0268: + project.getProperty("pack200.max.perm.size"), source
0269: .getAbsolutePath(), target.getAbsolutePath());
0270:
0271: if (results.getExitcode() == 0) {
0272: result = true;
0273: } else {
0274: System.out.println(results.getStdout());
0275: System.out.println(results.getStderr());
0276: System.out.println(results.getExitcode());
0277: result = false;
0278: }
0279:
0280: if (result == true) {
0281: target.setLastModified(source.lastModified());
0282: }
0283:
0284: return result;
0285: }
0286:
0287: public static boolean unpackInternally(final File source,
0288: final File target) throws IOException {
0289: try {
0290: JarOutputStream os = new JarOutputStream(
0291: new FileOutputStream(target));
0292: unpacker.unpack(source, os);
0293: os.close();
0294: target.setLastModified(source.lastModified());
0295: } catch (IOException exc) {
0296: exc.printStackTrace();
0297: return false;
0298: }
0299: return true;
0300: }
0301:
0302: /**
0303: * Verifies that the jar archive is correct. This method tries to access all
0304: * jar archive entries and to load all the classes.
0305: *
0306: * @param file Jar archive to check.
0307: * @return <code>true</code> is the archive is correct, <code>false</code>
0308: * otherwise.
0309: * @throws java.io.IOException if an I/O error occurs.
0310: */
0311: public static boolean verify(final File file) throws IOException {
0312: Results results = runClass(VERIFIER_CLASSNAME, file
0313: .getAbsolutePath());
0314:
0315: if (results.getExitcode() == 0) {
0316: return true;
0317: } else {
0318: System.out.println(results.getStdout());
0319: System.out.println(results.getStderr());
0320: System.out.println(results.getExitcode());
0321: return false;
0322: }
0323: }
0324:
0325: /**
0326: * Verifies that the if jar archive is placed next to jad, the jad file
0327: * contains correct jar size
0328: *
0329: * @param file Jar archive to check.
0330: * @return <code>true</code> is the archive is correct, <code>false</code>
0331: * otherwise.
0332: * @throws java.io.IOException if an I/O error occurs.
0333: */
0334: public static boolean verifyJad(final File file) throws IOException {
0335: final String name = file.getName();
0336: if (name.endsWith(".jar")) {
0337: File jad = new File(file.getParent(), name.substring(0,
0338: name.length() - 4)
0339: + ".jad");
0340: if (jad.exists()) {
0341: FileInputStream fis = new FileInputStream(jad);
0342: String string = read(fis).toString();
0343: fis.close();
0344: final Matcher matcher = Pattern.compile(
0345: "MIDlet-Jar-Size: ([0-9]+).*").matcher(string);
0346: if (matcher.find()) {
0347: final long size = new Long(matcher.group(1))
0348: .longValue();
0349: final long realSize = file.length();
0350: if (realSize != size) {
0351: System.out
0352: .println("... java descriptor file exist : "
0353: + jad);
0354: System.out.println("... expected jar size : "
0355: + size);
0356: System.out.println("... real jar size : "
0357: + realSize);
0358: return false;
0359: }
0360: }
0361:
0362: }
0363: }
0364: return true;
0365: }
0366:
0367: /**
0368: * Fully reads an input stream into a character sequence using the system's
0369: * default encoding.
0370: *
0371: * @param in Input sream to read.
0372: * @return The read data as a character sequence.
0373: * @throws java.io.IOException if an I/O error occurs.
0374: */
0375: public static CharSequence read(final InputStream in)
0376: throws IOException {
0377: StringBuilder builder = new StringBuilder();
0378: byte[] buffer = new byte[1024];
0379: while (in.available() > 0) {
0380: int read = in.read(buffer);
0381:
0382: String readString = new String(buffer, 0, read);
0383: for (String string : readString.split(NEWLINE_REGEXP)) {
0384: builder.append(string).append(LINE_SEPARATOR);
0385: }
0386: }
0387:
0388: return builder;
0389: }
0390:
0391: /**
0392: * Fully transfers the given input stream to the given output stream.
0393: * @param in Input stream to read and transfer.
0394: * @param out Output stream to transfer data to.
0395: * @throws java.io.IOException if an I/O error occurs.
0396: */
0397: public static void copy(final InputStream in, final OutputStream out)
0398: throws IOException {
0399:
0400: while (in.available() > 0) {
0401: out.write(buffer, 0, in.read(buffer));
0402: }
0403: }
0404:
0405: /**
0406: * Unzips a zip archive to the specified directory.
0407: *
0408: * @param file Zip archive to extract.
0409: * @param directory Directory which will be the target for the extraction.
0410: * @throws java.io.IOException if an I/O error occurs.
0411: */
0412: public static void unzip(final File file, final File directory)
0413: throws IOException {
0414: ZipFile zip = new ZipFile(file);
0415:
0416: if (directory.exists() && directory.isFile()) {
0417: throw new IOException(
0418: "Directory is an existing file, cannot unzip.");
0419: }
0420:
0421: if (!directory.exists() && !directory.mkdirs()) {
0422: throw new IOException("Cannot create directory");
0423: }
0424:
0425: Enumeration<? extends ZipEntry> entries = (Enumeration<? extends ZipEntry>) zip
0426: .entries();
0427: while (entries.hasMoreElements()) {
0428: ZipEntry entry = entries.nextElement();
0429:
0430: File entryFile = new File(directory, entry.getName());
0431:
0432: InputStream in;
0433: OutputStream out;
0434: if (entry.getName().endsWith(SLASH)) {
0435: entryFile.mkdirs();
0436: } else {
0437: in = zip.getInputStream(entry);
0438: out = new FileOutputStream(entryFile);
0439:
0440: copy(in, out);
0441:
0442: in.close();
0443: out.close();
0444: }
0445:
0446: entryFile.setLastModified(entry.getTime());
0447: }
0448:
0449: zip.close();
0450: }
0451:
0452: public static void nativeUnzip(final File file, final File directory)
0453: throws IOException {
0454: final String[] command = new String[] {
0455: NATIVE_UNZIP_EXECUTABLE, file.getAbsolutePath(), "-d",
0456: directory.getAbsolutePath() };
0457:
0458: if (project != null) {
0459: project.log(" running command: "
0460: + Arrays.asList(command));
0461: }
0462:
0463: final Results results = run(command);
0464:
0465: if (results.getExitcode() != 0) {
0466: System.out.println(results.getStdout());
0467: System.out.println(results.getStderr());
0468: throw new IOException();
0469: }
0470: }
0471:
0472: /**
0473: * Deletes a file. If the file is a directory its contents are recursively
0474: * deleted.
0475: *
0476: * @param file File to be deleted.
0477: */
0478: public static void delete(final File file) {
0479: if (file.isDirectory()) {
0480: for (File child : file.listFiles()) {
0481: delete(child);
0482: }
0483: }
0484: if (!file.delete()) {
0485: file.deleteOnExit();
0486: }
0487: }
0488:
0489: /**
0490: * Measures the size of a file. If the file is a directory, its size would be
0491: * equal to the sum of sizes of all its files and subdirectories.
0492: *
0493: * @param file File whose size should be measured.
0494: * @return The size of file.
0495: */
0496: public static long size(final File file) {
0497: long size = 0;
0498:
0499: if (file.isDirectory()) {
0500: for (File child : file.listFiles()) {
0501: size += size(child);
0502: }
0503: }
0504:
0505: return size + file.length();
0506: }
0507:
0508: /**
0509: * Converts the given string to its java-style ASCII equivalent, escaping
0510: * non ASCII characters with their \\uXXXX sequences.
0511: *
0512: * @param string String to escape.
0513: * @return The escaped string.
0514: */
0515: public static String toAscii(final String string) {
0516: Properties properties = new Properties();
0517:
0518: properties.put(UBERKEY, string);
0519:
0520: ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
0521: try {
0522: properties.store(outputStream, "");
0523: } catch (IOException e) {
0524: e.printStackTrace();
0525: return string;
0526: }
0527:
0528: Matcher matcher = Pattern.compile(UBERKEY_REGEXP,
0529: Pattern.MULTILINE).matcher(outputStream.toString());
0530:
0531: if (matcher.find()) {
0532: return matcher.group(1);
0533: } else {
0534: return string;
0535: }
0536: }
0537:
0538: /**
0539: * Writes the given character sequence to the given file.
0540: *
0541: * @param file File to which the character sequence should be written.
0542: * @param chars Character sequence which should be written to the file.
0543: * @throws java.io.IOException if an I/O error occurs.
0544: */
0545: public static void write(final File file, final CharSequence chars)
0546: throws IOException {
0547: OutputStreamWriter writer = new OutputStreamWriter(
0548: new FileOutputStream(file), UTF8);
0549: writer.write(chars.toString());
0550: writer.close();
0551: }
0552:
0553: /**
0554: * Copies the contents of a file to the given output stream.
0555: *
0556: * @param source File whose contents should be copied.
0557: * @param target Output stream to which the file's contents should be
0558: * transferred.
0559: * @throws java.io.IOException if an I/O error occurs.
0560: */
0561: public static void copy(final File source, final OutputStream target)
0562: throws IOException {
0563: FileInputStream input = new FileInputStream(source);
0564: copy(input, target);
0565: input.close();
0566: }
0567:
0568: /**
0569: * Copies one file to another.
0570: *
0571: * @param source File to be copied.
0572: * @param target File which should be come the copy of the source one.
0573: * @throws java.io.IOException if an I/O error occurs.
0574: */
0575: public static void copy(final File source, final File target)
0576: throws IOException {
0577: FileOutputStream out = new FileOutputStream(target);
0578: copy(source, out);
0579: out.close();
0580: }
0581:
0582: /**
0583: * Sends an HTTP POST request to the given URL. The supplied parameters will be
0584: * passed as part of the request body according to
0585: * {@link http://www.faqs.org/rfcs/rfc1945.html}.
0586: *
0587: * @param url URL to shich the POST request should be sent.
0588: * @param args Request parameters.
0589: * @return The first line of the server response, e.g. "HTTP/1.x 200 OK".
0590: * @throws java.io.IOException if an I/O error occurs.
0591: */
0592: public static String post(final String url,
0593: final Map<String, Object> args) throws IOException {
0594: final String boundary = "---------------" + Math.random();
0595: final byte[] realBoundary = ("--" + boundary).getBytes("UTF-8");
0596: final byte[] endBoundary = ("--" + boundary + "--")
0597: .getBytes("UTF-8");
0598: final byte[] crlf = new byte[] { 13, 10 };
0599:
0600: final HttpURLConnection connection = (HttpURLConnection) new URL(
0601: url).openConnection();
0602:
0603: connection.setRequestMethod("POST");
0604: connection.setRequestProperty("Content-Type",
0605: "multipart/form-data; boundary=" + boundary);
0606: connection.setDoOutput(true);
0607: connection.setDoInput(true);
0608:
0609: connection.connect();
0610: final OutputStream out = connection.getOutputStream();
0611:
0612: final Iterator<String> iterator = args.keySet().iterator();
0613: while (iterator.hasNext()) {
0614: String key = iterator.next();
0615: Object value = args.get(key);
0616:
0617: out.write(realBoundary);
0618: out.write(crlf);
0619:
0620: if (value instanceof File) {
0621: File file = (File) value;
0622:
0623: out
0624: .write(("Content-Disposition: form-data; name=\""
0625: + key
0626: + "\"; filename=\""
0627: + file.getName() + "\"")
0628: .getBytes("UTF-8"));
0629: out.write(crlf);
0630:
0631: out
0632: .write(("Content-Type: "
0633: + "application/octet-stream")
0634: .getBytes("UTF-8"));
0635: out.write(crlf);
0636: out.write(crlf);
0637:
0638: copy(file, out);
0639: }
0640:
0641: if (value instanceof String) {
0642: String string = (String) value;
0643:
0644: out.write(("Content-Disposition: form-data; "
0645: + "name=\"" + key + "\"").getBytes("UTF-8"));
0646: out.write(crlf);
0647: out.write(crlf);
0648:
0649: out.write(string.getBytes("UTF-8"));
0650: }
0651:
0652: out.write(crlf);
0653: }
0654:
0655: out.write(endBoundary);
0656: out.close();
0657:
0658: return "" + connection.getResponseCode() + " "
0659: + connection.getResponseMessage();
0660: }
0661:
0662: /**
0663: * Signs the given jar file using the data provided in the given keystore.
0664: *
0665: * @param file Jar archive which will be signed.
0666: * @param keystore Path to the keystore file.
0667: * @param alias Keystore alias.
0668: * @param password Keystore password.
0669: * @return The results of executing the <code>jarsigner</code> utility.
0670: * @throws java.io.IOException if an I/O error occurs.
0671: */
0672: public static Results sign(final File file, final String keystore,
0673: final String alias, final String password)
0674: throws IOException {
0675: List<String> command = new ArrayList<String>();
0676:
0677: command.add(JARSIGNER_EXECUTABLE);
0678: command.add("-keystore");
0679: command.add(keystore);
0680: command.add(file.getAbsolutePath());
0681: command.add(alias);
0682:
0683: Process process = new ProcessBuilder(command).start();
0684: process.getOutputStream().write(password.getBytes());
0685:
0686: return handleProcess(process);
0687: }
0688:
0689: public static int getPermissions(final File file) {
0690: try {
0691: final Results results = run(LS_EXECUTABLE, "-ld", file
0692: .getAbsolutePath());
0693:
0694: final String output = results.getStdout().toString().trim();
0695:
0696: if (project != null) {
0697: project.log(" " + output);
0698: } else {
0699: System.out.println(output);
0700: }
0701:
0702: int permissions = 0;
0703: for (int i = 0; i < 9; i++) {
0704: char character = output.charAt(i + 1);
0705:
0706: if (i % 3 == 0) {
0707: permissions *= 10;
0708: }
0709:
0710: if (character == '-') {
0711: continue;
0712: } else if ((i % 3 == 0) && (character == 'r')) {
0713: permissions += 4;
0714: } else if ((i % 3 == 1) && (character == 'w')) {
0715: permissions += 2;
0716: } else if ((i % 3 == 2) && (character == 'x')) {
0717: permissions += 1;
0718: } else {
0719: return -1;
0720: }
0721: }
0722:
0723: return permissions;
0724: } catch (IOException e) {
0725: return -1;
0726: }
0727: }
0728:
0729: // private //////////////////////////////////////////////////////////////////////
0730: /**
0731: * Calculates the digital digest of the given file's contents using the
0732: * supplied algorithm.
0733: *
0734: * @param file File for which the digest should be calculated.
0735: * @param algorithm Algorithm which should be used for calculating the digest.
0736: * @return The calculated digest as a string.
0737: * @throws java.io.IOException if an I/O error occurs.
0738: */
0739: private static String getDigest(final File file,
0740: final String algorithm) throws IOException {
0741: try {
0742: MessageDigest md = MessageDigest.getInstance(algorithm);
0743: md.reset();
0744:
0745: InputStream input = null;
0746: try {
0747: input = new FileInputStream(file);
0748:
0749: while (input.available() > 0) {
0750: md.update(buffer, 0, input.read(buffer));
0751: }
0752: } finally {
0753: if (input != null) {
0754: input.close();
0755: }
0756: }
0757:
0758: byte[] bytes = md.digest();
0759:
0760: StringBuilder builder = new StringBuilder();
0761:
0762: for (int i = 0; i < bytes.length; i++) {
0763: byte b = bytes[i];
0764:
0765: String byteHex = Integer.toHexString(b);
0766: if (byteHex.length() == 1) {
0767: byteHex = "0" + byteHex;
0768: }
0769: if (byteHex.length() > 2) {
0770: byteHex = byteHex.substring(byteHex.length() - 2);
0771: }
0772:
0773: builder.append(byteHex);
0774: }
0775:
0776: return builder.toString();
0777: } catch (NoSuchAlgorithmException e) {
0778: throw new IOException("Could not find the aglorithm");
0779: }
0780: }
0781:
0782: /**
0783: * Runs the given class in a separate JVM.
0784: *
0785: * @param clazz Classname of the class which should be run.
0786: * @param args Command-line arguments for the class.
0787: * @return Results of executing the command (exitcode, stdout and stderr
0788: * contents).
0789: * @throws java.io.IOException if an I/O error occurs.
0790: */
0791: private static Results runClass(final String clazz,
0792: final String... args) throws IOException {
0793: final String classPath = project
0794: .getProperty(CLASSPATH_VALUE_PROPERTY);
0795:
0796: final List<String> command = new ArrayList<String>();
0797:
0798: command.add(JAVA_EXECUTABLE);
0799: command.add(CLASSPATH_ARG);
0800: command.add(classPath);
0801: command.add(clazz);
0802: command.addAll(Arrays.asList(args));
0803:
0804: return run(command.toArray(new String[command.size()]));
0805: }
0806:
0807: private static Results handleProcess(Process process)
0808: throws IOException {
0809: StringBuilder processStdOut = new StringBuilder();
0810: StringBuilder processStdErr = new StringBuilder();
0811:
0812: int errorCode = 0;
0813: boolean doRun = true;
0814: long delay = INITIAL_DELAY;
0815:
0816: final String projectMaxTime = project
0817: .getProperty(MAX_EXECUTION_TIME_PROPERTY);
0818: long maxExecutionTime = (projectMaxTime != null) ? Long
0819: .parseLong(projectMaxTime) : MAX_EXECUTION_TIME;
0820: long start = System.currentTimeMillis();
0821: long end = start + maxExecutionTime;
0822:
0823: while (doRun
0824: && (maxExecutionTime == 0 || System.currentTimeMillis() < end)) {
0825: try {
0826: Thread.sleep(delay);
0827: if (delay < MAX_DELAY) {
0828: delay += DELTA_DELAY;
0829: }
0830: } catch (InterruptedException e) {
0831: // do nothing - this may happen every now and then
0832: }
0833:
0834: try {
0835: errorCode = process.exitValue();
0836: doRun = false;
0837: } catch (IllegalThreadStateException e) {
0838: ; // do nothing - the process is still running
0839: }
0840:
0841: CharSequence string = read(process.getInputStream());
0842: if (string.length() > 0) {
0843: processStdOut.append(string);
0844: }
0845:
0846: string = read(process.getErrorStream());
0847: if (string.length() > 0) {
0848: processStdErr.append(string);
0849: }
0850: }
0851: process.destroy();
0852: return new Results(processStdOut, processStdErr, errorCode);
0853: }
0854:
0855: /**
0856: * Runs the specified command using the <code>ProcessBuilder</code> class.
0857: *
0858: * @param command Path to the executable and its arguments.
0859: * @return Results of executing the command (exitcode, stdout and stderr
0860: * contents).
0861: * @throws java.io.IOException if an I/O error occurs.
0862: */
0863: private static Results run(final String... command)
0864: throws IOException {
0865:
0866: Process process = new ProcessBuilder(command).start();
0867:
0868: return handleProcess(process);
0869: }
0870:
0871: /////////////////////////////////////////////////////////////////////////////////
0872: // Instance
0873: /**
0874: * The private default constructor which prevents the class from being
0875: * instantiated.
0876: */
0877: private Utils() {
0878: // does nothing
0879: }
0880:
0881: /////////////////////////////////////////////////////////////////////////////////
0882: // Inner Classes
0883: /**
0884: * This class is a container for the results of executing a process. It keeps
0885: * the values of <code><stdout></code>, <code><stderr></code> and
0886: * the exitcode.
0887: *
0888: * @author Kirill Sorokin
0889: */
0890: public static class Results {
0891: /**
0892: * Value of <code><stdout></code>.
0893: */
0894: private CharSequence stdout;
0895:
0896: /**
0897: * Value of <code><stdout></code>.
0898: */
0899: private CharSequence stderr;
0900:
0901: /**
0902: * Value of the exitcode.
0903: */
0904: private int exitcode;
0905:
0906: /**
0907: * Creates a new instance of <code>Results</code>. The constructor simply
0908: * initializes the class properties with the passed-in values.
0909: *
0910: * @param stdout Contents of the process's <code><stdout></code>.
0911: * @param stderr Contents of the process's <code><stderr></code>.
0912: * @param exitcode The process's exitcode.
0913: */
0914: public Results(final CharSequence stdout,
0915: final CharSequence stderr, final int exitcode) {
0916: this .stdout = stdout;
0917: this .stderr = stderr;
0918: this .exitcode = exitcode;
0919: }
0920:
0921: /**
0922: * Getter for the 'stdout' property.
0923: *
0924: * @return Value of the 'stdout' property.
0925: */
0926: public CharSequence getStdout() {
0927: return stdout;
0928: }
0929:
0930: /**
0931: * Getter for the 'stderr' property.
0932: *
0933: * @return Value of the 'stderr' property.
0934: */
0935: public CharSequence getStderr() {
0936: return stderr;
0937: }
0938:
0939: /**
0940: * Getter for the 'exitcode' property.
0941: *
0942: * @return Value of the 'exitcode' property.
0943: */
0944: public int getExitcode() {
0945: return exitcode;
0946: }
0947: }
0948:
0949: /////////////////////////////////////////////////////////////////////////////////
0950: // Constants
0951: /**
0952: * Maximum allowed execution time for a process.
0953: */
0954: public static final int MAX_EXECUTION_TIME = 300000; // NOMAGI
0955:
0956: /**
0957: * Property for setting maximum allowed execution time for a process.
0958: */
0959: public static final String MAX_EXECUTION_TIME_PROPERTY = "process.max.execution.time"; // NOI18N
0960:
0961: /**
0962: * Max deplay (in milliseconds) which to wait between cheking the process state.
0963: */
0964: public static final int MAX_DELAY = 50; // NOMAGI
0965:
0966: /**
0967: * Delta deplay (in milliseconds) which to increase the delay between cheking the process state.
0968: */
0969: public static final int DELTA_DELAY = 1; // NOMAGI
0970: /**
0971: * Initial deplay (in milliseconds) between cheking the process state.
0972: */
0973: public static final int INITIAL_DELAY = 1; // NOMAGI
0974:
0975: /**
0976: * Prefix for JVM command-line arguments.
0977: */
0978: public static final String ARG_PREFIX = "-J"; // NOI18N
0979:
0980: /**
0981: * Maximum heap size command-line argument prefix.
0982: */
0983: public static final String XMX_ARG = "-Xmx"; // NOI18N
0984:
0985: /**
0986: * PermSize command-line argument prefix.
0987: */
0988: public static final String PERM_SIZE_ARG = "-XX:PermSize="; // NOI18N
0989:
0990: /**
0991: * MacPermSize command-line argument prefix.
0992: */
0993: public static final String MAX_PERM_SIZE_ARG = "-XX:MaxPermSize="; // NOI18N
0994:
0995: /**
0996: * Classpath command-line argument prefix.
0997: */
0998: public static final String CLASSPATH_ARG = "-cp"; // NOI18N
0999:
1000: /**
1001: * Classname of the class which should be called to verify the unpacked jar
1002: * file.
1003: */
1004: public static final String VERIFIER_CLASSNAME = "org.netbeans.installer.infra.build.ant.utils.VerifyFile"; // NOI18N
1005:
1006: /**
1007: * Name of the ant project's property which contains the classpath which should
1008: * be used for running classes.
1009: */
1010: public static final String CLASSPATH_VALUE_PROPERTY = "custom.tasks.cls"; // NOI18N
1011:
1012: /**
1013: * MD5 digital digest algorithm code name.
1014: */
1015: public static final String MD5 = "MD5"; // NOI18N
1016:
1017: /**
1018: * Extension of jar files.
1019: */
1020: public static final String JAR_EXTENSION = ".jar"; // NOI18N
1021:
1022: /**
1023: * Marker file which indicated that the jar file is signed.
1024: */
1025: public static final String SUN_MICR_RSA = "META-INF/SUN_MICR.RSA"; // NOI18N
1026:
1027: /**
1028: * Marker file which indicated that the jar file is signed.
1029: */
1030: public static final String SUN_MICR_SF = "META-INF/SUN_MICR.SF"; // NOI18N
1031:
1032: /**
1033: * A regular expression which matches any line separator.
1034: */
1035: public static final String NEWLINE_REGEXP = "(?:\n\r|\r\n|\n|\r)"; // NOI18N
1036:
1037: /**
1038: * Forward slash.
1039: */
1040: public static final String SLASH = "/"; // NOI18N
1041:
1042: /**
1043: * An artificial key name used in converting a string to ASCII.
1044: */
1045: public static final String UBERKEY = "uberkey"; // NOI18N
1046:
1047: /**
1048: * An artificial regular expresion used in converting a string to ASCII.
1049: */
1050: public static final String UBERKEY_REGEXP = "uberkey=(.*)$"; // NOI18N
1051:
1052: /**
1053: * Name of the UTF-8 encoding.
1054: */
1055: public static final String UTF8 = "UTF-8"; // NOI18N
1056:
1057: /**
1058: * Name of the system property which contains the operating system name.
1059: */
1060: public static final String OS_NAME = "os.name"; // NOI18N
1061:
1062: /**
1063: * Name of the windows operationg system.
1064: */
1065: public static final String WINDOWS = "Windows"; // NOI18N
1066:
1067: /**
1068: * Name of the windows operationg system.
1069: */
1070: public static final boolean IS_WINDOWS = System
1071: .getProperty(OS_NAME).contains(WINDOWS); // NOI18N
1072: /**
1073: * Name of the system property which contains the current java home.
1074: */
1075: public static final String JAVA_HOME = "java.home"; // NOI18N
1076: /**
1077: * Value of the system property which contains the current java home.
1078: */
1079: public static final String JAVA_HOME_VALUE = System
1080: .getProperty(JAVA_HOME); // NOI18N
1081:
1082: /**
1083: * Path to the java executable on non-windows platforms. Relative to the java
1084: * home.
1085: */
1086: public static final String JAVA = "bin/java"; // NOI18N
1087:
1088: /**
1089: * Path to the java executable on windows platforms. Relative to the java
1090: * home.
1091: */
1092: public static final String JAVA_EXE = "bin\\java.exe"; // NOI18N
1093:
1094: public static final String JAVA_EXECUTABLE = JAVA_HOME_VALUE
1095: + File.separator + ((IS_WINDOWS) ? JAVA_EXE : JAVA);
1096:
1097: public static final String PACKER_EXECUTABLE = JAVA_HOME_VALUE
1098: + ((IS_WINDOWS) ? "\\bin\\pack200.exe" : "/bin/pack200");//NOI18N
1099: public static final String UNPACKER_EXECUTABLE = JAVA_HOME_VALUE
1100: + ((IS_WINDOWS) ? "\\bin\\unpack200.exe" : "/bin/unpack200");//NOI18N
1101: public static final String NATIVE_UNZIP_EXECUTABLE = (IS_WINDOWS) ? "unzip.exe"
1102: : "unzip"; //NOI18N
1103: public static final String JARSIGNER_EXECUTABLE = JAVA_HOME_VALUE
1104: + ((IS_WINDOWS) ? "\\..\\bin\\jarsigner.exe"
1105: : "/../bin/jarsigner");//NOI18N
1106: public static final String LS_EXECUTABLE = (IS_WINDOWS) ? "ls.exe"
1107: : "ls";//NOI18N
1108: public static final String LINE_SEPARATOR = System
1109: .getProperty("line.separator");
1110: }
|