1 | /* |
2 | * Copyright (c) 2001-2009, Jean Tessier |
3 | * All rights reserved. |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions |
7 | * are met: |
8 | * |
9 | * * Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * |
12 | * * Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * |
16 | * * Neither the name of Jean Tessier nor the names of his contributors |
17 | * may be used to endorse or promote products derived from this software |
18 | * without specific prior written permission. |
19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR |
24 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
25 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
26 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
27 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
28 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
29 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
30 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
31 | */ |
32 | |
33 | package com.jeantessier.dependency; |
34 | |
35 | import java.util.*; |
36 | |
37 | import org.apache.log4j.*; |
38 | import org.xml.sax.*; |
39 | import org.xml.sax.helpers.*; |
40 | |
41 | public class NodeHandler extends DefaultHandler { |
42 | private static final int PACKAGE = 1; |
43 | private static final int CLASS = 2; |
44 | private static final int FEATURE = 3; |
45 | |
46 | private NodeFactory factory; |
47 | |
48 | private int currentNodeType; |
49 | private int currentDependencyType; |
50 | private Attributes currentDependencyAttributes; |
51 | private Node currentNode; |
52 | private Attributes currentPackageAttributes; |
53 | private Attributes currentClassAttributes; |
54 | private Attributes currentFeatureAttributes; |
55 | private StringBuffer currentName = new StringBuffer(); |
56 | |
57 | private HashSet<DependencyListener> dependencyListeners = new HashSet<DependencyListener>(); |
58 | |
59 | public NodeHandler() { |
60 | this(new NodeFactory()); |
61 | } |
62 | |
63 | public NodeHandler(NodeFactory factory) { |
64 | this.factory = factory; |
65 | } |
66 | |
67 | public NodeFactory getFactory() { |
68 | return factory; |
69 | } |
70 | |
71 | public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { |
72 | Logger.getLogger(getClass()).debug("qName = " + qName); |
73 | |
74 | for (int i=0; i<atts.getLength(); i++) { |
75 | Logger.getLogger(getClass()).debug(" " + atts.getQName(i) + ": " + atts.getValue(i)); |
76 | } |
77 | |
78 | currentName.delete(0, currentName.length()); |
79 | |
80 | if ("dependencies".equals(qName)) { |
81 | fireBeginSession(); |
82 | } else if ("package".equals(qName)) { |
83 | currentNodeType = PACKAGE; |
84 | currentPackageAttributes = new AttributesImpl(atts); |
85 | } else if ("class".equals(qName)) { |
86 | currentNodeType = CLASS; |
87 | currentClassAttributes = new AttributesImpl(atts); |
88 | } else if ("feature".equals(qName)) { |
89 | currentNodeType = FEATURE; |
90 | currentFeatureAttributes = new AttributesImpl(atts); |
91 | } else if ("inbound".equals(qName) || "outbound".equals(qName)) { |
92 | if ("package".equals(atts.getValue("type"))) { |
93 | currentDependencyType = PACKAGE; |
94 | } else if ("class".equals(atts.getValue("type"))) { |
95 | currentDependencyType = CLASS; |
96 | } else if ("feature".equals(atts.getValue("type"))) { |
97 | currentDependencyType = FEATURE; |
98 | } |
99 | currentDependencyAttributes = new AttributesImpl(atts); |
100 | } |
101 | |
102 | Logger.getLogger(getClass()).debug(" current node type: " + currentNodeType); |
103 | Logger.getLogger(getClass()).debug(" current dependency type: " + currentDependencyType); |
104 | } |
105 | |
106 | public void endElement(String namespaceURI, String localName, String qName) throws SAXException { |
107 | Logger.getLogger(getClass()).debug("qName = " + qName); |
108 | |
109 | if ("dependencies".equals(qName)) { |
110 | fireEndSession(); |
111 | } else if ("name".equals(qName)) { |
112 | Logger.getLogger(getClass()).debug(" Processing <name> tag:"); |
113 | Logger.getLogger(getClass()).debug(" current name: " + currentName); |
114 | Logger.getLogger(getClass()).debug(" current node type: " + currentNodeType); |
115 | |
116 | switch (currentNodeType) { |
117 | case PACKAGE: |
118 | currentNode = getFactory().createPackage(currentName.toString(), isConfirmed(currentPackageAttributes)); |
119 | break; |
120 | case CLASS: |
121 | currentNode = getFactory().createClass(currentName.toString(), isConfirmed(currentClassAttributes)); |
122 | fireBeginClass(currentNode.getName()); |
123 | break; |
124 | case FEATURE: |
125 | currentNode = getFactory().createFeature(currentName.toString(), isConfirmed(currentFeatureAttributes)); |
126 | break; |
127 | } |
128 | } else if ("outbound".equals(qName)) { |
129 | Logger.getLogger(getClass()).debug(" Processing <outbound> tag:"); |
130 | Logger.getLogger(getClass()).debug(" current_name: " + currentName); |
131 | Logger.getLogger(getClass()).debug(" current_dependency_type: " + currentDependencyType); |
132 | |
133 | Node other = null; |
134 | switch (currentDependencyType) { |
135 | case PACKAGE: |
136 | other = getFactory().createPackage(currentName.toString(), isConfirmed(currentDependencyAttributes)); |
137 | break; |
138 | case CLASS: |
139 | other = getFactory().createClass(currentName.toString(), isConfirmed(currentDependencyAttributes)); |
140 | break; |
141 | case FEATURE: |
142 | other = getFactory().createFeature(currentName.toString(), isConfirmed(currentDependencyAttributes)); |
143 | break; |
144 | } |
145 | currentNode.addDependency(other); |
146 | fireDependency(currentNode, other); |
147 | } else if ("inbound".equals(qName)) { |
148 | Logger.getLogger(getClass()).debug(" Processing <inbound> tag:"); |
149 | Logger.getLogger(getClass()).debug(" current_name: " + currentName); |
150 | Logger.getLogger(getClass()).debug(" current_dependency_type: " + currentDependencyType); |
151 | |
152 | Node other = null; |
153 | switch (currentDependencyType) { |
154 | case PACKAGE: |
155 | other = getFactory().createPackage(currentName.toString(), isConfirmed(currentDependencyAttributes)); |
156 | break; |
157 | case CLASS: |
158 | other = getFactory().createClass(currentName.toString(), isConfirmed(currentDependencyAttributes)); |
159 | break; |
160 | case FEATURE: |
161 | other = getFactory().createFeature(currentName.toString(), isConfirmed(currentDependencyAttributes)); |
162 | break; |
163 | } |
164 | other.addDependency(currentNode); |
165 | fireDependency(other, currentNode); |
166 | } |
167 | } |
168 | |
169 | public void characters(char[] ch, int start, int length) throws SAXException { |
170 | currentName.append(ch, start, length); |
171 | Logger.getLogger(getClass()).debug("characters: \"" + new String(ch, start, length) + "\""); |
172 | } |
173 | |
174 | public void addDependencyListener(DependencyListener listener) { |
175 | synchronized(dependencyListeners) { |
176 | dependencyListeners.add(listener); |
177 | } |
178 | } |
179 | |
180 | public void removeDependencyListener(DependencyListener listener) { |
181 | synchronized(dependencyListeners) { |
182 | dependencyListeners.remove(listener); |
183 | } |
184 | } |
185 | |
186 | protected void fireBeginSession() { |
187 | DependencyEvent event = new DependencyEvent(this); |
188 | |
189 | HashSet<DependencyListener> listeners; |
190 | synchronized(dependencyListeners) { |
191 | listeners = (HashSet<DependencyListener>) dependencyListeners.clone(); |
192 | } |
193 | |
194 | for (DependencyListener listener : listeners) { |
195 | listener.beginSession(event); |
196 | } |
197 | } |
198 | |
199 | protected void fireBeginClass(String classname) { |
200 | DependencyEvent event = new DependencyEvent(this, classname); |
201 | |
202 | HashSet<DependencyListener> listeners; |
203 | synchronized(dependencyListeners) { |
204 | listeners = (HashSet<DependencyListener>) dependencyListeners.clone(); |
205 | } |
206 | |
207 | for (DependencyListener listener : listeners) { |
208 | listener.beginClass(event); |
209 | } |
210 | } |
211 | |
212 | protected void fireDependency(Node dependent, Node dependable) { |
213 | DependencyEvent event = new DependencyEvent(this, dependent, dependable); |
214 | |
215 | HashSet<DependencyListener> listeners; |
216 | synchronized(dependencyListeners) { |
217 | listeners = (HashSet<DependencyListener>) dependencyListeners.clone(); |
218 | } |
219 | |
220 | for (DependencyListener listener : listeners) { |
221 | listener.dependency(event); |
222 | } |
223 | } |
224 | |
225 | protected void fireEndClass(String classname) { |
226 | DependencyEvent event = new DependencyEvent(this, classname); |
227 | |
228 | HashSet<DependencyListener> listeners; |
229 | synchronized(dependencyListeners) { |
230 | listeners = (HashSet<DependencyListener>) dependencyListeners.clone(); |
231 | } |
232 | |
233 | for (DependencyListener listener : listeners) { |
234 | listener.endClass(event); |
235 | } |
236 | } |
237 | |
238 | protected void fireEndSession() { |
239 | DependencyEvent event = new DependencyEvent(this); |
240 | |
241 | HashSet<DependencyListener> listeners; |
242 | synchronized(dependencyListeners) { |
243 | listeners = (HashSet<DependencyListener>) dependencyListeners.clone(); |
244 | } |
245 | |
246 | for (DependencyListener listener : listeners) { |
247 | listener.endSession(event); |
248 | } |
249 | } |
250 | |
251 | private boolean isConfirmed(Attributes atts) { |
252 | return atts.getValue("confirmed") == null || "yes".equalsIgnoreCase(atts.getValue("confirmed")); |
253 | } |
254 | } |