package edu.hawaii.ics.yucheng; import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Properties; /** * An immutable class that contains the configuration information for a cluster * of nodes and a catalog. They are parsed from the 'clustercfg' file. * * @author Cheng Jade * @assignment ICS 421 Assignment 2-2 * @date Feb 29, 2010 * @bugs None */ public final class Configuration { // The catalog node configuration private final ConfigurationNode catalog; // The table name private final String tableName; // The partition method private final String partitionMethod; // The partition column private final String partionColumn; // The partition number private final int partionNumber; // The array of nodes configurations. private final ArrayList<ParameterPair> partitionList = new ArrayList<ParameterPair>(); // The array of nodes configurations. private final ArrayList<ConfigurationNode> nodeList = new ArrayList<ConfigurationNode>(); // method to add a node in a configuration list. public boolean addNode(ConfigurationNode node){ assert null != node; for (int i = 0; i < nodeList.size(); i++) if (nodeList.get(i).equals(node)) return false; nodeList.add(node); return true; } /** * Initializes a new instance of the Configuration class. * * @param path * The path to a file that contains configuration data. * * @throws NullPointerException * @throws ProgramException * Thrown if it cann't read the DDL command file, or the * specified path is null. */ public Configuration(final String path) throws ProgramException { // Throw an exception if the specified path is null. if (null == path) throw new NullPointerException("path"); // Declare a Properties object and load it with the specified file. final Properties properties = getProperties(path); // Obtain the catalog configuration. this.catalog = new ConfigurationNode(properties, "catalog"); // Obtain the table name. this.tableName = properties.getProperty("tablename"); // Obtain the partition method. this.partitionMethod = properties.getProperty("partition.method"); // Obtain the partition column. this.partionColumn = properties.getProperty("partition.column"); String partionNumberText = null; if (this.partitionMethod.equalsIgnoreCase("hash")) partionNumberText= properties.getProperty("partition.param1"); else if (this.partitionMethod.equalsIgnoreCase("range")) partionNumberText= properties.getProperty("numnodes"); else throw new ProgramException("invalid partition method."); if (null == partionNumberText) throw new ProgramException( "can't find partition number field in the configuration file."); try { partionNumber = Integer.parseInt(partionNumberText); } catch (final NumberFormatException e) { throw new ProgramException("Cannot parse number of partitions.", e); } if (this.partitionMethod.equalsIgnoreCase("hash")) { for (int i = 0; i < this.partionNumber; i++) partitionList.add(new ParameterPair(properties.getProperty("partition.param1"))); return; } for (int i = 0; i < this.partionNumber; i++) partitionList.add(new ParameterPair(properties, i + 1)); } /** * Returns the catalog configuration. * * @return The catalog configuration. */ public ConfigurationNode getCatalog() { return this.catalog; } // added when doing A2 public ConfigurationNode getNode(int index) { return this.nodeList.get(index); } // added when doing A2 public ParameterPair getPartition(int index) { return this.partitionList.get(index); } // added when doing A2 public String getTableName() { return this.tableName; } // added when doing A2 public String getPartitionMethod() { return this.partitionMethod; } // added when doing A2 public String getPartitionColumn() { return this.partionColumn; } // added when doing A2 public int nodeListsize() { return this.nodeList.size(); } // added when doing A2 public int partitionListsize() { return this.partitionList.size(); } /** * Returns a readable version of the contents of the configuration. * * @return A readable version of the contents of the configuration. */ @Override public String toString() { // If the directory is empty, return a special note. if (this.partitionList.size() == 0) return "The partition list is empty.\n"; // Loop over each item, and add it to the string builder. final StringBuilder builder = new StringBuilder(); builder.append("The configuration file contains:\n\n"); builder.append("Catalog: \n"); builder.append(this.catalog + "\n\n"); builder.append("Table Name: "); builder.append(this.tableName + "\n"); builder.append("Partition Method: "); builder.append(this.partitionMethod + "\n"); builder.append("Partition Column: "); builder.append(this.partionColumn + "\n"); builder.append("Partition Number: "); builder.append(this.partionNumber); for (int i = 0; i < this.partionNumber; i++) { builder.append("\n\nPartition "); builder.append(i + 1); builder.append(": \n"); builder.append(partitionList.get(i)); } if (nodeList.size() == 0) builder.append("\n\nConfiguration node list is empty."); else for (int i = 0; i < this.nodeList.size(); i++) { builder.append("\n\nNode "); builder.append(i + 1); builder.append(": \n"); builder.append(nodeList.get(i)); } // Return the string created above. return builder.toString(); } /** * Open a file, check for errors, and return a loaded properties object. * * @param path * The path to the properties file. * * @return A loaded properties object. * * @throws ProgramException * Thrown if there is a problem reading the configuration file. */ private static Properties getProperties(final String path) throws ProgramException { assert null != path; try { final FileInputStream file = new FileInputStream(path); try { final Properties properties = new Properties(); properties.load(file); return properties; } finally { file.close(); } } catch (final IOException e) { throw new ProgramException("Cannot read configuration file.", e); } } /** * The test main, the entry point when testing this class. * * @param args * The command line arguments. */ public static void main(final String[] args) { assert null != args; // Print usage information, if wrong number of arguments were used. if (args.length != 1) { final String name = Configuration.class.getSimpleName(); System.err.println("Usage: java " + name + " <path>"); System.err.println(" <path> path to a configuration file"); System.exit(1); return; } // Declare a Configuration object and populate it with data from a file // that is specified as the only command line argument. try { assert null != args[0]; System.out.println(new Configuration(args[0])); } catch (final ProgramException e) { System.err.println(e.getMessage()); System.exit(1); return; } // Exit cleanly while debugging from Eclipse. System.exit(0); } }