001    // Copyright 2007 by Basil Vandegriend.  All rights reserved.
002    
003    package com.basilv.envgen;
004    
005    import com.basilv.core.Assert;
006    import com.basilv.core.StringUtilities;
007    import com.csvreader.CsvReader;
008    
009    /**
010     * Loads environment properties from the specified CSV file and populates an instance of 
011     * EnvironmentProperties. 
012     * 
013     * The file format is as follows: 
014     * <ul>
015     * <li>Each row corresponds to a single property or to a comment.</li>
016     * <li>For a property, the first column contains the name of the property.<br> 
017     * Each subsequent column contains the value of the property for a single environment.</li>
018     * <li>For a comment, the first column must start with the symbol '#' or '//', or be completely empty. 
019     * The remainder of the row is ignored. </li>
020     * </ul>
021     */
022    public class EnvironmentPropertiesLoader
023    {
024    
025            /**
026             * Load the CSV file into an EnvironmentProperties instance.
027             * @param filename  Cannot be null or empty. Must correspond to a CSV file of the correct format.
028             * @return the EnvironmentProperties instance.
029             */
030            public static EnvironmentProperties load(String filename) {
031                    Assert.notNullOrEmpty("filename", filename);
032                    
033                    try {
034                            CsvReader reader = new CsvReader(filename);
035                            try {
036                                    EnvironmentProperties envProps = null;
037    
038                                    final int FIRST_ROW = 1; 
039                                    int rowNumber = FIRST_ROW; // Indexed from one.
040                                    while (reader.readRecord()) {
041                                            int columnCount = reader.getColumnCount();
042                                            Assert.isTrue("Must have at least two columns - one for the property name " +
043                                                    "and one row per environment for the property value.", columnCount > 1);
044                                            if (rowNumber == FIRST_ROW) {
045                                                    int envCount = columnCount - 1;
046                                                    envProps = new EnvironmentProperties(envCount);
047                                            }
048                                            
049                                            String propertyName = reader.get(0);
050                                            if (isComment(propertyName)) {
051                                                    continue;
052                                            }
053                                            
054                                            for (int column = 1; column < columnCount; column++) {
055                                                    int environment = column - 1;
056                                                    String propertyValue = reader.get(column);
057                                                    envProps.addProperty(environment, propertyName, propertyValue);
058                                            }
059                                            
060                                            rowNumber++;
061                                    }
062                                    if (envProps == null) {
063                                            Assert.shouldNotReach("File [" + filename + "] does not contain any rows.");
064                                    }
065                                    
066                                    return envProps;
067    
068                            } finally {
069                                    reader.close();
070                            }
071                    } catch (Exception e) {
072                            throw new RuntimeException("Error reading cvs file [" + 
073                                    filename + "] due to " + e.getMessage() + ".", e);
074                    }
075                    
076            }
077    
078            // Non-private for testing
079            static boolean isComment(String propertyName) {
080                    if (StringUtilities.isNullOrEmpty(propertyName)) {
081                            return true;
082                    }
083                    
084                    if (propertyName.startsWith("#")) {
085                            return true;
086                    }
087    
088                    if (propertyName.startsWith("//")) {
089                            return true;
090                    }
091    
092                    return false;
093            }
094            
095    }