svn-gvsig-desktop / trunk / build / distribution / IzPack / src / lib / com / izforge / izpack / compiler / Compiler.java @ 21757
History | View | Annotate | Download (63.1 KB)
1 |
/*
|
---|---|
2 |
* $Id: Compiler.java 5819 2006-06-14 07:29:09Z cesar $
|
3 |
* IzPack
|
4 |
* Copyright (C) 2001-2004 Julien Ponge
|
5 |
*
|
6 |
* File : Compiler.java
|
7 |
* Description : The IzPack compiler.
|
8 |
* Author's email : julien@izforge.com
|
9 |
* Author's Website : http://www.izforge.com
|
10 |
*
|
11 |
* Portions are Copyright (c) 2001 Johannes Lehtinen
|
12 |
* johannes.lehtinen@iki.fi
|
13 |
* http://www.iki.fi/jle/
|
14 |
*
|
15 |
* Portions are Copyright (c) 2002 Paul Wilkinson
|
16 |
* paulw@wilko.com
|
17 |
*
|
18 |
* Portions are Copyright (C) 2004 Gaganis Giorgos (geogka@it.teithe.gr)
|
19 |
*
|
20 |
* This program is free software; you can redistribute it and/or
|
21 |
* modify it under the terms of the GNU General Public License
|
22 |
* as published by the Free Software Foundation; either version 2
|
23 |
* of the License, or any later version.
|
24 |
*
|
25 |
* This program is distributed in the hope that it will be useful,
|
26 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
27 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
28 |
* GNU General Public License for more details.
|
29 |
*
|
30 |
* You should have received a copy of the GNU General Public License
|
31 |
* along with this program; if not, write to the Free Software
|
32 |
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
33 |
*/
|
34 |
package com.izforge.izpack.compiler; |
35 |
|
36 |
import java.io.BufferedInputStream; |
37 |
import java.io.BufferedOutputStream; |
38 |
import java.io.File; |
39 |
import java.io.FileInputStream; |
40 |
import java.io.FileNotFoundException; |
41 |
import java.io.FileOutputStream; |
42 |
import java.io.IOException; |
43 |
import java.io.InputStream; |
44 |
import java.net.MalformedURLException; |
45 |
import java.net.URL; |
46 |
import java.net.URLClassLoader; |
47 |
import java.util.*; |
48 |
import java.util.jar.JarInputStream; |
49 |
import java.util.zip.ZipEntry; |
50 |
|
51 |
import net.n3.nanoxml.NonValidator; |
52 |
import net.n3.nanoxml.StdXMLBuilder; |
53 |
import net.n3.nanoxml.StdXMLParser; |
54 |
import net.n3.nanoxml.StdXMLReader; |
55 |
import net.n3.nanoxml.XMLElement; |
56 |
|
57 |
import org.apache.tools.ant.DirectoryScanner; |
58 |
|
59 |
import com.izforge.izpack.CustomData; |
60 |
import com.izforge.izpack.ExecutableFile; |
61 |
import com.izforge.izpack.GUIPrefs; |
62 |
import com.izforge.izpack.Info; |
63 |
import com.izforge.izpack.PackFile; |
64 |
import com.izforge.izpack.Panel; |
65 |
import com.izforge.izpack.ParsableFile; |
66 |
import com.izforge.izpack.UpdateCheck; |
67 |
import com.izforge.izpack.event.CompilerListener; |
68 |
import com.izforge.izpack.installer.VariableSubstitutor; |
69 |
import com.izforge.izpack.util.Debug; |
70 |
import com.izforge.izpack.util.OsConstraint; |
71 |
|
72 |
/**
|
73 |
* The IzPack compiler class.
|
74 |
*
|
75 |
* @author Julien Ponge
|
76 |
* @author Tino Schwarze
|
77 |
* @author Chadwick McHenry
|
78 |
*/
|
79 |
public class Compiler extends Thread |
80 |
{ |
81 |
/** The compiler version. */
|
82 |
public final static String VERSION = "1.0"; |
83 |
|
84 |
/** The IzPack version. */
|
85 |
public final static String IZPACK_VERSION = "3.7.2 (build 2005.04.22)"; |
86 |
|
87 |
/** Standard installer. */
|
88 |
public final static String STANDARD = "standard"; |
89 |
|
90 |
/** Web installer. */
|
91 |
public final static String WEB = "web"; |
92 |
|
93 |
/** The IzPack home directory. */
|
94 |
public static String IZPACK_HOME = "."; |
95 |
|
96 |
/** Constant for checking attributes. */
|
97 |
private static boolean YES = true; |
98 |
|
99 |
/** Constant for checking attributes. */
|
100 |
private static boolean NO = false; |
101 |
|
102 |
/** The IzPack home directory specified or found on startup. */
|
103 |
private static File home = new File (IZPACK_HOME); |
104 |
|
105 |
/** The XML filename. */
|
106 |
protected String filename; |
107 |
|
108 |
/** The base directory. */
|
109 |
protected String basedir; |
110 |
|
111 |
/** The installer kind. */
|
112 |
protected String kind; |
113 |
|
114 |
/** The output jar filename. */
|
115 |
protected String output; |
116 |
|
117 |
/** The packager listener. */
|
118 |
protected PackagerListener packagerListener;
|
119 |
|
120 |
/** List of CompilerListeners which should be called
|
121 |
* at packaging */
|
122 |
protected List compilerListeners; |
123 |
|
124 |
/** Collects and packs files into installation jars, as told. */
|
125 |
private Packager packager = null; |
126 |
|
127 |
/** Error code, set to true if compilation succeeded. */
|
128 |
private boolean compileFailed = true; |
129 |
|
130 |
/**
|
131 |
* The constructor.
|
132 |
*
|
133 |
* @param filename The XML filename.
|
134 |
* @param basedir The base directory.
|
135 |
* @param kind The installer kind.
|
136 |
* @param output The installer filename.
|
137 |
*/
|
138 |
public Compiler(String filename, String basedir, String kind, String output) |
139 |
{ |
140 |
// Default initialisation
|
141 |
this.filename = filename;
|
142 |
this.basedir = basedir;
|
143 |
this.kind = kind;
|
144 |
this.output = output;
|
145 |
} |
146 |
|
147 |
/**
|
148 |
* Sets the packager listener.
|
149 |
*
|
150 |
* @param listener The listener.
|
151 |
*/
|
152 |
public void setPackagerListener(PackagerListener listener) |
153 |
{ |
154 |
packagerListener = listener; |
155 |
} |
156 |
|
157 |
/** Compiles. */
|
158 |
public void compile() |
159 |
{ |
160 |
start(); |
161 |
} |
162 |
|
163 |
/** The run() method. */
|
164 |
public void run() |
165 |
{ |
166 |
try
|
167 |
{ |
168 |
executeCompiler(); // Execute the compiler - may send info to System.out
|
169 |
} catch (CompilerException ce)
|
170 |
{ |
171 |
System.out.println(ce.getMessage() + "\n"); |
172 |
} catch (Exception e) |
173 |
{ |
174 |
if (Debug.stackTracing())
|
175 |
{ |
176 |
e.printStackTrace(); |
177 |
} else
|
178 |
{ |
179 |
System.out.println("ERROR: " + e.getMessage()); |
180 |
} |
181 |
} |
182 |
} |
183 |
|
184 |
/**
|
185 |
* Compiles the installation.
|
186 |
*
|
187 |
* @exception Exception Description of the Exception
|
188 |
*/
|
189 |
public void executeCompiler() throws Exception |
190 |
{ |
191 |
// normalize and test: TODO: may allow failure if we require write access
|
192 |
File base = new File(basedir).getAbsoluteFile(); |
193 |
if (!base.canRead() || !base.isDirectory())
|
194 |
throw new CompilerException("Invalid base directory: " + base); |
195 |
|
196 |
// We get the XML data tree
|
197 |
XMLElement data = getXMLTree(); |
198 |
|
199 |
// We create the Packager
|
200 |
packager = new Packager();
|
201 |
packager.setPackagerListener(packagerListener); |
202 |
|
203 |
// We add all the information
|
204 |
addCustomListeners(data); |
205 |
addVariables(data); |
206 |
addInfo(data); |
207 |
addGUIPrefs(data); |
208 |
addLangpacks(data); |
209 |
addResources(data); |
210 |
addNativeLibraries(data); |
211 |
addJars(data); |
212 |
addPanels(data); |
213 |
addPacks(data); |
214 |
|
215 |
// We ask the packager to create the installer
|
216 |
packager.createInstaller(new File(output)); |
217 |
this.compileFailed = false; |
218 |
} |
219 |
|
220 |
public boolean wasSuccessful() |
221 |
{ |
222 |
return !this.compileFailed; |
223 |
} |
224 |
|
225 |
|
226 |
/**
|
227 |
* Returns the GUIPrefs.
|
228 |
*
|
229 |
* @param data The XML data.
|
230 |
* return The GUIPrefs.
|
231 |
* @exception CompilerException Description of the Exception
|
232 |
*/
|
233 |
protected void addGUIPrefs(XMLElement data) throws CompilerException |
234 |
{ |
235 |
notifyCompilerListener("addGUIPrefs", CompilerListener.BEGIN, data);
|
236 |
// We get the XMLElement & the attributes
|
237 |
XMLElement gp = data.getFirstChildNamed("guiprefs");
|
238 |
GUIPrefs prefs = new GUIPrefs();
|
239 |
if (gp != null) |
240 |
{ |
241 |
prefs.resizable = requireYesNoAttribute(gp, "resizable");
|
242 |
prefs.width = requireIntAttribute(gp, "width");
|
243 |
prefs.height = requireIntAttribute(gp, "height");
|
244 |
|
245 |
// Look and feel mappings
|
246 |
Iterator it = gp.getChildrenNamed("laf").iterator(); |
247 |
while (it.hasNext())
|
248 |
{ |
249 |
XMLElement laf = (XMLElement)it.next(); |
250 |
String lafName = requireAttribute(laf, "name"); |
251 |
requireChildNamed(laf, "os");
|
252 |
|
253 |
Iterator oit = laf.getChildrenNamed("os").iterator(); |
254 |
while (oit.hasNext())
|
255 |
{ |
256 |
XMLElement os = (XMLElement)oit.next(); |
257 |
String osName = requireAttribute(os, "family"); |
258 |
prefs.lookAndFeelMapping.put(osName, lafName); |
259 |
} |
260 |
|
261 |
Iterator pit = laf.getChildrenNamed("param").iterator(); |
262 |
Map params = new TreeMap(); |
263 |
while (pit.hasNext())
|
264 |
{ |
265 |
XMLElement param = (XMLElement)pit.next(); |
266 |
String name = requireAttribute(param, "name"); |
267 |
String value = requireAttribute(param, "value"); |
268 |
params.put(name, value); |
269 |
} |
270 |
prefs.lookAndFeelParams.put(lafName, params); |
271 |
} |
272 |
// Load modifier
|
273 |
it = gp.getChildrenNamed("modifier").iterator();
|
274 |
while (it.hasNext())
|
275 |
{ |
276 |
XMLElement curentModifier = (XMLElement)it.next(); |
277 |
String key = requireAttribute(curentModifier, "key"); |
278 |
String value = requireAttribute(curentModifier, "value"); |
279 |
prefs.modifier.put(key, value); |
280 |
|
281 |
} |
282 |
// make sure jar contents of each are available in installer
|
283 |
// map is easier to read/modify than if tree
|
284 |
HashMap lafMap = new HashMap(); |
285 |
lafMap.put("liquid", "liquidlnf.jar"); |
286 |
lafMap.put("kunststoff","kunststoff.jar"); |
287 |
lafMap.put("metouia", "metouia.jar"); |
288 |
lafMap.put("looks", "looks.jar"); |
289 |
|
290 |
// is this really what we want? a double loop? needed, since above, it's
|
291 |
// the /last/ lnf for an os which is used, so can't add during initial
|
292 |
// loop
|
293 |
Iterator kit = prefs.lookAndFeelMapping.keySet().iterator();
|
294 |
while (kit.hasNext())
|
295 |
{ |
296 |
String lafName = (String)prefs.lookAndFeelMapping.get(kit.next()); |
297 |
String lafJarName = (String) lafMap.get(lafName); |
298 |
if (lafJarName == null) |
299 |
parseError(gp, "Unrecognized Look and Feel: " + lafName);
|
300 |
|
301 |
URL lafJarURL = findIzPackResource("lib/" + lafJarName, |
302 |
"Look and Feel Jar file", gp);
|
303 |
packager.addJarContent(lafJarURL); |
304 |
} |
305 |
} |
306 |
packager.setGUIPrefs(prefs); |
307 |
notifyCompilerListener("addGUIPrefs", CompilerListener.END, data);
|
308 |
} |
309 |
|
310 |
/**
|
311 |
* Add project specific external jar files to the installer.
|
312 |
*
|
313 |
* @param data The XML data.
|
314 |
*/
|
315 |
protected void addJars(XMLElement data) throws Exception |
316 |
{ |
317 |
notifyCompilerListener("addJars", CompilerListener.BEGIN, data);
|
318 |
Iterator iter = data.getChildrenNamed("jar").iterator(); |
319 |
while (iter.hasNext())
|
320 |
{ |
321 |
XMLElement el = (XMLElement) iter.next(); |
322 |
String src = requireAttribute(el, "src"); |
323 |
URL url = findProjectResource(src, "Jar file", el); |
324 |
packager.addJarContent(url); |
325 |
// Additionals for mark a jar file also used in the uninstaller.
|
326 |
// The contained files will be copied from the installer into the
|
327 |
// uninstaller if needed.
|
328 |
// Therefore the contained files of the jar should be in the installer also
|
329 |
// they are used only from the uninstaller. This is the reason why the stage
|
330 |
// wiil be only observed for the uninstaller.
|
331 |
String stage = el.getAttribute("stage"); |
332 |
if( stage != null && |
333 |
( stage.equalsIgnoreCase("both") || stage.equalsIgnoreCase("uninstall"))) |
334 |
{ |
335 |
CustomData ca = new CustomData( null, |
336 |
getContainedFilePaths(url), null, CustomData.UNINSTALLER_JAR );
|
337 |
packager.addCustomJar( ca, url); |
338 |
} |
339 |
} |
340 |
notifyCompilerListener("addJars", CompilerListener.END, data);
|
341 |
} |
342 |
|
343 |
/**
|
344 |
* Add native libraries to the installer.
|
345 |
*
|
346 |
* @param data The XML data.
|
347 |
*/
|
348 |
protected void addNativeLibraries(XMLElement data) throws Exception |
349 |
{ |
350 |
boolean needAddOns = false; |
351 |
notifyCompilerListener("addNativeLibraries", CompilerListener.BEGIN, data);
|
352 |
Iterator iter = data.getChildrenNamed("native").iterator(); |
353 |
while (iter.hasNext())
|
354 |
{ |
355 |
XMLElement el = (XMLElement) iter.next(); |
356 |
String type = requireAttribute(el, "type"); |
357 |
String name = requireAttribute(el, "name"); |
358 |
String path = "bin/native/" + type + "/" + name; |
359 |
URL url = findIzPackResource(path, "Native Library", el); |
360 |
packager.addNativeLibrary(name, url); |
361 |
// Additionals for mark a native lib also used in the uninstaller
|
362 |
// The lib will be copied from the installer into the uninstaller if needed.
|
363 |
// Therefore the lib should be in the installer also it is used only from
|
364 |
// the uninstaller. This is the reason why the stage wiil be only observed
|
365 |
// for the uninstaller.
|
366 |
String stage = el.getAttribute("stage"); |
367 |
List constraints = OsConstraint.getOsList(el);
|
368 |
if( stage != null && |
369 |
( stage.equalsIgnoreCase("both") || stage.equalsIgnoreCase("uninstall"))) |
370 |
{ |
371 |
ArrayList al = new ArrayList(); |
372 |
al.add(name); |
373 |
CustomData cad = new CustomData(null,al, constraints, CustomData.UNINSTALLER_LIB); |
374 |
packager.addNativeUninstallerLibrary(cad); |
375 |
needAddOns = true;
|
376 |
} |
377 |
|
378 |
} |
379 |
if( needAddOns )
|
380 |
{ |
381 |
// Add the uninstaller extensions as a resource if specified
|
382 |
XMLElement root = requireChildNamed(data, "info");
|
383 |
XMLElement uninstallInfo = root.getFirstChildNamed("uninstaller");
|
384 |
if (validateYesNoAttribute(uninstallInfo, "write", YES)) |
385 |
{ |
386 |
URL url = findIzPackResource("lib/uninstaller-ext.jar", "Uninstaller extensions", root); |
387 |
packager.addResource("IzPack.uninstaller-ext", url);
|
388 |
} |
389 |
|
390 |
} |
391 |
notifyCompilerListener("addNativeLibraries", CompilerListener.END, data);
|
392 |
} |
393 |
|
394 |
/**
|
395 |
* Add packs and their contents to the installer.
|
396 |
*
|
397 |
* @param data The XML data.
|
398 |
*/
|
399 |
protected void addPacks(XMLElement data) throws CompilerException |
400 |
{ |
401 |
notifyCompilerListener("addPacks", CompilerListener.BEGIN, data);
|
402 |
// Initialisation
|
403 |
XMLElement root = requireChildNamed(data, "packs");
|
404 |
|
405 |
// at least one pack is required
|
406 |
Vector packElements = root.getChildrenNamed("pack"); |
407 |
if (packElements.isEmpty())
|
408 |
parseError(root, "<packs> requires a <pack>");
|
409 |
|
410 |
Iterator packIter = packElements.iterator();
|
411 |
while (packIter.hasNext())
|
412 |
{ |
413 |
XMLElement el = (XMLElement) packIter.next(); |
414 |
|
415 |
// Trivial initialisations
|
416 |
String name = requireAttribute(el, "name"); |
417 |
String id = el.getAttribute("id"); |
418 |
boolean loose = "true".equalsIgnoreCase(el.getAttribute("loose", "false")); |
419 |
String description = requireChildNamed(el, "description").getContent(); |
420 |
boolean required = requireYesNoAttribute(el, "required"); |
421 |
|
422 |
PackInfo pack = new PackInfo(name, id, description, required, loose);
|
423 |
pack.setOsConstraints(OsConstraint.getOsList(el)); // TODO: unverified
|
424 |
pack.setPreselected(validateYesNoAttribute(el, "preselected", YES));
|
425 |
|
426 |
// We get the parsables list
|
427 |
Iterator iter = el.getChildrenNamed("parsable").iterator(); |
428 |
while (iter.hasNext())
|
429 |
{ |
430 |
XMLElement p = (XMLElement) iter.next(); |
431 |
String target = requireAttribute(p, "targetfile"); |
432 |
String type = p.getAttribute("type", "plain"); |
433 |
String encoding = p.getAttribute("encoding", null); |
434 |
List osList = OsConstraint.getOsList(p); // TODO: unverified |
435 |
|
436 |
pack.addParsable(new ParsableFile(target, type, encoding, osList));
|
437 |
} |
438 |
|
439 |
// We get the executables list
|
440 |
iter = el.getChildrenNamed("executable").iterator();
|
441 |
while (iter.hasNext())
|
442 |
{ |
443 |
XMLElement e = (XMLElement) iter.next(); |
444 |
ExecutableFile executable = new ExecutableFile();
|
445 |
String val; // temp value |
446 |
|
447 |
executable.path = requireAttribute(e, "targetfile");
|
448 |
|
449 |
// when to execute this executable
|
450 |
val = e.getAttribute("stage", "never"); |
451 |
if ("postinstall".equalsIgnoreCase(val)) |
452 |
executable.executionStage = ExecutableFile.POSTINSTALL; |
453 |
else if ("uninstall".equalsIgnoreCase(val)) |
454 |
executable.executionStage = ExecutableFile.UNINSTALL; |
455 |
|
456 |
// type of this executable
|
457 |
val = e.getAttribute("type", "bin"); |
458 |
if ("jar".equalsIgnoreCase(val)) |
459 |
{ |
460 |
executable.type = ExecutableFile.JAR; |
461 |
executable.mainClass = e.getAttribute("class"); // executable class |
462 |
} |
463 |
|
464 |
// what to do if execution fails
|
465 |
val = e.getAttribute("failure", "ask"); |
466 |
if ("abort".equalsIgnoreCase(val)) |
467 |
executable.onFailure = ExecutableFile.ABORT; |
468 |
else if ("warn".equalsIgnoreCase(val)) |
469 |
executable.onFailure = ExecutableFile.WARN; |
470 |
|
471 |
// whether to keep the executable after executing it
|
472 |
val = e.getAttribute("keep");
|
473 |
executable.keepFile = "true".equalsIgnoreCase(val);
|
474 |
|
475 |
// get arguments for this executable
|
476 |
XMLElement args = e.getFirstChildNamed("args");
|
477 |
if (null != args) |
478 |
{ |
479 |
Iterator argIterator = args.getChildrenNamed("arg").iterator(); |
480 |
while (argIterator.hasNext())
|
481 |
{ |
482 |
XMLElement arg = (XMLElement) argIterator.next(); |
483 |
executable.argList.add(requireAttribute(arg, "value"));
|
484 |
} |
485 |
} |
486 |
|
487 |
executable.osList = OsConstraint.getOsList(e); // TODO: unverified
|
488 |
|
489 |
pack.addExecutable(executable); |
490 |
} |
491 |
|
492 |
// We get the files list
|
493 |
iter = el.getChildrenNamed("file").iterator();
|
494 |
while (iter.hasNext())
|
495 |
{ |
496 |
XMLElement f = (XMLElement) iter.next(); |
497 |
String src = requireAttribute(f, "src"); |
498 |
String targetdir = requireAttribute(f, "targetdir"); |
499 |
List osList = OsConstraint.getOsList(f); // TODO: unverified |
500 |
int override = getOverrideValue(f);
|
501 |
Map additionals = getAdditionals(f);
|
502 |
|
503 |
|
504 |
File file = new File(src); |
505 |
if (! file.isAbsolute())
|
506 |
file = new File(basedir, src); |
507 |
|
508 |
try
|
509 |
{ |
510 |
addRecursively(file, targetdir, osList, override, pack, additionals); |
511 |
} catch (Exception x) |
512 |
{ |
513 |
parseError(f, x.getMessage(), x); |
514 |
} |
515 |
} |
516 |
|
517 |
// We get the singlefiles list
|
518 |
iter = el.getChildrenNamed("singlefile").iterator();
|
519 |
while (iter.hasNext())
|
520 |
{ |
521 |
XMLElement f = (XMLElement) iter.next(); |
522 |
String src = requireAttribute(f, "src"); |
523 |
String target = requireAttribute(f, "target"); |
524 |
List osList = OsConstraint.getOsList(f); // TODO: unverified |
525 |
int override = getOverrideValue(f);
|
526 |
Map additionals = getAdditionals(f);
|
527 |
|
528 |
File file = new File(src); |
529 |
if (! file.isAbsolute())
|
530 |
file = new File(basedir, src); |
531 |
|
532 |
try
|
533 |
{ |
534 |
pack.addFile(file, target, osList, override, additionals); |
535 |
} catch (FileNotFoundException x) |
536 |
{ |
537 |
parseError(f, x.getMessage(), x); |
538 |
} |
539 |
} |
540 |
|
541 |
// We get the fileset list
|
542 |
iter = el.getChildrenNamed("fileset").iterator();
|
543 |
while (iter.hasNext())
|
544 |
{ |
545 |
XMLElement f = (XMLElement) iter.next(); |
546 |
String dir_attr = requireAttribute(f, "dir"); |
547 |
|
548 |
File dir = new File(dir_attr); |
549 |
if (! dir.isAbsolute())
|
550 |
dir = new File(basedir, dir_attr); |
551 |
if (! dir.isDirectory()) // also tests '.exists()' |
552 |
parseError(f, "Invalid directory 'dir': " + dir_attr);
|
553 |
|
554 |
boolean casesensitive = validateYesNoAttribute(f, "casesensitive", YES); |
555 |
boolean defexcludes = validateYesNoAttribute(f, "defaultexcludes", YES); |
556 |
String targetdir = requireAttribute(f, "targetdir"); |
557 |
List osList = OsConstraint.getOsList(f); // TODO: unverified |
558 |
int override = getOverrideValue(f);
|
559 |
Map additionals = getAdditionals(f);
|
560 |
|
561 |
// get includes and excludes
|
562 |
Vector xcludesList = null; |
563 |
String[] includes = null; |
564 |
xcludesList = f.getChildrenNamed("include");
|
565 |
if (! xcludesList.isEmpty())
|
566 |
{ |
567 |
includes = new String[xcludesList.size()]; |
568 |
for (int j = 0; j < xcludesList.size(); j++) |
569 |
{ |
570 |
XMLElement xclude = (XMLElement) xcludesList.get(j); |
571 |
includes[j] = requireAttribute(xclude, "name");
|
572 |
} |
573 |
} |
574 |
String[] excludes = null; |
575 |
xcludesList = f.getChildrenNamed("exclude");
|
576 |
if (! xcludesList.isEmpty())
|
577 |
{ |
578 |
excludes = new String[xcludesList.size()]; |
579 |
for (int j = 0; j < xcludesList.size(); j++) |
580 |
{ |
581 |
XMLElement xclude = (XMLElement) xcludesList.get(j); |
582 |
excludes[j] = requireAttribute(xclude, "name");
|
583 |
} |
584 |
} |
585 |
|
586 |
// parse additional fileset attributes "includes" and "excludes"
|
587 |
String [] toDo = new String[] {"includes", "excludes" }; |
588 |
// use the existing containers filled from include and exclude
|
589 |
// and add the includes and excludes to it
|
590 |
String [][] containers = new String[][] { includes, excludes }; |
591 |
for( int j = 0; j < toDo.length; ++j ) |
592 |
{ |
593 |
String inex = f.getAttribute(toDo[j]);
|
594 |
if( inex != null && inex.length() > 0 ) |
595 |
{ // This is the same "splitting" as ant PatternSet do ...
|
596 |
StringTokenizer tok = new StringTokenizer(inex, ", ", false); |
597 |
int newSize = tok.countTokens();
|
598 |
int k = 0; |
599 |
String [] nCont = null; |
600 |
if(containers[j] != null && containers[j].length > 0 ) |
601 |
{ // old container exist; create a new which can hold all values
|
602 |
// and copy the old stuff to the front
|
603 |
newSize += containers[j].length; |
604 |
nCont = new String[newSize]; |
605 |
for(; k < containers[j].length; ++k)
|
606 |
nCont[k] = containers[j][k]; |
607 |
} |
608 |
if( nCont == null ) // No container for old values created, |
609 |
// create a new one.
|
610 |
nCont = new String[newSize]; |
611 |
for( ; k < newSize; ++k)
|
612 |
// Fill the new one or expand the existent container
|
613 |
nCont[k] = tok.nextToken(); |
614 |
containers[j] = nCont; |
615 |
} |
616 |
} |
617 |
includes = containers[0]; // push the new includes to the local var |
618 |
excludes = containers[1]; // push the new excludes to the local var |
619 |
|
620 |
// scan and add fileset
|
621 |
DirectoryScanner ds = new DirectoryScanner();
|
622 |
ds.setIncludes(includes); |
623 |
ds.setExcludes(excludes); |
624 |
if (defexcludes)
|
625 |
ds.addDefaultExcludes(); |
626 |
ds.setBasedir(dir); |
627 |
ds.setCaseSensitive(casesensitive); |
628 |
ds.scan(); |
629 |
|
630 |
String[] files = ds.getIncludedFiles(); |
631 |
String[] dirs = ds.getIncludedDirectories(); |
632 |
|
633 |
// Directory scanner has done recursion, add files and directories
|
634 |
for (int i = 0; i < files.length; ++i) |
635 |
{ |
636 |
try
|
637 |
{ |
638 |
String target = new File(targetdir, files[i]).getPath(); |
639 |
pack.addFile(new File(dir, files[i]), target, osList, |
640 |
override, additionals); |
641 |
} catch (FileNotFoundException x) |
642 |
{ |
643 |
parseError(f, x.getMessage(), x); |
644 |
} |
645 |
} |
646 |
for (int i = 0; i < dirs.length; ++i) |
647 |
{ |
648 |
try
|
649 |
{ |
650 |
String target = new File(targetdir, dirs[i]).getPath(); |
651 |
pack.addFile(new File(dir, dirs[i]), target, osList, |
652 |
override, additionals); |
653 |
} catch (FileNotFoundException x) |
654 |
{ |
655 |
parseError(f, x.getMessage(), x); |
656 |
} |
657 |
} |
658 |
} |
659 |
|
660 |
// get the updatechecks list
|
661 |
iter = el.getChildrenNamed("updatecheck").iterator();
|
662 |
while (iter.hasNext())
|
663 |
{ |
664 |
XMLElement f = (XMLElement) iter.next(); |
665 |
|
666 |
String casesensitive = f.getAttribute("casesensitive"); |
667 |
|
668 |
// get includes and excludes
|
669 |
ArrayList includesList = new ArrayList(); |
670 |
ArrayList excludesList = new ArrayList(); |
671 |
|
672 |
// get includes and excludes
|
673 |
Iterator include_it = f.getChildrenNamed("include").iterator(); |
674 |
while (include_it.hasNext())
|
675 |
{ |
676 |
XMLElement inc_el = (XMLElement) include_it.next(); |
677 |
includesList.add(requireAttribute(inc_el, "name"));
|
678 |
} |
679 |
|
680 |
Iterator exclude_it = f.getChildrenNamed("exclude").iterator(); |
681 |
while (exclude_it.hasNext())
|
682 |
{ |
683 |
XMLElement excl_el = (XMLElement) exclude_it.next(); |
684 |
excludesList.add(requireAttribute(excl_el, "name"));
|
685 |
} |
686 |
|
687 |
pack.addUpdateCheck( |
688 |
new UpdateCheck(includesList, excludesList, casesensitive));
|
689 |
} |
690 |
//We get the dependencies
|
691 |
iter = el.getChildrenNamed("depends").iterator();
|
692 |
while (iter.hasNext())
|
693 |
{ |
694 |
XMLElement dep = (XMLElement) iter.next(); |
695 |
String depName = requireAttribute(dep,"packname"); |
696 |
pack.addDependency(depName); |
697 |
|
698 |
} |
699 |
|
700 |
// We add the pack
|
701 |
packager.addPack(pack); |
702 |
} |
703 |
checkDependencies(packager.getPacksList()); |
704 |
|
705 |
notifyCompilerListener("addPacks", CompilerListener.END, data);
|
706 |
} |
707 |
/**
|
708 |
* Checks whether the dependencies stated in the configuration file are
|
709 |
* correct. Specifically it checks that no pack point to a non existent
|
710 |
* pack and also that there are no circular dependencies in the packs.
|
711 |
*/
|
712 |
public void checkDependencies(List packs) throws CompilerException |
713 |
{ |
714 |
// Because we use package names in the configuration file we assosiate
|
715 |
// the names with the objects
|
716 |
Map names = new HashMap(); |
717 |
for (int i = 0; i < packs.size(); i++) |
718 |
{ |
719 |
PackInfo pack = (PackInfo) packs.get(i); |
720 |
names.put(pack.getPack().name,pack); |
721 |
} |
722 |
int result = dfs(packs,names);
|
723 |
//@todo More informative messages to include the source of the error
|
724 |
if(result == -2) |
725 |
parseError("Circular dependency detected");
|
726 |
else if(result == -1) |
727 |
parseError("A dependency doesn't exist");
|
728 |
} |
729 |
/** We use the dfs graph search algorithm to check whether the graph
|
730 |
* is acyclic as described in:
|
731 |
* Thomas H. Cormen, Charles Leiserson, Ronald Rivest and Clifford Stein. Introduction
|
732 |
* to algorithms 2nd Edition 540-549,MIT Press, 2001
|
733 |
* @param packs The graph
|
734 |
* @param names The name map
|
735 |
* @return
|
736 |
*/
|
737 |
private int dfs(List packs,Map names) |
738 |
{ |
739 |
Map edges = new HashMap(); |
740 |
for (int i = 0; i < packs.size(); i++) |
741 |
{ |
742 |
PackInfo pack = (PackInfo) packs.get(i); |
743 |
if(pack.colour == PackInfo.WHITE)
|
744 |
{ |
745 |
if(dfsVisit(pack,names,edges)!=0) |
746 |
return -1; |
747 |
} |
748 |
|
749 |
} |
750 |
return checkBackEdges(edges);
|
751 |
} |
752 |
/**
|
753 |
* This function checks for the existence of back edges.
|
754 |
*/
|
755 |
private int checkBackEdges(Map edges) |
756 |
{ |
757 |
Set keys = edges.keySet();
|
758 |
for (Iterator iterator = keys.iterator(); iterator.hasNext();) |
759 |
{ |
760 |
final Object key = iterator.next(); |
761 |
int color = ((Integer) edges.get(key)).intValue(); |
762 |
if(color == PackInfo.GREY)
|
763 |
{ |
764 |
return -2; |
765 |
} |
766 |
} |
767 |
return 0; |
768 |
|
769 |
} |
770 |
/**
|
771 |
* This class is used for the classification of the edges
|
772 |
*/
|
773 |
private class Edge |
774 |
{ |
775 |
PackInfo u; |
776 |
PackInfo v; |
777 |
Edge(PackInfo u,PackInfo v) |
778 |
{ |
779 |
this.u = u;
|
780 |
this.v = v;
|
781 |
} |
782 |
} |
783 |
private int dfsVisit(PackInfo u,Map names,Map edges) |
784 |
{ |
785 |
u.colour = PackInfo.GREY; |
786 |
List deps = u.getDependencies();
|
787 |
if (deps != null) |
788 |
{ |
789 |
for (int i = 0; i < deps.size(); i++) |
790 |
{ |
791 |
String name = (String) deps.get(i); |
792 |
PackInfo v = (PackInfo)names.get(name); |
793 |
if(v == null) |
794 |
return -1; |
795 |
Edge edge = new Edge(u,v);
|
796 |
if(edges.get(edge) == null) |
797 |
edges.put(edge,new Integer(v.colour)); |
798 |
|
799 |
if(v.colour == PackInfo.WHITE)
|
800 |
{ |
801 |
|
802 |
final int result = dfsVisit(v,names,edges); |
803 |
if(result != 0) |
804 |
return result;
|
805 |
} |
806 |
} |
807 |
} |
808 |
u.colour = PackInfo.BLACK; |
809 |
return 0; |
810 |
} |
811 |
|
812 |
|
813 |
|
814 |
|
815 |
/**
|
816 |
* Recursive method to add files in a pack.
|
817 |
*
|
818 |
* @param file The file to add.
|
819 |
* @param targetdir The relative path to the parent.
|
820 |
* @param osList The target OS constraints.
|
821 |
* @param override Overriding behaviour.
|
822 |
* @param pack Pack to be packed into
|
823 |
* @param additionals Map which contains additional data
|
824 |
* @exception FileNotFoundException if the file does not exist
|
825 |
*/
|
826 |
protected void addRecursively(File file, String targetdir, |
827 |
List osList, int override, |
828 |
PackInfo pack, Map additionals)
|
829 |
throws IOException |
830 |
{ |
831 |
String targetfile = targetdir + "/" + file.getName(); |
832 |
if (! file.isDirectory())
|
833 |
pack.addFile(file, targetfile, osList, override, additionals); |
834 |
else
|
835 |
{ |
836 |
File[] files = file.listFiles(); |
837 |
if (files.length == 0) // The directory is empty so must be added |
838 |
pack.addFile(file, targetfile, osList, override, additionals); |
839 |
else
|
840 |
{ |
841 |
// new targetdir = targetfile;
|
842 |
for (int i = 0; i < files.length; i++) |
843 |
addRecursively(files[i], targetfile, osList, override, |
844 |
pack, additionals); |
845 |
} |
846 |
} |
847 |
} |
848 |
|
849 |
/**
|
850 |
* Parse panels and their paramters, locate the panels resources and add to
|
851 |
* the Packager.
|
852 |
*
|
853 |
* @param data The XML data.
|
854 |
* @exception CompilerException Description of the Exception
|
855 |
*/
|
856 |
protected void addPanels(XMLElement data) throws CompilerException |
857 |
{ |
858 |
notifyCompilerListener("addPanels", CompilerListener.BEGIN, data);
|
859 |
XMLElement root = requireChildNamed(data, "panels");
|
860 |
|
861 |
// at least one panel is required
|
862 |
Vector panels = root.getChildrenNamed("panel"); |
863 |
if (panels.isEmpty())
|
864 |
parseError(root, "<panels> requires a <panel>");
|
865 |
|
866 |
// We process each panel markup
|
867 |
Iterator iter = panels.iterator();
|
868 |
while (iter.hasNext())
|
869 |
{ |
870 |
XMLElement xmlPanel = (XMLElement) iter.next(); |
871 |
|
872 |
// create the serialized Panel data
|
873 |
Panel panel = new Panel(); |
874 |
panel.osConstraints = OsConstraint.getOsList(xmlPanel); |
875 |
String className = xmlPanel.getAttribute("classname"); |
876 |
|
877 |
// Panel files come in jars packaged w/ IzPack
|
878 |
String jarPath = "bin/panels/" + className + ".jar"; |
879 |
URL url = findIzPackResource(jarPath, "Panel jar file", xmlPanel); |
880 |
String fullClassName = null; |
881 |
try
|
882 |
{ |
883 |
fullClassName = getFullClassName(url, className); |
884 |
} |
885 |
catch (Exception e) |
886 |
{ |
887 |
; |
888 |
} |
889 |
if( fullClassName != null) |
890 |
panel.className = fullClassName; |
891 |
else
|
892 |
panel.className = className; |
893 |
// insert into the packager
|
894 |
packager.addPanelJar(panel, url); |
895 |
} |
896 |
notifyCompilerListener("addPanels", CompilerListener.END, data);
|
897 |
} |
898 |
|
899 |
/**
|
900 |
* Adds the resources.
|
901 |
*
|
902 |
* @param data The XML data.
|
903 |
* @exception CompilerException Description of the Exception
|
904 |
*/
|
905 |
protected void addResources(XMLElement data) throws CompilerException |
906 |
{ |
907 |
notifyCompilerListener("addResources", CompilerListener.BEGIN, data);
|
908 |
XMLElement root = data.getFirstChildNamed("resources");
|
909 |
if (root == null) |
910 |
return;
|
911 |
|
912 |
// We process each res markup
|
913 |
Iterator iter = root.getChildrenNamed("res").iterator(); |
914 |
while (iter.hasNext())
|
915 |
{ |
916 |
XMLElement res = (XMLElement) iter.next(); |
917 |
String id = requireAttribute(res, "id"); |
918 |
String src = requireAttribute(res, "src"); |
919 |
boolean parse = validateYesNoAttribute(res, "parse", NO); |
920 |
|
921 |
// basedir is not prepended if src is already an absolute path
|
922 |
URL url = findProjectResource(src, "Resource", res); |
923 |
|
924 |
// substitute variable values in the resource if parsed
|
925 |
if (parse)
|
926 |
{ |
927 |
if (packager.getVariables().isEmpty())
|
928 |
{ |
929 |
parseWarn(res, "No variables defined. " +
|
930 |
url.getPath() + " not parsed.");
|
931 |
} else
|
932 |
{ |
933 |
String type = res.getAttribute("type"); |
934 |
String encoding = res.getAttribute("encoding"); |
935 |
File parsedFile = null; |
936 |
|
937 |
try
|
938 |
{ |
939 |
// make the substitutions into a temp file
|
940 |
InputStream bin = new BufferedInputStream(url.openStream()); |
941 |
|
942 |
parsedFile = File.createTempFile("izpp", null); |
943 |
parsedFile.deleteOnExit(); |
944 |
FileOutputStream outFile = new FileOutputStream(parsedFile); |
945 |
BufferedOutputStream bout = new BufferedOutputStream(outFile); |
946 |
|
947 |
VariableSubstitutor vs = new VariableSubstitutor(packager.getVariables());
|
948 |
vs.substitute(bin, bout, type, encoding); |
949 |
bin.close(); |
950 |
bout.close(); |
951 |
|
952 |
// and specify the substituted file to be added to the packager
|
953 |
url = parsedFile.toURL(); |
954 |
} catch (IOException x) |
955 |
{ |
956 |
parseError(res, x.getMessage(), x); |
957 |
} |
958 |
} |
959 |
} |
960 |
|
961 |
packager.addResource(id, url); |
962 |
} |
963 |
notifyCompilerListener("addResources", CompilerListener.END, data);
|
964 |
} |
965 |
|
966 |
/**
|
967 |
* Adds the ISO3 codes of the langpacks and associated resources.
|
968 |
*
|
969 |
* @param data The XML data.
|
970 |
* @exception CompilerException Description of the Exception
|
971 |
*/
|
972 |
protected void addLangpacks(XMLElement data) |
973 |
throws CompilerException
|
974 |
{ |
975 |
notifyCompilerListener("addLangpacks", CompilerListener.BEGIN, data);
|
976 |
XMLElement root = requireChildNamed(data, "locale");
|
977 |
|
978 |
// at least one langpack is required
|
979 |
Vector locals = root.getChildrenNamed("langpack"); |
980 |
if (locals.isEmpty())
|
981 |
parseError(root, "<locale> requires a <langpack>");
|
982 |
|
983 |
// We process each langpack markup
|
984 |
Iterator iter = locals.iterator();
|
985 |
while (iter.hasNext())
|
986 |
{ |
987 |
XMLElement el = (XMLElement) iter.next(); |
988 |
String iso3 = requireAttribute(el, "iso3"); |
989 |
String path;
|
990 |
|
991 |
path = "bin/langpacks/installer/" + iso3 + ".xml"; |
992 |
URL iso3xmlURL = findIzPackResource(path, "ISO3 file", el); |
993 |
|
994 |
path = "bin/langpacks/flags/" + iso3 + ".gif"; |
995 |
URL iso3FlagURL = findIzPackResource(path, "ISO3 flag image", el); |
996 |
|
997 |
packager.addLangPack(iso3, iso3xmlURL, iso3FlagURL); |
998 |
} |
999 |
notifyCompilerListener("addLangpacks", CompilerListener.END, data);
|
1000 |
} |
1001 |
|
1002 |
/**
|
1003 |
* Builds the Info class from the XML tree.
|
1004 |
*
|
1005 |
* @param data The XML data.
|
1006 |
* return The Info.
|
1007 |
* @exception Exception Description of the Exception
|
1008 |
*/
|
1009 |
protected void addInfo(XMLElement data) throws Exception |
1010 |
{ |
1011 |
notifyCompilerListener("addInfo", CompilerListener.BEGIN, data);
|
1012 |
// Initialisation
|
1013 |
XMLElement root = requireChildNamed(data, "info");
|
1014 |
|
1015 |
Info info = new Info();
|
1016 |
String temp = null; |
1017 |
info.setAppName(requireContent(requireChildNamed(root, "appname")));
|
1018 |
info.setAppVersion(requireContent(requireChildNamed(root, "appversion")));
|
1019 |
// We get the installation subpath
|
1020 |
XMLElement subpath = root.getFirstChildNamed("appsubpath");
|
1021 |
if(subpath != null) |
1022 |
{ |
1023 |
info.setInstallationSubPath(requireContent(subpath)); |
1024 |
} |
1025 |
|
1026 |
// validate and insert app URL
|
1027 |
final XMLElement URLElem = root.getFirstChildNamed("url"); |
1028 |
if(URLElem != null) |
1029 |
{ |
1030 |
URL appURL = requireURLContent(URLElem);
|
1031 |
info.setAppURL(appURL.toString()); |
1032 |
} |
1033 |
|
1034 |
// We get the authors list
|
1035 |
XMLElement authors = root.getFirstChildNamed("authors");
|
1036 |
if (authors != null) |
1037 |
{ |
1038 |
Iterator iter = authors.getChildrenNamed("author").iterator(); |
1039 |
while (iter.hasNext())
|
1040 |
{ |
1041 |
XMLElement author = (XMLElement) iter.next(); |
1042 |
String name = requireAttribute(author, "name"); |
1043 |
String email = requireAttribute(author, "email"); |
1044 |
info.addAuthor(new Info.Author(name, email));
|
1045 |
} |
1046 |
} |
1047 |
|
1048 |
// We get the java version required
|
1049 |
XMLElement javaVersion = root.getFirstChildNamed("javaversion");
|
1050 |
if (javaVersion != null) |
1051 |
info.setJavaVersion(requireContent(javaVersion)); |
1052 |
|
1053 |
// validate and insert (and require if -web kind) web dir
|
1054 |
XMLElement webDirURL = root.getFirstChildNamed("webdir");
|
1055 |
if (webDirURL != null) |
1056 |
info.setWebDirURL(requireURLContent(webDirURL).toString()); |
1057 |
if (kind != null) |
1058 |
{ |
1059 |
if (kind.equalsIgnoreCase(WEB) && webDirURL == null) |
1060 |
{ |
1061 |
parseError(root, "<webdir> required when \"WEB\" installer requested");
|
1062 |
} |
1063 |
else if (kind.equalsIgnoreCase(STANDARD) && webDirURL != null) |
1064 |
{ |
1065 |
// Need a Warning? parseWarn(webDirURL, "Not creating web installer.");
|
1066 |
info.setWebDirURL(null);
|
1067 |
} |
1068 |
} |
1069 |
|
1070 |
// Add the uninstaller as a resource if specified
|
1071 |
XMLElement uninstallInfo = root.getFirstChildNamed("uninstaller");
|
1072 |
if (validateYesNoAttribute(uninstallInfo, "write", YES)) |
1073 |
{ |
1074 |
URL url = findIzPackResource("lib/uninstaller.jar", "Uninstaller", root); |
1075 |
packager.addResource("IzPack.uninstaller", url);
|
1076 |
} |
1077 |
|
1078 |
packager.setInfo(info); |
1079 |
notifyCompilerListener("addInfo", CompilerListener.END, data);
|
1080 |
} |
1081 |
|
1082 |
/**
|
1083 |
* Variable declaration is a fragment of the xml file. For example:
|
1084 |
* <pre>
|
1085 |
* <variables>
|
1086 |
* <variable name="nom" value="value"/>
|
1087 |
* <variable name="foo" value="pippo"/>
|
1088 |
* </variables>
|
1089 |
* </pre>
|
1090 |
* variable declared in this can be referred to in parsable files.
|
1091 |
*
|
1092 |
* @param data The XML data.
|
1093 |
* @exception CompilerException Description of the Exception
|
1094 |
*/
|
1095 |
protected void addVariables(XMLElement data) throws CompilerException |
1096 |
{ |
1097 |
notifyCompilerListener("addVariables", CompilerListener.BEGIN, data);
|
1098 |
// We get the varible list
|
1099 |
XMLElement root = data.getFirstChildNamed("variables");
|
1100 |
if (root == null) |
1101 |
return;
|
1102 |
|
1103 |
Properties variables = packager.getVariables();
|
1104 |
|
1105 |
Iterator iter = root.getChildrenNamed("variable").iterator(); |
1106 |
while (iter.hasNext())
|
1107 |
{ |
1108 |
XMLElement var = (XMLElement) iter.next(); |
1109 |
String name = requireAttribute(var, "name"); |
1110 |
String value = requireAttribute(var, "value"); |
1111 |
if (variables.contains(name))
|
1112 |
parseWarn(var, "Variable '" + name + "' being overwritten"); |
1113 |
variables.setProperty(name, value); |
1114 |
} |
1115 |
notifyCompilerListener("addVariables", CompilerListener.END, data);
|
1116 |
} |
1117 |
|
1118 |
/**
|
1119 |
* Returns the XMLElement representing the installation XML file.
|
1120 |
*
|
1121 |
* @return The XML tree.
|
1122 |
* @exception CompilerException For problems with the installation file
|
1123 |
* @exception IOException for errors reading the installation file
|
1124 |
*/
|
1125 |
protected XMLElement getXMLTree() throws CompilerException, IOException |
1126 |
{ |
1127 |
// Initialises the parser
|
1128 |
StdXMLParser parser = new StdXMLParser();
|
1129 |
parser.setBuilder(new StdXMLBuilder());
|
1130 |
parser.setReader(new StdXMLReader(new FileInputStream(filename))); |
1131 |
parser.setValidator(new NonValidator());
|
1132 |
|
1133 |
// We get it
|
1134 |
XMLElement data = null;
|
1135 |
try
|
1136 |
{ |
1137 |
data = (XMLElement) parser.parse(); |
1138 |
} catch (Exception x) |
1139 |
{ |
1140 |
throw new CompilerException("Error parsing installation file", x); |
1141 |
} |
1142 |
|
1143 |
// We check it
|
1144 |
if (!"installation".equalsIgnoreCase(data.getName())) |
1145 |
parseError(data, "this is not an IzPack XML installation file");
|
1146 |
if (!requireAttribute(data, "version").equalsIgnoreCase(VERSION)) |
1147 |
parseError( |
1148 |
data, |
1149 |
"the file version is different from the compiler version");
|
1150 |
|
1151 |
// We finally return the tree
|
1152 |
return data;
|
1153 |
} |
1154 |
|
1155 |
protected int getOverrideValue(XMLElement f) |
1156 |
throws CompilerException
|
1157 |
{ |
1158 |
int override = PackFile.OVERRIDE_UPDATE;
|
1159 |
|
1160 |
String override_val = f.getAttribute("override"); |
1161 |
if (override_val != null) |
1162 |
{ |
1163 |
if (override_val.equalsIgnoreCase("true")) |
1164 |
{ |
1165 |
override = PackFile.OVERRIDE_TRUE; |
1166 |
} else if (override_val.equalsIgnoreCase("false")) |
1167 |
{ |
1168 |
override = PackFile.OVERRIDE_FALSE; |
1169 |
} else if (override_val.equalsIgnoreCase("asktrue")) |
1170 |
{ |
1171 |
override = PackFile.OVERRIDE_ASK_TRUE; |
1172 |
} else if (override_val.equalsIgnoreCase("askfalse")) |
1173 |
{ |
1174 |
override = PackFile.OVERRIDE_ASK_FALSE; |
1175 |
} else if (override_val.equalsIgnoreCase("update")) |
1176 |
{ |
1177 |
override = PackFile.OVERRIDE_UPDATE; |
1178 |
} |
1179 |
else
|
1180 |
parseError(f, "invalid value for attribute \"override\"");
|
1181 |
} |
1182 |
|
1183 |
return override;
|
1184 |
} |
1185 |
|
1186 |
/**
|
1187 |
* Look for a project specified resources, which, if not absolute, are sought
|
1188 |
* relative to the projects basedir. The path should use '/' as the
|
1189 |
* fileSeparator. If the resource is not found, a CompilerException is thrown
|
1190 |
* indicating fault in the parent element.
|
1191 |
*
|
1192 |
* @param path the relative path (using '/' as separator) to the resource.
|
1193 |
* @param desc the description of the resource used to report errors
|
1194 |
* @param parent the XMLElement the resource is specified in, used to
|
1195 |
* report errors
|
1196 |
* @return a URL to the resource.
|
1197 |
*/
|
1198 |
private URL findProjectResource(String path, String desc, XMLElement parent) |
1199 |
throws CompilerException
|
1200 |
{ |
1201 |
URL url = null; |
1202 |
File resource = new File(path); |
1203 |
if (! resource.isAbsolute())
|
1204 |
resource = new File(basedir, path); |
1205 |
|
1206 |
if (! resource.exists()) // fatal |
1207 |
parseError(parent, desc + " not found: " + resource);
|
1208 |
|
1209 |
try
|
1210 |
{ |
1211 |
url = resource.toURL(); |
1212 |
} catch(MalformedURLException how) |
1213 |
{ |
1214 |
parseError(parent, desc + "(" + resource + ")", how); |
1215 |
} |
1216 |
|
1217 |
return url;
|
1218 |
} |
1219 |
|
1220 |
/**
|
1221 |
* Look for an IzPack resource either in the compiler jar, or within
|
1222 |
* IZPACK_HOME. The path must not be absolute. The path must use '/' as the
|
1223 |
* fileSeparator (it's used to access the jar file). If the resource is not
|
1224 |
* found, a CompilerException is thrown indicating fault in the parent
|
1225 |
* element.
|
1226 |
*
|
1227 |
* @param path the relative path (using '/' as separator) to the resource.
|
1228 |
* @param desc the description of the resource used to report errors
|
1229 |
* @param parent the XMLElement the resource is specified in, used to
|
1230 |
* report errors
|
1231 |
* @return a URL to the resource.
|
1232 |
*/
|
1233 |
private URL findIzPackResource(String path, String desc, XMLElement parent) |
1234 |
throws CompilerException
|
1235 |
{ |
1236 |
URL url = getClass().getResource("/" + path); |
1237 |
if (url == null) |
1238 |
{ |
1239 |
File resource = new File(path); |
1240 |
if (! resource.isAbsolute())
|
1241 |
resource = new File(IZPACK_HOME, path); |
1242 |
|
1243 |
if (! resource.exists()) // fatal |
1244 |
parseError(parent, desc + " not found: " + resource);
|
1245 |
|
1246 |
try
|
1247 |
{ |
1248 |
url = resource.toURL(); |
1249 |
} catch(MalformedURLException how) |
1250 |
{ |
1251 |
parseError(parent, desc + "(" + resource + ")", how); |
1252 |
} |
1253 |
} |
1254 |
|
1255 |
return url;
|
1256 |
} |
1257 |
/**
|
1258 |
* Create parse error with consistent messages. Includes file name. For use
|
1259 |
* When parent is unknown.
|
1260 |
*
|
1261 |
* @param message Brief message explaining error
|
1262 |
*/
|
1263 |
protected void parseError(String message) |
1264 |
throws CompilerException
|
1265 |
{ |
1266 |
this.compileFailed = true; |
1267 |
throw new CompilerException( |
1268 |
filename + ":" + message);
|
1269 |
} |
1270 |
/**
|
1271 |
* Create parse error with consistent messages. Includes file name and line #
|
1272 |
* of parent. It is an error for 'parent' to be null.
|
1273 |
*
|
1274 |
* @param parent The element in which the error occured
|
1275 |
* @param message Brief message explaining error
|
1276 |
*/
|
1277 |
protected void parseError(XMLElement parent, String message) |
1278 |
throws CompilerException
|
1279 |
{ |
1280 |
this.compileFailed = true; |
1281 |
throw new CompilerException( |
1282 |
filename + ":" + parent.getLineNr() + ": " + message); |
1283 |
} |
1284 |
|
1285 |
/**
|
1286 |
* Create a chained parse error with consistent messages. Includes file name
|
1287 |
* and line # of parent. It is an error for 'parent' to be null.
|
1288 |
*
|
1289 |
* @param parent The element in which the error occured
|
1290 |
* @param message Brief message explaining error
|
1291 |
*/
|
1292 |
protected void parseError(XMLElement parent, String message, Throwable cause) |
1293 |
throws CompilerException
|
1294 |
{ |
1295 |
this.compileFailed = true; |
1296 |
throw new CompilerException( |
1297 |
filename + ":" + parent.getLineNr() + ": " + message, |
1298 |
cause); |
1299 |
} |
1300 |
|
1301 |
/**
|
1302 |
* Create a parse warning with consistent messages. Includes file name
|
1303 |
* and line # of parent. It is an error for 'parent' to be null.
|
1304 |
*
|
1305 |
* @param parent The element in which the warning occured
|
1306 |
* @param message Warning message
|
1307 |
*/
|
1308 |
protected void parseWarn(XMLElement parent, String message) |
1309 |
{ |
1310 |
System.out.println(filename + ":" + parent.getLineNr() + ": " + message); |
1311 |
} |
1312 |
|
1313 |
/**
|
1314 |
* Call getFirstChildNamed on the parent, producing a meaningful error
|
1315 |
* message on failure. It is an error for 'parent' to be null.
|
1316 |
*
|
1317 |
* @param parent The element to search for a child
|
1318 |
* @param name Name of the child element to get
|
1319 |
*/
|
1320 |
protected XMLElement requireChildNamed(XMLElement parent, String name) |
1321 |
throws CompilerException
|
1322 |
{ |
1323 |
XMLElement child = parent.getFirstChildNamed(name); |
1324 |
if (child == null) |
1325 |
parseError( |
1326 |
parent, |
1327 |
"<" + parent.getName() + "> requires child <" + name + ">"); |
1328 |
return child;
|
1329 |
} |
1330 |
|
1331 |
/**
|
1332 |
* Call getContent on an element, producing a meaningful error message if not
|
1333 |
* present, or empty, or a valid URL. It is an error for 'element' to be
|
1334 |
* null.
|
1335 |
*
|
1336 |
* @param element The element to get content of
|
1337 |
*/
|
1338 |
protected URL requireURLContent(XMLElement element) |
1339 |
throws CompilerException
|
1340 |
{ |
1341 |
URL url = null; |
1342 |
try
|
1343 |
{ |
1344 |
url = new URL(requireContent(element)); |
1345 |
} |
1346 |
catch (MalformedURLException x) |
1347 |
{ |
1348 |
parseError(element, "<" + element.getName() + "> requires valid URL", x); |
1349 |
} |
1350 |
return url;
|
1351 |
} |
1352 |
|
1353 |
/**
|
1354 |
* Call getContent on an element, producing a meaningful error message if not
|
1355 |
* present, or empty. It is an error for 'element' to be null.
|
1356 |
*
|
1357 |
* @param element The element to get content of
|
1358 |
*/
|
1359 |
protected String requireContent(XMLElement element) throws CompilerException |
1360 |
{ |
1361 |
String content = element.getContent();
|
1362 |
if (content == null || content.length() == 0) |
1363 |
parseError(element, "<" + element.getName() + "> requires content"); |
1364 |
return content;
|
1365 |
} |
1366 |
|
1367 |
/**
|
1368 |
* Call getAttribute on an element, producing a meaningful error message if
|
1369 |
* not present, or empty. It is an error for 'element' or 'attribute' to be null.
|
1370 |
*
|
1371 |
* @param element The element to get the attribute value of
|
1372 |
* @param attribute The name of the attribute to get
|
1373 |
*/
|
1374 |
protected String requireAttribute(XMLElement element, String attribute) |
1375 |
throws CompilerException
|
1376 |
{ |
1377 |
String value = element.getAttribute(attribute);
|
1378 |
if (value == null) |
1379 |
parseError( |
1380 |
element, |
1381 |
"<" + element.getName() + "> requires attribute '" + attribute + "'"); |
1382 |
return value;
|
1383 |
} |
1384 |
|
1385 |
/**
|
1386 |
* Get a required attribute of an element, ensuring it is an integer. A
|
1387 |
* meaningful error message is generated as a CompilerException if not
|
1388 |
* present or parseable as an int. It is an error for 'element' or
|
1389 |
* 'attribute' to be null.
|
1390 |
*
|
1391 |
* @param element The element to get the attribute value of
|
1392 |
* @param attribute The name of the attribute to get
|
1393 |
*/
|
1394 |
protected int requireIntAttribute(XMLElement element, String attribute) |
1395 |
throws CompilerException
|
1396 |
{ |
1397 |
String value = element.getAttribute(attribute);
|
1398 |
if (value == null || value.length() == 0) |
1399 |
parseError( |
1400 |
element, |
1401 |
"<" + element.getName() + "> requires attribute '" + attribute + "'"); |
1402 |
try
|
1403 |
{ |
1404 |
return Integer.parseInt(value); |
1405 |
} catch (NumberFormatException x) |
1406 |
{ |
1407 |
parseError(element, "'" + attribute + "' must be an integer"); |
1408 |
} |
1409 |
return 0; // never happens |
1410 |
} |
1411 |
|
1412 |
/**
|
1413 |
* Call getAttribute on an element, producing a meaningful error message if
|
1414 |
* not present, or one of "yes" or "no". It is an error for 'element' or
|
1415 |
* 'attribute' to be null.
|
1416 |
*
|
1417 |
* @param element The element to get the attribute value of
|
1418 |
* @param attribute The name of the attribute to get
|
1419 |
*/
|
1420 |
protected boolean requireYesNoAttribute(XMLElement element, String attribute) |
1421 |
throws CompilerException
|
1422 |
{ |
1423 |
String value = requireAttribute(element, attribute);
|
1424 |
if (value.equalsIgnoreCase("yes")) |
1425 |
return true; |
1426 |
if (value.equalsIgnoreCase("no")) |
1427 |
return false; |
1428 |
|
1429 |
parseError( |
1430 |
element, |
1431 |
"<" + element.getName() + "> invalid attribute '" |
1432 |
+ attribute + "': Expected (yes|no)");
|
1433 |
|
1434 |
return false; // never happens |
1435 |
} |
1436 |
|
1437 |
/**
|
1438 |
* Call getAttribute on an element, producing a meaningful warning if not
|
1439 |
* "yes" or "no". If the 'element' or 'attribute' are null, the default value
|
1440 |
* is returned.
|
1441 |
*
|
1442 |
* @param element The element to get the attribute value of
|
1443 |
* @param attribute The name of the attribute to get
|
1444 |
* @param defaultValue Value returned if attribute not present or invalid
|
1445 |
*/
|
1446 |
protected boolean validateYesNoAttribute( |
1447 |
XMLElement element, |
1448 |
String attribute,
|
1449 |
boolean defaultValue)
|
1450 |
{ |
1451 |
if (element == null) |
1452 |
return defaultValue;
|
1453 |
|
1454 |
String value =
|
1455 |
element.getAttribute(attribute, (defaultValue ? "yes" : "no")); |
1456 |
if (value.equalsIgnoreCase("yes")) |
1457 |
return true; |
1458 |
if (value.equalsIgnoreCase("no")) |
1459 |
return false; |
1460 |
|
1461 |
// TODO: should this be an error if it's present but "none of the above"?
|
1462 |
parseWarn( |
1463 |
element, |
1464 |
"<" + element.getName() + "> invalid attribute '" |
1465 |
+ attribute + "': Expected (yes|no) if present");
|
1466 |
|
1467 |
return defaultValue;
|
1468 |
} |
1469 |
|
1470 |
/**
|
1471 |
* The main method if the compiler is invoked by a command-line call.
|
1472 |
*
|
1473 |
* @param args The arguments passed on the command-line.
|
1474 |
*/
|
1475 |
public static void main(String[] args) |
1476 |
{ |
1477 |
// Outputs some informations
|
1478 |
System.out.println(""); |
1479 |
System.out.println(".:: IzPack - Version " + IZPACK_VERSION + " ::."); |
1480 |
System.out.println(""); |
1481 |
System.out.println("< compiler specifications version : " + VERSION + " >"); |
1482 |
System.out.println(""); |
1483 |
System.out.println("- Copyright (C) 2001-2004 Julien Ponge"); |
1484 |
System.out.println(
|
1485 |
"- Visit http://www.izforge.com/ for the latests releases");
|
1486 |
System.out.println(
|
1487 |
"- Released under the terms of the GNU GPL either version 2");
|
1488 |
System.out.println(" of the licence, or any later version."); |
1489 |
System.out.println(""); |
1490 |
|
1491 |
// exit code 1 means: error
|
1492 |
int exitCode = 1; |
1493 |
|
1494 |
// We analyse the command line parameters
|
1495 |
try
|
1496 |
{ |
1497 |
// Our arguments
|
1498 |
String filename;
|
1499 |
String base = "."; |
1500 |
String kind = "standard"; |
1501 |
String output;
|
1502 |
|
1503 |
// First check
|
1504 |
int nArgs = args.length;
|
1505 |
if (nArgs < 3) |
1506 |
throw new Exception("no arguments given"); |
1507 |
|
1508 |
// We get the IzPack home directory
|
1509 |
int stdArgsIndex;
|
1510 |
if (args[0].equalsIgnoreCase("-HOME")) |
1511 |
{ |
1512 |
stdArgsIndex = 2;
|
1513 |
IZPACK_HOME = args[1];
|
1514 |
} else
|
1515 |
{ |
1516 |
stdArgsIndex = 0;
|
1517 |
String izHome = System.getProperty("IZPACK_HOME"); |
1518 |
if (izHome != null) |
1519 |
IZPACK_HOME = izHome; |
1520 |
} |
1521 |
|
1522 |
home = new File(IZPACK_HOME); |
1523 |
if (! home.exists() && home.isDirectory())
|
1524 |
{ |
1525 |
System.err.println("IZPACK_HOME (" + IZPACK_HOME + ") doesn't exist"); |
1526 |
System.exit(-1); |
1527 |
} |
1528 |
|
1529 |
// The users wants to know the command line parameters
|
1530 |
if (args[stdArgsIndex].equalsIgnoreCase("-?")) |
1531 |
{ |
1532 |
System.out.println(
|
1533 |
"-> Command line parameters are : (xml file) [args]");
|
1534 |
System.out.println(
|
1535 |
" (xml file): the xml file describing the installation");
|
1536 |
System.out.println(
|
1537 |
" -b (base) : indicates the base path that the compiler will use for filenames");
|
1538 |
System.out.println(" default is the current path"); |
1539 |
System.out.println(
|
1540 |
" -k (kind) : indicates the kind of installer to generate");
|
1541 |
System.out.println(" default is standard"); |
1542 |
System.out.println(" -o (out) : indicates the output file name"); |
1543 |
System.out.println(" default is the xml file name\n"); |
1544 |
|
1545 |
System.out.println(
|
1546 |
" When using vm option -DSTACKTRACE=true there is all kind of debug info ");
|
1547 |
System.out.println(""); |
1548 |
} else
|
1549 |
{ |
1550 |
// We can parse the other parameters & try to compile the installation
|
1551 |
|
1552 |
// We get the input file name and we initialize the output file name
|
1553 |
filename = args[stdArgsIndex]; |
1554 |
// default jar files names are based on input file name
|
1555 |
output = filename.substring(0, filename.length() - 3) + "jar"; |
1556 |
|
1557 |
// We parse the other ones
|
1558 |
int pos = stdArgsIndex + 1; |
1559 |
while (pos < nArgs)
|
1560 |
if ((args[pos].startsWith("-")) && (args[pos].length() == 2)) |
1561 |
{ |
1562 |
switch (args[pos].toLowerCase().charAt(1)) |
1563 |
{ |
1564 |
case 'b' : |
1565 |
if ((pos + 1) < nArgs) |
1566 |
{ |
1567 |
pos++; |
1568 |
base = args[pos]; |
1569 |
} else
|
1570 |
throw new Exception("base argument missing"); |
1571 |
break;
|
1572 |
case 'k' : |
1573 |
if ((pos + 1) < nArgs) |
1574 |
{ |
1575 |
pos++; |
1576 |
kind = args[pos]; |
1577 |
} else
|
1578 |
throw new Exception("kind argument missing"); |
1579 |
break;
|
1580 |
case 'o' : |
1581 |
if ((pos + 1) < nArgs) |
1582 |
{ |
1583 |
pos++; |
1584 |
output = args[pos]; |
1585 |
} else
|
1586 |
throw new Exception("output argument missing"); |
1587 |
break;
|
1588 |
default :
|
1589 |
throw new Exception("unknown argument"); |
1590 |
} |
1591 |
pos++; |
1592 |
} else
|
1593 |
throw new Exception("bad argument"); |
1594 |
|
1595 |
// Outputs what we are going to do
|
1596 |
System.out.println("-> Processing : " + filename); |
1597 |
System.out.println("-> Output : " + output); |
1598 |
System.out.println("-> Base path : " + base); |
1599 |
System.out.println("-> Kind : " + kind); |
1600 |
System.out.println(""); |
1601 |
|
1602 |
// Calls the compiler
|
1603 |
Compiler compiler = new Compiler(filename, base, kind, output); |
1604 |
CmdlinePackagerListener listener = new CmdlinePackagerListener();
|
1605 |
compiler.setPackagerListener(listener); |
1606 |
compiler.compile(); |
1607 |
|
1608 |
// Waits
|
1609 |
while (compiler.isAlive())
|
1610 |
Thread.sleep(100); |
1611 |
|
1612 |
if (compiler.wasSuccessful())
|
1613 |
exitCode = 0;
|
1614 |
|
1615 |
System.out.println("Build time: " + new Date()); |
1616 |
} |
1617 |
} catch (Exception err) |
1618 |
{ |
1619 |
// Something bad has happened
|
1620 |
System.err.println("-> Fatal error :"); |
1621 |
System.err.println(" " + err.getMessage()); |
1622 |
err.printStackTrace(); |
1623 |
System.err.println(""); |
1624 |
System.err.println("(tip : use -? to get the commmand line parameters)"); |
1625 |
} |
1626 |
|
1627 |
// Closes the JVM
|
1628 |
System.exit(exitCode);
|
1629 |
} |
1630 |
|
1631 |
//-------------------------------------------------------------------------
|
1632 |
//------------- Listener stuff ------------------------- START ------------
|
1633 |
|
1634 |
/**
|
1635 |
* This method parses install.xml for defined listeners and put they
|
1636 |
* to the right position. If posible, the listeners will be validated.
|
1637 |
* Listener declaration is a fragmention in install.xml like : <listeners>
|
1638 |
* <listener compiler="PermissionCompilerListener" installer="PermissionInstallerListener"/>
|
1639 |
* </<listeners>
|
1640 |
*
|
1641 |
* @param data the XML data
|
1642 |
* @exception Exception Description of the Exception
|
1643 |
*/
|
1644 |
private void addCustomListeners(XMLElement data) throws Exception |
1645 |
{ |
1646 |
compilerListeners = new ArrayList(); |
1647 |
// We get the listeners
|
1648 |
XMLElement root = data.getFirstChildNamed("listeners");
|
1649 |
if (root == null) |
1650 |
return;
|
1651 |
Iterator iter = root.getChildrenNamed("listener").iterator(); |
1652 |
while (iter.hasNext())
|
1653 |
{ |
1654 |
|
1655 |
XMLElement xmlAction = (XMLElement) iter.next(); |
1656 |
Object [] listener = getCompilerListenerInstance( xmlAction); |
1657 |
if( listener != null) |
1658 |
addCompilerListener((CompilerListener) listener[0] );
|
1659 |
String [] typeNames = new String[] {"installer", "uninstaller"}; |
1660 |
int [] types = new int[] {CustomData.INSTALLER_LISTENER, CustomData.UNINSTALLER_LISTENER}; |
1661 |
for( int i = 0; i < typeNames.length; ++i ) |
1662 |
{ |
1663 |
String className = xmlAction.getAttribute(typeNames[i]);
|
1664 |
if( className != null ) |
1665 |
{ |
1666 |
String jarPath = "bin/customActions/" + className + ".jar"; |
1667 |
URL url = findIzPackResource(jarPath, "CustomAction jar file", xmlAction); |
1668 |
CustomData ca = new CustomData( getFullClassName(url, className),
|
1669 |
getContainedFilePaths(url), OsConstraint.getOsList(xmlAction), types[i] ); |
1670 |
packager.addCustomJar( ca, url); |
1671 |
} |
1672 |
} |
1673 |
} |
1674 |
|
1675 |
} |
1676 |
|
1677 |
/**
|
1678 |
* Returns a list which contains the pathes of all
|
1679 |
* files which are included in the given url.
|
1680 |
* This method expects as the url param a jar.
|
1681 |
* @param url url of the jar file
|
1682 |
* @return full qualified paths of the contained files
|
1683 |
* @throws Exception
|
1684 |
*/
|
1685 |
private List getContainedFilePaths(URL url) |
1686 |
throws Exception |
1687 |
{ |
1688 |
JarInputStream jis = new JarInputStream(url.openStream()); |
1689 |
ZipEntry zentry = null; |
1690 |
String fullName = null; |
1691 |
ArrayList fullNames = new ArrayList(); |
1692 |
while ( (zentry = jis.getNextEntry()) != null) |
1693 |
{ |
1694 |
String name = zentry.getName();
|
1695 |
// Add only files, no directory entries.
|
1696 |
if( ! zentry.isDirectory())
|
1697 |
fullNames.add(name); |
1698 |
} |
1699 |
jis.close(); |
1700 |
return( fullNames );
|
1701 |
} |
1702 |
|
1703 |
/**
|
1704 |
* Returns the qualified class name for the given class.
|
1705 |
* This method expects as the url param a jar file which contains
|
1706 |
* the given class. It scans the zip entries of the jar file.
|
1707 |
* @param url url of the jar file which contains the class
|
1708 |
* @param className short name of the class for which the full name
|
1709 |
* should be resolved
|
1710 |
* @return full qualified class name
|
1711 |
* @throws Exception
|
1712 |
*/
|
1713 |
private String getFullClassName(URL url, String className) |
1714 |
throws Exception |
1715 |
{ |
1716 |
JarInputStream jis = new JarInputStream(url.openStream()); |
1717 |
ZipEntry zentry = null; |
1718 |
String fullName = null; |
1719 |
while ( (zentry = jis.getNextEntry()) != null) |
1720 |
{ |
1721 |
String name = zentry.getName();
|
1722 |
int lastPos = name.lastIndexOf(".class"); |
1723 |
if( lastPos < 0 ) |
1724 |
{ |
1725 |
continue; // No class file. |
1726 |
} |
1727 |
name = name.replace('/', '.'); |
1728 |
int pos = -1; |
1729 |
if( className != null ) |
1730 |
{ |
1731 |
pos = name.indexOf(className); |
1732 |
} |
1733 |
if( name.length() == pos + className.length() + 6 ) // "Main" class found |
1734 |
{ |
1735 |
jis.close(); |
1736 |
return(name.substring(0, lastPos)); |
1737 |
} |
1738 |
} |
1739 |
jis.close(); |
1740 |
return( null ); |
1741 |
} |
1742 |
|
1743 |
/**
|
1744 |
* Returns the compiler listener which is defined in the xml
|
1745 |
* element. As xml element a "listner" node will be expected.
|
1746 |
* Additional it is expected, that "findIzPackResource" returns
|
1747 |
* an url based on "bin/customActions/[className].jar". The
|
1748 |
* class will be loaded via an URLClassLoader.
|
1749 |
* @param var the xml element of the "listener" node
|
1750 |
* @return instance of the defined compiler listener
|
1751 |
* @throws Exception
|
1752 |
*/
|
1753 |
private Object [] getCompilerListenerInstance( XMLElement var ) throws Exception |
1754 |
{ |
1755 |
final String defaultRootPath = "com.izforge.izpack."; |
1756 |
final String defaultCompilerPath = "compiler."; |
1757 |
String className = var.getAttribute("compiler"); |
1758 |
Class listener = null; |
1759 |
Object instance = null; |
1760 |
if( className == null ) |
1761 |
return(null); |
1762 |
|
1763 |
// CustomAction files come in jars packaged IzPack
|
1764 |
String jarPath = "bin/customActions/" + className + ".jar"; |
1765 |
URL url = findIzPackResource(jarPath, "CustomAction jar file", var); |
1766 |
String fullName = getFullClassName(url, className);
|
1767 |
if( url != null ) |
1768 |
{ |
1769 |
if(getClass().getResource("/" + jarPath) != null ) |
1770 |
{ // Oops, standalone, URLClassLoader will not work ...
|
1771 |
// Write the jar to a temp file.
|
1772 |
InputStream in = null; |
1773 |
FileOutputStream outFile = null; |
1774 |
byte[] buffer = new byte[5120]; |
1775 |
File tf = null; |
1776 |
try
|
1777 |
{ |
1778 |
tf = File. createTempFile("izpj", ".jar"); |
1779 |
tf.deleteOnExit(); |
1780 |
outFile = new FileOutputStream(tf); |
1781 |
in = getClass().getResourceAsStream("/" + jarPath);
|
1782 |
long bytesCopied = 0; |
1783 |
int bytesInBuffer;
|
1784 |
while ((bytesInBuffer = in.read(buffer)) != -1) |
1785 |
{ |
1786 |
outFile.write(buffer, 0, bytesInBuffer);
|
1787 |
bytesCopied += bytesInBuffer; |
1788 |
} |
1789 |
} |
1790 |
finally
|
1791 |
{ |
1792 |
if( in != null ) |
1793 |
in.close(); |
1794 |
if( outFile != null ) |
1795 |
outFile.close(); |
1796 |
} |
1797 |
url = tf.toURL(); |
1798 |
|
1799 |
} |
1800 |
// Use the class loader of the interface as parent, else
|
1801 |
// compile will fail at using it via an Ant task.
|
1802 |
URLClassLoader ucl = new URLClassLoader( new URL[] {url}, |
1803 |
CompilerListener.class.getClassLoader() ); |
1804 |
listener = ucl.loadClass(fullName); |
1805 |
} |
1806 |
if( listener != null ) |
1807 |
instance = listener.newInstance(); |
1808 |
else
|
1809 |
parseError(var, "Cannot find defined compiler listener " + className);
|
1810 |
if( ! CompilerListener.class.isInstance(instance) )
|
1811 |
parseError(var, "'" + className + "' must be implemented " + CompilerListener.class.toString()); |
1812 |
List constraints = OsConstraint.getOsList(var);
|
1813 |
return( new Object[] {instance, className, constraints} ); |
1814 |
} |
1815 |
|
1816 |
/**
|
1817 |
* Add a CompilerListener.
|
1818 |
* A registered CompilerListener will be called at every
|
1819 |
* enhancmend point of compiling.
|
1820 |
* @param pe CompilerListener which should be added
|
1821 |
*/
|
1822 |
private void addCompilerListener(CompilerListener pe) |
1823 |
{ |
1824 |
compilerListeners.add(pe); |
1825 |
} |
1826 |
|
1827 |
/**
|
1828 |
* Calls all defined compile listeners notify method with the given data
|
1829 |
* @param callerName name of the calling method as string
|
1830 |
* @param state CompileListener.BEGIN or END
|
1831 |
* @param data current install data
|
1832 |
* @throws CompilerException
|
1833 |
*/
|
1834 |
private void notifyCompilerListener( String callerName, |
1835 |
int state, XMLElement data ) throws CompilerException |
1836 |
{ |
1837 |
Iterator i = compilerListeners.iterator();
|
1838 |
while( i != null && i.hasNext()) |
1839 |
{ |
1840 |
((CompilerListener)i.next()).notify(callerName, state, data, packager); |
1841 |
} |
1842 |
|
1843 |
} |
1844 |
/**
|
1845 |
* Calls the reviseAdditionalDataMap method of all registered
|
1846 |
* CompilerListener's.
|
1847 |
* @param f file releated XML node
|
1848 |
* @return a map with the additional attributes
|
1849 |
*/
|
1850 |
private Map getAdditionals(XMLElement f) throws CompilerException |
1851 |
{ |
1852 |
Iterator i = compilerListeners.iterator();
|
1853 |
Map retval = null; |
1854 |
try
|
1855 |
{ |
1856 |
while( i != null && i.hasNext()) |
1857 |
{ |
1858 |
retval = ((CompilerListener)i.next()).reviseAdditionalDataMap(retval, f); |
1859 |
} |
1860 |
} |
1861 |
catch(CompilerException ce)
|
1862 |
{ |
1863 |
parseError(f, ce.getMessage()); |
1864 |
} |
1865 |
return( retval);
|
1866 |
} |
1867 |
//-------------------------------------------------------------------------
|
1868 |
//------------- Listener stuff ------------------------- END ------------
|
1869 |
|
1870 |
/**
|
1871 |
* Used to handle the packager messages in the command-line mode.
|
1872 |
*
|
1873 |
* @author julien
|
1874 |
* created October 26, 2002
|
1875 |
*/
|
1876 |
static class CmdlinePackagerListener implements PackagerListener |
1877 |
{ |
1878 |
/**
|
1879 |
* Called as the packager sends messages.
|
1880 |
*
|
1881 |
* @param info The information.
|
1882 |
*/
|
1883 |
public void packagerMsg(String info) |
1884 |
{ |
1885 |
System.out.println(info);
|
1886 |
} |
1887 |
|
1888 |
/** Called when the packager starts. */
|
1889 |
public void packagerStart() |
1890 |
{ |
1891 |
System.out.println("[ Begin ]"); |
1892 |
System.out.println(""); |
1893 |
} |
1894 |
|
1895 |
/** Called when the packager stops. */
|
1896 |
public void packagerStop() |
1897 |
{ |
1898 |
System.out.println(""); |
1899 |
System.out.println("[ End ]"); |
1900 |
} |
1901 |
} |
1902 |
} |