View Javadoc

1   /*
2    * Copyright 2006 - 2012 Christina Bohk and Roland Ewald
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   */
16  package p3j.misc;
17  
18  import james.core.data.DBConnectionData;
19  
20  import java.io.File;
21  import java.io.FileNotFoundException;
22  import java.io.FileOutputStream;
23  import java.text.DecimalFormat;
24  import java.util.ArrayList;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Map.Entry;
28  
29  import javax.xml.transform.OutputKeys;
30  import javax.xml.transform.Transformer;
31  import javax.xml.transform.TransformerException;
32  import javax.xml.transform.TransformerFactory;
33  import javax.xml.transform.dom.DOMSource;
34  import javax.xml.transform.stream.StreamResult;
35  
36  import org.w3c.dom.Document;
37  
38  import p3j.simulation.ExecutionMode;
39  
40  /**
41   * Miscellaneous (auxiliary) functions and constants. For simulation-related
42   * constants, see {@link p3j.simulation.calculation.deterministic.Constants}.
43   * 
44   * Created on February 12, 2007
45   * 
46   * @author Christina Bohk
47   * @author Roland Ewald
48   */
49  public final class Misc {
50  
51  	/**
52  	 * The delimiter used by hibernate to name classes. For example, a hibernate
53  	 * object representing p3j.pppm.sets.Set would be of type
54  	 * p3j.pppm.sets.Set$$CGLibetc.
55  	 */
56  	private static final String DELIMITER_OF_HIBERNATE_TYPES = "$$";
57  
58  	/** Base of numerical system that is used. */
59  	public static final int BASE_NUM = 10;
60  
61  	/** Number format to be used when editing matrices. */
62  	public static final DecimalFormat NUMBER_FORMAT = new DecimalFormat(
63  	    "0.00000000");
64  
65  	/** Minimal precision value (used to avoid rounding problems). */
66  	public static final double EPSILON = 0.0000000001;
67  
68  	/** The name of the configuration file. */
69  	public static final String CONFIG_FILE = "conf/config.xml";
70  
71  	/** The default datbase URL. */
72  	public static final String DEFAULT_DB_URL = "jdbc:hsqldb:file:./pppm_db";
73  
74  	/** The default database user name. */
75  	public static final String DEFAULT_DB_USER = "root";
76  
77  	/** The default database password. */
78  	public static final String DEFAULT_DB_PWD = "";
79  
80  	/** The default execution mode. */
81  	public static final ExecutionMode DEFAULT_EXEC_MODE = ExecutionMode.MONTE_CARLO;
82  
83  	/** Default setup for database connection. */
84  	public static final DBConnectionData DEFAULT_DB_CONN = new DBConnectionData(
85  	    DEFAULT_DB_URL, DEFAULT_DB_USER, DEFAULT_DB_PWD, null);
86  
87  	/** The default location of the hibernate configuration file. */
88  	public static final String DEFAULT_HIBERNATE_CONFIG_FILE = "conf/hibernate.cfg.xml";
89  
90  	/** The default location of the hibernate configuration file for testing. */
91  	public static final String TEST_HIBERNATE_CONFIG_FILE = "test.hibernate.cfg.xml";
92  
93  	/** The default number of trials. */
94  	public static final int DEFAULT_NUM_TRIALS = 1000;
95  
96  	/** The default number of parallel threads. */
97  	public static final int DEFAULT_NUM_PARALLEL_THREADS = 1;
98  
99  	// Keys for the configuration file:
100 
101 	/** The key for the database URL. */
102 	public static final String PREF_DB_URL = "Database URL";
103 
104 	/** The key for the database user name. */
105 	public static final String PREF_DB_USER = "Database User Name";
106 
107 	/** The key for the database password. */
108 	public static final String PREF_DB_PWD = "Database Password";
109 
110 	/** The key for the number of trials. */
111 	public static final String PREF_NUM_TRIALS = "Number of Trials";
112 
113 	/** The key for the number of parallel threads. */
114 	public static final String PREF_NUM_PARALLEL_THREADS = "Parallel Threads (Monte-Carlo)";
115 
116 	/** The key for the execution mode. */
117 	public static final String PREF_EXECUTION_MODE = "Execution Mode";
118 
119 	// Some common GUI Labels
120 
121 	/** The Constant GUI_LABEL_PROBABILITY. */
122 	public static final String GUI_LABEL_PROBABILITY = "Probability (in [0,1]):";
123 
124 	/** The Constant GUI_LABEL_NAME. */
125 	public static final String GUI_LABEL_NAME = "Name:";
126 
127 	/** The Constant GUI_LABEL_DESCRIPTION. */
128 	public static final String GUI_LABEL_DESCRIPTION = "Description:";
129 
130 	/** The Constant GUI_LABEL_DEVIATION. */
131 	public static final String GUI_LABEL_DEVIATION = "Standard deviation";
132 
133 	/** The label for the jump-off year in the GUI. */
134 	public static final String GUI_LABEL_JUMP_OFF_YEAR = "Jump-Off Year";
135 
136 	/** The number of age classes. */
137 	public static final String GUI_LABEL_NUM_AGE_CLASSES = "Number of Age Classes:";
138 
139 	/** The number of descendant generations. */
140 	public static final String GUI_LABEL_DESCENDANT_GENERATIONS = "Descendant Generations:";
141 
142 	/** The projection horizon. */
143 	public static final String GUI_LABEL_PROJECTION_HORIZON = "Projection Horizon:";
144 
145 	/**
146 	 * This class should not be instantiated.
147 	 */
148 	private Misc() {
149 	}
150 
151 	/**
152 	 * Retrieves file ending.
153 	 * 
154 	 * @param file
155 	 *          the file name
156 	 * 
157 	 * @return file ending
158 	 */
159 	public static String getFileEnding(File file) {
160 		return file.getName().substring(file.getName().lastIndexOf('.') + 1);
161 	}
162 
163 	/**
164 	 * Parses string to double. Replaces ',' by '.'.
165 	 * 
166 	 * @param value
167 	 *          string to be parsed
168 	 * 
169 	 * @return double value
170 	 */
171 	public static double parseToDouble(Object value) {
172 		return Double.parseDouble(value.toString().replace(',', '.'));
173 	}
174 
175 	/**
176 	 * Converts a string into a probability (a double that has to be in [0,1]).
177 	 * 
178 	 * @param probString
179 	 *          string containing a probability
180 	 * 
181 	 * @return double value if valid, otherwise 0
182 	 */
183 	public static double parseToDoubleProb(String probString) {
184 		double probability = parseToDouble(probString);
185 		if (probability < 0 || probability > 1) {
186 			return 0;
187 		}
188 		return probability;
189 	}
190 
191 	/**
192 	 * Two values are recognised as equal as long as their absolute differece does
193 	 * not exceed EPSILON.
194 	 * 
195 	 * @param x
196 	 *          the first value
197 	 * @param y
198 	 *          the second value
199 	 * 
200 	 * @return true if |x-y| < e
201 	 */
202 	public static boolean numEqual(double x, double y) {
203 		return Math.abs(x - y) < EPSILON;
204 	}
205 
206 	/**
207 	 * Parses string to integer.
208 	 * 
209 	 * @param numString
210 	 *          the string containing the number
211 	 * 
212 	 * @return integer value of string
213 	 */
214 	public static int parseToInt(String numString) {
215 		return Integer.parseInt(numString);
216 	}
217 
218 	/**
219 	 * Rounds a value to a certain number of digits after the comma.
220 	 * 
221 	 * @param value
222 	 *          the value
223 	 * @param digits
224 	 *          the desired maximum number of digits after the comma
225 	 * 
226 	 * @return value value rounded to a given number of digits after the comma
227 	 */
228 	public static double round(double value, int digits) {
229 		return ((int) (value * Math.pow(BASE_NUM, digits)) / Math.pow(BASE_NUM,
230 		    digits));
231 	}
232 
233 	/**
234 	 * Writes a document to a file.
235 	 * 
236 	 * @param fileName
237 	 *          the name of the file
238 	 * @param document
239 	 *          the document to be written
240 	 * 
241 	 * @throws FileNotFoundException
242 	 *           if destination file could not be found/created
243 	 * @throws TransformerException
244 	 *           if transformation of document to XML failed
245 	 */
246 	@Deprecated
247 	public static void writeDocumentToFile(String fileName, Document document)
248 	    throws FileNotFoundException, TransformerException {
249 
250 		File f = new File(fileName);
251 
252 		FileOutputStream fop = new FileOutputStream(f);
253 
254 		// Writing document...
255 		TransformerFactory tff = TransformerFactory.newInstance();
256 		Transformer tf = tff.newTransformer();
257 
258 		tf.setOutputProperty(OutputKeys.METHOD, "xml");
259 		tf.setOutputProperty(OutputKeys.INDENT, "yes");
260 
261 		DOMSource source = new DOMSource(document);
262 		StreamResult result = new StreamResult(fop);
263 
264 		tf.transform(source, result);
265 	}
266 
267 	/**
268 	 * Auto-casts any kind of object to the desired case. This is a work-around
269 	 * for Java's many insufficiencies regarding generics etc. Handle with care,
270 	 * only use this when you know what you are doing!
271 	 * 
272 	 * @param o
273 	 *          the object
274 	 * 
275 	 * @param <X>
276 	 *          the desired type
277 	 * 
278 	 * @return the object, now casted to the desired type
279 	 */
280 	@SuppressWarnings("unchecked")
281 	public static <X> X autoCast(Object o) {
282 		return (X) o;
283 	}
284 
285 	/**
286 	 * Checks whether two classes are the same. This is tricky here: Hibernate
287 	 * enhances/replaces existing types, so classes from DB and from JVM are not
288 	 * the same! Classes for the DB have '_$$_...' etc. with them.
289 	 * 
290 	 * @param class1
291 	 *          one class
292 	 * @param class2
293 	 *          the other class
294 	 * 
295 	 * @return true if classes are the same, otherwise false
296 	 */
297 	public static boolean checkClassEquality(Class<?> class1, Class<?> class2) {
298 		return getCleanedClassName(class1).compareTo(getCleanedClassName(class2)) == 0;
299 	}
300 
301 	/**
302 	 * Cleans up class name by removing everything after '_$$_', which is used by
303 	 * Hibernate to identify generated custom classes
304 	 * ('my.Class_$$_javassist...').
305 	 * 
306 	 * @param theClass
307 	 *          the class for which the name should be cleaned up
308 	 * 
309 	 * @return the cleaned-up class name
310 	 */
311 	public static String getCleanedClassName(Class<?> theClass) {
312 		String name = theClass.getCanonicalName();
313 		int cutOffIndex = name.indexOf(DELIMITER_OF_HIBERNATE_TYPES);
314 		return cutOffIndex < 0 ? name : name.substring(0, cutOffIndex);
315 	}
316 
317 	/**
318 	 * Merges list of lists to a newly created {@link ArrayList}.
319 	 * 
320 	 * @param listsToMerge
321 	 *          the lists to merge
322 	 * @param <D>
323 	 *          the type of the list elements
324 	 * @return the new list, containing all elements of the others
325 	 */
326 	public static <D> List<D> mergeList(List<D>... listsToMerge) {
327 		List<D> result = new ArrayList<D>();
328 		for (List<D> listToMerge : listsToMerge) {
329 			result.addAll(listToMerge);
330 		}
331 		return result;
332 	}
333 
334 	/**
335 	 * Inverts a map.
336 	 * 
337 	 * @param src
338 	 *          the content
339 	 * @param dest
340 	 *          the destination map to be filled (will be cleared at first)
341 	 * 
342 	 * @param <X>
343 	 *          the type of the original keys
344 	 * @param <Y>
345 	 *          the type of the original values
346 	 */
347 	public static <X, Y> void invertMap(Map<X, Y> src, Map<Y, X> dest) {
348 		dest.clear();
349 		for (Entry<X, Y> entry : src.entrySet()) {
350 			if (dest.containsKey(entry.getValue())) {
351 				throw new IllegalArgumentException("Passed map contains value '"
352 				    + entry + "' twice, cannot be inverted.");
353 			}
354 			dest.put(entry.getValue(), entry.getKey());
355 		}
356 	}
357 
358 }