View Javadoc

1   /*
2       Copyright 2006 Ernest Micklei @ PhilemonWorks.com
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  */
17  package com.philemonworks.selfdiagnose;
18  
19  import java.io.IOException;
20  import java.util.Locale;
21  import java.util.Properties;
22  import java.util.Stack;
23  
24  import org.apache.log4j.Logger;
25  import org.xml.sax.Attributes;
26  import org.xml.sax.SAXException;
27  import org.xml.sax.helpers.DefaultHandler;
28  
29  /**
30   * SelfDiagnoseHandler is a SAX handler that can read the configuration xml file
31   * called <strong>selfdiagnose.xml</strong> that conforms to the XSD <strong>selfdiagnose-2.0.xsd</strong>
32   *
33   * @author E.M.Micklei
34   */
35  public class SelfDiagnoseHandler extends DefaultHandler {
36  	private Stack iteratorStack = new Stack();
37      private static Properties taskMapping;
38  	/**
39  	 * In order to read the configuration, all task element definitions must be known.
40  	 */
41  	static {
42  	    taskMapping = new Properties();
43  	    try {
44  	        taskMapping.load(SelfDiagnoseHandler.class.getResourceAsStream("/task-mapping.properties"));
45          } catch (IOException e) {
46              Logger.getLogger(SelfDiagnoseHandler.class).error("Unable to initialize SelfDiagnoseHandler",e);
47          }
48  	}
49  	/**
50  	 * Register a DiagnosticTask with an XML tag (which is constructed from the short class name in lowercase).
51  	 * If the configuration has an element named by this tag then a new DiagnosticTask
52  	 * is created and initialized by the handler.
53  	 * @param diagnosticTaskClass Class must be concrete subclass of DiagnosticTask
54  	 */
55  	public static void addBindingFor(Class diagnosticTaskClass){
56  		if (!DiagnosticTask.class.isAssignableFrom(diagnosticTaskClass))
57  			throw new RuntimeException("Only DiagnosticTask classes can be handled");
58  		String tag = DiagnoseUtil.shortName(diagnosticTaskClass).toLowerCase(Locale.getDefault());
59  		taskMapping.setProperty(tag, diagnosticTaskClass.getName());
60  	}
61  	/*
62  	 * (non-Javadoc)
63  	 * 
64  	 * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String,
65  	 *      org.xml.sax.Attributes)
66  	 */
67  	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
68  		if ("selfdiagnose".equals(qName))
69  			return; // document root
70  		if ("tasks".equals(qName))
71  			return; // sequence
72  		if ("task".equals(qName)) {
73  			this.handleCustomTask(attributes);
74  			return;
75  		}	
76  		if ("iterator".equals(qName)) {
77  		    this.handleIterator(attributes);
78  		    return;
79  		}
80          try {
81              // element names for tasks are case-insensitive
82              String className = taskMapping.getProperty(qName.toLowerCase(Locale.getDefault()));
83              Class taskClass = Thread.currentThread().getContextClassLoader().loadClass(className);
84              if (taskClass == null)
85                  throw new RuntimeException("No task class registered (case-insensitive) for:" + qName);
86  			DiagnosticTask task = (DiagnosticTask)taskClass.newInstance();
87  			task.initializeFromAttributes(attributes);
88  			this.addTaskToRegistration(task);
89  		} catch (Exception ex){
90  			throw new SAXException("Failed to create/initialize the task for:"+qName,ex);
91  		}		
92  	}
93      public void endElement(String uri, String localName, String name) throws SAXException {
94          if ("iterator".equals(name)) {
95              CollectionIteratorTask cit = (CollectionIteratorTask) iteratorStack.pop();
96              this.addTaskToRegistration(cit);           
97          }
98      }
99      private void handleIterator(Attributes attributes) {
100         CollectionIteratorTask cit = new CollectionIteratorTask();
101         cit.initializeFromAttributes(attributes);
102         iteratorStack.push(cit);        
103     }
104 	private void handleCustomTask(Attributes attributes) throws SAXException {
105 		String className = attributes.getValue("class");
106 		CustomDiagnosticTask customTask = new CustomDiagnosticTask();
107 		if (className == null) throw new SAXException("Missing xml attribute [class] for tag [task]");
108 		try {
109 			Class taskClass = Thread.currentThread().getContextClassLoader().loadClass(className);
110 			DiagnosticTask task = (DiagnosticTask)taskClass.newInstance();
111 			task.initializeFromAttributes(attributes);			
112 			customTask.setTask(task);
113 		} catch (Exception e) {
114 			customTask.setErrorMessage(e.getMessage());
115 			this.addTaskToRegistration(customTask);
116 			throw new SAXException(e);
117 		}
118 		this.addTaskToRegistration(customTask);
119 	}
120 	private void addTaskToRegistration(DiagnosticTask task) {
121 	    // if the task is contained by an iterator then add it to the container
122 	    if (!iteratorStack.isEmpty()) {
123 	        CollectionIteratorTask cit = (CollectionIteratorTask) iteratorStack.lastElement();
124 	        cit.register(task);
125 	        return;
126 	    }
127 	    SelfDiagnose.register(task,SelfDiagnose.getConfigFilename());
128 	}
129 }