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;
17
18import java.io.File;
19import java.io.IOException;
20import java.util.ArrayList;
21import java.util.HashSet;
22import java.util.Iterator;
23import java.util.Set;
24
25import org.tp23.antinstaller.InstallException;
26import org.tp23.antinstaller.Installer;
27import org.tp23.antinstaller.PropertiesFileRenderer;
28import org.tp23.antinstaller.input.ConditionalField;
29import org.tp23.antinstaller.input.InputField;
30import org.tp23.antinstaller.input.OutputField;
31import org.tp23.antinstaller.input.ResultContainer;
32import org.tp23.antinstaller.input.SelectInput;
33import org.tp23.antinstaller.input.TargetInput;
34import org.tp23.antinstaller.input.TargetSelectInput;
35import org.tp23.antinstaller.page.Page;
36import org.tp23.antinstaller.page.ProgressPage;
37import org.tp23.antinstaller.page.SimpleInputPage;
38import org.tp23.antinstaller.renderer.swing.plaf.LookAndFeelFactory;
39import org.tp23.antinstaller.runtime.exe.LoadConfigFilter;
40import org.tp23.antinstaller.runtime.exe.PropertyLoaderFilter;
41import org.tp23.antinstaller.runtime.logic.ExpressionBuilder;
42/**
43 *
44 * <p>Loads the configuration file into memory as an Installer object. </p>
45 * <p>This class also contains the main() method to check the config files for common errors </p>
46 * <p>Copyright: Copyright (c) 2004</p>
47 * <p>Company: tp23</p>
48 * @todo this should be an interface not a class
49 * @author Paul Hinds
50 * @version $Id: ConfigurationLoader.java,v 1.15 2007/01/28 08:44:43 teknopaul Exp $
51 */
52public class ConfigurationLoader extends LoadConfigFilter{
53    
54    /**
55     * Command line config checker
56     * @param args String[]
57     * @throws InstallException 
58     */
59    public static void main(String[] args) {
60        ConfigurationLoader configurationLoader = new ConfigurationLoader();
61        String configFile = INSTALLER_CONFIG_FILE;
62        if(args.length > 1 && args[1].endsWith(".xml")){
63            configFile = args[1];
64        }
65        int ret = 1;
66        try {
67            configurationLoader.readConfig(new File(args[0]), configFile);
68            ret = configurationLoader.validate();
69            
70            if(ret > 0){
71                System.out.println("VALIDATION FAILED");
72            }
73        }
74        catch (ConfigurationException ex) {
75            ex.printStackTrace();
76            System.exit(ret);
77        }
78        catch (IOException ex) {
79            ex.printStackTrace();
80            System.exit(ret);
81        } catch (InstallException ex) {
82            // probably ifProperty syntax wrong
83            ex.printStackTrace();
84            System.exit(ret);
85        }
86    }
87    
88    /**
89     * This method is not valid until super.readConfig() has been run
90     * @return
91     */
92    public Installer getInstaller(){
93        return installer;
94    }
95    
96    public int validate() throws IOException, ConfigurationException, InstallException{
97        Page[] pages = installer.getPages();
98        boolean foundErrors = false;
99        Set pageNames = new HashSet();
00        Set targets = new HashSet();
01        Set propertyNames = new HashSet();
02        Set pagePropertyNames = null;
03        
04        if(validateInstallerAttributes()){
05            foundErrors = true;
06        }
07        
08        for (int p = 0; p < pages.length; p++) {
09           System.out.println("Checking page: " + pages[p].getName() );
10            if(pageNames.contains(pages[p].getName())){
11                System.out.println("Error: page name '"
12                                    + pages[p].getName()
13                                    + "' repeated - auto loading of configuration will fail");
14                foundErrors = true;
15            }
16            pageNames.add(pages[p].getName());
17            
18            //TODO check page requirements
19            //test ifProperty syntax
20            // TODO passes validation even if nothing will evaluate
21            if (pages[p] instanceof SimpleInputPage) {
22                SimpleInputPage sPage = (SimpleInputPage)pages[p];
23                if(sPage.getIfProperty() != null){
24                    try {
25                        ResultContainer mock = new ResultContainer();
26                        ExpressionBuilder.parseLogicalExpressions( mock,
27                                sPage.getIfProperty() );
28                    }
29                    catch( ConfigurationException configExc ){
30                        System.out.println("Error: loading ifProperty," + sPage.getIfProperty() + " ,page: " + pages[p].getName() );
31                        foundErrors = true;   
32                    }
33                }
34            }
35
36            
37            pagePropertyNames = new HashSet();
38            
39            OutputField[] fields = pages[p].getOutputField();
40            for (int f = 0; f < fields.length; f++) {
41                if(!fields[f].validateObject()){
42                    foundErrors = true;
43                    System.out.println("Error in page:" + pages[p].getName());
44                }
45                if(fields[f] instanceof TargetInput){
46                    TargetInput tgtInput = (TargetInput)fields[f];
47                    targets.add(tgtInput.getTarget());
48                }
49                if(fields[f] instanceof InputField && !(fields[f] instanceof ConditionalField) ){
50                    InputField genericInput = (InputField)fields[f];
51                    if(genericInput.getProperty().endsWith(PropertiesFileRenderer.TARGETS_SUFFIX)){
52                        System.out.println("Error: invalid property name:" + genericInput.getProperty());
53                        System.out.println("InputField names must not end with -targets");
54                    }
55                    String propertyName = genericInput.getProperty();
56                    //System.out.println("Checking page.property: " + pages[p].getName() + "," + propertyName );
57                    if(propertyNames.contains(propertyName)){
58                        //foundErrors = true;
59                        System.out.println("Repeated property name:"  + propertyName);
60                        System.out.println("Loading defaults from file will probably not work:"  + propertyName);
61                    }
62                    else{
63                        propertyNames.add(propertyName);
64                    }
65                    // repeated properties on the same page are an error always
66                    if(pagePropertyNames.contains(propertyName)){
67                        foundErrors = true;
68                        System.out.println("Repeated property name: page=" + 
69                                pages[p].getName() + ", property=" + propertyName);
70                    }
71                    else{
72                        pagePropertyNames.add(propertyName);
73                    }
74                    
75                }
76            }
77            
78        }
79        System.out.println("Finished checking config inputs");
80        // check page structure
81        if(!(pages[pages.length-1] instanceof ProgressPage)){
82            foundErrors = true;
83            System.out.println("Last Page should be a progress page");
84        }
85        else{
86            if (pages[pages.length-1].getPostDisplayTarget() != null){
87                foundErrors = true;
88                System.out.println("Progress pages do not support postDisplayTarget");
89            }
90        }
91        // check for targets
92        int numOfPageTargets = 0;
93        for (int p = 0; p < pages.length; p++) {
94            numOfPageTargets += pages[p].getAllTargets().size();
95        }
96        if(numOfPageTargets == 0){
97            System.out.println("Warning: No Page Targets (not a problem if there are target input types)");
98        }
99        
00        Iterator iter = targets.iterator();
01        while (iter.hasNext()) {
02            String tgt = (String) iter.next();
03            if(tgt.endsWith(PropertiesFileRenderer.TARGETS_SUFFIX)){
04                System.out.println("Error: invalid target name:" + tgt);
05                System.out.println("Target names must not end with -targets");
06                foundErrors = true;
07            }
08        }
09
10        //@todo check targets exist in build.xml remember OSSpecific could be tricky to validate
11        
12        int numOfTargetInputs = 0;
13        // check ifTargets
14        ArrayList targetsSoFar = new ArrayList();
15        for (int p = 0; p < pages.length; p++) {
16            if(pages[p] instanceof SimpleInputPage){
17                SimpleInputPage simple = (SimpleInputPage)pages[p];
18                String ifTarget = simple.getIfTarget();
19                if(ifTarget != null && !targetsSoFar.contains(ifTarget)){
20                    System.out.println("ifTarget=" + ifTarget);
21                    System.out.println("ifTarget will never test true, no prior target in page:"+pages[p].getName());
22                    // disabled due to bug 1412658 could be reinstated with proper test and OSSpecific handling 
23                    //foundErrors = true;
24                }
25            }
26            // add after to ensure testing previous pages
27            targetsSoFar.addAll(pages[p].getAllTargets());
28            OutputField[] fields = pages[p].getOutputField();
29            for (int f = 0; f < fields.length; f++) {
30                if(fields[f] instanceof TargetInput){
31                    if(numOfTargetInputs == 0){
32                        System.out.println("Found target input type");
33                    }
34                    numOfTargetInputs++;
35                    TargetInput ti = (TargetInput)fields[f];
36                    targetsSoFar.add(ti.getTarget());
37                }
38                if(fields[f] instanceof TargetSelectInput){
39                    if(numOfTargetInputs == 0){
40                        System.out.println("Found target input type");
41                    }
42                    numOfTargetInputs++;
43                    TargetSelectInput ti = (TargetSelectInput)fields[f];
44                    SelectInput.Option[] options = ti.getOptions();
45                    for (int i = 0; i < options.length; i++) {
46                        SelectInput.Option option = options[i];
47                        targetsSoFar.add(option.value);
48                    }
49                }
50            }
51        }
52        if(numOfPageTargets == 0 && numOfTargetInputs == 0){
53            System.out.println("Warning: No targets found, installer may do nothing.");
54        }
55//      if(targetsSoFar.contains("default")){
56//          System.out.println("Target:target can not be \"default\"");
57//          foundErrors = true;
58//      }
59
60
61        System.out.println("Finished checking config");
62        if(!foundErrors){
63            return 0;
64        }
65        return 1;
66    }
67
68    private boolean validateInstallerAttributes(){
69        
70        System.out.println("Checking installer: " + installer.getName() );
71        boolean foundErrors = false;
72        
73        String[] validBooleanValues = {"true", "false"};
74        foundErrors |= validateValue("antialiased", installer.getAntialiased(), true, validBooleanValues);
75
76        // done in DTD
77        //foundErrors |= validateValue("verbose", installer.isVerbose(), true, validBooleanValues);
78        //foundErrors |= validateValue("debug", installer.isDebug(), true, validBooleanValues);
79        
80        String[] validLAFValues = {LookAndFeelFactory.DEFAULT_LAF,
81                LookAndFeelFactory.GREYMETAL_LAF,
82                LookAndFeelFactory.NATIVE_LAF,
83                LookAndFeelFactory.JGOODIES_LAF,
84                LookAndFeelFactory.NULL_LAF };
85        if( validateValue("lookAndFeel", installer.getLookAndFeel(), true, validLAFValues) ){
86            System.out.println("Warning: non standard LookAndFeel ensure the correct classes are on the classpath at runtime:" + installer.getLookAndFeel());
87        }
88        
89        if (installer.getName() == null){
90            System.out.println("Error: installer element attribute does not exist: name");
91            foundErrors = true;
92        }
93        
94        try {
95            String wide = installer.getWide();
96            if(wide != null){
97                installer.parseWideValue(wide);
98            }
99        } catch (Exception e) {
00            System.out.println("Error: installer element attribute incorrect format (e.g. 600:275): wide");
01            foundErrors = true;
02        }
03        
04        String[] validLoadDefaultValues = {PropertyLoaderFilter.FALSE,
05                PropertyLoaderFilter.LOAD,
06                PropertyLoaderFilter.PROMPT, 
07                PropertyLoaderFilter.PROMPT_AUTO};
08        
09        boolean loadDefaultsNull = true;
10        if( installer.supportsAutoBuild() ){
11            loadDefaultsNull = false;
12        }
13        foundErrors |= validateValue("loadDefaults", installer.getLoadDefaults(), loadDefaultsNull, validLoadDefaultValues);
14
15        VersionHelper vHelper = new VersionHelper();
16        if( installer.supportsAutoBuild() ){
17            if( ! vHelper.isValid(installer.getVersion()) ){
18                System.out.println("Error: invalid version attribute, required for -auto builds:" + installer.getVersion());
19                foundErrors = true;
20            }
21        }
22        if(installer.getVersion() != null){
23            if( ! vHelper.isValid(installer.getVersion()) ){
24                System.out.println("Error: invalid version attribute format examples 1.2.0 , 0.2beta:" + installer.getVersion());
25                foundErrors = true;
26            }
27        }
28        
29        return foundErrors;
30    }
31    /**
32     * @return foundErrors  (true if there was an error)
33     */
34    private boolean validateValue(String att, String value, boolean allowsNull, String[] validValues){
35        if(value == null){
36            if(!allowsNull){
37                System.out.println("Error: installer element attribute does not exist: " + att);
38                return true;
39            }
40            return false;
41        }
42        else {
43            for (int i = 0; i < validValues.length; i++) {
44                if(validValues[i].equals(value)){
45                    return false;
46                }
47            }
48            System.out.println("Error: installer element attribute not valid value: " + att);
49            return true;
50        }
51    }
52
53}
54