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