Source code: feynman/framework/simulation/Marshaller.java
1 /*
2 * $Header: /cvsroot/feynman/src/feynman/framework/simulation/Marshaller.java,v 1.1.1.1 2002/11/12 02:25:41 wesley_bailey Exp $
3 * $Revision: 1.1.1.1 $
4 * $Date: 2002/11/12 02:25:41 $
5 * $Copyright: Copyright (C) 2002 Path Integral Software $
6 */
7 package feynman.framework.simulation;
8
9 import org.apache.regexp.RE;
10 import org.apache.regexp.RESyntaxException;
11 import java.io.*;
12 import java.util.*;
13 import java.lang.reflect.*;
14
15 /**
16 * Utility class to load the properties file that the user has defined. If
17 * there is a switch to an XML format and using a real Marshalling/Unmarshalling
18 * tool like Castor, then this class can easily be refactored to an adaptor class.
19 * <p>
20 * The constructor is private since this is a utility class so there is no instance
21 * of this class to create or get. To use this class treat it just like the Math
22 * utility class in the following manner:
23 * <p>
24 * <pre>
25 * Simulation simulation = Marshaller.unmarshall("Simulation.properties");
26 * </pre>
27 * </p>
28 *
29 * @author Wes Bailey
30 * @version $Revision: 1.1.1.1 $ $Date: 2002/11/12 02:25:41 $
31 */
32 public class Marshaller {
33
34 // Define instance variables.
35 private static File file;
36 private static FileWriter fw;
37 private static FileInputStream fin;
38 private static PrintWriter pw;
39 private static Properties props;
40
41 /**
42 * This is a utility class so there is no instance of the class to be created or
43 * retrieved.
44 */
45 private Marshaller() {
46 // utility class
47 }
48
49 /**
50 * Method to save a serialized version of the simulation object.
51 *
52 * @param sim The simulation bean to serialize.
53 * @param outfile The file to save the contents of the bean to.
54 */
55 public static void marshall(Simulation sim, String outfile) throws MarshallingException {
56
57 try {
58 file = new File(outfile);
59 fw = new FileWriter(file);
60 pw = new PrintWriter(fw);
61
62 pw.println(sim.toString());
63
64 pw.close();
65 fw.close();
66 }
67 catch (IOException e) {
68 throw new MarshallingException(e.toString());
69 }
70
71 }
72
73 /**
74 * Method to create a simulation object with attribute values specified by the
75 * properties file descriptoin of the object.
76 *
77 * @param infile The name of the properties file to parse and create the bean from.
78 */
79 public static Simulation unmarshall(String infile) throws MarshallingException {
80
81 // The simulation is a singleton class.
82 Simulation sim = Simulation.getInstance();
83
84 // Prepare for reflection operations to invoke the correct methods from the
85 // properties file.
86 Method [] methods = sim.getClass().getMethods();
87
88 try {
89
90 // Define the properties file used to define the simulation bean
91 file = new File(infile);
92 fin = new FileInputStream(file);
93
94 // Create the properties based on the file
95 props = new Properties();
96 props.load(fin);
97
98 /*
99 * For debugging...
100 for (Enumeration e = props.propertyNames(); e.hasMoreElements(); ) {
101 String name = (String) e.nextElement();
102 System.out.println("name: " + name + "\t value: " + props.getProperty(name));
103 }
104 */
105
106 // Setup validation regular expressions.
107 RE stringRegexp;
108 RE intRegexp;
109 RE decimalRegexp;
110 RE booleanRegexp;
111 try {
112 stringRegexp = new RE("^[a-zA-Z\\.]*$");
113 intRegexp = new RE("^[0-9]*$");
114 decimalRegexp = new RE("^[0-9]*\\.[0-9]*$");
115 booleanRegexp = new RE("^(true|false)$");
116 }
117 catch (RESyntaxException e) {
118 throw new MarshallingException("Please report the following error as a bug report: " + e.toString());
119 }
120
121 // Create the array to be used in the method.invoke(Object obj, Object [] objs)
122 Object [] invokeParam = new Object[1];
123
124 // For each method in the array, examine and determine if we have a setter
125 // method. If we do then load the appropriate value from the properties file.
126 for (int i=0; i<methods.length; i++) {
127
128 // Work with the method object as the loop, and not the properties. Make it
129 // easier later when we want to invoke the actual method.
130 Method method = methods[i];
131
132 // Catch on the setter methods. They start with the string set and
133 // have only one parameter.
134 if (method.getName().startsWith("set")) {
135
136 // Check the documentation for the Class object if this doesn't make
137 // sense to you.
138 Class [] params = method.getParameterTypes();
139
140 if (params.length == 1) {
141
142 // Should be obvious what we are capturing here.
143 Class param = params[0];
144 String paramType = param.getName();
145 String propName = method.getName().substring(3);
146 String propValue = props.getProperty(propName);
147
148 /*
149 * Test each based on the parameter type. If there is a property
150 * that is assigned, then test if the value is in the correct format
151 * using the regular expressions to test validity. If they are valid,
152 * then invoke the setter method for the property on the Simulation sim
153 * object with the appropriate parameter array. Throw a marshalling
154 * exception with more information to the user on the invalid property
155 * otherwise.
156 */
157 if (!(propValue == null)) {
158 if (paramType.equals("int")) {
159 if(intRegexp.match(propValue)) {
160 invokeParam[0] = new Integer(propValue);
161 method.invoke(sim, invokeParam);
162 } else {
163 throw new MarshallingException("Invalid " + propName + " value: " + propValue);
164 }
165 } else if (paramType.equals("double")) {
166 if (decimalRegexp.match(propValue)) {
167 invokeParam[0] = new Double(propValue);
168 method.invoke(sim, invokeParam);
169 } else {
170 throw new MarshallingException("Invalid " + propName + " value: " + propValue);
171 }
172 } else if (paramType.equals("java.lang.String")) {
173 if (stringRegexp.match(propValue)) {
174 invokeParam[0] = propValue;
175 method.invoke(sim, invokeParam);
176 } else {
177 throw new MarshallingException("Invalid " + propName + " value: " + propValue);
178 }
179 } else if (paramType.equals("boolean")) {
180 if (booleanRegexp.match(propValue)) {
181 invokeParam[0] = new Boolean(propValue);
182 method.invoke(sim, invokeParam);
183 } else {
184 throw new MarshallingException("Invalid " + propName + " value: " + propValue);
185 }
186 }
187 }
188 }
189 }
190 }
191
192 // Close up the properties file input stream
193 fin.close();
194
195 // Return the constructed bean.
196 return sim;
197
198 }
199 catch (IllegalAccessException e) {
200 throw new MarshallingException("Can't access property: " + e.toString());
201 }
202 catch (InvocationTargetException e) {
203 throw new MarshallingException("Invalid property: " + e.toString());
204 }
205 catch (FileNotFoundException e) {
206 throw new MarshallingException("Invalid File: " + file + " " + e.toString());
207 }
208 catch (IOException e) {
209 throw new MarshallingException("Problem File: " + file + " " + e.toString());
210 }
211
212 }
213
214 }