source: other-projects/trunk/realistic-books/packages/AntInstaller/src/org/tp23/antinstaller/runtime/exe/LoadConfigFilter.java@ 19253

Last change on this file since 19253 was 19253, checked in by davidb, 15 years ago

Establishing a source code repository for Veronica's Realistic Book's software

File size: 16.7 KB
Line 
1/*
2 * Copyright 2005 Paul Hinds
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.tp23.antinstaller.runtime.exe;
17
18import java.io.File;
19import java.io.FileInputStream;
20import java.io.IOException;
21import java.io.InputStream;
22import java.lang.reflect.InvocationTargetException;
23import java.lang.reflect.Method;
24import java.util.ArrayList;
25
26import javax.xml.parsers.DocumentBuilder;
27import javax.xml.parsers.DocumentBuilderFactory;
28
29import org.tp23.antinstaller.InstallException;
30import org.tp23.antinstaller.Installer;
31import org.tp23.antinstaller.InstallerContext;
32import org.tp23.antinstaller.input.AppRootInput;
33import org.tp23.antinstaller.input.CheckboxInput;
34import org.tp23.antinstaller.input.CommentOutput;
35import org.tp23.antinstaller.input.ConditionalField;
36import org.tp23.antinstaller.input.ConfirmPasswordTextInput;
37import org.tp23.antinstaller.input.DateInput;
38import org.tp23.antinstaller.input.DirectoryInput;
39import org.tp23.antinstaller.input.ExtValidatedTextInput;
40import org.tp23.antinstaller.input.FileInput;
41import org.tp23.antinstaller.input.HiddenPropertyInput;
42import org.tp23.antinstaller.input.InputField;
43import org.tp23.antinstaller.input.LargeSelectInput;
44import org.tp23.antinstaller.input.OutputField;
45import org.tp23.antinstaller.input.PasswordTextInput;
46import org.tp23.antinstaller.input.SelectInput;
47import org.tp23.antinstaller.input.TargetInput;
48import org.tp23.antinstaller.input.TargetSelectInput;
49import org.tp23.antinstaller.input.UnvalidatedTextInput;
50import org.tp23.antinstaller.input.ValidatedTextInput;
51import org.tp23.antinstaller.page.LicensePage;
52import org.tp23.antinstaller.page.Page;
53import org.tp23.antinstaller.page.ProgressPage;
54import org.tp23.antinstaller.page.SimpleInputPage;
55import org.tp23.antinstaller.page.SplashPage;
56import org.tp23.antinstaller.page.TextPage;
57import org.tp23.antinstaller.runtime.ConfigurationException;
58import org.w3c.dom.Document;
59import org.w3c.dom.Element;
60import org.w3c.dom.NamedNodeMap;
61import org.w3c.dom.Node;
62import org.w3c.dom.NodeList;
63import org.xml.sax.EntityResolver;
64import org.xml.sax.InputSource;
65
66
67/**
68 * Loads the Ant Install configuration and sets the Installer object back
69 * into the context. A similar technique to the apache digester is used to
70 * populate object attributes in this class.
71 * N.B. The only types that can be set for object attributes are Strings, booleans
72 * or ints.
73 * @author Paul Hinds
74 * @version $Id: LoadConfigFilter.java,v 1.9 2007/01/28 08:44:39 teknopaul Exp $
75 */
76public class LoadConfigFilter implements ExecuteFilter {
77
78 //TODO move to InstallerContext
79 public static final String INSTALLER_CONFIG_FILE = "antinstall-config.xml";
80
81 protected Installer installer = new Installer();
82 protected InstallerContext ctx;
83
84 /**
85 * @see org.tp23.antinstaller.runtime.exe.ExecuteFilter#exec(org.tp23.antinstaller.InstallerContext)
86 */
87 public void exec(InstallerContext ctx) throws InstallException {
88 this.ctx = ctx;
89
90 try {
91 installer = readConfig(ctx.getFileRoot(), ctx.getInstallerConfigFile());
92 ctx.setInstaller(installer);
93 ctx.log("Config loaded");
94 }
95 catch (IOException e) {
96 throw new InstallException("Not able to load and read the AntInstaller config", e);
97 }
98 catch (ConfigurationException e) {
99 throw new InstallException("Not able to load and read the AntInstaller config", e);
100 }
101 }
102
103 /**
104 * Currently read the config using any available XML parser
105 * This method reads the config from the file system
106 * @param fileRoot The directory where the config file is stored
107 * @param the name of the configuration file (usually antinstall-config.xml)
108 * @return Installer
109 */
110 public Installer readConfig(File fileRoot, String fileName) throws IOException, ConfigurationException {
111
112 installer.getResultContainer().setInstallRoot(fileRoot);
113
114 File config = new File(fileRoot, fileName);
115 if(!config.exists()){ // passed in incorrectly on the command line or bad installer
116 throw new IOException();
117 }
118 InputSource xmlInp = new InputSource(new FileInputStream(config));
119 readConfig(xmlInp);
120
121 return installer;
122 }
123 /**
124 * This overloaded method reads from the provided input stream to facilitate
125 * reading configs directly from the Jar, the file root is still needed
126 * for Ant's basedir. Used by InputStreamLoadConfigFilter
127 * @return Installer
128 */
129 protected Installer readConfig(File fileRoot, InputStream configSource) throws IOException, ConfigurationException {
130
131 installer.getResultContainer().setInstallRoot(fileRoot);
132
133 InputSource xmlInp = new InputSource(configSource);
134 readConfig(xmlInp);
135
136 return installer;
137 }
138 /**
139 * Currently read the config using any available XML parser
140 * @todo read the installer with only xerces
141 * @return Installer
142 */
143 protected Installer readConfig(InputSource xmlInp) throws IOException, ConfigurationException {
144
145 Document doc = null;
146 try {
147
148 DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
149 DocumentBuilder parser = docBuilderFactory.newDocumentBuilder();
150
151 // RFE [ 1475361 ] Using a custom entity resolver
152 String entityResolverClass = System.getProperty("antinstaller.EntityResolverClass");
153 EntityResolver er = null;
154 if(entityResolverClass != null){
155 try{
156 er = (EntityResolver)Class.forName(entityResolverClass).newInstance();
157 }
158 catch(Exception e){
159 // Property error use default this is a very specific requirement
160 er = new CustomEntityResolver();
161 }
162 }
163 else{
164 er = new CustomEntityResolver();
165 }
166
167 parser.setEntityResolver(er);
168
169 doc = parser.parse(xmlInp);
170 Element root = doc.getDocumentElement();
171 root.normalize();
172 setProperties(installer, root.getAttributes());
173 NodeList allPages = root.getElementsByTagName("page");
174 //TODO make this pluggable
175 getPages(installer, allPages);
176
177 }
178 catch (Exception e) {
179 throw new IOException("DomFactory error: caused by:" + e.getClass() + ":" + e.getMessage());
180 }
181 return installer;
182 }
183
184
185 /**
186 * Used when reading the config
187 * @param allPages NodeList
188 * @throws ConfigurationException
189 */
190 private void getPages(Installer installerConfig, NodeList allPages) throws ConfigurationException {
191 ArrayList pages = new ArrayList();
192 for (int i = 0; i < allPages.getLength(); i++) {
193 Element pageElem = (Element) allPages.item(i);
194 Page page = getPageType(pageElem.getAttribute("type"));
195 setProperties(page, pageElem.getAttributes());
196 pages.add(page);
197 getOutputFields(page, pageElem);
198 }
199 Page[] pageArr = new Page[pages.size()];
200 pages.toArray(pageArr);
201 installerConfig.setPages(pageArr);
202 }
203 /**
204 * Used when reading the config
205 * @param page Page
206 * @param pageElem Element
207 * @throws ConfigurationException
208 */
209 private void getOutputFields(Page page, Element pageElem) throws ConfigurationException {
210 page.setOutputField( getInnerOutputFields( pageElem ));
211 }
212
213 private OutputField[] getInnerOutputFields( Element elem) throws ConfigurationException {
214 NodeList allFields = elem.getChildNodes();
215 ArrayList fields = new ArrayList();
216 for (int i = 0; i < allFields.getLength(); i++) {
217 if(! (allFields.item(i) instanceof Element))continue;
218 Element fieldElem = (Element)allFields.item(i);
219 OutputField field = getOutputFieldType(fieldElem.getNodeName(), fieldElem);
220 if(field != null){
221 setProperties(field, fieldElem.getAttributes());
222 fields.add(field);
223 field.setResultContainer(installer.getResultContainer());
224 }
225 }
226 OutputField[] fieldArr = new OutputField[fields.size()];
227
228 return (OutputField[])fields.toArray(fieldArr);
229 }
230
231 /**
232 * Used when reading the config
233 * @param type String
234 * @throws ConfigurationException
235 * @return Page
236 */
237 private Page getPageType(String type) throws ConfigurationException {
238 if (type.equalsIgnoreCase("license")) {
239 return new LicensePage();
240 }
241 else if (type.equalsIgnoreCase("input")) {
242 return new SimpleInputPage();
243 }
244 else if (type.equalsIgnoreCase("progress")) {
245 return new ProgressPage();
246 }
247 else if (type.equalsIgnoreCase("splash")) {
248 return new SplashPage();
249 }
250 else if (type.equalsIgnoreCase("text")) {
251 return new TextPage();
252 }
253 throw new ConfigurationException("Unknown Page type:" + type);
254 }
255 /**
256 * Used when reading the config
257 * @param type String
258 * @param field Element
259 * @throws ConfigurationException
260 * @return InputField
261 */
262 private OutputField getOutputFieldType(String type, Element field) throws ConfigurationException {
263 if (type.equalsIgnoreCase("text")) {
264 return new UnvalidatedTextInput();
265 }
266 else if (type.equalsIgnoreCase("directory")) {
267 return new DirectoryInput();
268 }
269 else if (type.equalsIgnoreCase("target")) {
270 return new TargetInput();
271 }
272 else if (type.equalsIgnoreCase("file")) {
273 return new FileInput();
274 }
275 else if (type.equalsIgnoreCase("comment")) {
276 return new CommentOutput();
277 }
278 else if (type.equalsIgnoreCase("checkbox")) {
279 return new CheckboxInput();
280 }
281 else if (type.equalsIgnoreCase("validated")) {
282 return new ValidatedTextInput();
283 }
284 else if (type.equalsIgnoreCase("ext-validated")) {
285 return new ExtValidatedTextInput();
286 }
287 else if (type.equalsIgnoreCase("password")) {
288 return new PasswordTextInput();
289 }
290 else if (type.equalsIgnoreCase("password-confirm")) {
291 return new ConfirmPasswordTextInput();
292 }
293 else if (type.equalsIgnoreCase("hidden")) {
294 return new HiddenPropertyInput();
295 }
296 else if (type.equalsIgnoreCase("date")) {
297 return new DateInput();
298 }
299 else if (type.equalsIgnoreCase("app-root")) {
300 return new AppRootInput();
301 }
302 else if (type.equalsIgnoreCase("conditional")) {
303 ConditionalField conditionalField = new ConditionalField();
304 OutputField[] outFields = getInnerOutputFields( field );
305 InputField[] inFields = new InputField[ outFields.length ];
306 for( int i = 0; i < outFields.length; i++ ) {
307 inFields[i] = (InputField) outFields[i];
308 }
309 conditionalField.setFields( inFields );
310 return conditionalField;
311 }
312 else if (type.equalsIgnoreCase("select")) {
313 SelectInput sInput = new SelectInput();
314 NodeList allOptions = field.getElementsByTagName("option");
315 ArrayList options = new ArrayList();
316 for (int i = 0; i < allOptions.getLength(); i++) {
317 Element optionElem = (Element) allOptions.item(i);
318 SelectInput.Option option = sInput.getNewOption();
319 option.setText(optionElem.getAttribute("text"));
320 option.value = optionElem.getAttribute("value");
321 options.add(option);
322 }
323 SelectInput.Option[] optionArr = new SelectInput.Option[options.size()];
324 options.toArray(optionArr);
325 sInput.setOptions(optionArr);
326
327 return sInput;
328 }
329 else if (type.equalsIgnoreCase("target-select")) {
330 TargetSelectInput sInput = new TargetSelectInput();
331 NodeList allOptions = field.getElementsByTagName("option");
332 ArrayList options = new ArrayList();
333 for (int i = 0; i < allOptions.getLength(); i++) {
334 Element optionElem = (Element) allOptions.item(i);
335 SelectInput.Option option = sInput.getNewOption();
336 option.setText(optionElem.getAttribute("text"));
337 option.value = optionElem.getAttribute("value");
338 options.add(option);
339 }
340 SelectInput.Option[] optionArr = new SelectInput.Option[options.size()];
341 options.toArray(optionArr);
342 sInput.setOptions(optionArr);
343
344 return sInput;
345 }
346 else if (type.equalsIgnoreCase("large-select")) {
347 LargeSelectInput sInput = new LargeSelectInput();
348 NodeList allOptions = field.getElementsByTagName("option");
349 ArrayList options = new ArrayList();
350 for (int i = 0; i < allOptions.getLength(); i++) {
351 Element optionElem = (Element) allOptions.item(i);
352 LargeSelectInput.Option option = sInput.getNewOption();
353 option.setText(optionElem.getAttribute("text"));
354 option.value = optionElem.getAttribute("value");
355 options.add(option);
356 }
357 LargeSelectInput.Option[] optionArr = new LargeSelectInput.Option[options.size()];
358 options.toArray(optionArr);
359 sInput.setOptions(optionArr);
360
361 return sInput;
362 }
363 System.out.println("Unrecognised Input Element:"+type);
364 return null;
365 //throw new ConfigurationException("Unknown Input Field type:" + type);
366 }
367
368
369
370 /**
371 * Calls bean setter methods based on attribures found. Could use BeanUtils here
372 * but we want to stay clear of external dependencies.
373 * @param bean Object
374 * @param map NamedNodeMap
375 */
376 private void setProperties(Object bean, NamedNodeMap map) {
377 int numAtts = map.getLength();
378 for (int a = 0; a < numAtts; a++) {
379 Node attribute = map.item(a);
380 String name = attribute.getNodeName();
381 String value = attribute.getNodeValue();
382 String methodName = "set" + Character.toUpperCase(name.charAt(0)) + name.substring(1);
383 Method[] allMethods = bean.getClass().getMethods();
384 for (int m = 0; m < allMethods.length; m++) {
385 if (allMethods[m].getName().equals(methodName)) {
386 try {
387 Class[] parameters = allMethods[m].getParameterTypes();
388 Object[] paramValues;
389 if (parameters[0].equals(Boolean.class)) {
390 paramValues = new Boolean[1];
391 if ( OutputField.isTrue(value) ) {
392 paramValues[0] = Boolean.TRUE;
393 }
394 else {
395 paramValues[0] = Boolean.FALSE;
396 }
397 }
398 else
399 if (parameters[0].equals(Integer.class)) {
400 paramValues = new Integer[1];
401 paramValues[0] = new Integer(value);
402 }
403 else {
404 paramValues = new String[1];
405 paramValues[0] = value;
406 }
407 allMethods[m].invoke(bean, paramValues);
408 continue;
409 }
410 catch (IndexOutOfBoundsException ex) {
411 // not the setter we are looking for
412 // this is the wrong overloaded method
413 continue;
414 }
415 // Ignore reflection errors and continue
416 catch (IllegalArgumentException e) {
417 }
418 catch (IllegalAccessException e) {
419 }
420 catch (InvocationTargetException e) {
421 }
422 }
423 }
424 }
425 }
426
427 private static class CustomEntityResolver implements EntityResolver{
428 public InputSource resolveEntity(String publicId, String systemId) {
429
430 if (publicId.equals("-//tp23 //DTD Ant Installer Config//EN") &&
431 systemId.equals("http://antinstaller.sf.net/dtd/antinstall-config-0.2.dtd")) {
432 InputSource localSrc = new InputSource(this.getClass().getResourceAsStream(
433 "/org/tp23/antinstaller/antinstall-config-0.2.dtd"));
434 return localSrc;
435 }
436 if (publicId.equals("-//tp23 //DTD Ant Installer Config//EN") &&
437 systemId.equals("http://antinstaller.sf.net/dtd/antinstall-config-0.3.dtd")) {
438 InputSource localSrc = new InputSource(this.getClass().getResourceAsStream(
439 "/org/tp23/antinstaller/antinstall-config-0.3.dtd"));
440 return localSrc;
441 }
442 if (publicId.equals("-//tp23 //DTD Ant Installer Config//EN") &&
443 systemId.equals("http://antinstaller.sf.net/dtd/antinstall-config-0.4.dtd")) {
444 InputSource localSrc = new InputSource(this.getClass().getResourceAsStream(
445 "/org/tp23/antinstaller/antinstall-config-0.4.dtd"));
446 return localSrc;
447 }
448 if (publicId.equals("-//tp23 //DTD Ant Installer Config//EN") &&
449 systemId.equals("http://antinstaller.sf.net/dtd/antinstall-config-0.5.dtd")) {
450 InputSource localSrc = new InputSource(this.getClass().getResourceAsStream(
451 "/org/tp23/antinstaller/antinstall-config-0.5.dtd"));
452 return localSrc;
453 }
454 if (publicId.equals("-//tp23 //DTD Ant Installer Config//EN") &&
455 systemId.equals("http://antinstaller.sf.net/dtd/antinstall-config-0.6.dtd")) {
456 InputSource localSrc = new InputSource(this.getClass().getResourceAsStream(
457 "/org/tp23/antinstaller/antinstall-config-0.6.dtd"));
458 return localSrc;
459 }
460 if (publicId.equals("-//tp23 //DTD Ant Installer Config//EN") &&
461 systemId.equals("http://antinstaller.sf.net/dtd/antinstall-config-0.7.dtd")) {
462 InputSource localSrc = new InputSource(this.getClass().getResourceAsStream(
463 "/org/tp23/antinstaller/antinstall-config-0.7.dtd"));
464 return localSrc;
465 }
466 if (publicId.equals("-//tp23 //DTD Ant Installer Config//EN") &&
467 systemId.equals("http://antinstaller.sf.net/dtd/antinstall-config-0.8.dtd")) {
468 InputSource localSrc = new InputSource(this.getClass().getResourceAsStream(
469 "/org/tp23/antinstaller/antinstall-config-0.8.dtd"));
470 return localSrc;
471 }
472 else {
473 return null;
474 }
475 }
476 }
477}
Note: See TracBrowser for help on using the repository browser.