Source Code Cross Referenced for CompilerConfig.java in  » Installer » IzPack » com » izforge » izpack » compiler » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Installer » IzPack » com.izforge.izpack.compiler 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $Id: CompilerConfig.java 2061 2008-02-25 20:05:31Z jponge $
0003:         * IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved.
0004:         * 
0005:         * http://izpack.org/
0006:         * http://izpack.codehaus.org/
0007:         * 
0008:         * Copyright 2001 Johannes Lehtinen
0009:         * Copyright 2002 Paul Wilkinson
0010:         * Copyright 2004 Gaganis Giorgos
0011:         * Copyright 2007 Syed Khadeer / Hans Aikema
0012:         *
0013:         * 
0014:         * Licensed under the Apache License, Version 2.0 (the "License");
0015:         * you may not use this file except in compliance with the License.
0016:         * You may obtain a copy of the License at
0017:         * 
0018:         *     http://www.apache.org/licenses/LICENSE-2.0
0019:         *     
0020:         * Unless required by applicable law or agreed to in writing, software
0021:         * distributed under the License is distributed on an "AS IS" BASIS,
0022:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0023:         * See the License for the specific language governing permissions and
0024:         * limitations under the License.
0025:         */
0026:
0027:        package com.izforge.izpack.compiler;
0028:
0029:        import com.izforge.izpack.CustomData;
0030:        import com.izforge.izpack.ExecutableFile;
0031:        import com.izforge.izpack.GUIPrefs;
0032:        import com.izforge.izpack.Info;
0033:        import com.izforge.izpack.PackFile;
0034:        import com.izforge.izpack.Panel;
0035:        import com.izforge.izpack.ParsableFile;
0036:        import com.izforge.izpack.UpdateCheck;
0037:        import com.izforge.izpack.compiler.Compiler.CmdlinePackagerListener;
0038:        import com.izforge.izpack.event.CompilerListener;
0039:        import com.izforge.izpack.rules.Condition;
0040:        import com.izforge.izpack.rules.RulesEngine;
0041:        import com.izforge.izpack.util.Debug;
0042:        import com.izforge.izpack.util.Log;
0043:        import com.izforge.izpack.util.OsConstraint;
0044:        import com.izforge.izpack.util.VariableSubstitutor;
0045:        import net.n3.nanoxml.IXMLParser;
0046:        import net.n3.nanoxml.IXMLReader;
0047:        import net.n3.nanoxml.NonValidator;
0048:        import net.n3.nanoxml.StdXMLParser;
0049:        import net.n3.nanoxml.StdXMLReader;
0050:        import net.n3.nanoxml.XMLBuilderFactory;
0051:        import net.n3.nanoxml.XMLElement;
0052:        import net.n3.nanoxml.XMLException;
0053:        import net.n3.nanoxml.XMLParserFactory;
0054:        import net.n3.nanoxml.XMLWriter;
0055:        import org.apache.tools.ant.DirectoryScanner;
0056:
0057:        import java.io.BufferedInputStream;
0058:        import java.io.BufferedOutputStream;
0059:        import java.io.ByteArrayInputStream;
0060:        import java.io.ByteArrayOutputStream;
0061:        import java.io.File;
0062:        import java.io.FileInputStream;
0063:        import java.io.FileNotFoundException;
0064:        import java.io.FileOutputStream;
0065:        import java.io.IOException;
0066:        import java.io.InputStream;
0067:        import java.io.OutputStream;
0068:        import java.net.MalformedURLException;
0069:        import java.net.URI;
0070:        import java.net.URL;
0071:        import java.net.URLClassLoader;
0072:        import java.util.ArrayList;
0073:        import java.util.Date;
0074:        import java.util.Enumeration;
0075:        import java.util.HashMap;
0076:        import java.util.Iterator;
0077:        import java.util.List;
0078:        import java.util.Map;
0079:        import java.util.Properties;
0080:        import java.util.Set;
0081:        import java.util.StringTokenizer;
0082:        import java.util.TreeMap;
0083:        import java.util.Vector;
0084:        import java.util.jar.JarInputStream;
0085:        import java.util.zip.ZipEntry;
0086:        import java.util.zip.ZipFile;
0087:        import java.util.zip.ZipInputStream;
0088:
0089:        /**
0090:         * A parser for the installer xml configuration. This parses a document
0091:         * conforming to the installation.dtd and populates a Compiler instance to
0092:         * perform the install compilation. 
0093:         * 
0094:         * @author Scott Stark
0095:         * @version $Revision: 2061 $
0096:         */
0097:        public class CompilerConfig extends Thread {
0098:            /** The compiler version. */
0099:            public final static String VERSION = "1.0";
0100:
0101:            /** Standard installer. */
0102:            public final static String STANDARD = "standard";
0103:
0104:            /** Web installer. */
0105:            public final static String WEB = "web";
0106:
0107:            /** Constant for checking attributes. */
0108:            private static boolean YES = true;
0109:
0110:            /** Constant for checking attributes. */
0111:            private static boolean NO = false;
0112:
0113:            private final static String IZ_TEST_FILE = "ShellLink.dll";
0114:
0115:            private final static String IZ_TEST_SUBDIR = "bin" + File.separator
0116:                    + "native" + File.separator + "izpack";
0117:
0118:            /** The xml install file */
0119:            private String filename;
0120:            /** The xml install configuration text */
0121:            private String installText;
0122:            /** The base directory. */
0123:            protected String basedir;
0124:
0125:            /** The installer packager compiler */
0126:            private Compiler compiler;
0127:
0128:            /**
0129:             * List of CompilerListeners which should be called at packaging
0130:             */
0131:            protected List<CompilerListener> compilerListeners = new ArrayList<CompilerListener>();
0132:
0133:            /**
0134:             * Set the IzPack home directory
0135:             * @param izHome - the izpack home directory
0136:             */
0137:            public static void setIzpackHome(String izHome) {
0138:                Compiler.setIzpackHome(izHome);
0139:            }
0140:
0141:            /**
0142:             * The constructor.
0143:             * 
0144:             * @param filename The XML filename.
0145:             * @param basedir The base directory.
0146:             * @param kind The installer kind.
0147:             * @param output The installer filename.
0148:             * @throws CompilerException
0149:             */
0150:            public CompilerConfig(String filename, String basedir, String kind,
0151:                    String output) throws CompilerException {
0152:                this (filename, basedir, kind, output, null);
0153:            }
0154:
0155:            /**
0156:             * The constructor.
0157:             * 
0158:             * @param filename The XML filename.
0159:             * @param basedir The base directory.
0160:             * @param kind The installer kind.
0161:             * @param output The installer filename.
0162:             * @param listener The PackagerListener.
0163:             * @throws CompilerException
0164:             */
0165:            public CompilerConfig(String filename, String basedir, String kind,
0166:                    String output, PackagerListener listener)
0167:                    throws CompilerException {
0168:                this (filename, basedir, kind, output, "default", listener);
0169:            }
0170:
0171:            /**
0172:             * @param filename The XML filename.
0173:             * @param kind The installer kind.
0174:             * @param output The installer filename.
0175:             * @param compr_format The compression format to be used for packs.
0176:             * @param listener The PackagerListener.
0177:             * @throws CompilerException
0178:             */
0179:            public CompilerConfig(String filename, String base, String kind,
0180:                    String output, String compr_format,
0181:                    PackagerListener listener) throws CompilerException {
0182:                this (filename, base, kind, output, compr_format, listener, null);
0183:            }
0184:
0185:            /**
0186:             * 
0187:             * @param basedir The base directory.
0188:             * @param kind The installer kind.
0189:             * @param output The installer filename.
0190:             * @param listener The PackagerListener.
0191:             * @param installText The install xml configuration text
0192:             * @throws CompilerException
0193:             */
0194:            public CompilerConfig(String basedir, String kind, String output,
0195:                    PackagerListener listener, String installText)
0196:                    throws CompilerException {
0197:                this (null, basedir, kind, output, "default", listener,
0198:                        installText);
0199:            }
0200:
0201:            /**
0202:             * 
0203:             * @param filename The XML filename.
0204:             * @param basedir The base directory.
0205:             * @param kind The installer kind.
0206:             * @param output The installer filename.
0207:             * @param compr_format The compression format to be used for packs.
0208:             * @param listener The PackagerListener.
0209:             * @param installText The install xml configuration text
0210:             * @throws CompilerException
0211:             */
0212:            public CompilerConfig(String filename, String basedir, String kind,
0213:                    String output, String compr_format,
0214:                    PackagerListener listener, String installText)
0215:                    throws CompilerException {
0216:                this (filename, basedir, kind, output, compr_format, -1,
0217:                        listener, installText);
0218:            }
0219:
0220:            /**
0221:             * @param filename The XML filename.
0222:             * @param basedir The base directory.
0223:             * @param kind The installer kind.
0224:             * @param output The installer filename.
0225:             * @param compr_format The compression format to be used for packs.
0226:             * @param compr_level Compression level to be used if supported.
0227:             * @param listener The PackagerListener.
0228:             * @param installText The install xml configuration text
0229:             * @throws CompilerException
0230:             */
0231:            public CompilerConfig(String filename, String basedir, String kind,
0232:                    String output, String compr_format, int compr_level,
0233:                    PackagerListener listener, String installText)
0234:                    throws CompilerException {
0235:                this .filename = filename;
0236:                this .installText = installText;
0237:                this .basedir = basedir;
0238:                this .compiler = new Compiler(basedir, kind, output,
0239:                        compr_format, compr_level);
0240:                compiler.setPackagerListener(listener);
0241:            }
0242:
0243:            /**
0244:             * Add a name value pair to the project property set. It is <i>not</i>
0245:             * replaced it is already in the set of properties.
0246:             * 
0247:             * @param name the name of the property
0248:             * @param value the value to set
0249:             * @return true if the property was not already set
0250:             */
0251:            public boolean addProperty(String name, String value) {
0252:                return compiler.addProperty(name, value);
0253:            }
0254:
0255:            /**
0256:             * Access the install compiler
0257:             * @return the install compiler
0258:             */
0259:            public Compiler getCompiler() {
0260:                return compiler;
0261:            }
0262:
0263:            /**
0264:             * Retrieves the packager listener
0265:             */
0266:            public PackagerListener getPackagerListener() {
0267:                return compiler.getPackagerListener();
0268:            }
0269:
0270:            /** Compile the installation */
0271:            public void compile() {
0272:                start();
0273:            }
0274:
0275:            /** The run() method. */
0276:            public void run() {
0277:                try {
0278:                    executeCompiler();
0279:                } catch (CompilerException ce) {
0280:                    System.out.println(ce.getMessage() + "\n");
0281:                } catch (Exception e) {
0282:                    if (Debug.stackTracing()) {
0283:                        e.printStackTrace();
0284:                    } else {
0285:                        System.out.println("ERROR: " + e.getMessage());
0286:                    }
0287:                }
0288:            }
0289:
0290:            /**
0291:             * Compiles the installation.
0292:             * 
0293:             * @exception Exception Description of the Exception
0294:             */
0295:            public void executeCompiler() throws Exception {
0296:                // normalize and test: TODO: may allow failure if we require write
0297:                // access
0298:                File base = new File(basedir).getAbsoluteFile();
0299:                if (!base.canRead() || !base.isDirectory())
0300:                    throw new CompilerException("Invalid base directory: "
0301:                            + base);
0302:
0303:                // add izpack built in property
0304:                compiler.setProperty("basedir", base.toString());
0305:
0306:                // We get the XML data tree
0307:                XMLElement data = getXMLTree();
0308:                // loads the specified packager
0309:                loadPackagingInformation(data);
0310:
0311:                // Listeners to various events
0312:                addCustomListeners(data);
0313:
0314:                // Read the properties and perform replacement on the rest of the tree
0315:                substituteProperties(data);
0316:
0317:                // We add all the information
0318:                addVariables(data);
0319:                addDynamicVariables(data);
0320:                addConditions(data);
0321:                addInfo(data);
0322:                addGUIPrefs(data);
0323:                addLangpacks(data);
0324:                addResources(data);
0325:                addNativeLibraries(data);
0326:                addJars(data);
0327:                addPanels(data);
0328:                addPacks(data);
0329:
0330:                // We ask the packager to create the installer
0331:                compiler.createInstaller();
0332:            }
0333:
0334:            private void loadPackagingInformation(XMLElement data)
0335:                    throws CompilerException {
0336:                notifyCompilerListener("loadPackager", CompilerListener.BEGIN,
0337:                        data);
0338:                // Initialisation
0339:                XMLElement root = data.getFirstChildNamed("packaging");
0340:                String packagerclassname = "com.izforge.izpack.compiler.Packager";
0341:                String unpackerclassname = "com.izforge.izpack.installer.Unpacker";
0342:                XMLElement packager = null;
0343:                if (root != null) {
0344:                    packager = root.getFirstChildNamed("packager");
0345:
0346:                    if (packager != null) {
0347:                        packagerclassname = requireAttribute(packager, "class");
0348:                    }
0349:
0350:                    XMLElement unpacker = root.getFirstChildNamed("unpacker");
0351:
0352:                    if (unpacker != null) {
0353:                        unpackerclassname = requireAttribute(unpacker, "class");
0354:                    }
0355:                }
0356:                compiler.initPackager(packagerclassname);
0357:                if (packager != null) {
0358:                    XMLElement options = packager.getFirstChildNamed("options");
0359:                    if (options != null) {
0360:                        compiler.getPackager().addConfigurationInformation(
0361:                                options);
0362:                    }
0363:                }
0364:                compiler.addProperty("UNPACKER_CLASS", unpackerclassname);
0365:                notifyCompilerListener("loadPackager", CompilerListener.END,
0366:                        data);
0367:            }
0368:
0369:            public boolean wasSuccessful() {
0370:                return compiler.wasSuccessful();
0371:            }
0372:
0373:            /**
0374:             * Returns the GUIPrefs.
0375:             * 
0376:             * @param data The XML data.
0377:             * @exception CompilerException Description of the Exception
0378:             */
0379:            protected void addGUIPrefs(XMLElement data)
0380:                    throws CompilerException {
0381:                notifyCompilerListener("addGUIPrefs", CompilerListener.BEGIN,
0382:                        data);
0383:                // We get the XMLElement & the attributes
0384:                XMLElement gp = data.getFirstChildNamed("guiprefs");
0385:                GUIPrefs prefs = new GUIPrefs();
0386:                if (gp != null) {
0387:                    prefs.resizable = requireYesNoAttribute(gp, "resizable");
0388:                    prefs.width = requireIntAttribute(gp, "width");
0389:                    prefs.height = requireIntAttribute(gp, "height");
0390:
0391:                    // Look and feel mappings
0392:                    Iterator<XMLElement> it = gp.getChildrenNamed("laf")
0393:                            .iterator();
0394:                    while (it.hasNext()) {
0395:                        XMLElement laf = it.next();
0396:                        String lafName = requireAttribute(laf, "name");
0397:                        requireChildNamed(laf, "os");
0398:
0399:                        Iterator<XMLElement> oit = laf.getChildrenNamed("os")
0400:                                .iterator();
0401:                        while (oit.hasNext()) {
0402:                            XMLElement os = oit.next();
0403:                            String osName = requireAttribute(os, "family");
0404:                            prefs.lookAndFeelMapping.put(osName, lafName);
0405:                        }
0406:
0407:                        Iterator<XMLElement> pit = laf
0408:                                .getChildrenNamed("param").iterator();
0409:                        Map<String, String> params = new TreeMap<String, String>();
0410:                        while (pit.hasNext()) {
0411:                            XMLElement param = pit.next();
0412:                            String name = requireAttribute(param, "name");
0413:                            String value = requireAttribute(param, "value");
0414:                            params.put(name, value);
0415:                        }
0416:                        prefs.lookAndFeelParams.put(lafName, params);
0417:                    }
0418:                    // Load modifier
0419:                    it = gp.getChildrenNamed("modifier").iterator();
0420:                    while (it.hasNext()) {
0421:                        XMLElement curentModifier = it.next();
0422:                        String key = requireAttribute(curentModifier, "key");
0423:                        String value = requireAttribute(curentModifier, "value");
0424:                        prefs.modifier.put(key, value);
0425:
0426:                    }
0427:                    // make sure jar contents of each are available in installer
0428:                    // map is easier to read/modify than if tree
0429:                    HashMap<String, String> lafMap = new HashMap<String, String>();
0430:                    lafMap.put("liquid", "liquidlnf.jar");
0431:                    lafMap.put("kunststoff", "kunststoff.jar");
0432:                    lafMap.put("metouia", "metouia.jar");
0433:                    lafMap.put("looks", "looks.jar");
0434:                    lafMap.put("substance", "substance.jar");
0435:                    lafMap.put("nimbus", "nimbus.jar");
0436:
0437:                    // is this really what we want? a double loop? needed, since above,
0438:                    // it's
0439:                    // the /last/ lnf for an os which is used, so can't add during
0440:                    // initial
0441:                    // loop
0442:                    Iterator<String> kit = prefs.lookAndFeelMapping.keySet()
0443:                            .iterator();
0444:                    while (kit.hasNext()) {
0445:                        String lafName = prefs.lookAndFeelMapping.get(kit
0446:                                .next());
0447:                        String lafJarName = lafMap.get(lafName);
0448:                        if (lafJarName == null)
0449:                            parseError(gp, "Unrecognized Look and Feel: "
0450:                                    + lafName);
0451:
0452:                        URL lafJarURL = findIzPackResource("lib/" + lafJarName,
0453:                                "Look and Feel Jar file", gp);
0454:                        compiler.addJarContent(lafJarURL);
0455:                    }
0456:                }
0457:                compiler.setGUIPrefs(prefs);
0458:                notifyCompilerListener("addGUIPrefs", CompilerListener.END,
0459:                        data);
0460:            }
0461:
0462:            /**
0463:             * Add project specific external jar files to the installer.
0464:             * 
0465:             * @param data The XML data.
0466:             */
0467:            protected void addJars(XMLElement data) throws Exception {
0468:                notifyCompilerListener("addJars", CompilerListener.BEGIN, data);
0469:                Iterator<XMLElement> iter = data.getChildrenNamed("jar")
0470:                        .iterator();
0471:                while (iter.hasNext()) {
0472:                    XMLElement el = iter.next();
0473:                    String src = requireAttribute(el, "src");
0474:                    URL url = findProjectResource(src, "Jar file", el);
0475:                    compiler.addJarContent(url);
0476:                    // Additionals for mark a jar file also used in the uninstaller.
0477:                    // The contained files will be copied from the installer into the
0478:                    // uninstaller if needed.
0479:                    // Therefore the contained files of the jar should be in the
0480:                    // installer also
0481:                    // they are used only from the uninstaller. This is the reason why
0482:                    // the stage
0483:                    // wiil be only observed for the uninstaller.
0484:                    String stage = el.getAttribute("stage");
0485:                    if (stage != null
0486:                            && ("both".equalsIgnoreCase(stage) || "uninstall"
0487:                                    .equalsIgnoreCase(stage))) {
0488:                        CustomData ca = new CustomData(null,
0489:                                getContainedFilePaths(url), null,
0490:                                CustomData.UNINSTALLER_JAR);
0491:                        compiler.addCustomJar(ca, url);
0492:                    }
0493:                }
0494:                notifyCompilerListener("addJars", CompilerListener.END, data);
0495:            }
0496:
0497:            /**
0498:             * Add native libraries to the installer.
0499:             * 
0500:             * @param data The XML data.
0501:             */
0502:            protected void addNativeLibraries(XMLElement data) throws Exception {
0503:                boolean needAddOns = false;
0504:                notifyCompilerListener("addNativeLibraries",
0505:                        CompilerListener.BEGIN, data);
0506:                Iterator<XMLElement> iter = data.getChildrenNamed("native")
0507:                        .iterator();
0508:                while (iter.hasNext()) {
0509:                    XMLElement el = iter.next();
0510:                    String type = requireAttribute(el, "type");
0511:                    String name = requireAttribute(el, "name");
0512:                    String path = "bin/native/" + type + "/" + name;
0513:                    URL url = findIzPackResource(path, "Native Library", el);
0514:                    compiler.addNativeLibrary(name, url);
0515:                    // Additionals for mark a native lib also used in the uninstaller
0516:                    // The lib will be copied from the installer into the uninstaller if
0517:                    // needed.
0518:                    // Therefore the lib should be in the installer also it is used only
0519:                    // from
0520:                    // the uninstaller. This is the reason why the stage wiil be only
0521:                    // observed
0522:                    // for the uninstaller.
0523:                    String stage = el.getAttribute("stage");
0524:                    List<OsConstraint> constraints = OsConstraint.getOsList(el);
0525:                    if (stage != null
0526:                            && ("both".equalsIgnoreCase(stage) || "uninstall"
0527:                                    .equalsIgnoreCase(stage))) {
0528:                        ArrayList<String> al = new ArrayList<String>();
0529:                        al.add(name);
0530:                        CustomData cad = new CustomData(null, al, constraints,
0531:                                CustomData.UNINSTALLER_LIB);
0532:                        compiler.addNativeUninstallerLibrary(cad);
0533:                        needAddOns = true;
0534:                    }
0535:
0536:                }
0537:                if (needAddOns) {
0538:                    // Add the uninstaller extensions as a resource if specified
0539:                    XMLElement root = requireChildNamed(data, "info");
0540:                    XMLElement uninstallInfo = root
0541:                            .getFirstChildNamed("uninstaller");
0542:                    if (validateYesNoAttribute(uninstallInfo, "write", YES)) {
0543:                        URL url = findIzPackResource("lib/uninstaller-ext.jar",
0544:                                "Uninstaller extensions", root);
0545:                        compiler.addResource("IzPack.uninstaller-ext", url);
0546:                    }
0547:
0548:                }
0549:                notifyCompilerListener("addNativeLibraries",
0550:                        CompilerListener.END, data);
0551:            }
0552:
0553:            /**
0554:             * Add packs and their contents to the installer.
0555:             * 
0556:             * @param data The XML data.
0557:             */
0558:            protected void addPacks(XMLElement data) throws CompilerException {
0559:                notifyCompilerListener("addPacks", CompilerListener.BEGIN, data);
0560:
0561:                // the actual adding is delegated to addPacksSingle to enable recursive
0562:                // parsing of refpack package definitions
0563:                addPacksSingle(data);
0564:
0565:                compiler.checkDependencies();
0566:                compiler.checkExcludes();
0567:
0568:                notifyCompilerListener("addPacks", CompilerListener.END, data);
0569:            }
0570:
0571:            /**
0572:             * Add packs and their contents to the installer without checking 
0573:             * the dependencies and includes.
0574:             * 
0575:             * Helper method to recursively add more packs from refpack XML packs definitions
0576:             * 
0577:             * @param data The XML data
0578:             * @throws CompilerException
0579:             */
0580:            private void addPacksSingle(XMLElement data)
0581:                    throws CompilerException {
0582:                notifyCompilerListener("addPacksSingle",
0583:                        CompilerListener.BEGIN, data);
0584:                // Initialisation
0585:                XMLElement root = requireChildNamed(data, "packs");
0586:
0587:                // at least one pack is required
0588:                Vector<XMLElement> packElements = root.getChildrenNamed("pack");
0589:                Vector<XMLElement> refPackElements = root
0590:                        .getChildrenNamed("refpack");
0591:                if (packElements.isEmpty() && refPackElements.isEmpty())
0592:                    parseError(root, "<packs> requires a <pack> or <refpack>");
0593:
0594:                File baseDir = new File(basedir);
0595:
0596:                Iterator<XMLElement> packIter = packElements.iterator();
0597:                while (packIter.hasNext()) {
0598:                    XMLElement el = packIter.next();
0599:
0600:                    // Trivial initialisations
0601:                    String name = requireAttribute(el, "name");
0602:                    String id = el.getAttribute("id");
0603:                    String packImgId = el.getAttribute("packImgId");
0604:
0605:                    boolean loose = "true".equalsIgnoreCase(el.getAttribute(
0606:                            "loose", "false"));
0607:                    String description = requireChildNamed(el, "description")
0608:                            .getContent();
0609:                    boolean required = requireYesNoAttribute(el, "required");
0610:                    String group = el.getAttribute("group");
0611:                    String installGroups = el.getAttribute("installGroups");
0612:                    String excludeGroup = el.getAttribute("excludeGroup");
0613:                    boolean uninstall = "yes".equalsIgnoreCase(el.getAttribute(
0614:                            "uninstall", "yes"));
0615:                    String parent = el.getAttribute("parent");
0616:
0617:                    String conditionid = el.getAttribute("condition");
0618:
0619:                    if (required && excludeGroup != null) {
0620:                        parseError(
0621:                                el,
0622:                                "Pack, which has excludeGroup can not be required.",
0623:                                new Exception(
0624:                                        "Pack, which has excludeGroup can not be required."));
0625:                    }
0626:
0627:                    PackInfo pack = new PackInfo(name, id, description,
0628:                            required, loose, excludeGroup, uninstall);
0629:                    pack.setOsConstraints(OsConstraint.getOsList(el)); // TODO:
0630:                    pack.setParent(parent);
0631:                    pack.setCondition(conditionid);
0632:
0633:                    // unverified
0634:                    // if the pack belongs to an excludeGroup it's not preselected by default
0635:                    if (excludeGroup == null)
0636:                        pack.setPreselected(validateYesNoAttribute(el,
0637:                                "preselected", YES));
0638:                    else
0639:                        pack.setPreselected(validateYesNoAttribute(el,
0640:                                "preselected", NO));
0641:
0642:                    // Set the pack group if specified
0643:                    if (group != null)
0644:                        pack.setGroup(group);
0645:                    // Set the pack install groups if specified
0646:                    if (installGroups != null) {
0647:                        StringTokenizer st = new StringTokenizer(installGroups,
0648:                                ",");
0649:                        while (st.hasMoreTokens()) {
0650:                            String igroup = st.nextToken();
0651:                            pack.addInstallGroup(igroup);
0652:                        }
0653:                    }
0654:
0655:                    // Set the packImgId if specified
0656:                    if (packImgId != null) {
0657:                        pack.setPackImgId(packImgId);
0658:                    }
0659:
0660:                    // We get the parsables list
0661:                    Iterator<XMLElement> iter = el.getChildrenNamed("parsable")
0662:                            .iterator();
0663:                    while (iter.hasNext()) {
0664:                        XMLElement p = iter.next();
0665:                        String target = requireAttribute(p, "targetfile");
0666:                        String type = p.getAttribute("type", "plain");
0667:                        String encoding = p.getAttribute("encoding", null);
0668:                        List<OsConstraint> osList = OsConstraint.getOsList(p); // TODO: unverified
0669:                        String condition = p.getAttribute("condition");
0670:                        ParsableFile parsable = new ParsableFile(target, type,
0671:                                encoding, osList);
0672:                        parsable.setCondition(condition);
0673:                        pack.addParsable(parsable);
0674:                    }
0675:
0676:                    // We get the executables list
0677:                    iter = el.getChildrenNamed("executable").iterator();
0678:                    while (iter.hasNext()) {
0679:                        XMLElement e = iter.next();
0680:                        ExecutableFile executable = new ExecutableFile();
0681:                        String val; // temp value
0682:                        String condition = e.getAttribute("condition");
0683:                        executable.setCondition(condition);
0684:                        executable.path = requireAttribute(e, "targetfile");
0685:
0686:                        // when to execute this executable
0687:                        val = e.getAttribute("stage", "never");
0688:                        if ("postinstall".equalsIgnoreCase(val))
0689:                            executable.executionStage = ExecutableFile.POSTINSTALL;
0690:                        else if ("uninstall".equalsIgnoreCase(val))
0691:                            executable.executionStage = ExecutableFile.UNINSTALL;
0692:
0693:                        // type of this executable
0694:                        val = e.getAttribute("type", "bin");
0695:                        if ("jar".equalsIgnoreCase(val)) {
0696:                            executable.type = ExecutableFile.JAR;
0697:                            executable.mainClass = e.getAttribute("class"); // executable
0698:                            // class
0699:                        }
0700:
0701:                        // what to do if execution fails
0702:                        val = e.getAttribute("failure", "ask");
0703:                        if ("abort".equalsIgnoreCase(val))
0704:                            executable.onFailure = ExecutableFile.ABORT;
0705:                        else if ("warn".equalsIgnoreCase(val))
0706:                            executable.onFailure = ExecutableFile.WARN;
0707:                        else if ("ignore".equalsIgnoreCase(val))
0708:                            executable.onFailure = ExecutableFile.IGNORE;
0709:
0710:                        // whether to keep the executable after executing it
0711:                        val = e.getAttribute("keep");
0712:                        executable.keepFile = "true".equalsIgnoreCase(val);
0713:
0714:                        // get arguments for this executable
0715:                        XMLElement args = e.getFirstChildNamed("args");
0716:                        if (null != args) {
0717:                            Iterator<XMLElement> argIterator = args
0718:                                    .getChildrenNamed("arg").iterator();
0719:                            while (argIterator.hasNext()) {
0720:                                XMLElement arg = argIterator.next();
0721:                                executable.argList.add(requireAttribute(arg,
0722:                                        "value"));
0723:                            }
0724:                        }
0725:
0726:                        executable.osList = OsConstraint.getOsList(e); // TODO:
0727:                        // unverified
0728:
0729:                        pack.addExecutable(executable);
0730:                    }
0731:
0732:                    // We get the files list
0733:                    iter = el.getChildrenNamed("file").iterator();
0734:                    while (iter.hasNext()) {
0735:                        XMLElement f = iter.next();
0736:                        String src = requireAttribute(f, "src");
0737:                        String targetdir = requireAttribute(f, "targetdir");
0738:                        List<OsConstraint> osList = OsConstraint.getOsList(f); // TODO: unverified
0739:                        int override = getOverrideValue(f);
0740:                        Map additionals = getAdditionals(f);
0741:                        boolean unpack = src.endsWith(".zip")
0742:                                && "true".equalsIgnoreCase(f
0743:                                        .getAttribute("unpack"));
0744:                        String condition = f.getAttribute("condition");
0745:
0746:                        File file = new File(src);
0747:                        if (!file.isAbsolute())
0748:                            file = new File(basedir, src);
0749:
0750:                        try {
0751:                            if (unpack)
0752:                                addArchiveContent(baseDir, file, targetdir,
0753:                                        osList, override, pack, additionals,
0754:                                        condition);
0755:                            else
0756:                                addRecursively(baseDir, file, targetdir,
0757:                                        osList, override, pack, additionals,
0758:                                        condition);
0759:                        } catch (Exception x) {
0760:                            parseError(f, x.getMessage(), x);
0761:                        }
0762:                    }
0763:
0764:                    // We get the singlefiles list
0765:                    iter = el.getChildrenNamed("singlefile").iterator();
0766:                    while (iter.hasNext()) {
0767:                        XMLElement f = iter.next();
0768:                        String src = requireAttribute(f, "src");
0769:                        String target = requireAttribute(f, "target");
0770:                        List<OsConstraint> osList = OsConstraint.getOsList(f); // TODO: unverified
0771:                        int override = getOverrideValue(f);
0772:                        Map additionals = getAdditionals(f);
0773:                        String condition = f.getAttribute("condition");
0774:                        File file = new File(src);
0775:                        if (!file.isAbsolute())
0776:                            file = new File(basedir, src);
0777:
0778:                        try {
0779:                            pack.addFile(baseDir, file, target, osList,
0780:                                    override, additionals, condition);
0781:                        } catch (FileNotFoundException x) {
0782:                            parseError(f, x.getMessage(), x);
0783:                        }
0784:                    }
0785:
0786:                    // We get the fileset list
0787:                    iter = el.getChildrenNamed("fileset").iterator();
0788:                    while (iter.hasNext()) {
0789:                        XMLElement f = iter.next();
0790:                        String dir_attr = requireAttribute(f, "dir");
0791:
0792:                        File dir = new File(dir_attr);
0793:                        if (!dir.isAbsolute())
0794:                            dir = new File(basedir, dir_attr);
0795:                        if (!dir.isDirectory()) // also tests '.exists()'
0796:                            parseError(f, "Invalid directory 'dir': "
0797:                                    + dir_attr);
0798:
0799:                        boolean casesensitive = validateYesNoAttribute(f,
0800:                                "casesensitive", YES);
0801:                        boolean defexcludes = validateYesNoAttribute(f,
0802:                                "defaultexcludes", YES);
0803:                        String targetdir = requireAttribute(f, "targetdir");
0804:                        List<OsConstraint> osList = OsConstraint.getOsList(f); // TODO: unverified
0805:                        int override = getOverrideValue(f);
0806:                        Map additionals = getAdditionals(f);
0807:                        String condition = f.getAttribute("condition");
0808:
0809:                        // get includes and excludes
0810:                        Vector<XMLElement> xcludesList = null;
0811:                        String[] includes = null;
0812:                        xcludesList = f.getChildrenNamed("include");
0813:                        if (!xcludesList.isEmpty()) {
0814:                            includes = new String[xcludesList.size()];
0815:                            for (int j = 0; j < xcludesList.size(); j++) {
0816:                                XMLElement xclude = xcludesList.get(j);
0817:                                includes[j] = requireAttribute(xclude, "name");
0818:                            }
0819:                        }
0820:                        String[] excludes = null;
0821:                        xcludesList = f.getChildrenNamed("exclude");
0822:                        if (!xcludesList.isEmpty()) {
0823:                            excludes = new String[xcludesList.size()];
0824:                            for (int j = 0; j < xcludesList.size(); j++) {
0825:                                XMLElement xclude = xcludesList.get(j);
0826:                                excludes[j] = requireAttribute(xclude, "name");
0827:                            }
0828:                        }
0829:
0830:                        // parse additional fileset attributes "includes" and "excludes"
0831:                        String[] toDo = new String[] { "includes", "excludes" };
0832:                        // use the existing containers filled from include and exclude
0833:                        // and add the includes and excludes to it
0834:                        String[][] containers = new String[][] { includes,
0835:                                excludes };
0836:                        for (int j = 0; j < toDo.length; ++j) {
0837:                            String inex = f.getAttribute(toDo[j]);
0838:                            if (inex != null && inex.length() > 0) { // This is the same "splitting" as ant PatternSet do ...
0839:                                StringTokenizer tok = new StringTokenizer(inex,
0840:                                        ", ", false);
0841:                                int newSize = tok.countTokens();
0842:                                int k = 0;
0843:                                String[] nCont = null;
0844:                                if (containers[j] != null
0845:                                        && containers[j].length > 0) { // old container exist; create a new which can hold
0846:                                    // all values
0847:                                    // and copy the old stuff to the front
0848:                                    newSize += containers[j].length;
0849:                                    nCont = new String[newSize];
0850:                                    for (; k < containers[j].length; ++k)
0851:                                        nCont[k] = containers[j][k];
0852:                                }
0853:                                if (nCont == null) // No container for old values
0854:                                    // created,
0855:                                    // create a new one.
0856:                                    nCont = new String[newSize];
0857:                                for (; k < newSize; ++k)
0858:                                    // Fill the new one or expand the existent container
0859:                                    nCont[k] = tok.nextToken();
0860:                                containers[j] = nCont;
0861:                            }
0862:                        }
0863:                        includes = containers[0]; // push the new includes to the
0864:                        // local var
0865:                        excludes = containers[1]; // push the new excludes to the
0866:                        // local var
0867:
0868:                        // scan and add fileset
0869:                        DirectoryScanner ds = new DirectoryScanner();
0870:                        ds.setIncludes(includes);
0871:                        ds.setExcludes(excludes);
0872:                        if (defexcludes)
0873:                            ds.addDefaultExcludes();
0874:                        ds.setBasedir(dir);
0875:                        ds.setCaseSensitive(casesensitive);
0876:                        ds.scan();
0877:
0878:                        String[] files = ds.getIncludedFiles();
0879:                        String[] dirs = ds.getIncludedDirectories();
0880:
0881:                        // Directory scanner has done recursion, add files and
0882:                        // directories
0883:                        for (String file : files) {
0884:                            try {
0885:                                String target = new File(targetdir, file)
0886:                                        .getPath();
0887:                                pack.addFile(baseDir, new File(dir, file),
0888:                                        target, osList, override, additionals,
0889:                                        condition);
0890:                            } catch (FileNotFoundException x) {
0891:                                parseError(f, x.getMessage(), x);
0892:                            }
0893:                        }
0894:                        for (String dir1 : dirs) {
0895:                            try {
0896:                                String target = new File(targetdir, dir1)
0897:                                        .getPath();
0898:                                pack.addFile(baseDir, new File(dir, dir1),
0899:                                        target, osList, override, additionals,
0900:                                        condition);
0901:                            } catch (FileNotFoundException x) {
0902:                                parseError(f, x.getMessage(), x);
0903:                            }
0904:                        }
0905:                    }
0906:
0907:                    // get the updatechecks list
0908:                    iter = el.getChildrenNamed("updatecheck").iterator();
0909:                    while (iter.hasNext()) {
0910:                        XMLElement f = iter.next();
0911:
0912:                        String casesensitive = f.getAttribute("casesensitive");
0913:
0914:                        // get includes and excludes
0915:                        ArrayList<String> includesList = new ArrayList<String>();
0916:                        ArrayList<String> excludesList = new ArrayList<String>();
0917:
0918:                        // get includes and excludes
0919:                        Iterator<XMLElement> include_it = f.getChildrenNamed(
0920:                                "include").iterator();
0921:                        while (include_it.hasNext()) {
0922:                            XMLElement inc_el = include_it.next();
0923:                            includesList.add(requireAttribute(inc_el, "name"));
0924:                        }
0925:
0926:                        Iterator<XMLElement> exclude_it = f.getChildrenNamed(
0927:                                "exclude").iterator();
0928:                        while (exclude_it.hasNext()) {
0929:                            XMLElement excl_el = exclude_it.next();
0930:                            excludesList.add(requireAttribute(excl_el, "name"));
0931:                        }
0932:
0933:                        pack.addUpdateCheck(new UpdateCheck(includesList,
0934:                                excludesList, casesensitive));
0935:                    }
0936:                    // We get the dependencies
0937:                    iter = el.getChildrenNamed("depends").iterator();
0938:                    while (iter.hasNext()) {
0939:                        XMLElement dep = iter.next();
0940:                        String depName = requireAttribute(dep, "packname");
0941:                        pack.addDependency(depName);
0942:
0943:                    }
0944:                    // We add the pack
0945:                    compiler.addPack(pack);
0946:                }
0947:
0948:                Iterator<XMLElement> refPackIter = refPackElements.iterator();
0949:                while (refPackIter.hasNext()) {
0950:                    XMLElement el = refPackIter.next();
0951:
0952:                    // get the name of reference xml file
0953:                    String refFileName = requireAttribute(el, "file");
0954:                    String selfcontained = el.getAttribute("selfcontained");
0955:                    boolean isselfcontained = Boolean.valueOf(selfcontained);
0956:
0957:                    File refXMLFile = new File(refFileName);
0958:                    if (!refXMLFile.isAbsolute())
0959:                        refXMLFile = new File(basedir, refFileName);
0960:                    if (!refXMLFile.canRead()) {
0961:                        throw new CompilerException("Invalid file: "
0962:                                + refXMLFile);
0963:                    }
0964:
0965:                    InputStream specin = null;
0966:
0967:                    if (isselfcontained) {
0968:                        if (!refXMLFile.getAbsolutePath().endsWith(".zip")) {
0969:                            throw new CompilerException(
0970:                                    "Invalid file: "
0971:                                            + refXMLFile
0972:                                            + ". Selfcontained files can only be of type zip.");
0973:                        }
0974:                        ZipFile zip;
0975:                        try {
0976:                            zip = new ZipFile(refXMLFile, ZipFile.OPEN_READ);
0977:                            ZipEntry specentry = zip
0978:                                    .getEntry("META-INF/izpack.xml");
0979:                            specin = zip.getInputStream(specentry);
0980:                        } catch (IOException e) {
0981:                            throw new CompilerException(
0982:                                    "Error reading META-INF/izpack.xml in "
0983:                                            + refXMLFile);
0984:                        }
0985:                    } else {
0986:                        try {
0987:                            specin = new FileInputStream(refXMLFile
0988:                                    .getAbsolutePath());
0989:                        } catch (FileNotFoundException e) {
0990:                            throw new CompilerException(
0991:                                    "FileNotFoundException exception while reading refXMLFile");
0992:                        }
0993:                    }
0994:
0995:                    // Initialises the parser
0996:                    IXMLReader refXMLReader = null;
0997:
0998:                    // Load the reference XML file                        
0999:                    try {
1000:                        refXMLReader = new StdXMLReader(specin);
1001:                    } catch (CompilerException c) {
1002:                        throw new CompilerException(
1003:                                "Compiler exception while reading refXMLFile");
1004:                    } catch (IOException io) {
1005:                        throw new CompilerException(
1006:                                "IOException exception while reading refXMLFile");
1007:                    }
1008:
1009:                    StdXMLParser refXMLParser = new StdXMLParser();
1010:                    refXMLParser.setBuilder(XMLBuilderFactory
1011:                            .createXMLBuilder());
1012:                    refXMLParser.setReader(refXMLReader);
1013:                    refXMLParser.setValidator(new NonValidator());
1014:
1015:                    // We get it
1016:                    XMLElement refXMLData = null;
1017:                    try {
1018:                        refXMLData = (XMLElement) refXMLParser.parse();
1019:
1020:                    } catch (XMLException x) {
1021:                        throw new CompilerException(
1022:                                "Error parsing installation file", x);
1023:                    }
1024:
1025:                    // Now checked the loaded XML file for basic syntax
1026:                    // We check it
1027:                    if (!"installation".equalsIgnoreCase(refXMLData.getName())) {
1028:                        parseError(refXMLData,
1029:                                "this is not an IzPack XML installation file");
1030:                    }
1031:                    if (!VERSION.equalsIgnoreCase(requireAttribute(refXMLData,
1032:                            "version"))) {
1033:                        parseError(refXMLData,
1034:                                "the file version is different from the compiler version");
1035:                    }
1036:
1037:                    // Read the properties and perform replacement on the rest of the tree
1038:                    substituteProperties(refXMLData);
1039:
1040:                    // call addResources to add the referenced XML resources to this installation
1041:                    addResources(refXMLData);
1042:
1043:                    try {
1044:                        specin.close();
1045:                    } catch (IOException e) {
1046:                        // TODO Auto-generated catch block
1047:                        e.printStackTrace();
1048:                    }
1049:                    // Recursively call myself to add all packs and refpacks from the reference XML
1050:                    addPacksSingle(refXMLData);
1051:                }
1052:                notifyCompilerListener("addPacksSingle", CompilerListener.END,
1053:                        data);
1054:            }
1055:
1056:            /**
1057:             * Checks whether the dependencies stated in the configuration file are correct. Specifically it
1058:             * checks that no pack point to a non existent pack and also that there are no circular
1059:             * dependencies in the packs.
1060:             */
1061:            public void checkDependencies(List<PackInfo> packs)
1062:                    throws CompilerException {
1063:                // Because we use package names in the configuration file we assosiate
1064:                // the names with the objects
1065:                Map<String, PackInfo> names = new HashMap<String, PackInfo>();
1066:                for (PackInfo pack : packs) {
1067:                    names.put(pack.getPack().name, pack);
1068:                }
1069:                int result = dfs(packs, names);
1070:                // @todo More informative messages to include the source of the error
1071:                if (result == -2)
1072:                    parseError("Circular dependency detected");
1073:                else if (result == -1)
1074:                    parseError("A dependency doesn't exist");
1075:            }
1076:
1077:            /**
1078:             * We use the dfs graph search algorithm to check whether the graph is acyclic as described in:
1079:             * Thomas H. Cormen, Charles Leiserson, Ronald Rivest and Clifford Stein. Introduction to
1080:             * algorithms 2nd Edition 540-549,MIT Press, 2001
1081:             * 
1082:             * @param packs The graph
1083:             * @param names The name map
1084:             */
1085:            private int dfs(List<PackInfo> packs, Map<String, PackInfo> names) {
1086:                Map<Edge, Integer> edges = new HashMap<Edge, Integer>();
1087:                for (PackInfo pack : packs) {
1088:                    if (pack.colour == PackInfo.WHITE) {
1089:                        if (dfsVisit(pack, names, edges) != 0) {
1090:                            return -1;
1091:                        }
1092:                    }
1093:
1094:                }
1095:                return checkBackEdges(edges);
1096:            }
1097:
1098:            /**
1099:             * This function checks for the existence of back edges.
1100:             */
1101:            private int checkBackEdges(Map<Edge, Integer> edges) {
1102:                Set<Edge> keys = edges.keySet();
1103:                for (final Edge key : keys) {
1104:                    int color = edges.get(key);
1105:                    if (color == PackInfo.GREY) {
1106:                        return -2;
1107:                    }
1108:                }
1109:                return 0;
1110:
1111:            }
1112:
1113:            /**
1114:             * This class is used for the classification of the edges
1115:             */
1116:            private class Edge {
1117:
1118:                PackInfo u;
1119:
1120:                PackInfo v;
1121:
1122:                Edge(PackInfo u, PackInfo v) {
1123:                    this .u = u;
1124:                    this .v = v;
1125:                }
1126:            }
1127:
1128:            private int dfsVisit(PackInfo u, Map<String, PackInfo> names,
1129:                    Map<Edge, Integer> edges) {
1130:                u.colour = PackInfo.GREY;
1131:                List<String> deps = u.getDependencies();
1132:                if (deps != null) {
1133:                    for (String name : deps) {
1134:                        PackInfo v = names.get(name);
1135:                        if (v == null) {
1136:                            System.out.println("Failed to find dependency: "
1137:                                    + name);
1138:                            return -1;
1139:                        }
1140:                        Edge edge = new Edge(u, v);
1141:                        if (edges.get(edge) == null) {
1142:                            edges.put(edge, v.colour);
1143:                        }
1144:
1145:                        if (v.colour == PackInfo.WHITE) {
1146:
1147:                            final int result = dfsVisit(v, names, edges);
1148:                            if (result != 0) {
1149:                                return result;
1150:                            }
1151:                        }
1152:                    }
1153:                }
1154:                u.colour = PackInfo.BLACK;
1155:                return 0;
1156:            }
1157:
1158:            /**
1159:             * Add files in an archive to a pack
1160:             * @param archive the archive file to unpack
1161:             * @param targetdir the target directory where the content of the archive will be installed
1162:             * @param osList The target OS constraints.
1163:             * @param override Overriding behaviour.
1164:             * @param pack Pack to be packed into
1165:             * @param additionals Map which contains additional data
1166:             * @param condition 
1167:             */
1168:            protected void addArchiveContent(File baseDir, File archive,
1169:                    String targetdir, List<OsConstraint> osList, int override,
1170:                    PackInfo pack, Map additionals, String condition)
1171:                    throws IOException {
1172:
1173:                FileInputStream fin = new FileInputStream(archive);
1174:                ZipInputStream zin = new ZipInputStream(fin);
1175:                while (true) {
1176:                    ZipEntry zentry = zin.getNextEntry();
1177:                    if (zentry == null)
1178:                        break;
1179:                    if (zentry.isDirectory())
1180:                        continue;
1181:
1182:                    try {
1183:                        File temp = File.createTempFile("izpack", null);
1184:                        temp.deleteOnExit();
1185:
1186:                        FileOutputStream out = new FileOutputStream(temp);
1187:                        PackagerHelper.copyStream(zin, out);
1188:                        out.close();
1189:
1190:                        pack.addFile(baseDir, temp, targetdir + "/"
1191:                                + zentry.getName(), osList, override,
1192:                                additionals, condition);
1193:                    } catch (IOException e) {
1194:                        throw new IOException(
1195:                                "Couldn't create temporary file for "
1196:                                        + zentry.getName() + " in archive "
1197:                                        + archive + " (" + e.getMessage() + ")");
1198:                    }
1199:
1200:                }
1201:                fin.close();
1202:            }
1203:
1204:            /**
1205:             * Recursive method to add files in a pack.
1206:             * 
1207:             * @param file The file to add.
1208:             * @param targetdir The relative path to the parent.
1209:             * @param osList The target OS constraints.
1210:             * @param override Overriding behaviour.
1211:             * @param pack Pack to be packed into
1212:             * @param additionals Map which contains additional data
1213:             * @param condition 
1214:             * @exception FileNotFoundException if the file does not exist
1215:             */
1216:            protected void addRecursively(File baseDir, File file,
1217:                    String targetdir, List<OsConstraint> osList, int override,
1218:                    PackInfo pack, Map additionals, String condition)
1219:                    throws IOException {
1220:                String targetfile = targetdir + "/" + file.getName();
1221:                if (!file.isDirectory())
1222:                    pack.addFile(baseDir, file, targetfile, osList, override,
1223:                            additionals, condition);
1224:                else {
1225:                    File[] files = file.listFiles();
1226:                    if (files.length == 0) // The directory is empty so must be added
1227:                        pack.addFile(baseDir, file, targetfile, osList,
1228:                                override, additionals, condition);
1229:                    else {
1230:                        // new targetdir = targetfile;
1231:                        for (File file1 : files) {
1232:                            addRecursively(baseDir, file1, targetfile, osList,
1233:                                    override, pack, additionals, condition);
1234:                        }
1235:                    }
1236:                }
1237:            }
1238:
1239:            /**
1240:             * Parse panels and their paramters, locate the panels resources and add to the Packager.
1241:             * 
1242:             * @param data The XML data.
1243:             * @exception CompilerException Description of the Exception
1244:             */
1245:            protected void addPanels(XMLElement data) throws CompilerException {
1246:                notifyCompilerListener("addPanels", CompilerListener.BEGIN,
1247:                        data);
1248:                XMLElement root = requireChildNamed(data, "panels");
1249:
1250:                // at least one panel is required
1251:                Vector<XMLElement> panels = root.getChildrenNamed("panel");
1252:                if (panels.isEmpty())
1253:                    parseError(root, "<panels> requires a <panel>");
1254:
1255:                // We process each panel markup
1256:                Iterator<XMLElement> iter = panels.iterator();
1257:                while (iter.hasNext()) {
1258:                    XMLElement xmlPanel = iter.next();
1259:
1260:                    // create the serialized Panel data
1261:                    Panel panel = new Panel();
1262:                    panel.osConstraints = OsConstraint.getOsList(xmlPanel);
1263:                    String className = xmlPanel.getAttribute("classname");
1264:                    // add an id
1265:                    String panelid = xmlPanel.getAttribute("id");
1266:                    panel.setPanelid(panelid);
1267:                    String condition = xmlPanel.getAttribute("condition");
1268:                    panel.setCondition(condition);
1269:
1270:                    // Panel files come in jars packaged w/ IzPack
1271:                    String jarPath = "bin/panels/" + className + ".jar";
1272:                    URL url = findIzPackResource(jarPath, "Panel jar file",
1273:                            xmlPanel);
1274:                    String fullClassName = null;
1275:                    try {
1276:                        fullClassName = getFullClassName(url, className);
1277:                    } catch (IOException e) {
1278:                    }
1279:                    if (fullClassName != null)
1280:                        panel.className = fullClassName;
1281:                    else
1282:                        panel.className = className;
1283:                    // insert into the packager
1284:                    compiler.addPanelJar(panel, url);
1285:                }
1286:                notifyCompilerListener("addPanels", CompilerListener.END, data);
1287:            }
1288:
1289:            /**
1290:             * Adds the resources.
1291:             * 
1292:             * @param data The XML data.
1293:             * @exception CompilerException Description of the Exception
1294:             */
1295:            protected void addResources(XMLElement data)
1296:                    throws CompilerException {
1297:                notifyCompilerListener("addResources", CompilerListener.BEGIN,
1298:                        data);
1299:                XMLElement root = data.getFirstChildNamed("resources");
1300:                if (root == null)
1301:                    return;
1302:
1303:                // We process each res markup
1304:                Iterator<XMLElement> iter = root.getChildrenNamed("res")
1305:                        .iterator();
1306:                while (iter.hasNext()) {
1307:                    XMLElement res = iter.next();
1308:                    String id = requireAttribute(res, "id");
1309:                    String src = requireAttribute(res, "src");
1310:                    // the parse attribute causes substitution to occur
1311:                    boolean substitute = validateYesNoAttribute(res, "parse",
1312:                            NO);
1313:                    // the parsexml attribute causes the xml document to be parsed 
1314:                    boolean parsexml = validateYesNoAttribute(res, "parsexml",
1315:                            NO);
1316:
1317:                    // basedir is not prepended if src is already an absolute path
1318:                    URL originalUrl = findProjectResource(src, "Resource", res);
1319:                    URL url = originalUrl;
1320:
1321:                    InputStream is = null;
1322:                    OutputStream os = null;
1323:                    try {
1324:                        if (parsexml
1325:                                || (substitute && !compiler.getVariables()
1326:                                        .isEmpty())) {
1327:                            // make the substitutions into a temp file
1328:                            File parsedFile = File.createTempFile("izpp", null);
1329:                            parsedFile.deleteOnExit();
1330:                            FileOutputStream outFile = new FileOutputStream(
1331:                                    parsedFile);
1332:                            os = new BufferedOutputStream(outFile);
1333:                            // and specify the substituted file to be added to the
1334:                            // packager
1335:                            url = parsedFile.toURL();
1336:                        }
1337:
1338:                        if (parsexml) {
1339:                            IXMLParser parser = XMLParserFactory
1340:                                    .createDefaultXMLParser();
1341:                            // this constructor will open the specified url (this is
1342:                            // why the InputStream is not handled in a similar manner
1343:                            // to the OutputStream)
1344:                            IXMLReader reader = new StdXMLReader(null,
1345:                                    originalUrl.toExternalForm());
1346:                            parser.setReader(reader);
1347:                            XMLElement xml = (XMLElement) parser.parse();
1348:
1349:                            if (substitute
1350:                                    && !compiler.getVariables().isEmpty()) {
1351:                                // if we are also performing substitutions on the file
1352:                                // then create an in-memory copy to pass to the
1353:                                // substitutor
1354:                                ByteArrayOutputStream baos = new ByteArrayOutputStream();
1355:                                XMLWriter xmlWriter = new XMLWriter(baos);
1356:                                xmlWriter.write(xml);
1357:                                is = new ByteArrayInputStream(baos
1358:                                        .toByteArray());
1359:                            } else {
1360:                                // otherwise write direct to the temp file
1361:                                XMLWriter xmlWriter = new XMLWriter(os);
1362:                                xmlWriter.write(xml);
1363:                            }
1364:                        }
1365:
1366:                        // substitute variable values in the resource if parsed
1367:                        if (substitute) {
1368:                            if (compiler.getVariables().isEmpty()) {
1369:                                // reset url to original.
1370:                                url = originalUrl;
1371:                                parseWarn(res, "No variables defined. "
1372:                                        + url.getPath() + " not parsed.");
1373:                            } else {
1374:                                String type = res.getAttribute("type");
1375:                                String encoding = res.getAttribute("encoding");
1376:
1377:                                // if the xml parser did not open the url
1378:                                // ('parsexml' was not enabled)
1379:                                if (null == is) {
1380:                                    is = new BufferedInputStream(url
1381:                                            .openStream());
1382:                                }
1383:                                VariableSubstitutor vs = new VariableSubstitutor(
1384:                                        compiler.getVariables());
1385:                                vs.substitute(is, os, type, encoding);
1386:                            }
1387:                        }
1388:
1389:                    } catch (Exception e) {
1390:                        parseError(res, e.getMessage(), e);
1391:                    } finally {
1392:                        if (null != os) {
1393:                            try {
1394:                                os.close();
1395:                            } catch (IOException e) {
1396:                                // ignore as there is nothing we can realistically do
1397:                                // so lets at least try to close the input stream
1398:                            }
1399:                        }
1400:                        if (null != is) {
1401:                            try {
1402:                                is.close();
1403:                            } catch (IOException e) {
1404:                                // ignore as there is nothing we can realistically do
1405:                            }
1406:                        }
1407:                    }
1408:
1409:                    compiler.addResource(id, url);
1410:                }
1411:                notifyCompilerListener("addResources", CompilerListener.END,
1412:                        data);
1413:            }
1414:
1415:            /**
1416:             * Adds the ISO3 codes of the langpacks and associated resources.
1417:             * 
1418:             * @param data The XML data.
1419:             * @exception CompilerException Description of the Exception
1420:             */
1421:            protected void addLangpacks(XMLElement data)
1422:                    throws CompilerException {
1423:                notifyCompilerListener("addLangpacks", CompilerListener.BEGIN,
1424:                        data);
1425:                XMLElement root = requireChildNamed(data, "locale");
1426:
1427:                // at least one langpack is required
1428:                Vector<XMLElement> locals = root.getChildrenNamed("langpack");
1429:                if (locals.isEmpty())
1430:                    parseError(root, "<locale> requires a <langpack>");
1431:
1432:                // We process each langpack markup
1433:                Iterator<XMLElement> iter = locals.iterator();
1434:                while (iter.hasNext()) {
1435:                    XMLElement el = iter.next();
1436:                    String iso3 = requireAttribute(el, "iso3");
1437:                    String path;
1438:
1439:                    path = "bin/langpacks/installer/" + iso3 + ".xml";
1440:                    URL iso3xmlURL = findIzPackResource(path, "ISO3 file", el);
1441:
1442:                    path = "bin/langpacks/flags/" + iso3 + ".gif";
1443:                    URL iso3FlagURL = findIzPackResource(path,
1444:                            "ISO3 flag image", el);
1445:
1446:                    compiler.addLangPack(iso3, iso3xmlURL, iso3FlagURL);
1447:                }
1448:                notifyCompilerListener("addLangpacks", CompilerListener.END,
1449:                        data);
1450:            }
1451:
1452:            /**
1453:             * Builds the Info class from the XML tree.
1454:             * 
1455:             * @param data The XML data. return The Info.
1456:             * @exception Exception Description of the Exception
1457:             */
1458:            protected void addInfo(XMLElement data) throws Exception {
1459:                notifyCompilerListener("addInfo", CompilerListener.BEGIN, data);
1460:                // Initialisation
1461:                XMLElement root = requireChildNamed(data, "info");
1462:
1463:                Info info = new Info();
1464:                info.setAppName(requireContent(requireChildNamed(root,
1465:                        "appname")));
1466:                info.setAppVersion(requireContent(requireChildNamed(root,
1467:                        "appversion")));
1468:                // We get the installation subpath
1469:                XMLElement subpath = root.getFirstChildNamed("appsubpath");
1470:                if (subpath != null) {
1471:                    info.setInstallationSubPath(requireContent(subpath));
1472:                }
1473:
1474:                // validate and insert app URL
1475:                final XMLElement URLElem = root.getFirstChildNamed("url");
1476:                if (URLElem != null) {
1477:                    URL appURL = requireURLContent(URLElem);
1478:                    info.setAppURL(appURL.toString());
1479:                }
1480:
1481:                // We get the authors list
1482:                XMLElement authors = root.getFirstChildNamed("authors");
1483:                if (authors != null) {
1484:                    Iterator<XMLElement> iter = authors.getChildrenNamed(
1485:                            "author").iterator();
1486:                    while (iter.hasNext()) {
1487:                        XMLElement author = iter.next();
1488:                        String name = requireAttribute(author, "name");
1489:                        String email = requireAttribute(author, "email");
1490:                        info.addAuthor(new Info.Author(name, email));
1491:                    }
1492:                }
1493:
1494:                // We get the java version required
1495:                XMLElement javaVersion = root.getFirstChildNamed("javaversion");
1496:                if (javaVersion != null)
1497:                    info.setJavaVersion(requireContent(javaVersion));
1498:
1499:                // Is a JDK required?
1500:                XMLElement jdkRequired = root.getFirstChildNamed("requiresjdk");
1501:                if (jdkRequired != null)
1502:                    info.setJdkRequired("yes".equals(jdkRequired.getContent()));
1503:
1504:                // validate and insert (and require if -web kind) web dir
1505:                XMLElement webDirURL = root.getFirstChildNamed("webdir");
1506:                if (webDirURL != null)
1507:                    info.setWebDirURL(requireURLContent(webDirURL).toString());
1508:                String kind = compiler.getKind();
1509:                if (kind != null) {
1510:                    if (kind.equalsIgnoreCase(WEB) && webDirURL == null) {
1511:                        parseError(root,
1512:                                "<webdir> required when \"WEB\" installer requested");
1513:                    } else if (kind.equalsIgnoreCase(STANDARD)
1514:                            && webDirURL != null) {
1515:                        // Need a Warning? parseWarn(webDirURL, "Not creating web
1516:                        // installer.");
1517:                        info.setWebDirURL(null);
1518:                    }
1519:                }
1520:
1521:                // Add the uninstaller as a resource if specified
1522:                XMLElement uninstallInfo = root
1523:                        .getFirstChildNamed("uninstaller");
1524:                if (validateYesNoAttribute(uninstallInfo, "write", YES)) {
1525:                    URL url = findIzPackResource("lib/uninstaller.jar",
1526:                            "Uninstaller", root);
1527:                    compiler.addResource("IzPack.uninstaller", url);
1528:
1529:                    if (uninstallInfo != null) {
1530:                        String uninstallerName = uninstallInfo
1531:                                .getAttribute("name");
1532:                        if (uninstallerName != null
1533:                                && uninstallerName.length() > ".jar".length())
1534:                            info.setUninstallerName(uninstallerName);
1535:                    }
1536:                }
1537:                // Add the path for the summary log file if specified
1538:                XMLElement slfPath = root
1539:                        .getFirstChildNamed("summarylogfilepath");
1540:                if (slfPath != null)
1541:                    info.setSummaryLogFilePath(requireContent(slfPath));
1542:
1543:                XMLElement writeInstallInfo = root
1544:                        .getFirstChildNamed("writeinstallationinformation");
1545:                if (writeInstallInfo != null) {
1546:                    String writeInstallInfoString = requireContent(writeInstallInfo);
1547:                    info
1548:                            .setWriteInstallationInformation(validateYesNo(writeInstallInfoString));
1549:                }
1550:
1551:                // look for an unpacker class
1552:                String unpackerclass = compiler.getProperty("UNPACKER_CLASS");
1553:                info.setUnpackerClassName(unpackerclass);
1554:                compiler.setInfo(info);
1555:                notifyCompilerListener("addInfo", CompilerListener.END, data);
1556:            }
1557:
1558:            /**
1559:             * Variable declaration is a fragment of the xml file. For example:
1560:             * 
1561:             * <pre>
1562:             * 
1563:             *  
1564:             *   
1565:             *    
1566:             *        &lt;variables&gt;
1567:             *          &lt;variable name=&quot;nom&quot; value=&quot;value&quot;/&gt;
1568:             *          &lt;variable name=&quot;foo&quot; value=&quot;pippo&quot;/&gt;
1569:             *        &lt;/variables&gt;
1570:             *      
1571:             *    
1572:             *   
1573:             *  
1574:             * </pre>
1575:             * 
1576:             * variable declared in this can be referred to in parsable files.
1577:             * 
1578:             * @param data The XML data.
1579:             * @exception CompilerException Description of the Exception
1580:             */
1581:            protected void addVariables(XMLElement data)
1582:                    throws CompilerException {
1583:                notifyCompilerListener("addVariables", CompilerListener.BEGIN,
1584:                        data);
1585:                // We get the varible list
1586:                XMLElement root = data.getFirstChildNamed("variables");
1587:                if (root == null)
1588:                    return;
1589:
1590:                Properties variables = compiler.getVariables();
1591:
1592:                Iterator<XMLElement> iter = root.getChildrenNamed("variable")
1593:                        .iterator();
1594:                while (iter.hasNext()) {
1595:                    XMLElement var = iter.next();
1596:                    String name = requireAttribute(var, "name");
1597:                    String value = requireAttribute(var, "value");
1598:                    if (variables.contains(name))
1599:                        parseWarn(var, "Variable '" + name
1600:                                + "' being overwritten");
1601:                    variables.setProperty(name, value);
1602:                }
1603:                notifyCompilerListener("addVariables", CompilerListener.END,
1604:                        data);
1605:            }
1606:
1607:            protected void addDynamicVariables(XMLElement data)
1608:                    throws CompilerException {
1609:                notifyCompilerListener("addDynamicVariables",
1610:                        CompilerListener.BEGIN, data);
1611:                // We get the dynamic variable list
1612:                XMLElement root = data.getFirstChildNamed("dynamicvariables");
1613:                if (root == null)
1614:                    return;
1615:
1616:                Map<String, DynamicVariable> dynamicvariables = compiler
1617:                        .getDynamicVariables();
1618:
1619:                Iterator<XMLElement> iter = root.getChildrenNamed("variable")
1620:                        .iterator();
1621:                while (iter.hasNext()) {
1622:                    XMLElement var = iter.next();
1623:                    String name = requireAttribute(var, "name");
1624:                    String value = requireAttribute(var, "value");
1625:                    String conditionid = var.getAttribute("condition");
1626:                    if (dynamicvariables.containsKey(name))
1627:                        parseWarn(var, "DynamicVariable '" + name
1628:                                + "' being overwritten");
1629:                    DynamicVariable dynvar = new DynamicVariable();
1630:                    dynvar.setName(name);
1631:                    dynvar.setValue(value);
1632:                    dynvar.setConditionid(conditionid);
1633:                    dynamicvariables.put(name, dynvar);
1634:                }
1635:                notifyCompilerListener("addDynamicVariables",
1636:                        CompilerListener.END, data);
1637:            }
1638:
1639:            /**
1640:             * Parse conditions and add them to the compiler.
1641:             * @param data
1642:             * @throws CompilerException
1643:             */
1644:            protected void addConditions(XMLElement data)
1645:                    throws CompilerException {
1646:                notifyCompilerListener("addConditions", CompilerListener.BEGIN,
1647:                        data);
1648:                // We get the condition list
1649:                XMLElement root = data.getFirstChildNamed("conditions");
1650:                Map<String, Condition> conditions = compiler.getConditions();
1651:                if (root != null) {
1652:                    Iterator<XMLElement> iter = root.getChildrenNamed(
1653:                            "condition").iterator();
1654:                    while (iter.hasNext()) {
1655:                        XMLElement conditionel = iter.next();
1656:                        Condition condition = RulesEngine
1657:                                .analyzeCondition(conditionel);
1658:                        if (condition != null) {
1659:                            String conditionid = condition.getId();
1660:                            if (conditions.containsKey(conditionid)) {
1661:                                parseWarn(conditionel, "Condition with id '"
1662:                                        + conditionid + "' will be overwritten");
1663:                            }
1664:                            conditions.put(conditionid, condition);
1665:
1666:                        } else {
1667:                            parseWarn(conditionel,
1668:                                    "Condition couldn't be instantiated.");
1669:                        }
1670:                    }
1671:                }
1672:                notifyCompilerListener("addConditions", CompilerListener.END,
1673:                        data);
1674:            }
1675:
1676:            /**
1677:             * Properties declaration is a fragment of the xml file. For example:
1678:             * 
1679:             * <pre>
1680:             * 
1681:             *  
1682:             *   
1683:             *    
1684:             *        &lt;properties&gt;
1685:             *          &lt;property name=&quot;app.name&quot; value=&quot;Property Laden Installer&quot;/&gt;
1686:             *          &lt;!-- Ant styles 'location' and 'refid' are not yet supported --&gt;
1687:             *          &lt;property file=&quot;filename-relative-to-install?&quot;/&gt;
1688:             *          &lt;property file=&quot;filename-relative-to-install?&quot; prefix=&quot;prefix&quot;/&gt;
1689:             *          &lt;!-- Ant style 'url' and 'resource' are not yet supported --&gt;
1690:             *          &lt;property environment=&quot;prefix&quot;/&gt;
1691:             *        &lt;/properties&gt;
1692:             *      
1693:             *    
1694:             *   
1695:             *  
1696:             * </pre>
1697:             * 
1698:             * variable declared in this can be referred to in parsable files.
1699:             * 
1700:             * @param data The XML data.
1701:             * @exception CompilerException Description of the Exception
1702:             */
1703:            protected void substituteProperties(XMLElement data)
1704:                    throws CompilerException {
1705:                notifyCompilerListener("substituteProperties",
1706:                        CompilerListener.BEGIN, data);
1707:
1708:                XMLElement root = data.getFirstChildNamed("properties");
1709:                if (root != null) {
1710:                    // add individual properties
1711:                    Iterator<XMLElement> iter = root.getChildrenNamed(
1712:                            "property").iterator();
1713:                    while (iter.hasNext()) {
1714:                        XMLElement prop = iter.next();
1715:                        Property property = new Property(prop, this );
1716:                        property.execute();
1717:                    }
1718:                }
1719:
1720:                // temporarily remove the 'properties' branch, replace all properties in
1721:                // the remaining DOM, and replace properties branch.
1722:                // TODO: enhance XMLElement with an "indexOf(XMLElement)" method
1723:                // and addChild(XMLElement, int) so returns to the same place.
1724:                if (root != null)
1725:                    data.removeChild(root);
1726:
1727:                substituteAllProperties(data);
1728:                if (root != null)
1729:                    data.addChild(root);
1730:
1731:                notifyCompilerListener("substituteProperties",
1732:                        CompilerListener.END, data);
1733:            }
1734:
1735:            /**
1736:             * Perform recursive substitution on all properties
1737:             */
1738:            protected void substituteAllProperties(XMLElement element)
1739:                    throws CompilerException {
1740:                Enumeration attributes = element.enumerateAttributeNames();
1741:                while (attributes.hasMoreElements()) {
1742:                    String name = (String) attributes.nextElement();
1743:                    String value = compiler.replaceProperties(element
1744:                            .getAttribute(name));
1745:                    element.setAttribute(name, value);
1746:                }
1747:
1748:                String content = element.getContent();
1749:                if (content != null) {
1750:                    element.setContent(compiler.replaceProperties(content));
1751:                }
1752:
1753:                Enumeration children = element.enumerateChildren();
1754:                while (children.hasMoreElements()) {
1755:                    XMLElement child = (XMLElement) children.nextElement();
1756:                    substituteAllProperties(child);
1757:                }
1758:            }
1759:
1760:            /**
1761:             * Returns the XMLElement representing the installation XML file.
1762:             * 
1763:             * @return The XML tree.
1764:             * @exception CompilerException For problems with the installation file
1765:             * @exception IOException for errors reading the installation file
1766:             */
1767:            protected XMLElement getXMLTree() throws CompilerException,
1768:                    IOException {
1769:                // Initialises the parser
1770:                IXMLReader reader = null;
1771:                if (filename != null) {
1772:                    File file = new File(filename).getAbsoluteFile();
1773:                    if (!file.canRead())
1774:                        throw new CompilerException("Invalid file: " + file);
1775:                    reader = new StdXMLReader(new FileInputStream(filename));
1776:                    reader.setSystemID(file.toURL().toExternalForm());
1777:                    // add izpack built in property
1778:                    compiler.setProperty("izpack.file", file.toString());
1779:                } else if (installText != null) {
1780:                    reader = StdXMLReader.stringReader(installText);
1781:                } else {
1782:                    throw new CompilerException(
1783:                            "Neither install file nor text specified");
1784:                }
1785:
1786:                StdXMLParser parser = new StdXMLParser();
1787:                parser.setBuilder(XMLBuilderFactory.createXMLBuilder());
1788:                parser.setReader(reader);
1789:                parser.setValidator(new NonValidator());
1790:
1791:                // We get it
1792:                XMLElement data = null;
1793:                try {
1794:                    data = (XMLElement) parser.parse();
1795:                } catch (Exception x) {
1796:                    throw new CompilerException(
1797:                            "Error parsing installation file", x);
1798:                }
1799:
1800:                // We check it
1801:                if (!"installation".equalsIgnoreCase(data.getName()))
1802:                    parseError(data,
1803:                            "this is not an IzPack XML installation file");
1804:                if (!VERSION
1805:                        .equalsIgnoreCase(requireAttribute(data, "version")))
1806:                    parseError(data,
1807:                            "the file version is different from the compiler version");
1808:
1809:                // We finally return the tree
1810:                return data;
1811:            }
1812:
1813:            protected int getOverrideValue(XMLElement f)
1814:                    throws CompilerException {
1815:                int override = PackFile.OVERRIDE_UPDATE;
1816:
1817:                String override_val = f.getAttribute("override");
1818:                if (override_val != null) {
1819:                    if ("true".equalsIgnoreCase(override_val)) {
1820:                        override = PackFile.OVERRIDE_TRUE;
1821:                    } else if ("false".equalsIgnoreCase(override_val)) {
1822:                        override = PackFile.OVERRIDE_FALSE;
1823:                    } else if ("asktrue".equalsIgnoreCase(override_val)) {
1824:                        override = PackFile.OVERRIDE_ASK_TRUE;
1825:                    } else if ("askfalse".equalsIgnoreCase(override_val)) {
1826:                        override = PackFile.OVERRIDE_ASK_FALSE;
1827:                    } else if ("update".equalsIgnoreCase(override_val)) {
1828:                        override = PackFile.OVERRIDE_UPDATE;
1829:                    } else
1830:                        parseError(f,
1831:                                "invalid value for attribute \"override\"");
1832:                }
1833:
1834:                return override;
1835:            }
1836:
1837:            /**
1838:             * Look for a project specified resources, which, if not absolute, are sought relative to the
1839:             * projects basedir. The path should use '/' as the fileSeparator. If the resource is not found,
1840:             * a CompilerException is thrown indicating fault in the parent element.
1841:             * 
1842:             * @param path the relative path (using '/' as separator) to the resource.
1843:             * @param desc the description of the resource used to report errors
1844:             * @param parent the XMLElement the resource is specified in, used to report errors
1845:             * @return a URL to the resource.
1846:             */
1847:            private URL findProjectResource(String path, String desc,
1848:                    XMLElement parent) throws CompilerException {
1849:                URL url = null;
1850:                File resource = new File(path);
1851:                if (!resource.isAbsolute())
1852:                    resource = new File(basedir, path);
1853:
1854:                if (!resource.exists()) // fatal
1855:                    parseError(parent, desc + " not found: " + resource);
1856:
1857:                try {
1858:                    url = resource.toURL();
1859:                } catch (MalformedURLException how) {
1860:                    parseError(parent, desc + "(" + resource + ")", how);
1861:                }
1862:
1863:                return url;
1864:            }
1865:
1866:            /**
1867:             * Look for an IzPack resource either in the compiler jar, or within IZPACK_HOME. The path must
1868:             * not be absolute. The path must use '/' as the fileSeparator (it's used to access the jar
1869:             * file). If the resource is not found, a CompilerException is thrown indicating fault in the
1870:             * parent element.
1871:             * 
1872:             * @param path the relative path (using '/' as separator) to the resource.
1873:             * @param desc the description of the resource used to report errors
1874:             * @param parent the XMLElement the resource is specified in, used to report errors
1875:             * @return a URL to the resource.
1876:             */
1877:            private URL findIzPackResource(String path, String desc,
1878:                    XMLElement parent) throws CompilerException {
1879:                URL url = getClass().getResource("/" + path);
1880:                if (url == null) {
1881:                    File resource = new File(path);
1882:
1883:                    if (!resource.isAbsolute())
1884:                        resource = new File(Compiler.IZPACK_HOME, path);
1885:
1886:                    if (!resource.exists()) // fatal
1887:                        parseError(parent, desc + " not found: " + resource);
1888:
1889:                    try {
1890:                        url = resource.toURL();
1891:                    } catch (MalformedURLException how) {
1892:                        parseError(parent, desc + "(" + resource + ")", how);
1893:                    }
1894:                }
1895:
1896:                return url;
1897:            }
1898:
1899:            /**
1900:             * Create parse error with consistent messages. Includes file name. For use When parent is
1901:             * unknown.
1902:             * 
1903:             * @param message Brief message explaining error
1904:             */
1905:            protected void parseError(String message) throws CompilerException {
1906:                throw new CompilerException(filename + ":" + message);
1907:            }
1908:
1909:            /**
1910:             * Create parse error with consistent messages. Includes file name and line # of parent. It is
1911:             * an error for 'parent' to be null.
1912:             * 
1913:             * @param parent The element in which the error occured
1914:             * @param message Brief message explaining error
1915:             */
1916:            protected void parseError(XMLElement parent, String message)
1917:                    throws CompilerException {
1918:                throw new CompilerException(filename + ":" + parent.getLineNr()
1919:                        + ": " + message);
1920:            }
1921:
1922:            /**
1923:             * Create a chained parse error with consistent messages. Includes file name and line # of
1924:             * parent. It is an error for 'parent' to be null.
1925:             * 
1926:             * @param parent The element in which the error occured
1927:             * @param message Brief message explaining error
1928:             */
1929:            protected void parseError(XMLElement parent, String message,
1930:                    Throwable cause) throws CompilerException {
1931:                throw new CompilerException(filename + ":" + parent.getLineNr()
1932:                        + ": " + message, cause);
1933:            }
1934:
1935:            /**
1936:             * Create a parse warning with consistent messages. Includes file name and line # of parent. It
1937:             * is an error for 'parent' to be null.
1938:             * 
1939:             * @param parent The element in which the warning occured
1940:             * @param message Warning message
1941:             */
1942:            protected void parseWarn(XMLElement parent, String message) {
1943:                System.out.println(filename + ":" + parent.getLineNr() + ": "
1944:                        + message);
1945:            }
1946:
1947:            /**
1948:             * Call getFirstChildNamed on the parent, producing a meaningful error message on failure. It is
1949:             * an error for 'parent' to be null.
1950:             * 
1951:             * @param parent The element to search for a child
1952:             * @param name Name of the child element to get
1953:             */
1954:            protected XMLElement requireChildNamed(XMLElement parent,
1955:                    String name) throws CompilerException {
1956:                XMLElement child = parent.getFirstChildNamed(name);
1957:                if (child == null)
1958:                    parseError(parent, "<" + parent.getName()
1959:                            + "> requires child <" + name + ">");
1960:                return child;
1961:            }
1962:
1963:            /**
1964:             * Call getContent on an element, producing a meaningful error message if not present, or empty,
1965:             * or a valid URL. It is an error for 'element' to be null.
1966:             * 
1967:             * @param element The element to get content of
1968:             */
1969:            protected URL requireURLContent(XMLElement element)
1970:                    throws CompilerException {
1971:                URL url = null;
1972:                try {
1973:                    url = new URL(requireContent(element));
1974:                } catch (MalformedURLException x) {
1975:                    parseError(element, "<" + element.getName()
1976:                            + "> requires valid URL", x);
1977:                }
1978:                return url;
1979:            }
1980:
1981:            /**
1982:             * Call getContent on an element, producing a meaningful error message if not present, or empty.
1983:             * It is an error for 'element' to be null.
1984:             * 
1985:             * @param element The element to get content of
1986:             */
1987:            protected String requireContent(XMLElement element)
1988:                    throws CompilerException {
1989:                String content = element.getContent();
1990:                if (content == null || content.length() == 0)
1991:                    parseError(element, "<" + element.getName()
1992:                            + "> requires content");
1993:                return content;
1994:            }
1995:
1996:            protected boolean validateYesNo(String value) {
1997:                boolean result = false;
1998:                if ("yes".equalsIgnoreCase(value)) {
1999:                    result = true;
2000:                } else if ("no".equalsIgnoreCase(value)) {
2001:                    result = false;
2002:                } else {
2003:                    Debug.trace("yes/no not found. trying true/false");
2004:                    result = Boolean.valueOf(value);
2005:                }
2006:                return result;
2007:            }
2008:
2009:            /**
2010:             * Call getAttribute on an element, producing a meaningful error message if not present, or
2011:             * empty. It is an error for 'element' or 'attribute' to be null.
2012:             * 
2013:             * @param element The element to get the attribute value of
2014:             * @param attribute The name of the attribute to get
2015:             */
2016:            protected String requireAttribute(XMLElement element,
2017:                    String attribute) throws CompilerException {
2018:                String value = element.getAttribute(attribute);
2019:                if (value == null)
2020:                    parseError(element, "<" + element.getName()
2021:                            + "> requires attribute '" + attribute + "'");
2022:                return value;
2023:            }
2024:
2025:            /**
2026:             * Get a required attribute of an element, ensuring it is an integer. A meaningful error message
2027:             * is generated as a CompilerException if not present or parseable as an int. It is an error for
2028:             * 'element' or 'attribute' to be null.
2029:             * 
2030:             * @param element The element to get the attribute value of
2031:             * @param attribute The name of the attribute to get
2032:             */
2033:            protected int requireIntAttribute(XMLElement element,
2034:                    String attribute) throws CompilerException {
2035:                String value = element.getAttribute(attribute);
2036:                if (value == null || value.length() == 0)
2037:                    parseError(element, "<" + element.getName()
2038:                            + "> requires attribute '" + attribute + "'");
2039:                try {
2040:                    return Integer.parseInt(value);
2041:                } catch (NumberFormatException x) {
2042:                    parseError(element, "'" + attribute
2043:                            + "' must be an integer");
2044:                }
2045:                return 0; // never happens
2046:            }
2047:
2048:            /**
2049:             * Call getAttribute on an element, producing a meaningful error message if not present, or one
2050:             * of "yes" or "no". It is an error for 'element' or 'attribute' to be null.
2051:             * 
2052:             * @param element The element to get the attribute value of
2053:             * @param attribute The name of the attribute to get
2054:             */
2055:            protected boolean requireYesNoAttribute(XMLElement element,
2056:                    String attribute) throws CompilerException {
2057:                String value = requireAttribute(element, attribute);
2058:                if ("yes".equalsIgnoreCase(value))
2059:                    return true;
2060:                if ("no".equalsIgnoreCase(value))
2061:                    return false;
2062:
2063:                parseError(element, "<" + element.getName()
2064:                        + "> invalid attribute '" + attribute
2065:                        + "': Expected (yes|no)");
2066:
2067:                return false; // never happens
2068:            }
2069:
2070:            /**
2071:             * Call getAttribute on an element, producing a meaningful warning if not "yes" or "no". If the
2072:             * 'element' or 'attribute' are null, the default value is returned.
2073:             * 
2074:             * @param element The element to get the attribute value of
2075:             * @param attribute The name of the attribute to get
2076:             * @param defaultValue Value returned if attribute not present or invalid
2077:             */
2078:            protected boolean validateYesNoAttribute(XMLElement element,
2079:                    String attribute, boolean defaultValue) {
2080:                if (element == null)
2081:                    return defaultValue;
2082:
2083:                String value = element.getAttribute(attribute,
2084:                        (defaultValue ? "yes" : "no"));
2085:                if ("yes".equalsIgnoreCase(value))
2086:                    return true;
2087:                if ("no".equalsIgnoreCase(value))
2088:                    return false;
2089:
2090:                // TODO: should this be an error if it's present but "none of the
2091:                // above"?
2092:                parseWarn(element, "<" + element.getName()
2093:                        + "> invalid attribute '" + attribute
2094:                        + "': Expected (yes|no) if present");
2095:
2096:                return defaultValue;
2097:            }
2098:
2099:            /**
2100:             * The main method if the compiler is invoked by a command-line call.
2101:             * 
2102:             * @param args The arguments passed on the command-line.
2103:             */
2104:            public static void main(String[] args) {
2105:                // Outputs some informations
2106:                System.out.println("");
2107:                System.out.println(".::  IzPack - Version "
2108:                        + Compiler.IZPACK_VERSION + " ::.");
2109:                System.out.println("");
2110:                System.out.println("< compiler specifications version: "
2111:                        + VERSION + " >");
2112:                System.out.println("");
2113:                System.out.println("- Copyright (c) 2001-2008 Julien Ponge");
2114:                System.out
2115:                        .println("- Visit http://izpack.org/ for the latest releases");
2116:                System.out
2117:                        .println("- Released under the terms of the Apache Software License version 2.0.");
2118:                System.out.println("");
2119:
2120:                // exit code 1 means: error
2121:                int exitCode = 1;
2122:                String home = ".";
2123:                // We get the IzPack home directory 
2124:                String izHome = System.getProperty("IZPACK_HOME");
2125:                if (izHome != null)
2126:                    home = izHome;
2127:
2128:                // We analyse the command line parameters
2129:                try {
2130:                    // Our arguments
2131:                    String filename;
2132:                    String base = ".";
2133:                    String kind = "standard";
2134:                    String output;
2135:                    String compr_format = "default";
2136:                    int compr_level = -1;
2137:
2138:                    // First check
2139:                    int nArgs = args.length;
2140:                    if (nArgs < 1)
2141:                        throw new Exception("no arguments given");
2142:
2143:                    // The users wants to know the command line parameters
2144:                    if ("-?".equalsIgnoreCase(args[0])) {
2145:                        System.out
2146:                                .println("-> Command line parameters are : (xml file) [args]");
2147:                        System.out
2148:                                .println("   (xml file): the xml file describing the installation");
2149:                        System.out
2150:                                .println("   -h (IzPack home) : the root path of IzPack. This will be needed");
2151:                        System.out
2152:                                .println("               if the compiler is not called in the root directory  of IzPack.");
2153:                        System.out
2154:                                .println("               Do not forget quotations if there are blanks in the path.");
2155:                        System.out
2156:                                .println("   -b (base) : indicates the base path that the compiler will use for filenames");
2157:                        System.out
2158:                                .println("               of sources. Default is the current path. Attend to -h.");
2159:                        System.out
2160:                                .println("   -k (kind) : indicates the kind of installer to generate");
2161:                        System.out
2162:                                .println("               default is standard");
2163:                        System.out
2164:                                .println("   -o (out)  : indicates the output file name");
2165:                        System.out
2166:                                .println("               default is the xml file name\n");
2167:                        System.out
2168:                                .println("   -c (compression)  : indicates the compression format to be used for packs");
2169:                        System.out
2170:                                .println("               default is the internal deflate compression\n");
2171:                        System.out
2172:                                .println("   -l (compression-level)  : indicates the level for the used compression format");
2173:                        System.out
2174:                                .println("                if supported. Only integer are valid\n");
2175:
2176:                        System.out
2177:                                .println("   When using vm option -DSTACKTRACE=true there is all kind of debug info ");
2178:                        System.out.println("");
2179:                        exitCode = 0;
2180:                    } else {
2181:                        // We can parse the other parameters & try to compile the
2182:                        // installation
2183:
2184:                        // We get the input file name and we initialize the output file
2185:                        // name
2186:                        filename = args[0];
2187:                        // default jar files names are based on input file name
2188:                        output = filename.substring(0, filename.length() - 3)
2189:                                + "jar";
2190:
2191:                        // We parse the other ones
2192:                        int pos = 1;
2193:                        while (pos < nArgs)
2194:                            if ((args[pos].startsWith("-"))
2195:                                    && (args[pos].length() == 2)) {
2196:                                switch (args[pos].toLowerCase().charAt(1)) {
2197:                                case 'b':
2198:                                    if ((pos + 1) < nArgs) {
2199:                                        pos++;
2200:                                        base = args[pos];
2201:                                    } else
2202:                                        throw new Exception(
2203:                                                "base argument missing");
2204:                                    break;
2205:                                case 'k':
2206:                                    if ((pos + 1) < nArgs) {
2207:                                        pos++;
2208:                                        kind = args[pos];
2209:                                    } else
2210:                                        throw new Exception(
2211:                                                "kind argument missing");
2212:                                    break;
2213:                                case 'o':
2214:                                    if ((pos + 1) < nArgs) {
2215:                                        pos++;
2216:                                        output = args[pos];
2217:                                    } else
2218:                                        throw new Exception(
2219:                                                "output argument missing");
2220:                                    break;
2221:                                case 'c':
2222:                                    if ((pos + 1) < nArgs) {
2223:                                        pos++;
2224:                                        compr_format = args[pos];
2225:                                    } else
2226:                                        throw new Exception(
2227:                                                "compression format argument missing");
2228:                                    break;
2229:                                case 'l':
2230:                                    if ((pos + 1) < nArgs) {
2231:                                        pos++;
2232:                                        compr_level = Integer
2233:                                                .parseInt(args[pos]);
2234:                                    } else
2235:                                        throw new Exception(
2236:                                                "compression level argument missing");
2237:                                    break;
2238:                                case 'h':
2239:                                    if ((pos + 1) < nArgs) {
2240:                                        pos++;
2241:                                        home = args[pos];
2242:                                    } else
2243:                                        throw new Exception(
2244:                                                "IzPack home path argument missing");
2245:                                    break;
2246:                                default:
2247:                                    throw new Exception("unknown argument");
2248:                                }
2249:                                pos++;
2250:                            } else
2251:                                throw new Exception("bad argument");
2252:
2253:                        home = resolveIzPackHome(home);
2254:                        // Outputs what we are going to do
2255:                        System.out.println("-> Processing  : " + filename);
2256:                        System.out.println("-> Output      : " + output);
2257:                        System.out.println("-> Base path   : " + base);
2258:                        System.out.println("-> Kind        : " + kind);
2259:                        System.out.println("-> Compression : " + compr_format);
2260:                        System.out.println("-> Compr. level: " + compr_level);
2261:                        System.out.println("-> IzPack home : " + home);
2262:                        System.out.println("");
2263:
2264:                        Compiler.setIzpackHome(home);
2265:
2266:                        // Calls the compiler
2267:                        CmdlinePackagerListener listener = new CmdlinePackagerListener();
2268:                        CompilerConfig compiler = new CompilerConfig(filename,
2269:                                base, kind, output, compr_format, compr_level,
2270:                                listener, null);
2271:                        compiler.executeCompiler();
2272:
2273:                        // Waits
2274:                        while (compiler.isAlive())
2275:                            Thread.sleep(100);
2276:
2277:                        if (compiler.wasSuccessful())
2278:                            exitCode = 0;
2279:
2280:                        System.out.println("Build time: " + new Date());
2281:                    }
2282:                } catch (Exception err) {
2283:                    // Something bad has happened
2284:                    System.err.println("-> Fatal error :");
2285:                    System.err.println("   " + err.getMessage());
2286:                    err.printStackTrace();
2287:                    System.err.println("");
2288:                    System.err
2289:                            .println("(tip : use -? to get the commmand line parameters)");
2290:                }
2291:
2292:                // Closes the JVM
2293:                System.exit(exitCode);
2294:            }
2295:
2296:            private static String resolveIzPackHome(String home) {
2297:                File test = new File(home, IZ_TEST_SUBDIR + File.separator
2298:                        + IZ_TEST_FILE);
2299:                if (test.exists())
2300:                    return (home);
2301:                // Try to resolve the path using compiler.jar which also should be under
2302:                // IZPACK_HOME.
2303:                String self = Compiler.class.getName();
2304:                self = self.replace('.', '/');
2305:                self = "/" + self + ".class";
2306:                URL url = Compiler.class.getResource(self);
2307:                String np = url.getFile();
2308:                int start = np.indexOf(self);
2309:                np = np.substring(0, start);
2310:                if (np.endsWith("!")) { // Where shut IZPACK_HOME at the standalone-compiler be??
2311:                    // No idea.
2312:                    if (np.endsWith("standalone-compiler.jar!"))
2313:                        return (".");
2314:                    np = np.substring(0, np.length() - 1);
2315:                }
2316:                File root = null;
2317:                if (URI.create(np).isAbsolute())
2318:                    root = new File(URI.create(np));
2319:                else
2320:                    root = new File(np);
2321:                while (true) {
2322:                    if (root == null)
2323:                        throw new IllegalArgumentException(
2324:                                "No valid IzPack home directory found");
2325:                    test = new File(root, IZ_TEST_SUBDIR + File.separator
2326:                            + IZ_TEST_FILE);
2327:                    if (test.exists())
2328:                        return (root.getAbsolutePath());
2329:                    root = root.getParentFile();
2330:                }
2331:            }
2332:
2333:            // -------------------------------------------------------------------------
2334:            // ------------- Listener stuff ------------------------- START ------------
2335:
2336:            /**
2337:             * This method parses install.xml for defined listeners and put them in the right position. If
2338:             * posible, the listeners will be validated. Listener declaration is a fragmention in
2339:             * install.xml like : <listeners> <listener compiler="PermissionCompilerListener"
2340:             * installer="PermissionInstallerListener"/> </<listeners>
2341:             * 
2342:             * @param data the XML data
2343:             * @exception Exception Description of the Exception
2344:             */
2345:            private void addCustomListeners(XMLElement data) throws Exception {
2346:                // We get the listeners
2347:                XMLElement root = data.getFirstChildNamed("listeners");
2348:                if (root == null)
2349:                    return;
2350:                Iterator<XMLElement> iter = root.getChildrenNamed("listener")
2351:                        .iterator();
2352:                while (iter.hasNext()) {
2353:                    XMLElement xmlAction = iter.next();
2354:                    Object[] listener = getCompilerListenerInstance(xmlAction);
2355:                    if (listener != null)
2356:                        addCompilerListener((CompilerListener) listener[0]);
2357:                    String[] typeNames = new String[] { "installer",
2358:                            "uninstaller" };
2359:                    int[] types = new int[] { CustomData.INSTALLER_LISTENER,
2360:                            CustomData.UNINSTALLER_LISTENER };
2361:                    for (int i = 0; i < typeNames.length; ++i) {
2362:                        String className = xmlAction.getAttribute(typeNames[i]);
2363:                        if (className != null) {
2364:                            // Check for a jar attribute on the listener
2365:                            String jarPath = xmlAction.getAttribute("jar");
2366:                            jarPath = compiler.replaceProperties(jarPath);
2367:                            if (jarPath == null)
2368:                                jarPath = "bin/customActions/" + className
2369:                                        + ".jar";
2370:                            List<OsConstraint> constraints = OsConstraint
2371:                                    .getOsList(xmlAction);
2372:                            compiler.addCustomListener(types[i], className,
2373:                                    jarPath, constraints);
2374:                        }
2375:                    }
2376:                }
2377:
2378:            }
2379:
2380:            /**
2381:             * Returns a list which contains the pathes of all files which are included in the given url.
2382:             * This method expects as the url param a jar.
2383:             * 
2384:             * @param url url of the jar file
2385:             * @return full qualified paths of the contained files
2386:             * @throws Exception
2387:             */
2388:            private List<String> getContainedFilePaths(URL url)
2389:                    throws Exception {
2390:                JarInputStream jis = new JarInputStream(url.openStream());
2391:                ZipEntry zentry = null;
2392:                ArrayList<String> fullNames = new ArrayList<String>();
2393:                while ((zentry = jis.getNextEntry()) != null) {
2394:                    String name = zentry.getName();
2395:                    // Add only files, no directory entries.
2396:                    if (!zentry.isDirectory())
2397:                        fullNames.add(name);
2398:                }
2399:                jis.close();
2400:                return (fullNames);
2401:            }
2402:
2403:            /**
2404:             * Returns the qualified class name for the given class. This method expects as the url param a
2405:             * jar file which contains the given class. It scans the zip entries of the jar file.
2406:             * 
2407:             * @param url url of the jar file which contains the class
2408:             * @param className short name of the class for which the full name should be resolved
2409:             * @return full qualified class name
2410:             * @throws IOException 
2411:             */
2412:            private String getFullClassName(URL url, String className)
2413:                    throws IOException //throws Exception
2414:            {
2415:                JarInputStream jis = new JarInputStream(url.openStream());
2416:                ZipEntry zentry = null;
2417:                while ((zentry = jis.getNextEntry()) != null) {
2418:                    String name = zentry.getName();
2419:                    int lastPos = name.lastIndexOf(".class");
2420:                    if (lastPos < 0) {
2421:                        continue; // No class file.
2422:                    }
2423:                    name = name.replace('/', '.');
2424:                    int pos = -1;
2425:                    int nonCasePos = -1;
2426:                    if (className != null) {
2427:                        pos = name.indexOf(className);
2428:                        nonCasePos = name.toLowerCase().indexOf(
2429:                                className.toLowerCase());
2430:                    }
2431:                    if (pos != -1
2432:                            && name.length() == pos + className.length() + 6) // "Main" class found
2433:                    {
2434:                        jis.close();
2435:                        return (name.substring(0, lastPos));
2436:                    }
2437:
2438:                    if (nonCasePos != -1
2439:                            && name.length() == nonCasePos + className.length()
2440:                                    + 6)
2441:                        // "Main" class with different case found
2442:                        throw new IllegalArgumentException(
2443:                                "Fatal error! The declared panel name in the xml file ("
2444:                                        + className
2445:                                        + ") differs in case to the founded class file ("
2446:                                        + name + ").");
2447:                }
2448:                jis.close();
2449:                return (null);
2450:            }
2451:
2452:            /**
2453:             * Returns the compiler listener which is defined in the xml element. As
2454:             * xml element a "listner" node will be expected. Additional it is expected,
2455:             * that either "findIzPackResource" returns an url based on
2456:             * "bin/customActions/[className].jar", or that the listener element has
2457:             * a jar attribute specifying the listener jar path. The class will be
2458:             * loaded via an URLClassLoader.
2459:             * 
2460:             * @param var the xml element of the "listener" node
2461:             * @return instance of the defined compiler listener
2462:             * @throws Exception
2463:             */
2464:            private Object[] getCompilerListenerInstance(XMLElement var)
2465:                    throws Exception {
2466:                String className = var.getAttribute("compiler");
2467:                Class listener = null;
2468:                Object instance = null;
2469:                if (className == null)
2470:                    return (null);
2471:
2472:                // CustomAction files come in jars packaged IzPack, or they can be
2473:                // specified via a jar attribute on the listener
2474:                String jarPath = var.getAttribute("jar");
2475:                jarPath = compiler.replaceProperties(jarPath);
2476:                if (jarPath == null)
2477:                    jarPath = "bin/customActions/" + className + ".jar";
2478:                URL url = findIzPackResource(jarPath, "CustomAction jar file",
2479:                        var);
2480:                String fullName = getFullClassName(url, className);
2481:                if (fullName == null) {
2482:                    // class not found
2483:                    return null;
2484:                }
2485:                if (url != null) {
2486:                    if (getClass().getResource("/" + jarPath) != null) { // Oops, standalone, URLClassLoader will not work ...
2487:                        // Write the jar to a temp file.
2488:                        InputStream in = null;
2489:                        FileOutputStream outFile = null;
2490:                        byte[] buffer = new byte[5120];
2491:                        File tf = null;
2492:                        try {
2493:                            tf = File.createTempFile("izpj", ".jar");
2494:                            tf.deleteOnExit();
2495:                            outFile = new FileOutputStream(tf);
2496:                            in = getClass().getResourceAsStream("/" + jarPath);
2497:                            long bytesCopied = 0;
2498:                            int bytesInBuffer;
2499:                            while ((bytesInBuffer = in.read(buffer)) != -1) {
2500:                                outFile.write(buffer, 0, bytesInBuffer);
2501:                                bytesCopied += bytesInBuffer;
2502:                            }
2503:                        } finally {
2504:                            if (in != null)
2505:                                in.close();
2506:                            if (outFile != null)
2507:                                outFile.close();
2508:                        }
2509:                        url = tf.toURL();
2510:
2511:                    }
2512:                    // Use the class loader of the interface as parent, else
2513:                    // compile will fail at using it via an Ant task.
2514:                    URLClassLoader ucl = new URLClassLoader(new URL[] { url },
2515:                            CompilerListener.class.getClassLoader());
2516:                    listener = ucl.loadClass(fullName);
2517:                }
2518:                if (listener != null)
2519:                    instance = listener.newInstance();
2520:                else
2521:                    parseError(var, "Cannot find defined compiler listener "
2522:                            + className);
2523:                if (!CompilerListener.class.isInstance(instance))
2524:                    parseError(var, "'" + className + "' must be implemented "
2525:                            + CompilerListener.class.toString());
2526:                List<OsConstraint> constraints = OsConstraint.getOsList(var);
2527:                return (new Object[] { instance, className, constraints });
2528:            }
2529:
2530:            /**
2531:             * Add a CompilerListener. A registered CompilerListener will be called at every enhancmend
2532:             * point of compiling.
2533:             * 
2534:             * @param pe CompilerListener which should be added
2535:             */
2536:            private void addCompilerListener(CompilerListener pe) {
2537:                compilerListeners.add(pe);
2538:            }
2539:
2540:            /**
2541:             * Calls all defined compile listeners notify method with the given data
2542:             * 
2543:             * @param callerName name of the calling method as string
2544:             * @param state CompileListener.BEGIN or END
2545:             * @param data current install data
2546:             * @throws CompilerException
2547:             */
2548:            private void notifyCompilerListener(String callerName, int state,
2549:                    XMLElement data) throws CompilerException {
2550:                Iterator<CompilerListener> i = compilerListeners.iterator();
2551:                IPackager packager = compiler.getPackager();
2552:                while (i != null && i.hasNext()) {
2553:                    CompilerListener listener = i.next();
2554:                    listener.notify(callerName, state, data, packager);
2555:                }
2556:
2557:            }
2558:
2559:            /**
2560:             * Calls the reviseAdditionalDataMap method of all registered CompilerListener's.
2561:             * 
2562:             * @param f file releated XML node
2563:             * @return a map with the additional attributes
2564:             */
2565:            private Map getAdditionals(XMLElement f) throws CompilerException {
2566:                Iterator<CompilerListener> i = compilerListeners.iterator();
2567:                Map retval = null;
2568:                try {
2569:                    while (i != null && i.hasNext()) {
2570:                        retval = (i.next()).reviseAdditionalDataMap(retval, f);
2571:                    }
2572:                } catch (CompilerException ce) {
2573:                    parseError(f, ce.getMessage());
2574:                }
2575:                return (retval);
2576:            }
2577:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.