001/* 002 * IzPack - Copyright 2001-2005 Julien Ponge, All Rights Reserved. 003 * 004 * http://www.izforge.com/izpack/ 005 * http://developer.berlios.de/projects/izpack/ 006 * 007 * Copyright 2003 Jonathan Halliday 008 * 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 */ 021 022package com.izforge.izpack.installer; 023 024import java.io.BufferedWriter; 025import java.io.File; 026import java.io.FileInputStream; 027import java.io.InputStream; 028import java.io.ObjectOutputStream; 029import java.io.OutputStreamWriter; 030import java.util.Iterator; 031import java.util.List; 032import java.util.TreeMap; 033import java.util.Vector; 034import java.util.zip.ZipEntry; 035import java.util.zip.ZipOutputStream; 036 037import net.n3.nanoxml.NonValidator; 038import net.n3.nanoxml.StdXMLBuilder; 039import net.n3.nanoxml.StdXMLParser; 040import net.n3.nanoxml.StdXMLReader; 041import net.n3.nanoxml.XMLElement; 042 043import com.izforge.izpack.ExecutableFile; 044import com.izforge.izpack.LocaleDatabase; 045import com.izforge.izpack.Panel; 046import com.izforge.izpack.util.Housekeeper; 047import com.izforge.izpack.util.OsConstraint; 048 049/** 050 * Runs the install process in text only (no GUI) mode. 051 * 052 * @author Jonathan Halliday <jonathan.halliday@arjuna.com> 053 * @author Julien Ponge <julien@izforge.com> 054 * @author Johannes Lehtinen <johannes.lehtinen@iki.fi> 055 */ 056public class AutomatedInstaller extends InstallerBase 057{ 058 059 // there are panels which can be instantiated multiple times 060 // we therefore need to select the right XML section for each 061 // instance 062 private TreeMap panelInstanceCount; 063 064 /** The automated installation data. */ 065 private AutomatedInstallData idata = new AutomatedInstallData(); 066 067 /** 068 * Constructing an instance triggers the install. 069 * 070 * @param inputFilename Name of the file containing the installation data. 071 * @exception Exception Description of the Exception 072 */ 073 public AutomatedInstaller(String inputFilename) throws Exception 074 { 075 super(); 076 077 File input = new File(inputFilename); 078 079 // Loads the installation data 080 loadInstallData(idata); 081 082 // Loads the xml data 083 idata.xmlData = getXMLData(input); 084 085 // Loads the langpack 086 idata.localeISO3 = idata.xmlData.getAttribute("langpack", "eng"); 087 InputStream in = getClass().getResourceAsStream("/langpacks/" + idata.localeISO3 + ".xml"); 088 idata.langpack = new LocaleDatabase(in); 089 idata.setVariable(ScriptParser.ISO3_LANG, idata.localeISO3); 090 091 // create the resource manager singleton 092 ResourceManager.create(idata); 093 094 // Load custom langpack if exist. 095 addCustomLangpack(idata); 096 097 this.panelInstanceCount = new TreeMap(); 098 099 doInstall(idata); 100 } 101 102 /** 103 * Writes the uninstalldata. 104 * 105 * Unfortunately, Java doesn't allow multiple inheritance, so <code>AutomatedInstaller</code> 106 * and <code>InstallerFrame</code> can't share this code ... :-/ 107 * 108 * TODO: We should try to fix this in the future. 109 */ 110 private void writeUninstallData() 111 { 112 try 113 { 114 // We get the data 115 UninstallData udata = UninstallData.getInstance(); 116 List files = udata.getFilesList(); 117 ZipOutputStream outJar = idata.uninstallOutJar; 118 119 if (outJar == null) return; 120 121 System.out.println("[ Writing the uninstaller data ... ]"); 122 123 // We write the files log 124 outJar.putNextEntry(new ZipEntry("install.log")); 125 BufferedWriter logWriter = new BufferedWriter(new OutputStreamWriter(outJar)); 126 logWriter.write(idata.getInstallPath()); 127 logWriter.newLine(); 128 Iterator iter = files.iterator(); 129 while (iter.hasNext()) 130 { 131 logWriter.write((String) iter.next()); 132 if (iter.hasNext()) logWriter.newLine(); 133 } 134 logWriter.flush(); 135 outJar.closeEntry(); 136 137 // We write the uninstaller jar file log 138 outJar.putNextEntry(new ZipEntry("jarlocation.log")); 139 logWriter = new BufferedWriter(new OutputStreamWriter(outJar)); 140 logWriter.write(udata.getUninstallerJarFilename()); 141 logWriter.newLine(); 142 logWriter.write(udata.getUninstallerPath()); 143 logWriter.flush(); 144 outJar.closeEntry(); 145 146 // Write out executables to execute on uninstall 147 outJar.putNextEntry(new ZipEntry("executables")); 148 ObjectOutputStream execStream = new ObjectOutputStream(outJar); 149 iter = udata.getExecutablesList().iterator(); 150 execStream.writeInt(udata.getExecutablesList().size()); 151 while (iter.hasNext()) 152 { 153 ExecutableFile file = (ExecutableFile) iter.next(); 154 execStream.writeObject(file); 155 } 156 execStream.flush(); 157 outJar.closeEntry(); 158 159 // Cleanup 160 outJar.flush(); 161 outJar.close(); 162 } 163 catch (Exception err) 164 { 165 err.printStackTrace(); 166 } 167 } 168 169 /** 170 * Runs the automated installation logic for each panel in turn. 171 * 172 * @param installdata the installation data. 173 * @throws Exception 174 */ 175 private void doInstall(AutomatedInstallData installdata) throws Exception 176 { 177 // TODO: i18n 178 System.out.println("[ Starting automated installation ]"); 179 180 // walk the panels in order 181 Iterator panelsIterator = installdata.panelsOrder.iterator(); 182 while (panelsIterator.hasNext()) 183 { 184 Panel p = (Panel) panelsIterator.next(); 185 String praefix = "com.izforge.izpack.panels."; 186 if (p.className.compareTo(".") > -1) 187 // Full qualified class name 188 praefix = ""; 189 if (!OsConstraint.oneMatchesCurrentSystem(p.osConstraints)) continue; 190 191 String panelClassName = p.className; 192 String automationHelperClassName = praefix + panelClassName + "AutomationHelper"; 193 Class automationHelperClass = null; 194 // determine if the panel supports automated install 195 try 196 { 197 automationHelperClass = Class.forName(automationHelperClassName); 198 } 199 catch (ClassNotFoundException e) 200 { 201 // this is OK - not all panels have/need automation support. 202 continue; 203 } 204 205 // instantiate the automation logic for the panel 206 PanelAutomation automationHelperInstance = null; 207 if (automationHelperClass != null) 208 { 209 try 210 { 211 automationHelperInstance = (PanelAutomation) automationHelperClass 212 .newInstance(); 213 } 214 catch (Exception e) 215 { 216 System.err.println("ERROR: no default constructor for " 217 + automationHelperClassName + ", skipping..."); 218 continue; 219 } 220 } 221 222 // We get the panels root xml markup 223 Vector panelRoots = installdata.xmlData.getChildrenNamed(panelClassName); 224 int panelRootNo = 0; 225 226 if (this.panelInstanceCount.containsKey(panelClassName)) 227 { 228 // get number of panel instance to process 229 panelRootNo = ((Integer) this.panelInstanceCount.get(panelClassName)).intValue(); 230 } 231 232 XMLElement panelRoot = (XMLElement) panelRoots.elementAt(panelRootNo); 233 234 this.panelInstanceCount.put(panelClassName, new Integer(panelRootNo + 1)); 235 236 // execute the installation logic for the current panel, if it has 237 // any: 238 if (automationHelperInstance != null) 239 { 240 try 241 { 242 automationHelperInstance.runAutomated(installdata, panelRoot); 243 } 244 catch (Exception e) 245 { 246 System.err.println("ERROR: automated installation failed for panel " 247 + panelClassName); 248 e.printStackTrace(); 249 continue; 250 } 251 252 } 253 254 } 255 256 // this does nothing if the uninstaller was not included 257 writeUninstallData(); 258 259 System.out.println("[ Automated installation done ]"); 260 261 // Bye 262 Housekeeper.getInstance().shutDown(0); 263 } 264 265 /** 266 * Loads the xml data for the automated mode. 267 * 268 * @param input The file containing the installation data. 269 * @exception Exception thrown if there are problems reading the file. 270 */ 271 public XMLElement getXMLData(File input) throws Exception 272 { 273 FileInputStream in = new FileInputStream(input); 274 275 // Initialises the parser 276 StdXMLParser parser = new StdXMLParser(); 277 parser.setBuilder(new StdXMLBuilder()); 278 parser.setReader(new StdXMLReader(in)); 279 parser.setValidator(new NonValidator()); 280 281 XMLElement rtn = (XMLElement) parser.parse(); 282 in.close(); 283 284 return rtn; 285 } 286}