Skip to main content
summaryrefslogtreecommitdiffstats
blob: cf2fb22876f6f27e7f380be8a0a069ba85ac789a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*******************************************************************************
 * Copyright (c) 2004 Red Hat, Inc.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Keith Seitz <keiths@redhat.com> - initial API and implementation
 *******************************************************************************/ 
package org.eclipse.linuxtools.oprofile.core.opxml;

import java.util.HashMap;
import java.util.Stack;

import org.eclipse.linuxtools.oprofile.core.opxml.checkevent.CheckEventsProcessor;
import org.eclipse.linuxtools.oprofile.core.opxml.info.OpInfoProcessor;
import org.eclipse.linuxtools.oprofile.core.opxml.modeldata.ModelDataProcessor;
import org.eclipse.linuxtools.oprofile.core.opxml.sessions.SessionsProcessor;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;

/**
 * The SAX handler class that is used to parse the output of opxml.
 * @see org.eclipse.linuxtools.oprofile.core.opxml.OpxmlRunner
 */
public class OprofileSAXHandler extends DefaultHandler {
	// The only allowed instance of this class
	private static OprofileSAXHandler _instance = null;
	
	// A Map of all the XML processors for opxml
	private static HashMap<String,Class<?>> _processors = new HashMap<String,Class<?>>();
	
	// The current processor being used to parse the document
	private XMLProcessor _processor = null;
	private Object _callData;
	
	/* A stack of XML processors. This allows processors to invoke sub-processors
	   for handling nested tags more efficiently. */
	private Stack<XMLProcessor> _processorStack = new Stack<XMLProcessor>();
	
	// A convenience class for specifying XMLProcessors
	private static class ProcessorItem {
		public String tagName;
		public Class<?> handlerClass;
		public ProcessorItem(String name, Class<?> cls) {
			tagName = name;
			handlerClass = cls;
		}
	}
	
	// The list of all "root" XML tags and their handler classes 
	private static final ProcessorItem[] _handlerList = {
		new ProcessorItem(OpxmlConstants.INFO_TAG, OpInfoProcessor.class),
		new ProcessorItem(OpxmlConstants.CHECKEVENTS_TAG, CheckEventsProcessor.class),
		new ProcessorItem(OpxmlConstants.MODELDATA_TAG, ModelDataProcessor.class),
		new ProcessorItem(OpxmlConstants.SESSIONS_TAG, SessionsProcessor.class)
	};
	
	/**
	 * Returns an instance of the handler. This must be used to access the parser!
	 * @return a handler instance
	 */
	public static OprofileSAXHandler getInstance(Object callData) {
		if (_instance == null) {
			_instance = new OprofileSAXHandler();
			
			// Initialize processor map
			for (int i = 0; i < _handlerList.length; ++i) {
				_processors.put(_handlerList[i].tagName, _handlerList[i].handlerClass);
			}
		}
		
		// Set calldata into handler
		_instance.setCallData (callData);
		return _instance;
	}
	
	/**
	 * Sets the calldata for the processor.
	 * @param callData the calldata to pass to the processor
	 */
	public void setCallData(Object callData)
	{
		_callData = callData;
	}
	
	/**
	 * Returns the processor for a given request type.
	 * @param type the name of the processor
	 * @return the requested processor or null
	 */
	public static XMLProcessor getProcessor(String type) {
		XMLProcessor processor = null;
		
		Class<?> handlerClass = (Class<?>) _processors.get(type);
		if (handlerClass != null) {
			try {
				processor = (XMLProcessor) handlerClass.newInstance();
			} catch (InstantiationException e) {
			} catch (IllegalAccessException e) {
			}
		}
		
		return processor;
	}
	
	/**
	 * @see org.xml.sax.ContentHandler#startDocument()
	 */
	public void startDocument() {
		// Reset processor
		_processor = null;
	}
	
	/**
	 * @see org.xml.sax.ContentHandler#endDocument()
	 */
	public void endDocument() {
	}
	
	/**
	 * @see org.xml.sax.ContentHandler#startElement(String, String, String, Attributes)
	 */
	public void startElement(String uri, String lName, String qName, Attributes attrs) {
		if (_processor == null) {
			// Get processor for this event type
			_processor = getProcessor(qName);
			_processor.reset(_callData);
		}
		
		// If we already have a processor, so let it deal with this new element.
		// Allow the processor to deal with it's own tag as well: this way it can
		// grab attributes from it.
		_processor.startElement(qName, attrs, _callData);
	}
	
	/**
	 * @see org.xml.sax.ContentHandler#endElement(String, String, String)
	 */
	public void endElement(String uri, String name, String qName) {
		_processor.endElement(qName, _callData);
	}
	
	/**
	 * @see org.xml.sax.ContentHandler#characters(char[], int, int)
	 */
	public void characters(char ch[], int start, int length) {
		// Ignore characters which are only whitespace
		String str = new String(ch, start, length).trim();
		if (str.length() > 0 && _processor != null)
			_processor.characters(new String(ch, start, length), _callData);
	}
	
	/**
	 * Returns the processor used to parse the document.
	 * @return the XMLProcessor
	 */
	public XMLProcessor getProcessor() {
		return _processor;
	}
	
	/**
	 * Pushes the current XMLProcessor onto the stack and installs the given
	 * processor as the document's parser/handler.
	 * @param proc the processor to continue parsing the document
	 */
	public void push(XMLProcessor proc) {
		_processorStack.add(_processor);
		_processor = proc;
		_processor.reset(_callData);
	}
	
	/**
	 * Removes the current XMLProcessor and installs the previous processor.
	 * NOTE: This assumes that endElement caused the pop, so it calls endElement in
	 * the parent processor.
	 * @param tag the XML tag to pass to the parent processor
	 */
	public void pop(String tag) {
		_processor = (XMLProcessor) _processorStack.pop();
		_processor.endElement(tag, _callData);
	}
}

Back to the top