1 package com.atlassian.johnson.config;
2
3 import com.atlassian.johnson.event.*;
4 import com.atlassian.johnson.setup.SetupConfig;
5 import com.atlassian.johnson.Initable;
6 import com.atlassian.seraph.util.PathMapper;
7 import com.opensymphony.util.ClassLoaderUtil;
8 import org.apache.log4j.Category;
9 import org.w3c.dom.Element;
10 import org.w3c.dom.Node;
11 import org.w3c.dom.NodeList;
12 import org.w3c.dom.Text;
13
14 import javax.xml.parsers.DocumentBuilderFactory;
15 import java.net.URL;
16 import java.util.*;
17
18
19
20
21 public class JohnsonConfig
22 {
23 private static final Category log = Category.getInstance(JohnsonConfig.class);
24 private static JohnsonConfig instance;
25
26 private static final String DEFAULT_CONFIGURATION_FILE = "johnson-config.xml";
27
28 private String configurationFile;
29 private SetupConfig setupConfig;
30 private List eventChecks;
31 private List requestEventChecks;
32 private List applicationEventChecks;
33 private Map eventChecksById;
34 private Map params;
35 private String setupPath;
36 private String errorPath;
37 private PathMapper ignoreMapper;
38 private Map eventLevels;
39 private Map eventTypes;
40 private List ignorePaths;
41
42 public static JohnsonConfig getInstance()
43 {
44 if (instance == null)
45 {
46 try
47 {
48 if (instance == null)
49 {
50 instance = new JohnsonConfig(DEFAULT_CONFIGURATION_FILE);
51 }
52 }
53 catch (ConfigurationException e)
54 {
55 log.error("Could not configure JohnsonConfig instance: " + e, e);
56 }
57 }
58
59 return instance;
60 }
61
62 public JohnsonConfig(String configurationFile) throws ConfigurationException
63 {
64 this.configurationFile = configurationFile;
65 init();
66 }
67
68 public List getEventChecks()
69 {
70 return eventChecks;
71 }
72
73 public List getRequestEventChecks()
74 {
75 return requestEventChecks;
76 }
77
78 public List getApplicationEventChecks()
79 {
80 return applicationEventChecks;
81 }
82
83 public EventCheck getEventCheck(int id)
84 {
85 return (EventCheck) eventChecksById.get(new Integer(id));
86 }
87
88 public Map getParams()
89 {
90 return params;
91 }
92
93 public SetupConfig getSetupConfig()
94 {
95 return setupConfig;
96 }
97
98 public String getSetupPath()
99 {
100 return setupPath;
101 }
102
103 public String getErrorPath()
104 {
105 return errorPath;
106 }
107
108 public List getIgnorePaths()
109 {
110 return ignorePaths;
111 }
112
113 public boolean isIgnoredPath(String uri)
114 {
115 return ignoreMapper.get(uri) != null;
116 }
117
118 public EventLevel getEventLevel(String level)
119 {
120 return (EventLevel) eventLevels.get(level);
121 }
122
123 public EventType getEventType(String type)
124 {
125 return (EventType) eventTypes.get(type);
126 }
127
128 private void init() throws ConfigurationException
129 {
130 try
131 {
132 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
133 URL fileUrl = ClassLoaderUtil.getResource(configurationFile, this.getClass());
134
135 if (fileUrl == null)
136 throw new IllegalArgumentException("No such XML file:" + configurationFile);
137
138
139 org.w3c.dom.Document doc = factory.newDocumentBuilder().parse(fileUrl.toString());
140 Element rootEl = doc.getDocumentElement();
141
142 setupConfig = (SetupConfig) configureClass(rootEl, "setupconfig");
143 configureEventChecks(rootEl);
144 eventLevels = configureEventConstants(rootEl, "eventlevels", "eventlevel");
145 eventTypes = configureEventConstants(rootEl, "eventtypes", "eventtype");
146 params = configureParameters(rootEl);
147 setupPath = (String) configurePaths(rootEl, "setup").get(0);
148 errorPath = (String) configurePaths(rootEl, "error").get(0);
149 ignorePaths = configurePaths(rootEl, "ignore");
150
151
152 ignoreMapper = new PathMapper();
153 for (Iterator iterator = ignorePaths.iterator(); iterator.hasNext();)
154 {
155 String path = (String) iterator.next();
156 ignoreMapper.put(path, path);
157 }
158
159 }
160 catch (Exception e)
161 {
162 e.printStackTrace();
163 throw new ConfigurationException("Exception configuring: " + e);
164 }
165 }
166
167 private Map configureEventConstants(Element rootEl, String tagname, String childname)
168 {
169 NodeList nl = rootEl.getElementsByTagName(tagname);
170
171 if (nl != null && nl.getLength() > 0)
172 {
173 Element element = (Element) nl.item(0);
174 NodeList children = element.getElementsByTagName(childname);
175 Map result = new HashMap(children.getLength());
176
177 for (int i = 0; i < children.getLength(); i++)
178 {
179 Element child = (Element) children.item(i);
180 String key = child.getAttribute("key");
181 String description = getContainedText(child, "description");
182
183 if (childname.equals("eventlevel"))
184 {
185 result.put(key, new EventLevel(key, description));
186 }
187 else if (childname.equals("eventtype"))
188 {
189 result.put(key, new EventType(key, description));
190 }
191 }
192
193 return result;
194 }
195
196 return Collections.EMPTY_MAP;
197 }
198
199 private List configurePaths(Element rootEl, String tagname)
200 {
201 NodeList nl = rootEl.getElementsByTagName(tagname);
202
203 if (nl != null && nl.getLength() > 0)
204 {
205 Element element = (Element) nl.item(0);
206 NodeList children = element.getElementsByTagName("path");
207 List result = new ArrayList(children.getLength());
208
209 for (int i = 0; i < children.getLength(); i++)
210 {
211 Element child = (Element) children.item(i);
212 result.add(((Text) child.getFirstChild()).getData().trim());
213 }
214
215 return result;
216 }
217
218 return Collections.EMPTY_LIST;
219 }
220
221 private Map configureParameters(Element rootEl)
222 {
223 NodeList nl = rootEl.getElementsByTagName("parameters");
224
225 if (nl.getLength() > 0)
226 {
227 Element parametersEl = (Element) nl.item(0);
228 return getInitParameters(parametersEl);
229 }
230
231 return Collections.EMPTY_MAP;
232 }
233
234 private Initable configureClass(Element rootEl, String tagname) throws ConfigurationException
235 {
236 try
237 {
238 NodeList elementList = rootEl.getElementsByTagName(tagname);
239
240 for (int i = 0; i < elementList.getLength(); i++)
241 {
242 Element authEl = (Element) elementList.item(i);
243 String clazz = authEl.getAttribute("class");
244
245 Initable initable = (Initable) ClassLoaderUtil.loadClass(clazz, this.getClass()).newInstance();
246 Map params = getInitParameters(authEl);
247 initable.init(params);
248 return initable;
249 }
250 }
251 catch (Exception e)
252 {
253 throw new ConfigurationException("Could not create: " + tagname + ": ", e);
254 }
255
256 return null;
257 }
258
259
260 private void configureEventChecks(Element rootEl) throws ConfigurationException
261 {
262 NodeList nl = rootEl.getElementsByTagName("eventchecks");
263
264 if (nl != null && nl.getLength() > 0)
265 {
266 eventChecks = new LinkedList();
267 requestEventChecks = new LinkedList();
268 applicationEventChecks = new LinkedList();
269 eventChecksById = new HashMap();
270
271 Element eventChecksEl = (Element) nl.item(0);
272 NodeList eventCheckList = eventChecksEl.getElementsByTagName("eventcheck");
273
274 for (int i = 0; i < eventCheckList.getLength(); i++)
275 {
276 Element eventCheckEl = (Element) eventCheckList.item(i);
277 String eventCheckClazz = eventCheckEl.getAttribute("class");
278
279 if (eventCheckClazz == null || "".equals(eventCheckClazz))
280
281 throw new ConfigurationException("eventcheck element with bad class attribute");
282
283 Object o = null;
284 try
285 {
286 log.debug("Adding eventcheck of class: " + eventCheckClazz);
287 o = ClassLoaderUtil.loadClass(eventCheckClazz, this.getClass()).newInstance();
288 }
289 catch (Exception e)
290 {
291 log.error(e);
292 throw new ConfigurationException("Could not create eventcheck: " + eventCheckClazz + ". Exception: " + e);
293 }
294
295 EventCheck eventCheck = null;
296 if (o instanceof EventCheck)
297 {
298 eventCheck = (EventCheck) o;
299 eventChecks.add(eventCheck);
300 }
301 else
302 {
303 throw new ConfigurationException("Eventcheck " + eventCheckClazz + " does not implement EventCheck interface.");
304 }
305
306 Map params = getInitParameters(eventCheckEl);
307 eventCheck.init(params);
308
309 if (eventCheck instanceof RequestEventCheck)
310 {
311 requestEventChecks.add(eventCheck);
312 }
313
314 if (eventCheck instanceof ApplicationEventCheck)
315 {
316 applicationEventChecks.add(eventCheck);
317 }
318
319 String eventCheckId = eventCheckEl.getAttribute("id");
320 if (eventCheckId != null && !"".equals(eventCheckId))
321 {
322 try
323 {
324 Integer id = Integer.valueOf(eventCheckId);
325 if (!eventChecksById.containsKey(id))
326 {
327 eventChecksById.put(id, eventCheck);
328 }
329 else
330 {
331 throw new ConfigurationException("Duplicate eventcheck id '" + id + "'.");
332 }
333 }
334 catch (NumberFormatException e)
335 {
336 throw new ConfigurationException("Eventcheck id must be an integer.", e);
337 }
338 }
339 }
340 }
341 else
342 {
343 eventChecks = Collections.EMPTY_LIST;
344 requestEventChecks = Collections.EMPTY_LIST;
345 applicationEventChecks = Collections.EMPTY_LIST;
346 eventChecksById = Collections.EMPTY_MAP;
347 }
348 }
349
350 private Map getInitParameters(Element el)
351 {
352 Map params = new HashMap();
353
354 NodeList nl = el.getElementsByTagName("init-param");
355
356 for (int i = 0; i < nl.getLength(); i++)
357 {
358 Node initParam = nl.item(i);
359 String paramName = getContainedText(initParam, "param-name");
360 String paramValue = getContainedText(initParam, "param-value");
361 params.put(paramName, paramValue);
362 }
363
364 return params;
365 }
366
367 public static void setInstance(JohnsonConfig johnsonConfig)
368 {
369 instance = johnsonConfig;
370 }
371
372 private String getContainedText(Node parent, String childTagName)
373 {
374 try
375 {
376 Node tag = ((Element) parent).getElementsByTagName(childTagName).item(0);
377 return ((Text) tag.getFirstChild()).getData();
378 }
379 catch (Exception e)
380 {
381 return null;
382 }
383 }
384 }