1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.finalist.jaggenerator;
18
19 import org.w3c.dom.Document;
20 import org.w3c.dom.Element;
21 import org.w3c.dom.NodeList;
22 import org.xml.sax.SAXException;
23
24 import javax.xml.parsers.DocumentBuilder;
25 import javax.xml.parsers.DocumentBuilderFactory;
26 import javax.xml.parsers.ParserConfigurationException;
27 import java.io.File;
28 import java.io.FileWriter;
29 import java.io.IOException;
30 import java.util.*;
31
32 /***
33 * The ConfigManager deals with loading / saving JAG configuraton information
34 * to/from an XML config file.
35 *
36 * @author Michael O'Connor - Finalist IT Group
37 */
38 public class ConfigManager {
39
40 private static final String JAG_CONFIG = "jag-config";
41 private static final File JAG_CONFIG_FILE = new File("jag-config.xml");
42 private static final String[] STRING_ARRAY = new String[0];
43 private static final File DATABASE_DRIVERS_CLASSPATH_FILE =
44 new File("set_database_drivers_classpath.bat");
45 private static final String SET_COMMAND = "set DATABASE_DRIVERS_CLASSPATH=";
46 private static final char SEMICOLON = ';';
47
48 /***
49 * The name of the XML tag that contains the GUI configuration properties.
50 */
51 protected static final String XMLTAG_GUI = "gui";
52
53 private static ConfigManager ourInstance;
54 private Document doc;
55
56
57 private ConfigManager() {
58 load();
59 }
60
61
62 /***
63 * The ConfigManager is a singleton - this method obtains the one and only instance.
64 *
65 * @return
66 */
67 public synchronized static ConfigManager getInstance() {
68 if (ourInstance == null) {
69 ourInstance = new ConfigManager();
70 }
71 return ourInstance;
72 }
73
74 /***
75 * Gets the config information, parsed as an XML document.
76 * <p/>
77 * <b>NOTE:</b> this Document is provided READ-ONLY - any changes made to the doc will NOT be persisted!
78 *
79 * @return the doc.
80 */
81 public Document getDocument() {
82 return doc;
83 }
84
85 /***
86 * Creates a Map that contains key-value pairs representing the XML elements / text nodes
87 * that fall underneath the node with the supplied name. If there are more than one node with the supplied
88 * name, only the first of these is translated into a Map.
89 * <p/>
90 * Property values are of type String[] : if a given property within the Map occurs more than
91 * once in the XML there will be more than one String in the array.
92 *
93 * @param rootElementName The name of the parent node whose children we want making into a Properties object.
94 *
95 * @return a Map whose keys are Strings and whose values are String[].
96 * The map will be empty (but never <code>null</code>) if there are no nodes with the name
97 * specified in <code>rootElementName</code>.
98 */
99 public Map retrievePropertiesFromXML(String rootElementName) {
100 HashMap props = new HashMap();
101 Element propsRoot = (Element) doc.getElementsByTagName(rootElementName).item(0);
102 if (propsRoot != null) {
103 NodeList children = propsRoot.getChildNodes();
104
105 for (int j = 0; j < children.getLength(); j++) {
106 if (children.item(j) instanceof Element) {
107 Element child = (Element) children.item(j);
108 String key = child.getNodeName();
109 String[] existingValues = (String[]) props.get(key);
110 if (existingValues == null) {
111 props.put(key, new String[]{child.getFirstChild().getNodeValue()});
112 }
113 else {
114 ArrayList newValues = new ArrayList(Arrays.asList(existingValues));
115 newValues.add(child.getFirstChild().getNodeValue());
116 props.put(key, newValues.toArray(STRING_ARRAY));
117 }
118 }
119 }
120 }
121
122 return props;
123 }
124
125 /***
126 * Saves the configurations to the XML JAG_CONFIG_FILE.
127 */
128 public void save() {
129 try {
130 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
131 DocumentBuilder builder = dbf.newDocumentBuilder();
132 Document newDoc = builder.newDocument();
133 Element root = newDoc.createElement(JAG_CONFIG);
134
135
136 Element dbRoot = DatabaseManager.getInstance().appendXML(root);
137 root.appendChild(dbRoot);
138
139 newDoc.appendChild(root);
140
141
142 HashMap mappingsMap = new HashMap();
143 mappingsMap.put(DatabaseManager.NAME, DatabaseManager.getInstance().getTypeMappings());
144 Element mappingsRoot = appendPropertiesAsXML(root, mappingsMap, DatabaseManager.APPSERVER_TYPEMAPPINGS);
145 root.appendChild(mappingsRoot);
146
147 String XMLDoc = com.finalist.jaggenerator.JagGenerator.outXML(newDoc);
148 FileWriter fw = new FileWriter(JAG_CONFIG_FILE);
149 fw.write(XMLDoc);
150 fw.close();
151
152 }
153 catch (ParserConfigurationException e) {
154 e.printStackTrace();
155 }
156 catch (IOException e) {
157 e.printStackTrace();
158 }
159
160 saveDatabaseDriversClasspath();
161 }
162
163
164 /***
165 * Reads in JAG's configuration from the XML JAG_CONFIG_FILE.
166 */
167 private void load() {
168 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
169 DocumentBuilder builder = null;
170 try {
171 builder = dbf.newDocumentBuilder();
172 doc = builder.parse(JAG_CONFIG_FILE);
173
174 }
175 catch (ParserConfigurationException e) {
176 e.printStackTrace();
177 JagGenerator.kickTheBucket("The XML parser can't even start up!");
178 }
179 catch (SAXException e) {
180 e.printStackTrace();
181 JagGenerator.kickTheBucket("JAG's config JAG_CONFIG_FILE (" + JAG_CONFIG_FILE + ") is invalid!");
182 }
183 catch (IOException e) {
184 e.printStackTrace();
185 JagGenerator.kickTheBucket("JAG's can't access the config JAG_CONFIG_FILE (" + JAG_CONFIG_FILE + ")!");
186 }
187 }
188
189 /***
190 * Temporary work-around for dynamic loading of database driver classes..
191 * <p/>
192 * Write the database drivers classpath to a JAG_CONFIG_FILE, which is used by the startup scripts to build
193 * the JAG classpath.
194 */
195 private void saveDatabaseDriversClasspath() {
196 try {
197 DATABASE_DRIVERS_CLASSPATH_FILE.delete();
198 StringBuffer temp = new StringBuffer(SET_COMMAND);
199 Database[] databases = DatabaseManager.getInstance().getSupportedDatabases();
200 for (int i = 0; i < databases.length; i++) {
201 temp.append(databases[i].getFilename());
202 temp.append(SEMICOLON);
203 }
204
205 FileWriter fw = new FileWriter(DATABASE_DRIVERS_CLASSPATH_FILE);
206 fw.write(temp.toString());
207 fw.flush();
208 fw.close();
209 }
210 catch (IOException e) {
211 e.printStackTrace();
212 }
213 }
214
215 /***
216 * Converts a Properties object into XML and appends it to the supplied root element.
217 *
218 * @param root The root element to attach the properties XML to.
219 * @param props The Map containing the properties to be XML-ised. Must be a mapping of
220 * String to String[].
221 * @param rootElementName The name for the base XML tag.
222 */
223 private Element appendPropertiesAsXML(Element root, Map props, String rootElementName) {
224 Document doc = root.getOwnerDocument();
225 Element propsRoot = doc.createElement(rootElementName);
226
227 Iterator i = props.entrySet().iterator();
228 while (i.hasNext()) {
229 Map.Entry entry = (Map.Entry) i.next();
230 String propertyName = (String) entry.getKey();
231 String[] value = (String[]) entry.getValue();
232 for (int j = 0; j < value.length; j++) {
233 Element nelly = doc.createElement(propertyName);
234 if (value[j] != null) {
235 nelly.appendChild(doc.createTextNode(value[j]));
236 }
237 propsRoot.appendChild(nelly);
238 }
239 }
240 return propsRoot;
241 }
242 }