001: /*
002: * Copyright 2005 Paul Hinds
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.tp23.antinstaller.runtime;
017:
018: import java.io.File;
019: import java.io.IOException;
020: import java.util.ArrayList;
021: import java.util.HashSet;
022: import java.util.Iterator;
023: import java.util.Set;
024:
025: import org.tp23.antinstaller.InstallException;
026: import org.tp23.antinstaller.Installer;
027: import org.tp23.antinstaller.PropertiesFileRenderer;
028: import org.tp23.antinstaller.input.ConditionalField;
029: import org.tp23.antinstaller.input.InputField;
030: import org.tp23.antinstaller.input.OutputField;
031: import org.tp23.antinstaller.input.ResultContainer;
032: import org.tp23.antinstaller.input.SelectInput;
033: import org.tp23.antinstaller.input.TargetInput;
034: import org.tp23.antinstaller.input.TargetSelectInput;
035: import org.tp23.antinstaller.page.ConditionalPage;
036: import org.tp23.antinstaller.page.Page;
037: import org.tp23.antinstaller.page.ProgressPage;
038: import org.tp23.antinstaller.page.SimpleInputPage;
039: import org.tp23.antinstaller.renderer.swing.plaf.LookAndFeelFactory;
040: import org.tp23.antinstaller.runtime.exe.LoadConfigFilter;
041: import org.tp23.antinstaller.runtime.exe.PropertyLoaderFilter;
042: import org.tp23.antinstaller.runtime.logic.ExpressionBuilder;
043:
044: /**
045: *
046: * <p>Loads the configuration file into memory as an Installer object. </p>
047: * <p>This class also contains the main() method to check the config files for common errors </p>
048: * <p>Copyright: Copyright (c) 2004</p>
049: * <p>Company: tp23</p>
050: * @todo this should be an interface not a class
051: * @author Paul Hinds
052: * @version $Id: ConfigurationLoader.java,v 1.15 2007/01/28 08:44:43 teknopaul Exp $
053: */
054: public class ConfigurationLoader extends LoadConfigFilter {
055:
056: /**
057: * Command line config checker
058: * @param args String[]
059: * @throws InstallException
060: */
061: public static void main(String[] args) {
062: ConfigurationLoader configurationLoader = new ConfigurationLoader();
063: String configFile = INSTALLER_CONFIG_FILE;
064: if (args.length > 1 && args[1].endsWith(".xml")) {
065: configFile = args[1];
066: }
067: int ret = 1;
068: try {
069: configurationLoader.readConfig(new File(args[0]),
070: configFile);
071: ret = configurationLoader.validate();
072:
073: if (ret > 0) {
074: System.out.println("VALIDATION FAILED");
075: }
076: } catch (ConfigurationException ex) {
077: ex.printStackTrace();
078: System.exit(ret);
079: } catch (IOException ex) {
080: ex.printStackTrace();
081: System.exit(ret);
082: } catch (InstallException ex) {
083: // probably ifProperty syntax wrong
084: ex.printStackTrace();
085: System.exit(ret);
086: }
087: }
088:
089: /**
090: * This method is not valid until super.readConfig() has been run
091: * @return
092: */
093: public Installer getInstaller() {
094: return installer;
095: }
096:
097: public int validate() throws IOException, ConfigurationException,
098: InstallException {
099: Page[] pages = installer.getPages();
100: boolean foundErrors = false;
101: Set pageNames = new HashSet();
102: Set targets = new HashSet();
103: Set propertyNames = new HashSet();
104: Set pagePropertyNames = null;
105:
106: if (validateInstallerAttributes()) {
107: foundErrors = true;
108: }
109:
110: for (int p = 0; p < pages.length; p++) {
111: System.out.println("Checking page: " + pages[p].getName());
112: if (pageNames.contains(pages[p].getName())) {
113: System.out
114: .println("Error: page name '"
115: + pages[p].getName()
116: + "' repeated - auto loading of configuration will fail");
117: foundErrors = true;
118: }
119: pageNames.add(pages[p].getName());
120:
121: //TODO check page requirements
122: // test ifProperty syntax
123: // TODO passes validation even if nothing will evaluate
124: if (pages[p] instanceof ConditionalPage) {
125: ConditionalPage sPage = (ConditionalPage) pages[p];
126: if (sPage.getIfProperty() != null) {
127: try {
128: ResultContainer mock = new ResultContainer();
129: ExpressionBuilder.parseLogicalExpressions(mock,
130: sPage.getIfProperty());
131: } catch (ConfigurationException configExc) {
132: System.out.println("Error: loading ifProperty,"
133: + sPage.getIfProperty() + " ,page: "
134: + pages[p].getName());
135: foundErrors = true;
136: }
137: }
138: }
139: // TODO TextPage validation
140:
141: pagePropertyNames = new HashSet();
142:
143: OutputField[] fields = pages[p].getOutputField();
144: for (int f = 0; f < fields.length; f++) {
145: if (!fields[f].validateObject()) {
146: foundErrors = true;
147: System.out.println("Error in page:"
148: + pages[p].getName());
149: }
150: if (fields[f] instanceof TargetInput) {
151: TargetInput tgtInput = (TargetInput) fields[f];
152: targets.add(tgtInput.getTarget());
153: }
154: if (fields[f] instanceof InputField
155: && !(fields[f] instanceof ConditionalField)) {
156: InputField genericInput = (InputField) fields[f];
157: if (genericInput.getProperty().endsWith(
158: PropertiesFileRenderer.TARGETS_SUFFIX)) {
159: System.out
160: .println("Error: invalid property name:"
161: + genericInput.getProperty());
162: System.out
163: .println("InputField names must not end with -targets");
164: }
165: String propertyName = genericInput.getProperty();
166: //System.out.println("Checking page.property: " + pages[p].getName() + "," + propertyName );
167: if (propertyNames.contains(propertyName)) {
168: //foundErrors = true;
169: System.out.println("Repeated property name:"
170: + propertyName);
171: System.out
172: .println("Loading defaults from file will probably not work:"
173: + propertyName);
174: } else {
175: propertyNames.add(propertyName);
176: }
177: // repeated properties on the same page are an error always
178: if (pagePropertyNames.contains(propertyName)) {
179: foundErrors = true;
180: System.out
181: .println("Repeated property name: page="
182: + pages[p].getName()
183: + ", property=" + propertyName);
184: } else {
185: pagePropertyNames.add(propertyName);
186: }
187:
188: }
189: }
190:
191: }
192: System.out.println("Finished checking config inputs");
193: // check page structure
194: if (!(pages[pages.length - 1] instanceof ProgressPage)) {
195: foundErrors = true;
196: System.out.println("Last Page should be a progress page");
197: } else {
198: if (pages[pages.length - 1].getPostDisplayTarget() != null) {
199: foundErrors = true;
200: System.out
201: .println("Progress pages do not support postDisplayTarget");
202: }
203: }
204: // check for targets
205: int numOfPageTargets = 0;
206: for (int p = 0; p < pages.length; p++) {
207: numOfPageTargets += pages[p].getAllTargets().size();
208: }
209: if (numOfPageTargets == 0) {
210: System.out
211: .println("Warning: No Page Targets (not a problem if there are target input types)");
212: }
213:
214: Iterator iter = targets.iterator();
215: while (iter.hasNext()) {
216: String tgt = (String) iter.next();
217: if (tgt.endsWith(PropertiesFileRenderer.TARGETS_SUFFIX)) {
218: System.out.println("Error: invalid target name:" + tgt);
219: System.out
220: .println("Target names must not end with -targets");
221: foundErrors = true;
222: }
223: }
224:
225: //@todo check targets exist in build.xml remember OSSpecific could be tricky to validate
226:
227: int numOfTargetInputs = 0;
228: // check ifTargets
229: ArrayList targetsSoFar = new ArrayList();
230: for (int p = 0; p < pages.length; p++) {
231: if (pages[p] instanceof SimpleInputPage) {
232: SimpleInputPage simple = (SimpleInputPage) pages[p];
233: String ifTarget = simple.getIfTarget();
234: if (ifTarget != null
235: && !targetsSoFar.contains(ifTarget)) {
236: System.out.println("ifTarget=" + ifTarget);
237: System.out
238: .println("ifTarget will never test true, no prior target in page:"
239: + pages[p].getName());
240: // disabled due to bug 1412658 could be reinstated with proper test and OSSpecific handling
241: //foundErrors = true;
242: }
243: }
244: // add after to ensure testing previous pages
245: targetsSoFar.addAll(pages[p].getAllTargets());
246: OutputField[] fields = pages[p].getOutputField();
247: for (int f = 0; f < fields.length; f++) {
248: if (fields[f] instanceof TargetInput) {
249: if (numOfTargetInputs == 0) {
250: System.out.println("Found target input type");
251: }
252: numOfTargetInputs++;
253: TargetInput ti = (TargetInput) fields[f];
254: targetsSoFar.add(ti.getTarget());
255: }
256: if (fields[f] instanceof TargetSelectInput) {
257: if (numOfTargetInputs == 0) {
258: System.out.println("Found target input type");
259: }
260: numOfTargetInputs++;
261: TargetSelectInput ti = (TargetSelectInput) fields[f];
262: SelectInput.Option[] options = ti.getOptions();
263: for (int i = 0; i < options.length; i++) {
264: SelectInput.Option option = options[i];
265: targetsSoFar.add(option.value);
266: }
267: }
268: }
269: }
270: if (numOfPageTargets == 0 && numOfTargetInputs == 0) {
271: System.out
272: .println("Warning: No targets found, installer may do nothing.");
273: }
274: // if(targetsSoFar.contains("default")){
275: // System.out.println("Target:target can not be \"default\"");
276: // foundErrors = true;
277: // }
278:
279: System.out.println("Finished checking config");
280: if (!foundErrors) {
281: return 0;
282: }
283: return 1;
284: }
285:
286: private boolean validateInstallerAttributes() {
287:
288: System.out
289: .println("Checking installer: " + installer.getName());
290: boolean foundErrors = false;
291:
292: String[] validBooleanValues = { "true", "false" };
293: foundErrors |= validateValue("antialiased", installer
294: .getAntialiased(), true, validBooleanValues);
295:
296: // done in DTD
297: //foundErrors |= validateValue("verbose", installer.isVerbose(), true, validBooleanValues);
298: //foundErrors |= validateValue("debug", installer.isDebug(), true, validBooleanValues);
299:
300: String[] validLAFValues = { LookAndFeelFactory.DEFAULT_LAF,
301: LookAndFeelFactory.GREYMETAL_LAF,
302: LookAndFeelFactory.NATIVE_LAF,
303: LookAndFeelFactory.JGOODIES_LAF,
304: LookAndFeelFactory.NULL_LAF };
305: if (validateValue("lookAndFeel", installer.getLookAndFeel(),
306: true, validLAFValues)) {
307: System.out
308: .println("Warning: non standard LookAndFeel ensure the correct classes are on the classpath at runtime:"
309: + installer.getLookAndFeel());
310: }
311:
312: if (installer.getName() == null) {
313: System.out
314: .println("Error: installer element attribute does not exist: name");
315: foundErrors = true;
316: }
317:
318: try {
319: String wide = installer.getWide();
320: if (wide != null) {
321: installer.parseWideValue(wide);
322: }
323: } catch (Exception e) {
324: System.out
325: .println("Error: installer element attribute incorrect format (e.g. 600:275): wide");
326: foundErrors = true;
327: }
328:
329: String[] validLoadDefaultValues = { PropertyLoaderFilter.FALSE,
330: PropertyLoaderFilter.LOAD, PropertyLoaderFilter.PROMPT,
331: PropertyLoaderFilter.PROMPT_AUTO };
332:
333: boolean loadDefaultsNull = true;
334: if (installer.supportsAutoBuild()) {
335: loadDefaultsNull = false;
336: }
337: foundErrors |= validateValue("loadDefaults", installer
338: .getLoadDefaults(), loadDefaultsNull,
339: validLoadDefaultValues);
340:
341: VersionHelper vHelper = new VersionHelper();
342: if (installer.supportsAutoBuild()) {
343: if (!vHelper.isValid(installer.getVersion())) {
344: System.out
345: .println("Error: invalid version attribute, required for -auto builds:"
346: + installer.getVersion());
347: foundErrors = true;
348: }
349: }
350: if (installer.getVersion() != null) {
351: if (!vHelper.isValid(installer.getVersion())) {
352: System.out
353: .println("Error: invalid version attribute format examples 1.2.0 , 0.2beta:"
354: + installer.getVersion());
355: foundErrors = true;
356: }
357: }
358:
359: return foundErrors;
360: }
361:
362: /**
363: * @return foundErrors (true if there was an error)
364: */
365: private boolean validateValue(String att, String value,
366: boolean allowsNull, String[] validValues) {
367: if (value == null) {
368: if (!allowsNull) {
369: System.out
370: .println("Error: installer element attribute does not exist: "
371: + att);
372: return true;
373: }
374: return false;
375: } else {
376: for (int i = 0; i < validValues.length; i++) {
377: if (validValues[i].equals(value)) {
378: return false;
379: }
380: }
381: System.out
382: .println("Error: installer element attribute not valid value: "
383: + att);
384: return true;
385: }
386: }
387:
388: }
|