source: release-kits/shared/ant-installer/src/org/tp23/antinstaller/runtime/exe/LoadConfigFilter.java@ 17514

Last change on this file since 17514 was 17514, checked in by oranfry, 16 years ago

changes to the way ant-installer loads and reloads the language packs, and a new attribute to the select input which triggers it to change the language to the input value

File size: 17.2 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 int line=0;
147 try {
148 line=1;
149 DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
150 line=2;
151 DocumentBuilder parser = docBuilderFactory.newDocumentBuilder();
152 line=3;
153 // RFE [ 1475361 ] Using a custom entity resolver
154 String entityResolverClass = System.getProperty("antinstaller.EntityResolverClass");
155
156 line=4;
157 EntityResolver er = null;
158
159 line=5;
160 if(entityResolverClass != null){
161 line=6;
162 try{
163 line=7;
164 er = (EntityResolver)Class.forName(entityResolverClass).newInstance();
165 }
166 catch(Exception e){
167 // Property error use default this is a very specific requirement
168 line=8;
169 er = new CustomEntityResolver();
170 }
171 line=9;
172 }
173 else{
174 line=10;
175 er = new CustomEntityResolver();
176 }
177 line=11;
178 parser.setEntityResolver(er);
179
180 line=12;
181 doc = parser.parse(xmlInp);
182 line=13;
183 Element root = doc.getDocumentElement();
184 line=14;
185 root.normalize();
186 line=15;
187 setProperties(installer, root.getAttributes());
188 line=16;
189 NodeList allPages = root.getElementsByTagName("page");
190 //TODO make this pluggable
191 line=17;
192 getPages(installer, allPages);
193 }
194 catch (Exception e) {
195 e.printStackTrace();
196 System.out.println( e.getMessage() );
197 throw new IOException("DomFactory error: caused by:" + e.getClass() + ":" + e.getMessage() + ". Line: " + line);
198 }
199 return installer;
200 }
201
202
203 /**
204 * Used when reading the config
205 * @param allPages NodeList
206 * @throws ConfigurationException
207 */
208 private void getPages(Installer installerConfig, NodeList allPages) throws ConfigurationException {
209 ArrayList pages = new ArrayList();
210 for (int i = 0; i < allPages.getLength(); i++) {
211 Element pageElem = (Element) allPages.item(i);
212 Page page = getPageType(pageElem.getAttribute("type"));
213 setProperties(page, pageElem.getAttributes());
214 pages.add(page);
215 getOutputFields(page, pageElem);
216 }
217 Page[] pageArr = new Page[pages.size()];
218 pages.toArray(pageArr);
219 installerConfig.setPages(pageArr);
220 }
221 /**
222 * Used when reading the config
223 * @param page Page
224 * @param pageElem Element
225 * @throws ConfigurationException
226 */
227 private void getOutputFields(Page page, Element pageElem) throws ConfigurationException {
228 page.setOutputField( getInnerOutputFields( pageElem ));
229 }
230
231 private OutputField[] getInnerOutputFields( Element elem) throws ConfigurationException {
232 NodeList allFields = elem.getChildNodes();
233 ArrayList fields = new ArrayList();
234 for (int i = 0; i < allFields.getLength(); i++) {
235 if(! (allFields.item(i) instanceof Element))continue;
236 Element fieldElem = (Element)allFields.item(i);
237 OutputField field = getOutputFieldType(fieldElem.getNodeName(), fieldElem);
238 if(field != null){
239 setProperties(field, fieldElem.getAttributes());
240 fields.add(field);
241 field.setResultContainer(installer.getResultContainer());
242 }
243 }
244 OutputField[] fieldArr = new OutputField[fields.size()];
245
246 return (OutputField[])fields.toArray(fieldArr);
247 }
248
249 /**
250 * Used when reading the config
251 * @param type String
252 * @throws ConfigurationException
253 * @return Page
254 */
255 private Page getPageType(String type) throws ConfigurationException {
256 if (type.equalsIgnoreCase("license")) {
257 return new LicensePage();
258 }
259 else if (type.equalsIgnoreCase("input")) {
260 return new SimpleInputPage();
261 }
262 else if (type.equalsIgnoreCase("progress")) {
263 return new ProgressPage();
264 }
265 else if (type.equalsIgnoreCase("splash")) {
266 return new SplashPage();
267 }
268 else if (type.equalsIgnoreCase("text")) {
269 return new TextPage();
270 }
271 throw new ConfigurationException("Unknown Page type:" + type);
272 }
273 /**
274 * Used when reading the config
275 * @param type String
276 * @param field Element
277 * @throws ConfigurationException
278 * @return InputField
279 */
280 private OutputField getOutputFieldType(String type, Element field) throws ConfigurationException {
281
282 if (type.equalsIgnoreCase("text")) {
283 return new UnvalidatedTextInput();
284 }
285 else if (type.equalsIgnoreCase("directory")) {
286 return new DirectoryInput();
287 }
288 else if (type.equalsIgnoreCase("target")) {
289 return new TargetInput();
290 }
291 else if (type.equalsIgnoreCase("file")) {
292 return new FileInput();
293 }
294 else if (type.equalsIgnoreCase("comment")) {
295 return new CommentOutput();
296 }
297 else if (type.equalsIgnoreCase("checkbox")) {
298 return new CheckboxInput();
299 }
300 else if (type.equalsIgnoreCase("validated")) {
301 return new ValidatedTextInput();
302 }
303 else if (type.equalsIgnoreCase("ext-validated")) {
304 return new ExtValidatedTextInput();
305 }
306 else if (type.equalsIgnoreCase("password")) {
307 return new PasswordTextInput();
308 }
309 else if (type.equalsIgnoreCase("password-confirm")) {
310 return new ConfirmPasswordTextInput();
311 }
312 else if (type.equalsIgnoreCase("hidden")) {
313 return new HiddenPropertyInput();
314 }
315 else if (type.equalsIgnoreCase("date")) {
316 return new DateInput();
317 }
318 else if (type.equalsIgnoreCase("app-root")) {
319 return new AppRootInput();
320 }
321 else if (type.equalsIgnoreCase("conditional")) {
322 ConditionalField conditionalField = new ConditionalField();
323 OutputField[] outFields = getInnerOutputFields( field );
324 InputField[] inFields = new InputField[ outFields.length ];
325 for( int i = 0; i < outFields.length; i++ ) {
326 inFields[i] = (InputField) outFields[i];
327 }
328 conditionalField.setFields( inFields );
329 return conditionalField;
330 }
331 else if (type.equalsIgnoreCase("select")) {
332 SelectInput sInput = new SelectInput();
333 NodeList allOptions = field.getElementsByTagName("option");
334 ArrayList options = new ArrayList();
335 for (int i = 0; i < allOptions.getLength(); i++) {
336 Element optionElem = (Element) allOptions.item(i);
337 SelectInput.Option option = sInput.getNewOption();
338 option.setText(optionElem.getAttribute("text"));
339 option.value = optionElem.getAttribute("value");
340 options.add(option);
341 }
342 SelectInput.Option[] optionArr = new SelectInput.Option[options.size()];
343 options.toArray(optionArr);
344 sInput.setOptions(optionArr);
345
346 String s = field.getAttribute("useAsLocale");
347 if ( s != null || !s.equals("") ) {
348 sInput.setUseAsLocale(true);
349 }
350
351 return sInput;
352 }
353 else if (type.equalsIgnoreCase("target-select")) {
354 TargetSelectInput sInput = new TargetSelectInput();
355 NodeList allOptions = field.getElementsByTagName("option");
356 ArrayList options = new ArrayList();
357 for (int i = 0; i < allOptions.getLength(); i++) {
358 Element optionElem = (Element) allOptions.item(i);
359 SelectInput.Option option = sInput.getNewOption();
360 option.setText(optionElem.getAttribute("text"));
361 option.value = optionElem.getAttribute("value");
362 options.add(option);
363 }
364 SelectInput.Option[] optionArr = new SelectInput.Option[options.size()];
365 options.toArray(optionArr);
366 sInput.setOptions(optionArr);
367
368 return sInput;
369 }
370 else if (type.equalsIgnoreCase("large-select")) {
371 LargeSelectInput sInput = new LargeSelectInput();
372 NodeList allOptions = field.getElementsByTagName("option");
373 ArrayList options = new ArrayList();
374 for (int i = 0; i < allOptions.getLength(); i++) {
375 Element optionElem = (Element) allOptions.item(i);
376 LargeSelectInput.Option option = sInput.getNewOption();
377 option.setText(optionElem.getAttribute("text"));
378 option.value = optionElem.getAttribute("value");
379 options.add(option);
380 }
381 LargeSelectInput.Option[] optionArr = new LargeSelectInput.Option[options.size()];
382 options.toArray(optionArr);
383 sInput.setOptions(optionArr);
384
385 return sInput;
386 }
387 System.out.println("Unrecognised Input Element:"+type);
388 return null;
389 //throw new ConfigurationException("Unknown Input Field type:" + type);
390 }
391
392
393
394 /**
395 * Calls bean setter methods based on attribures found. Could use BeanUtils here
396 * but we want to stay clear of external dependencies.
397 * @param bean Object
398 * @param map NamedNodeMap
399 */
400 private void setProperties(Object bean, NamedNodeMap map) {
401 int numAtts = map.getLength();
402 for (int a = 0; a < numAtts; a++) {
403 Node attribute = map.item(a);
404 String name = attribute.getNodeName();
405 String value = attribute.getNodeValue();
406 String methodName = "set" + Character.toUpperCase(name.charAt(0)) + name.substring(1);
407 Method[] allMethods = bean.getClass().getMethods();
408 for (int m = 0; m < allMethods.length; m++) {
409 if (allMethods[m].getName().equals(methodName)) {
410 try {
411 Class[] parameters = allMethods[m].getParameterTypes();
412 Object[] paramValues;
413 if (parameters[0].equals(Boolean.class)) {
414 paramValues = new Boolean[1];
415 if ( OutputField.isTrue(value) ) {
416 paramValues[0] = Boolean.TRUE;
417 }
418 else {
419 paramValues[0] = Boolean.FALSE;
420 }
421 }
422 else
423 if (parameters[0].equals(Integer.class)) {
424 paramValues = new Integer[1];
425 paramValues[0] = new Integer(value);
426 }
427 else {
428 paramValues = new String[1];
429 paramValues[0] = value;
430 }
431 allMethods[m].invoke(bean, paramValues);
432 continue;
433 }
434 catch (IndexOutOfBoundsException ex) {
435 // not the setter we are looking for
436 // this is the wrong overloaded method
437 continue;
438 }
439 // Ignore reflection errors and continue
440 catch (IllegalArgumentException e) {
441 }
442 catch (IllegalAccessException e) {
443 }
444 catch (InvocationTargetException e) {
445 }
446 }
447 }
448 }
449 }
450
451 private static class CustomEntityResolver implements EntityResolver{
452 public InputSource resolveEntity(String publicId, String systemId) {
453
454 if (publicId.equals("-//tp23 //DTD Ant Installer Config//EN") &&
455 systemId.equals("http://antinstaller.sf.net/dtd/antinstall-config-0.2.dtd")) {
456 InputSource localSrc = new InputSource(this.getClass().getResourceAsStream(
457 "/org/tp23/antinstaller/antinstall-config-0.2.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.3.dtd")) {
462 InputSource localSrc = new InputSource(this.getClass().getResourceAsStream(
463 "/org/tp23/antinstaller/antinstall-config-0.3.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.4.dtd")) {
468 InputSource localSrc = new InputSource(this.getClass().getResourceAsStream(
469 "/org/tp23/antinstaller/antinstall-config-0.4.dtd"));
470 return localSrc;
471 }
472 if (publicId.equals("-//tp23 //DTD Ant Installer Config//EN") &&
473 systemId.equals("http://antinstaller.sf.net/dtd/antinstall-config-0.5.dtd")) {
474 InputSource localSrc = new InputSource(this.getClass().getResourceAsStream(
475 "/org/tp23/antinstaller/antinstall-config-0.5.dtd"));
476 return localSrc;
477 }
478 if (publicId.equals("-//tp23 //DTD Ant Installer Config//EN") &&
479 systemId.equals("http://antinstaller.sf.net/dtd/antinstall-config-0.6.dtd")) {
480 InputSource localSrc = new InputSource(this.getClass().getResourceAsStream(
481 "/org/tp23/antinstaller/antinstall-config-0.6.dtd"));
482 return localSrc;
483 }
484 if (publicId.equals("-//tp23 //DTD Ant Installer Config//EN") &&
485 systemId.equals("http://antinstaller.sf.net/dtd/antinstall-config-0.7.dtd")) {
486 InputSource localSrc = new InputSource(this.getClass().getResourceAsStream(
487 "/org/tp23/antinstaller/antinstall-config-0.7.dtd"));
488 return localSrc;
489 }
490 if (publicId.equals("-//tp23 //DTD Ant Installer Config//EN") &&
491 systemId.equals("http://antinstaller.sf.net/dtd/antinstall-config-0.8.dtd")) {
492 InputSource localSrc = new InputSource(this.getClass().getResourceAsStream(
493 "/org/tp23/antinstaller/antinstall-config-0.8.dtd"));
494 return localSrc;
495 }
496 else {
497 return null;
498 }
499 }
500 }
501}
Note: See TracBrowser for help on using the repository browser.