001: /*
002: * <copyright>
003: *
004: * Copyright 1997-2007 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.core.node;
028:
029: import java.io.CharArrayWriter;
030: import java.net.URL;
031: import java.util.ArrayList;
032: import java.util.Collections;
033: import java.util.HashMap;
034: import java.util.List;
035: import java.util.Map;
036: import org.cougaar.core.component.ComponentDescription;
037: import org.cougaar.util.Strings;
038: import org.cougaar.util.log.Logger;
039: import org.cougaar.util.log.Logging;
040: import org.xml.sax.Attributes;
041: import org.xml.sax.SAXException;
042: import org.xml.sax.SAXParseException;
043: import org.xml.sax.helpers.DefaultHandler;
044:
045: /**
046: * SAX {@link org.xml.sax.ContentHandler} that handles the society
047: * config parsing.
048: */
049: public class XMLConfigHandler extends DefaultHandler {
050:
051: private static final int STATE_INITIAL = 0;
052: private static final int STATE_PARSING = 1;
053: private static final int STATE_PARSED = 2;
054:
055: private final Map agents;
056: private final String nodename;
057: private final String agentname;
058: private final Logger logger;
059:
060: private final Map currentComponent = new HashMap(11);
061: private final CharArrayWriter argValueBuffer = new CharArrayWriter();
062:
063: private boolean processedNode;
064:
065: private boolean this Node;
066: private boolean this Agent;
067: private List currentList;
068: private String currentNode;
069: private String currentAgent;
070: private boolean inArgument;
071:
072: private int state = STATE_INITIAL;
073:
074: public XMLConfigHandler(String nodename, String agentname) {
075: this .nodename = nodename;
076: this .agentname = agentname;
077: this .logger = Logging.getLogger(getClass());
078: agents = new HashMap(agentname == null ? 11 : 1);
079: }
080:
081: public Map getAgents() {
082: return agents;
083: }
084:
085: public void startDocument() {
086: // not thread-safe, but close enough to warn developers
087: if (state != STATE_INITIAL) {
088: throw new RuntimeException(
089: "ContentHandler "
090: + (state == STATE_PARSING ? "already parsing"
091: : "completed parsing, please create a new instance"));
092: }
093: state = STATE_PARSING;
094: }
095:
096: public void endDocument() {
097: if (state != STATE_PARSING) {
098: throw new RuntimeException("ContentHandler "
099: + (state == STATE_INITIAL ? "never started"
100: : "already closed") + " document?");
101: }
102: state = STATE_PARSED;
103: }
104:
105: // begin element
106: public void startElement(String namespaceURI, String localName,
107: String qName, Attributes atts) throws SAXException {
108:
109: if (logger.isDetailEnabled()) {
110: StringBuffer buf = new StringBuffer();
111: buf.append("startElement(");
112: buf.append("namswpaceURI=").append(namespaceURI);
113: buf.append(", localName=").append(localName);
114: buf.append(", qName=").append(qName);
115: buf.append(", atts[").append(atts.getLength());
116: buf.append("]{");
117: for (int i = 0, n = atts.getLength(); i < n; i++) {
118: buf.append("\n(uri=").append(atts.getURI(i));
119: buf.append(" localName=").append(atts.getLocalName(i));
120: buf.append(" qName=").append(atts.getQName(i));
121: buf.append(" type=").append(atts.getType(i));
122: buf.append(" value=").append(atts.getValue(i));
123: buf.append("), ");
124: }
125: buf.append("\n}");
126: logger.detail(buf.toString());
127: }
128:
129: if (localName.equals("node")) {
130: startNode(atts);
131: } else if (localName.equals("agent")) {
132: startAgent(atts);
133: }
134:
135: if (!this Node && !this Agent) {
136: return;
137: }
138:
139: if (localName.equals("component")) {
140: startComponent(atts);
141: } else if (localName.equals("argument")) {
142: startArgument(atts);
143: } else {
144: // ignore
145: }
146: }
147:
148: // misc characters within an element, e.g. argument data
149: public void characters(char[] ch, int start, int length)
150: throws SAXException {
151:
152: if (logger.isDetailEnabled()) {
153: StringBuffer buf = new StringBuffer();
154: buf.append("characters(ch[").append(ch.length).append("]{");
155: buf.append(ch, start, length);
156: buf.append("}, ").append(start).append(", ");
157: buf.append(length).append(")");
158: logger.detail(buf.toString());
159: }
160:
161: if (inArgument) {
162: // inside component argument, so save characters
163: argValueBuffer.write(ch, start, length);
164: }
165: }
166:
167: // end element
168: public void endElement(String namespaceURI, String localName,
169: String qName) throws SAXException {
170:
171: if (logger.isDetailEnabled()) {
172: logger.detail("endElement(" + "namswpaceURI="
173: + namespaceURI + ", localName=" + localName
174: + ", qName=" + qName + ")");
175: }
176:
177: if (!this Node && !this Agent) {
178: return;
179: }
180:
181: if (localName.equals("argument")) {
182: endArgument();
183: } else if (localName.equals("component")) {
184: endComponent();
185: } else if (localName.equals("agent")) {
186: endAgent();
187: } else if (localName.equals("node")) {
188: endNode();
189: } else {
190: // ignore
191: }
192: }
193:
194: // xml parser error
195: public void error(SAXParseException exception) throws SAXException {
196: logger.error("Error parsing the file", exception);
197: super .error(exception);
198: }
199:
200: // xml parser warning
201: public void warning(SAXParseException exception)
202: throws SAXException {
203: logger.warn("Warning parsing the file", exception);
204: super .warning(exception);
205: }
206:
207: // our element handlers:
208:
209: private void startNode(Attributes atts) throws SAXException {
210: if (processedNode) {
211: return;
212: }
213:
214: String name = getValue(atts, "name");
215:
216: boolean anyName = (name == null || name.equals("*"));
217: boolean anyNode = (nodename == null || nodename.equals("*"));
218: boolean anyAgent = (agentname == null || agentname.equals("*"));
219:
220: this Node = (anyName || anyNode || nodename.equals(name));
221:
222: this Agent = (anyName || anyAgent || agentname.equals(name));
223:
224: if (!this Node || !this Agent) {
225: if (logger.isDebugEnabled()) {
226: logger.debug("skipping node " + name);
227: }
228: currentNode = null;
229: currentAgent = null;
230: return;
231: }
232:
233: processedNode = true;
234:
235: // make a new place for the node's components
236: currentNode = (anyName ? (anyNode ? null : nodename) : name);
237: currentAgent = currentNode;
238: currentList = (List) agents.get(currentNode);
239: if (currentList == null) {
240: currentList = new ArrayList(1);
241: agents.put(currentNode, currentList);
242: }
243:
244: if (logger.isInfoEnabled()) {
245: logger.info("starting node " + currentNode);
246: }
247: }
248:
249: private void endNode() throws SAXException {
250: if (this Node) {
251: if (logger.isInfoEnabled()) {
252: logger.info("finished node " + currentNode);
253: }
254: this Node = false;
255: currentNode = null;
256: currentAgent = null;
257: currentList = null;
258: } else {
259: if (logger.isDebugEnabled()) {
260: logger.debug("skipped node");
261: }
262: }
263: }
264:
265: private void startAgent(Attributes atts) throws SAXException {
266:
267: if (!this Node) {
268: boolean anyNode = (nodename == null || nodename.equals("*"));
269: if (!anyNode) {
270: return;
271: }
272: }
273:
274: String name = getValue(atts, "name");
275:
276: boolean anyName = (name == null || name.equals("*"));
277: boolean anyAgent = (agentname == null || agentname.equals("*"));
278:
279: this Agent = (anyName || anyAgent || agentname.equals(name));
280:
281: if (!this Agent) {
282: if (logger.isDebugEnabled()) {
283: logger.debug("skipping agent " + name);
284: }
285: // keep node's currentAgent and currentList
286: return;
287: }
288:
289: // make a new place for the agent's components
290: currentAgent = (anyName ? (anyAgent ? null : agentname) : name);
291: currentList = (List) agents.get(currentAgent);
292: if (currentList == null) {
293: currentList = new ArrayList(1);
294: agents.put(currentAgent, currentList);
295: }
296:
297: if (logger.isDebugEnabled()) {
298: logger.debug("starting agent " + currentAgent);
299: }
300: }
301:
302: private void endAgent() throws SAXException {
303: if (this Agent) {
304: if (logger.isDebugEnabled()) {
305: logger.debug("finished agent " + currentAgent);
306: }
307: this Agent = false;
308: // restore name to node's name
309: currentAgent = currentNode;
310: currentList = (List) agents.get(currentNode);
311: } else {
312: if (logger.isDebugEnabled()) {
313: logger.debug("skipped agent");
314: }
315: }
316: }
317:
318: private void startComponent(Attributes atts) throws SAXException {
319:
320: if (currentList == null) {
321: throw new RuntimeException(
322: "component not within node or agent?");
323: }
324: if (!currentComponent.isEmpty()) {
325: throw new RuntimeException(
326: "startComponent already within component? "
327: + currentComponent);
328: }
329:
330: currentComponent.put("name", getValue(atts, "name"));
331: currentComponent.put("class", getValue(atts, "class"));
332: currentComponent.put("priority", getValue(atts, "priority"));
333: currentComponent.put("insertionpoint", getValue(atts,
334: "insertionpoint"));
335: }
336:
337: private void endComponent() throws SAXException {
338:
339: if (currentComponent.isEmpty()) {
340: throw new RuntimeException(
341: "endComponent not within component?");
342: }
343: ComponentDescription desc = makeComponentDesc(currentComponent);
344: currentComponent.clear();
345:
346: currentList.add(desc);
347: }
348:
349: private void startArgument(Attributes atts) throws SAXException {
350: if (currentComponent.isEmpty()) {
351: throw new RuntimeException("Argument (" + atts
352: + ") not in component!");
353: }
354: if (inArgument) {
355: throw new RuntimeException(
356: "Already have an argument value buffer? "
357: + argValueBuffer);
358: }
359: inArgument = true;
360:
361: String name = atts.getValue("name");
362: if (name != null) {
363: if (name.indexOf('=') >= 0) {
364: throw new RuntimeException(
365: "Invalid '=' in attribute name: " + name);
366: }
367: argValueBuffer.append(name.trim());
368: argValueBuffer.append("=");
369: }
370: String value = atts.getValue("value");
371: if (value != null) {
372: argValueBuffer.append(value.trim());
373: }
374: }
375:
376: private void endArgument() throws SAXException {
377: if (!inArgument) {
378: throw new RuntimeException("Not in argument?");
379: }
380: inArgument = false;
381:
382: String argument = argValueBuffer.toString().trim();
383: argValueBuffer.reset();
384:
385: ArrayList argumentList = (ArrayList) currentComponent
386: .get("arguments");
387: if (argumentList == null) {
388: argumentList = new ArrayList(1);
389: currentComponent.put("arguments", argumentList);
390: }
391: argumentList.add(argument);
392: }
393:
394: // utility methods:
395:
396: private static String getValue(Attributes atts, String qName) {
397: String ret = atts.getValue(qName);
398: if (ret == null) {
399: return null;
400: }
401: ret = ret.trim();
402: if (ret.length() == 0) {
403: return null;
404: }
405: return Strings.intern(ret);
406: }
407:
408: private static ComponentDescription makeComponentDesc(
409: Map componentProps) {
410: String name = (String) componentProps.get("name");
411: String classname = (String) componentProps.get("class");
412: String priority = (String) componentProps.get("priority");
413: String insertionPoint = (String) componentProps
414: .get("insertionpoint");
415: // String order = (String) componentProps.get("order");
416: ArrayList args = (ArrayList) componentProps.get("arguments");
417: List vParams = null;
418: if ((args != null) && (args.size() > 0)) {
419: vParams = Collections.unmodifiableList(args);
420: }
421: return makeComponentDesc(name, vParams, classname, priority,
422: insertionPoint);
423: }
424:
425: private static ComponentDescription makeComponentDesc(String name,
426: List vParams, String classname, String priority,
427: String insertionPoint) {
428: return new ComponentDescription(name, insertionPoint,
429: classname, null, //codebase
430: vParams, //params
431: null, //certificate
432: null, //lease
433: null, //policy
434: ComponentDescription.parsePriority(priority));
435: }
436: }
|