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 2004 Klaus Bartz 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.util; 023 024import java.io.File; 025import java.io.FileInputStream; 026import java.io.FileOutputStream; 027import java.io.InputStream; 028import java.util.Iterator; 029import java.util.Vector; 030 031import net.n3.nanoxml.NonValidator; 032import net.n3.nanoxml.StdXMLBuilder; 033import net.n3.nanoxml.StdXMLParser; 034import net.n3.nanoxml.StdXMLReader; 035import net.n3.nanoxml.XMLElement; 036 037import com.izforge.izpack.installer.InstallerException; 038import com.izforge.izpack.installer.ResourceManager; 039 040/** 041 * This class contains some helper methods to simplify handling of xml specification files. 042 * 043 * @author Klaus Bartz 044 * 045 */ 046public class SpecHelper 047{ 048 049 private String specFilename; 050 051 private XMLElement spec; 052 053 private boolean _haveSpec; 054 055 public static final String YES = "yes"; 056 057 public static final String NO = "no"; 058 059 private static final String PACK_KEY = "pack"; 060 061 private static final String PACK_NAME = "name"; 062 063 /** 064 * The default constructor. 065 */ 066 public SpecHelper() 067 { 068 super(); 069 } 070 071 /*--------------------------------------------------------------------------*/ 072 /** 073 * Reads the XML specification given by the file name. The result is stored in spec. 074 * 075 * @exception Exception for any problems in reading the specification 076 */ 077 /*--------------------------------------------------------------------------*/ 078 public void readSpec(String specFileName) throws Exception 079 { 080 readSpec(specFileName, null); 081 } 082 083 /*--------------------------------------------------------------------------*/ 084 /** 085 * Reads the XML specification given by the file name. The result is stored in spec. 086 * 087 * @exception Exception for any problems in reading the specification 088 */ 089 /*--------------------------------------------------------------------------*/ 090 public void readSpec(String specFileName, VariableSubstitutor substitutor) throws Exception 091 { 092 // open an input stream 093 InputStream input = null; 094 try 095 { 096 input = getResource(specFileName); 097 } 098 catch (Exception exception) 099 { 100 _haveSpec = false; 101 return; 102 } 103 if (input == null) 104 { 105 _haveSpec = false; 106 return; 107 } 108 109 readSpec(input, substitutor); 110 111 // close the stream 112 input.close(); 113 this.specFilename = specFileName; 114 } 115 116 /*--------------------------------------------------------------------------*/ 117 /** 118 * Reads the XML specification given by the input stream. The result is stored in spec. 119 * 120 * @exception Exception for any problems in reading the specification 121 */ 122 /*--------------------------------------------------------------------------*/ 123 public void readSpec(InputStream input) throws Exception 124 { 125 readSpec(input, null); 126 } 127 128 /*--------------------------------------------------------------------------*/ 129 /** 130 * Reads the XML specification given by the input stream. The result is stored in spec. 131 * 132 * @exception Exception for any problems in reading the specification 133 */ 134 /*--------------------------------------------------------------------------*/ 135 public void readSpec(InputStream input, VariableSubstitutor substitutor) throws Exception 136 { 137 // first try to substitute the variables 138 if (substitutor != null) 139 { 140 input = substituteVariables(input, substitutor); 141 } 142 143 // initialize the parser 144 StdXMLParser parser = new StdXMLParser(); 145 parser.setBuilder(new StdXMLBuilder()); 146 parser.setValidator(new NonValidator()); 147 parser.setReader(new StdXMLReader(input)); 148 149 // get the data 150 spec = (XMLElement) parser.parse(); 151 _haveSpec = true; 152 } 153 154 /** 155 * Gets the stream to a resource. 156 * 157 * @param res The resource id. 158 * @return The resource value, null if not found 159 */ 160 public InputStream getResource(String res) 161 { 162 try 163 { 164 // System.out.println ("retrieving resource " + res); 165 return ResourceManager.getInstance().getInputStream(res); 166 } 167 catch (Exception e) 168 { // Cannot catch ResourceNotFoundException because it is not public. 169 return null; 170 } 171 } 172 173 /** 174 * Returns a XML element which represents the pack for the given name. 175 * 176 * @param packDestName name of the pack which should be returned 177 * @return a XML element which represents the pack for the given name 178 */ 179 public XMLElement getPackForName(String packDestName) 180 { 181 Vector packs = getSpec().getChildrenNamed(PACK_KEY); 182 Iterator iter = null; 183 if (packs == null) return (null); 184 iter = packs.iterator(); 185 while (iter.hasNext()) 186 { 187 188 XMLElement pack = (XMLElement) iter.next(); 189 String packName = pack.getAttribute(PACK_NAME); 190 if (packName.equals(packDestName)) return (pack); 191 } 192 return (null); 193 194 } 195 196 /** 197 * Create parse error with consistent messages. Includes file name and line # of parent. It is 198 * an error for 'parent' to be null. 199 * 200 * @param parent The element in which the error occured 201 * @param message Brief message explaining error 202 */ 203 public void parseError(XMLElement parent, String message) throws InstallerException 204 { 205 throw new InstallerException(specFilename + ":" + parent.getLineNr() + ": " + message); 206 } 207 208 /** 209 * Returns true if a specification exist, else false. 210 * 211 * @return true if a specification exist, else false 212 */ 213 public boolean haveSpec() 214 { 215 return _haveSpec; 216 } 217 218 /** 219 * Returns the specification. 220 * 221 * @return the specification 222 */ 223 public XMLElement getSpec() 224 { 225 return spec; 226 } 227 228 /** 229 * Sets the specifaction to the given XML element. 230 * 231 * @param element 232 */ 233 public void setSpec(XMLElement element) 234 { 235 spec = element; 236 } 237 238 /** 239 * Returns a Vector with all leafs of the tree which is described with childdef. 240 * 241 * @param root the XMLElement which is the current root for the search 242 * @param childdef a String array which describes the tree; the last element contains the leaf 243 * name 244 * @return a Vector of XMLElements of all leafs founded under root 245 */ 246 public Vector getAllSubChildren(XMLElement root, String[] childdef) 247 { 248 return (getSubChildren(root, childdef, 0)); 249 } 250 251 /** 252 * Returns a Vector with all leafs of the tree which is described with childdef beginning at the 253 * given depth. 254 * 255 * @param root the XMLElement which is the current root for the search 256 * @param childdef a String array which describes the tree; the last element contains the leaf 257 * name 258 * @param depth depth to start in childdef 259 * @return a Vector of XMLElements of all leafs founded under root 260 */ 261 private Vector getSubChildren(XMLElement root, String[] childdef, int depth) 262 { 263 Vector retval = null; 264 Vector retval2 = null; 265 Vector children = root != null ? root.getChildrenNamed(childdef[depth]) : null; 266 if (children == null) return (null); 267 if (depth < childdef.length - 1) 268 { 269 Iterator iter = children.iterator(); 270 while (iter.hasNext()) 271 { 272 retval2 = getSubChildren((XMLElement) iter.next(), childdef, depth + 1); 273 if (retval2 != null) 274 { 275 if (retval == null) retval = new Vector(); 276 retval.addAll(retval2); 277 } 278 } 279 } 280 else 281 return (children); 282 return (retval); 283 } 284 285 /** 286 * Creates an temp file in to the substitutor the substituted contents of input writes; close it 287 * and (re)open it as FileInputStream. The file will be deleted on exit. 288 * 289 * @param input the opened input stream which contents should be substituted 290 * @param substitutor substitutor which should substitute the contents of input 291 * @return a file input stream of the created temporary file 292 * @throws Exception 293 */ 294 public InputStream substituteVariables(InputStream input, VariableSubstitutor substitutor) 295 throws Exception 296 { 297 File tempFile = File.createTempFile("izpacksubs", ""); 298 FileOutputStream fos = null; 299 tempFile.deleteOnExit(); 300 try 301 { 302 fos = new FileOutputStream(tempFile); 303 substitutor.substitute(input, fos, null, null); 304 } 305 finally 306 { 307 if (fos != null) fos.close(); 308 } 309 return new FileInputStream(tempFile); 310 } 311 312 /** 313 * Returns whether the value to the given attribute is "yes" or not. If the attribute does not 314 * exist, or the value is not "yes" and not "no", the default value is returned. 315 * 316 * @param element the XML element which contains the attribute 317 * @param attribute the name of the attribute 318 * @param defaultValue the default value 319 * @return whether the value to the given attribute is "yes" or not 320 */ 321 public boolean isAttributeYes(XMLElement element, String attribute, boolean defaultValue) 322 { 323 String value = element.getAttribute(attribute, (defaultValue ? YES : NO)); 324 if (value.equalsIgnoreCase(YES)) return true; 325 if (value.equalsIgnoreCase(NO)) return false; 326 327 return defaultValue; 328 } 329 330 /** 331 * Returns the attribute for the given attribute name. If no attribute exist, an 332 * InstallerException with a detail message is thrown. 333 * 334 * @param element XML element which should contain the attribute 335 * @param attrName key of the attribute 336 * @return the attribute as string 337 * @throws Exception 338 */ 339 public String getRequiredAttribute(XMLElement element, String attrName) 340 throws InstallerException 341 { 342 String attr = element.getAttribute(attrName); 343 if (attr == null) 344 { 345 parseError(element, "<" + element.getName() + "> requires attribute '" + attrName 346 + "'."); 347 } 348 return (attr); 349 } 350}