View Javadoc

1    /*
2     * This is free software; you can redistribute it and/or modify it
3     * under the terms of the GNU Lesser General Public License as
4     * published by the Free Software Foundation; either version 2.1 of
5     * the License, or (at your option) any later version.
6     *
7     * This software is distributed in the hope that it will be useful,
8     * but WITHOUT ANY WARRANTY; without even the implied warranty of
9     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10    * Lesser General Public License for more details.
11    *
12    * You should have received a copy of the GNU Lesser General Public
13    * License along with this software; if not, write to the Free
14    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
15    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
16    */
17  
18  package installtoolkit;
19  
20  import java.io.BufferedReader;
21  import java.io.File;
22  import java.io.IOException;
23  import java.io.StringReader;
24  import java.util.ArrayList;
25  import java.util.List;
26  
27  import javax.xml.parsers.ParserConfigurationException;
28  
29  import org.apache.tools.ant.BuildException;
30  import org.apache.tools.ant.Task;
31  import org.apache.tools.ant.taskdefs.Copy;
32  import org.apache.tools.ant.types.FileSet;
33  import org.dom4j.Document;
34  import org.dom4j.DocumentException;
35  import org.dom4j.Element;
36  import org.dom4j.io.SAXReader;
37  import org.xml.sax.SAXException;
38  
39  /**
40   * Base class for installer-builder tasks. <br/>
41   * This class holds common functions for all install-builder 
42   * tasks and handles the reading of the descriptorfile.
43   *
44   * 
45   * @author Christian Elberfeld <elberfeld@web.de>
46   *
47   */
48  public abstract class InstallerGeneratorTask extends Task {
49  
50  	/** The XML Namespace of the desriptor file */
51  	public static final String DESCRIPTOR_NAMESPACE = "http://install-toolkit.sourceforge.net/InstallerDescription";
52  	
53  	protected boolean debug = false;
54  	protected String version;
55  	protected File descriptor;
56  	protected File destdir;
57  	protected File workdir;
58  	protected boolean validate = true;
59  	protected File schema;
60  	
61  	protected String packageName;
62  	protected String manufacturer;
63  	protected String email;
64  	protected String shortDescription;
65  	protected List<String> longDescription;
66  	protected List<String> license;
67  	
68  	
69  	// -- [ Task execution ] -------------------------------------------
70  		
71  	/**
72  	 * The execute method reads the descriptor file and executes the 
73  	 * logic of the concrete class by calling the build() method.
74  	 * 
75  	 * @see Task#execute()
76  	 */
77  	@Override
78  	public void execute() throws BuildException {
79  
80  		try {
81  			
82  			if (debug) handleOutput("Starting execute()");
83  			
84  			if (this.version == null) throw new BuildException("Attribute \"version\" must be set");		
85  			if (this.descriptor == null) throw new BuildException("Attribute \"descriptor\" must be set");		
86  			if (this.destdir == null) throw new BuildException("Attribute \"destdir\" must be set");		
87  			if (this.workdir == null) throw new BuildException("Attribute \"workdir\" must be set");		
88  			if (this.schema == null) throw new BuildException("Attribute \"schema\" must be set");		
89  				
90  			readDescriptorFile();
91  			build();
92  	 
93  			if (debug) handleOutput("execute() finished");
94  			
95  		} catch (Exception e) {
96  			
97  			e.printStackTrace();
98  			throw new BuildException(e.getMessage(),e);
99  		}
100 		
101 	} // excecute()
102 
103 	/**
104 	 * The build() method must be overridden by the concrete install-builder 
105 	 * classes.
106 	 * 
107 	 * @throws Exception
108 	 */
109 	protected abstract void build() throws Exception;
110 
111 
112 	// -- [ Decriptor file reading ] -------------------------------------------
113 	
114 	private void readDescriptorFile() throws SAXException, DocumentException, IOException, ParserConfigurationException  {
115 	
116 		
117 		if (debug) handleOutput("Reading Descriptor file: "+this.descriptor);
118 		
119 		SAXReader reader = new SAXReader();
120 		reader.setFeature("http://apache.org/xml/features/validation/schema", this.validate);
121 		reader.setProperty("http://apache.org/xml/properties/schema/external-schemaLocation", DESCRIPTOR_NAMESPACE + " " + this.schema.getAbsolutePath());
122 		Document doc = reader.read(descriptor);
123 		 
124 		Element root = doc.getRootElement();
125 		if (debug) handleOutput("Reading Tag <Installer> ...");
126 		
127 		for (Object obj : root.elements()) {
128 			
129 			Element element = (Element) obj;
130 			
131 			if (element.getName() == "Package") {
132 				
133 				this.packageName = element.attributeValue("Name");
134 				if (debug) handleOutput("Package -> Name: "+this.packageName);
135 				
136 				 this.manufacturer = element.attributeValue("Manufacturer");
137 				 if (debug) handleOutput("Package -> Manufacturer: "+this.manufacturer);
138 
139 				 this.email = element.attributeValue("Email");
140 				 if (debug) handleOutput("Package -> Email: "+this.email);
141 
142 			}
143 			
144 			
145 			if (element.getName() == "Description") {
146 
147 				if (debug) handleOutput("Reading Tag: Description ...");
148 				readDescription(element);
149 			}
150 			
151 			
152 			if (element.getName() == "License") {
153 				
154 				 
155 				 BufferedReader license_reader = new BufferedReader(new StringReader(element.getText()));
156 				
157 				 this.license = new ArrayList<String>();
158 				 
159 				 String line = license_reader.readLine();		 
160 				 
161 				 while(line != null) {
162 					 
163 					 String l = line.trim();				 
164 					 if (debug) handleOutput("License (Line): "+l);
165 					 this.license.add(l);
166 									
167 					 line = license_reader.readLine();
168 				 }
169 				 
170 			} // if
171 						
172 			if (element.getName() == "Windows") {
173 				
174 				if (debug) handleOutput("Reading Tag: Windows ...");
175 				readWindowsTag(element);
176 			}
177 			
178 			if (element.getName() == "Deb") {
179 				
180 				if (debug) handleOutput("Reading Tag: Deb ...");
181 				readDebTag(element);
182 			}
183 			
184 		} // for
185 				 
186 		if (debug) handleOutput("Finished reading Descriptor file");
187 	}
188 	
189 	/**
190 	 * Helper method to read the &lt;Description&gt; tag.
191 	 * 
192 	 * @param root The &lt;Description&gt; element.
193 	 * @throws IOException 
194 	 */
195 	private void readDescription(Element root) throws IOException {
196 		
197 		for (Object obj : root.elements()) {
198 		
199 			Element element = (Element) obj;
200 			
201 			if (element.getName() == "Short") {
202 				
203 				 this.shortDescription = element.getText();
204 				 if (debug) handleOutput("Short Description: "+this.shortDescription);
205 			}
206 			
207 			if (element.getName() == "Long") {
208 				
209 				 BufferedReader desc_reader = new BufferedReader(new StringReader(element.getText()));
210 				 
211 				 this.longDescription = new ArrayList<String>();
212 				 
213 				 String line = desc_reader.readLine();
214 				 while(line != null) {
215 					 
216 					 String l = line.trim();
217 					 
218 					 if (l.length() > 0) {
219 				
220 						 if (debug) handleOutput("Long Description (Line): "+l);
221 						 this.longDescription.add(l);
222 					 }
223 					 
224 					 line = desc_reader.readLine();
225 				 }
226 				 
227 			} // if
228 			
229 		} // for
230 		
231 	} // readDescription()
232 	
233 	/**
234 	 * This method should be overridden if the task needs 
235 	 * informations from the &lt;Win&gt; element of the
236 	 * descriptor file.
237 	 * 
238 	 * @param root
239 	 */
240 	protected void readWindowsTag(Element root) {};
241 	
242 	/**
243 	 * This method should be overridden if the task needs 
244 	 * informations from the &lt;Deb&gt; element of the
245 	 * descriptor file.
246 	 * 
247 	 * @param root
248 	 */
249 	protected void readDebTag(Element root) {}
250 
251 	
252 	// -- [ Common functions ] -----------------------------------------------------
253 	
254 	/**
255 	 * Read patterns from the descriptor file
256 	 * 
257 	 * @param root The element containig &lt;Include&gt; and &lt;Exclude&gt; Elements as childs
258 	 * @returns The patterns as list of Pattern classes
259 	 * 
260 	 */
261 	protected List<Pattern> readPatterns(Element root) {
262 
263 		List<Pattern> patterns = new ArrayList<Pattern>();
264 		
265 		for (Object obj : root.elements()) {
266 
267 			Element element = (Element) obj;
268 			
269 			if (element.getName() == "Include") {
270 				
271 				Pattern pattern = new Pattern(element.getText(),false);
272 			    if (debug) handleOutput("Include Pattern: "+pattern);
273 			    patterns.add(pattern);
274 			}
275 			
276 			if (element.getName() == "Exclude") {
277 				
278 				Pattern pattern = new Pattern(element.getText(),true);
279 				if (debug) handleOutput("Exclude Pattern: "+pattern);
280 				patterns.add(pattern);
281 			}
282 			
283 		} // for
284 			
285 		return patterns;
286 		
287 	} // readPatterns()
288 	
289 		
290 	/**
291 	 * Create an Ant FileSet from a list of patterns
292 	 * 
293 	 * @param patterns List of Patterns
294 	 * @param dir The basedirectory for the fileset
295 	 * @return 
296 	 */
297 	protected FileSet createFilesetFromPatterns(List<Pattern> patterns,File dir) {
298 		
299 		FileSet fileset = new FileSet();
300 		
301 		if (debug) handleOutput("Creating FileSet [Basedir: "+dir.getAbsolutePath()+"]");
302 		fileset.setDir(dir);
303 		
304 		for (Pattern p : patterns) {
305 			
306 			if (p.isInvert()) {
307 				
308 				if (debug) handleOutput("Adding Exclude: "+p.getPattern());
309 				fileset.createExclude().setName(p.getPattern());
310 			
311 			} else {
312 				
313 				if (debug) handleOutput("Adding Include: "+p.getPattern());
314 				fileset.createInclude().setName(p.getPattern());
315 				
316 			} // if else
317 			
318 		} // for
319 				
320 		return fileset;
321 		
322 	} //createConfigsFileset()
323 	
324 	
325 	/**
326 	 * Copy a file
327 	 * 
328 	 * @param src Source file
329 	 * @param dst Destination file
330 	 */
331 	protected void copy(File src, File dst) {
332 		
333 		Copy copy_task = new Copy();
334 		copy_task.setProject(getProject());
335 		copy_task.setTaskName("copy");
336 		copy_task.setVerbose(this.debug);
337 		copy_task.setFile(src);
338 		copy_task.setTofile(dst);
339 		copy_task.execute();		
340 		
341 	} //copy()
342 
343 
344 	// -- [ Getter/Setter ] -------------------------------------------
345 	
346 	/**
347 	 * Enable debug output
348 	 * 
349 	 * @param debug
350 	 */
351 	public void setDebug(boolean debug) {
352 		this.debug = debug;
353 	}
354 
355 
356 	/**
357 	 * The descriptor file to read
358 	 * 
359 	 * @param descriptor
360 	 */
361 	public void setDescriptor(File descriptor) {
362 		this.descriptor = descriptor;
363 	}
364 
365 
366 	/**
367 	 * The version number of the generatd installer package
368 	 * 
369 	 * @param version
370 	 */
371 	public void setVersion(String version) {
372 		this.version = version;
373 	}
374 
375 	/**
376 	 * The XML Schema for the descriptor file
377 	 * 
378 	 * @param schema
379 	 */
380 	public void setSchema(File schema) {
381 		this.schema = schema;
382 	}
383 
384 	/**
385 	 * If false, the descriptor file will not be validated
386 	 * 
387 	 * @param validate
388 	 */
389 	public void setValidate(boolean validate) {
390 		this.validate = validate;
391 	}
392 
393 	/**
394 	 * The directory where the installer packge will be created
395 	 * 
396 	 * @param destdir
397 	 */
398 	public void setDestdir(File destdir) {
399 		this.destdir = destdir;
400 	}
401 
402 	/**
403 	 * The directory to compile the installer package
404 	 * 
405 	 * @param workdir
406 	 */
407 	public void setWorkdir(File workdir) {
408 		this.workdir = workdir;
409 	}
410 
411 
412 }