001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU General
007: * Public License Version 2 only ("GPL") or the Common Development and Distribution
008: * License("CDDL") (collectively, the "License"). You may not use this file except in
009: * compliance with the License. You can obtain a copy of the License at
010: * http://www.netbeans.org/cddl-gplv2.html or nbbuild/licenses/CDDL-GPL-2-CP. See the
011: * License for the specific language governing permissions and limitations under the
012: * License. When distributing the software, include this License Header Notice in
013: * each file and include the License file at nbbuild/licenses/CDDL-GPL-2-CP. Sun
014: * designates this particular file as subject to the "Classpath" exception as
015: * provided by Sun in the GPL Version 2 section of the License file that
016: * accompanied this code. If applicable, add the following below the License Header,
017: * with the fields enclosed by brackets [] replaced by your own identifying
018: * information: "Portions Copyrighted [year] [name of copyright owner]"
019: *
020: * Contributor(s):
021: *
022: * The Original Software is NetBeans. The Initial Developer of the Original Software
023: * is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun Microsystems, Inc. All
024: * Rights Reserved.
025: *
026: * If you wish your version of this file to be governed by only the CDDL or only the
027: * GPL Version 2, indicate your decision by adding "[Contributor] elects to include
028: * this software in this distribution under the [CDDL or GPL Version 2] license." If
029: * you do not indicate a single choice of license, a recipient has the option to
030: * distribute your version of this file under either the CDDL, the GPL Version 2 or
031: * to extend the choice of license to its licensees as provided above. However, if
032: * you add GPL Version 2 code and therefore, elected the GPL Version 2 license, then
033: * the option applies only if the new code is made subject to such option by the
034: * copyright holder.
035: */
036:
037: package org.netbeans.installer.utils.system.launchers.impl;
038:
039: import java.io.File;
040: import java.io.FileInputStream;
041: import java.io.FileOutputStream;
042: import java.io.IOException;
043: import java.io.InputStream;
044: import java.util.ArrayList;
045: import java.util.List;
046: import java.util.jar.Attributes;
047: import java.util.jar.JarFile;
048: import java.util.jar.Manifest;
049: import org.netbeans.installer.utils.FileProxy;
050: import org.netbeans.installer.utils.FileUtils;
051: import org.netbeans.installer.utils.LogManager;
052: import org.netbeans.installer.utils.ResourceUtils;
053: import org.netbeans.installer.utils.StreamUtils;
054: import org.netbeans.installer.utils.StringUtils;
055:
056: import org.netbeans.installer.utils.applications.JavaUtils;
057: import org.netbeans.installer.utils.exceptions.DownloadException;
058: import org.netbeans.installer.utils.helper.EngineResources;
059: import org.netbeans.installer.utils.helper.ErrorLevel;
060: import org.netbeans.installer.utils.system.launchers.Launcher;
061: import org.netbeans.installer.utils.system.launchers.LauncherProperties;
062: import org.netbeans.installer.utils.system.launchers.LauncherResource;
063: import org.netbeans.installer.utils.progress.Progress;
064:
065: /**
066: *
067: * @author Dmitry Lipin
068: */
069: public abstract class CommonLauncher extends Launcher {
070: private static final int BUF_SIZE = 102400;
071:
072: protected CommonLauncher(LauncherProperties pr) {
073: super (pr);
074: }
075:
076: protected long addData(FileOutputStream fos, InputStream is,
077: Progress progress, long total) throws IOException {
078: byte[] buffer = new byte[BUF_SIZE];
079: int readBytes;
080: int start = progress.getPercentage();
081: long totalRead = 0;
082: long perc = 0;
083: while (is.available() > 0) {
084: readBytes = is.read(buffer);
085: totalRead += readBytes;
086: fos.write(buffer, 0, readBytes);
087: if (total != 0) {
088: perc = (Progress.COMPLETE * totalRead) / total;
089: progress.setPercentage(start + (int) perc);
090: }
091: }
092: fos.flush();
093: return totalRead;
094: }
095:
096: protected long addData(FileOutputStream fos, File file,
097: Progress progress, long total) throws IOException {
098: FileInputStream fis = null;
099: try {
100: fis = new FileInputStream(file);
101: return addData(fos, fis, progress, total);
102: } finally {
103: if (fis != null) {
104: try {
105: fis.close();
106: } catch (IOException ex) {
107: LogManager.log(ex);
108: }
109: }
110: }
111:
112: }
113:
114: //add rnd data
115: protected void addData(FileOutputStream fos) throws IOException {
116: double rand = Math.random() * Byte.MAX_VALUE;
117: //fos.write(new byte[] {(byte)rand});
118: fos.write(new byte[] { '#' });
119: }
120:
121: protected long addString(FileOutputStream fos, String string,
122: boolean isUnicode) throws IOException {
123: byte[] bytes;
124: if (isUnicode) {
125: bytes = string.getBytes("UNICODE"); //NOI18N
126: } else {
127: bytes = string.getBytes();
128: }
129: fos.write(bytes);
130: return bytes.length;
131: }
132:
133: protected long addStringBuilder(FileOutputStream fos,
134: StringBuilder builder, boolean isUnicode)
135: throws IOException {
136: return addString(fos, builder.toString(), isUnicode);
137: }
138:
139: protected void checkAllParameters() throws IOException {
140: checkBundledJars();
141: checkJvmFile();
142: checkOutputFileName();
143: checkI18N();
144: checkMainClass();
145: checkTestJVMFile();
146: checkTestJVMClass();
147: checkCompatibleJava();
148: }
149:
150: private void checkI18N() throws IOException {
151: // i18n properties suffix
152: LogManager.log(ErrorLevel.DEBUG, "Check i18n...");
153: String suffix = getI18NResourcePrefix();
154: if (i18nMap.isEmpty() && suffix != null) {
155: // load from engine`s entries list
156: LogManager
157: .log("... i18n properties were not set. using default from resources");
158: InputStream is = ResourceUtils
159: .getResource(EngineResources.ENGINE_CONTENTS_LIST);
160: String[] resources = StringUtils.splitByLines(StreamUtils
161: .readStream(is));
162: List<String> list = new ArrayList<String>();
163: LogManager.log("... total engine resources: "
164: + resources.length); //NOI18N
165: for (String res : resources) {
166: if (res.startsWith(suffix)
167: && res.endsWith(FileUtils.PROPERTIES_EXTENSION)) {
168: list.add(res);
169: }
170: }
171: LogManager.log("... total i18n resources: " + list.size()); //NOI18N
172: setI18n(list);
173: }
174: }
175:
176: protected void checkBundledJars() throws IOException {
177: LogManager.log(ErrorLevel.DEBUG, "Checking bundled jars...");
178: for (LauncherResource f : jars) {
179: if (f.isBundled()) {
180: checkParameter("bundled JAR", f.getPath());
181: }
182: }
183: if (jars.size() == 0) {
184: throw new IOException(ResourceUtils.getString(
185: CommonLauncher.class, ERROR_NO_JAR_FILES_KEY));
186: }
187: }
188:
189: protected void checkJvmFile() throws IOException {
190: LogManager.log(ErrorLevel.DEBUG, "Checking JVMs...");
191: for (LauncherResource file : jvms) {
192: if (file.isBundled()) {
193: InputStream is = null;
194: try {
195: is = file.getInputStream();
196: if (is == null) {
197: throw new IOException(ResourceUtils.getString(
198: CommonLauncher.class,
199: ERROR_CANNOT_FIND_JVM_FILE_KEY, file
200: .getPath()));
201: }
202: } finally {
203: if (is != null) {
204: try {
205: is.close();
206: } catch (IOException e) {
207: LogManager.log(e);
208: }
209: }
210: }
211:
212: }
213: }
214: }
215:
216: private void checkMainClass() throws IOException {
217: LogManager.log(ErrorLevel.DEBUG, "Checking main class...");
218: // check main-class parameter
219: // read main class from jar file if it is not specified
220: if (mainClass == null) {
221: // get the first
222: for (LauncherResource file : jars) {
223: if (file.isBundled() && !file.isBasedOnResource()) {
224: JarFile jarFile = new JarFile(new File(file
225: .getPath()));
226: Manifest manifest = jarFile.getManifest();
227: jarFile.close();
228: if (manifest != null) {
229: mainClass = manifest.getMainAttributes()
230: .getValue(Attributes.Name.MAIN_CLASS);
231: }
232: if (mainClass != null) {
233: return;
234: }
235: }
236: }
237: throw new IOException(ResourceUtils.getString(
238: CommonLauncher.class,
239: ERROR_MAIN_CLASS_UNSPECIFIED_KEY));
240: } else {
241: for (LauncherResource file : jars) {
242: if (file.isBundled() && !file.isBasedOnResource()) {
243: JarFile jarFile = new JarFile(new File(file
244: .getPath()));
245: boolean mainClassExists = jarFile
246: .getJarEntry(mainClass.replace(".", "/")
247: + ".class") != null;
248: jarFile.close();
249: if (mainClassExists) {
250: return;
251: }
252: } else {
253: return;
254: }
255: }
256:
257: throw new IOException(ResourceUtils.getString(
258: CommonLauncher.class, ERROR_CANNOT_FIND_CLASS_KEY,
259: mainClass));
260: }
261: }
262:
263: private void checkTestJVMClass() throws IOException {
264: LogManager.log(ErrorLevel.DEBUG, "Checking testJVM class...");
265: if (testJVMClass == null) {
266: testJVMClass = JavaUtils.TEST_JDK_CLASSNAME;
267: }
268: }
269:
270: private void checkParameter(String paramDescr, String parameter)
271: throws IOException {
272: if (parameter == null) {
273: throw new IOException("Parameter " + paramDescr
274: + " can`t be null");
275: }
276: }
277:
278: protected void checkParameter(String paramDescr, File parameter)
279: throws IOException {
280: if (parameter == null) {
281: throw new IOException("Parameter " + paramDescr
282: + " can`t be null");
283: }
284: if (!parameter.exists()) {
285: throw new IOException(paramDescr + " doesn`t exist at "
286: + parameter);
287: }
288: }
289:
290: protected void checkCompatibleJava() throws IOException {
291: LogManager.log(ErrorLevel.DEBUG,
292: "Checking compatible java properties...");
293: if (compatibleJava.isEmpty()) {
294: compatibleJava.addAll(getDefaultCompatibleJava());
295: }
296:
297: }
298:
299: protected void checkTestJVMFile() throws IOException {
300: LogManager.log(ErrorLevel.DEBUG, "Checking testJVM file...");
301: if (testJVMFile == null) {
302: testJVMFile = new LauncherResource(
303: JavaUtils.TEST_JDK_RESOURCE);
304: }
305: }
306:
307: protected void checkOutputFileName() throws IOException {
308: LogManager
309: .log(ErrorLevel.DEBUG, "Checking output file name...");
310: if (outputFile == null) {
311: LogManager
312: .log(
313: ErrorLevel.DEBUG,
314: "... output file name is not specified, getting name from the first bundled file");
315: String outputFileName = null;
316: for (LauncherResource file : jars) {
317: if (file.isBundled() && !file.isBasedOnResource()) {
318: File jarFile = new File(file.getPath());
319: String name = jarFile.getName();
320: if (name.endsWith(FileUtils.JAR_EXTENSION)) {
321: outputFileName = name.substring(0, name
322: .lastIndexOf(FileUtils.JAR_EXTENSION));
323: }
324: outputFileName += getExtension();
325: outputFile = new File(jarFile.getParent(),
326: outputFileName);
327: break;
328: }
329: }
330: if (outputFile == null) {
331: String exString = ResourceUtils.getString(
332: CommonLauncher.class,
333: ERROR_CANNOT_GET_OUTPUT_NAME_KEY);
334: LogManager.log(exString);
335: throw new IOException(exString);
336: }
337: } else if (addExtenstion) {
338: LogManager.log(ErrorLevel.DEBUG,
339: "... output is defined, adding extension");
340: // outfile is defined but we need to set launcher-dependent extension
341: outputFile = new File(outputFile.getParent(), outputFile
342: .getName()
343: + getExtension());
344: addExtenstion = false;
345: }
346: LogManager.log("... out file : " + outputFile); //NOI18N
347: }
348:
349: protected String getJavaCounter(int counter) {
350: return "{" + counter + "}";
351: }
352:
353: protected long getBundledFilesSize() throws IOException {
354: long total = 0;
355:
356: for (LauncherResource jvmFile : jvms) {
357: total += jvmFile.getSize();
358: }
359: total += testJVMFile.getSize();
360:
361: for (LauncherResource jarFile : jars) {
362: total += jarFile.getSize();
363: }
364: for (LauncherResource other : otherResources) {
365: total += other.getSize();
366: }
367: return total;
368: }
369:
370: protected long getBundledFilesNumber() {
371: long total = 0;
372: for (LauncherResource jvmFile : jvms) {
373: if (jvmFile.isBundled()) {
374: total++;
375: }
376: }
377: if (testJVMFile.isBundled()) {
378: total++;
379: }
380: for (LauncherResource jarFile : jars) {
381: if (jarFile.isBundled()) {
382: total++;
383: }
384: }
385: for (LauncherResource other : otherResources) {
386: if (other.isBundled()) {
387: total++;
388: }
389: }
390: return total;
391: }
392:
393: private static final String ERROR_NO_JAR_FILES_KEY = "CnL.error.no.jars";//NOI18N
394: private static final String ERROR_CANNOT_FIND_JVM_FILE_KEY = "CnL.error.cannot.find.jvm.file";//NOI18N
395: private static final String ERROR_CANNOT_FIND_CLASS_KEY = "CnL.error.cannot.find.class";//NOI18N
396: private static final String ERROR_MAIN_CLASS_UNSPECIFIED_KEY = "CnL.error.main.class.unspecified";//NOI18N
397: private static final String ERROR_CANNOT_GET_OUTPUT_NAME_KEY = "CnL.error.cannot.get.output.name";//NOI18N
398: }
|