001: /*
002: * Copyright (c) 2001-2007, Jean Tessier
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions
007: * are met:
008: *
009: * * Redistributions of source code must retain the above copyright
010: * notice, this list of conditions and the following disclaimer.
011: *
012: * * Redistributions in binary form must reproduce the above copyright
013: * notice, this list of conditions and the following disclaimer in the
014: * documentation and/or other materials provided with the distribution.
015: *
016: * * Neither the name of Jean Tessier nor the names of his contributors
017: * may be used to endorse or promote products derived from this software
018: * without specific prior written permission.
019: *
020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
021: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
022: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
023: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
024: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
027: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
028: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
029: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
030: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031: */
032:
033: package com.jeantessier.dependency;
034:
035: import java.util.*;
036:
037: import org.apache.log4j.*;
038: import org.xml.sax.*;
039: import org.xml.sax.helpers.*;
040:
041: public class NodeHandler extends DefaultHandler {
042: private static final int PACKAGE = 1;
043: private static final int CLASS = 2;
044: private static final int FEATURE = 3;
045:
046: private NodeFactory factory;
047:
048: private int currentNodeType;
049: private int currentDependencyType;
050: private Attributes currentDependencyAttributes;
051: private Node currentNode;
052: private Attributes currentPackageAttributes;
053: private Attributes currentClassAttributes;
054: private Attributes currentFeatureAttributes;
055: private StringBuffer currentName = new StringBuffer();
056:
057: private HashSet<DependencyListener> dependencyListeners = new HashSet<DependencyListener>();
058:
059: public NodeHandler() {
060: this (new NodeFactory());
061: }
062:
063: public NodeHandler(NodeFactory factory) {
064: this .factory = factory;
065: }
066:
067: public NodeFactory getFactory() {
068: return factory;
069: }
070:
071: public void startElement(String namespaceURI, String localName,
072: String qName, Attributes atts) throws SAXException {
073: Logger.getLogger(getClass()).debug("qName = " + qName);
074:
075: for (int i = 0; i < atts.getLength(); i++) {
076: Logger.getLogger(getClass())
077: .debug(
078: " " + atts.getQName(i) + ": "
079: + atts.getValue(i));
080: }
081:
082: currentName.delete(0, currentName.length());
083:
084: if ("dependencies".equals(qName)) {
085: fireBeginSession();
086: } else if ("package".equals(qName)) {
087: currentNodeType = PACKAGE;
088: currentPackageAttributes = new AttributesImpl(atts);
089: } else if ("class".equals(qName)) {
090: currentNodeType = CLASS;
091: currentClassAttributes = new AttributesImpl(atts);
092: } else if ("feature".equals(qName)) {
093: currentNodeType = FEATURE;
094: currentFeatureAttributes = new AttributesImpl(atts);
095: } else if ("inbound".equals(qName) || "outbound".equals(qName)) {
096: if ("package".equals(atts.getValue("type"))) {
097: currentDependencyType = PACKAGE;
098: } else if ("class".equals(atts.getValue("type"))) {
099: currentDependencyType = CLASS;
100: } else if ("feature".equals(atts.getValue("type"))) {
101: currentDependencyType = FEATURE;
102: }
103: currentDependencyAttributes = new AttributesImpl(atts);
104: }
105:
106: Logger.getLogger(getClass()).debug(
107: " current node type: " + currentNodeType);
108: Logger.getLogger(getClass())
109: .debug(
110: " current dependency type: "
111: + currentDependencyType);
112: }
113:
114: public void endElement(String namespaceURI, String localName,
115: String qName) throws SAXException {
116: Logger.getLogger(getClass()).debug("qName = " + qName);
117:
118: if ("dependencies".equals(qName)) {
119: fireEndSession();
120: } else if ("name".equals(qName)) {
121: Logger.getLogger(getClass()).debug(
122: " Processing <name> tag:");
123: Logger.getLogger(getClass()).debug(
124: " current name: " + currentName);
125: Logger.getLogger(getClass()).debug(
126: " current node type: " + currentNodeType);
127:
128: switch (currentNodeType) {
129: case PACKAGE:
130: currentNode = getFactory().createPackage(
131: currentName.toString(),
132: isConfirmed(currentPackageAttributes));
133: break;
134: case CLASS:
135: currentNode = getFactory().createClass(
136: currentName.toString(),
137: isConfirmed(currentClassAttributes));
138: fireBeginClass(currentNode.toString());
139: break;
140: case FEATURE:
141: currentNode = getFactory().createFeature(
142: currentName.toString(),
143: isConfirmed(currentFeatureAttributes));
144: break;
145: }
146: } else if ("outbound".equals(qName)) {
147: Logger.getLogger(getClass()).debug(
148: " Processing <outbound> tag:");
149: Logger.getLogger(getClass()).debug(
150: " current_name: " + currentName);
151: Logger.getLogger(getClass()).debug(
152: " current_dependency_type: "
153: + currentDependencyType);
154:
155: Node other = null;
156: switch (currentDependencyType) {
157: case PACKAGE:
158: other = getFactory().createPackage(
159: currentName.toString(),
160: isConfirmed(currentDependencyAttributes));
161: break;
162: case CLASS:
163: other = getFactory().createClass(
164: currentName.toString(),
165: isConfirmed(currentDependencyAttributes));
166: break;
167: case FEATURE:
168: other = getFactory().createFeature(
169: currentName.toString(),
170: isConfirmed(currentDependencyAttributes));
171: break;
172: }
173: currentNode.addDependency(other);
174: fireDependency(currentNode, other);
175: } else if ("inbound".equals(qName)) {
176: Logger.getLogger(getClass()).debug(
177: " Processing <inbound> tag:");
178: Logger.getLogger(getClass()).debug(
179: " current_name: " + currentName);
180: Logger.getLogger(getClass()).debug(
181: " current_dependency_type: "
182: + currentDependencyType);
183:
184: Node other = null;
185: switch (currentDependencyType) {
186: case PACKAGE:
187: other = getFactory().createPackage(
188: currentName.toString(),
189: isConfirmed(currentDependencyAttributes));
190: break;
191: case CLASS:
192: other = getFactory().createClass(
193: currentName.toString(),
194: isConfirmed(currentDependencyAttributes));
195: break;
196: case FEATURE:
197: other = getFactory().createFeature(
198: currentName.toString(),
199: isConfirmed(currentDependencyAttributes));
200: break;
201: }
202: other.addDependency(currentNode);
203: fireDependency(other, currentNode);
204: }
205: }
206:
207: public void characters(char[] ch, int start, int length)
208: throws SAXException {
209: currentName.append(ch, start, length);
210: Logger.getLogger(getClass())
211: .debug(
212: "characters: \""
213: + new String(ch, start, length) + "\"");
214: }
215:
216: public void addDependencyListener(DependencyListener listener) {
217: synchronized (dependencyListeners) {
218: dependencyListeners.add(listener);
219: }
220: }
221:
222: public void removeDependencyListener(DependencyListener listener) {
223: synchronized (dependencyListeners) {
224: dependencyListeners.remove(listener);
225: }
226: }
227:
228: protected void fireBeginSession() {
229: DependencyEvent event = new DependencyEvent(this );
230:
231: HashSet<DependencyListener> listeners;
232: synchronized (dependencyListeners) {
233: listeners = (HashSet<DependencyListener>) dependencyListeners
234: .clone();
235: }
236:
237: for (DependencyListener listener : listeners) {
238: listener.beginSession(event);
239: }
240: }
241:
242: protected void fireBeginClass(String classname) {
243: DependencyEvent event = new DependencyEvent(this , classname);
244:
245: HashSet<DependencyListener> listeners;
246: synchronized (dependencyListeners) {
247: listeners = (HashSet<DependencyListener>) dependencyListeners
248: .clone();
249: }
250:
251: for (DependencyListener listener : listeners) {
252: listener.beginClass(event);
253: }
254: }
255:
256: protected void fireDependency(Node dependent, Node dependable) {
257: DependencyEvent event = new DependencyEvent(this , dependent,
258: dependable);
259:
260: HashSet<DependencyListener> listeners;
261: synchronized (dependencyListeners) {
262: listeners = (HashSet<DependencyListener>) dependencyListeners
263: .clone();
264: }
265:
266: for (DependencyListener listener : listeners) {
267: listener.dependency(event);
268: }
269: }
270:
271: protected void fireEndClass(String classname) {
272: DependencyEvent event = new DependencyEvent(this , classname);
273:
274: HashSet<DependencyListener> listeners;
275: synchronized (dependencyListeners) {
276: listeners = (HashSet<DependencyListener>) dependencyListeners
277: .clone();
278: }
279:
280: for (DependencyListener listener : listeners) {
281: listener.endClass(event);
282: }
283: }
284:
285: protected void fireEndSession() {
286: DependencyEvent event = new DependencyEvent(this );
287:
288: HashSet<DependencyListener> listeners;
289: synchronized (dependencyListeners) {
290: listeners = (HashSet<DependencyListener>) dependencyListeners
291: .clone();
292: }
293:
294: for (DependencyListener listener : listeners) {
295: listener.endSession(event);
296: }
297: }
298:
299: private boolean isConfirmed(Attributes atts) {
300: return atts.getValue("confirmed") == null
301: || "yes".equalsIgnoreCase(atts.getValue("confirmed"));
302: }
303: }
|