1 /***
2 * LayerOrder.java
3 *
4 * Project: Dependency Tool
5 *
6 * WHEN WHO WHAT
7 * 06.06.2003 pko initial public release
8 * 20.01.2003 pko creation
9 *
10 * Copyright 2003 ELCA Informatique SA
11 * Av. de la Harpe 22-24, 1000 Lausanne 13, Switzerland
12 * www.elca.ch
13 *
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public License
16 * as published by the Free Software Foundation; either version 2.1 of
17 * the License, or (at your option) any later version.
18 *
19 * This library is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
27 * USA
28 */
29
30 package ch.elca.dependency.graph;
31
32 import java.util.*;
33 import ch.elca.dependency.adapter.grappa.SubgraphFactory;
34 import ch.elca.dependency.adapter.grappa.NodeFactory;
35 import ch.elca.dependency.adapter.grappa.EdgeFactory;
36
37 import org.apache.log4j.Logger;
38
39 import att.grappa.Graph;
40 import att.grappa.Subgraph;
41 import att.grappa.GrappaConstants;
42 import att.grappa.Node;
43 import att.grappa.Edge;
44
45 /***
46 * This class represents Layers within a graph. It's creation is based
47 * on the perspectives config. It can be used to layer a graph and
48 * signalize violations of the layering model.
49 *
50 * @author Pawel Kowalski
51 * @version 1.0-beta
52 */
53 public class LayerOrder extends AbstractGraphProcessor implements LayeringListener {
54
55 /***
56 * Log4j Logger.
57 */
58 private static final Logger LOG = Logger.getLogger(LayerOrder.class);
59
60 /***
61 * Key to store and retrieve the LayerNumber property.
62 */
63 public static final String LAYER_NUMBER_KEY = "layer-number-key";
64
65 /***
66 * A list of all Layers within this Layering.
67 */
68 private ArrayList m_layers = null;
69
70 /***
71 * LayeringEventSupport used to delegate tasks associated with LayeringEvents.
72 */
73 private LayeringEventSupport m_layeringEventSupport = new LayeringEventSupport();
74
75 /***
76 * Creates a new <code>LayerOrder</code> instance.
77 *
78 */
79 public LayerOrder() {
80 this("");
81 }
82
83 /***
84 * Creates a new <code>LayerOrder</code> instance.
85 *
86 * @param name a <code>String</code> value
87 */
88 public LayerOrder(String name) {
89 setName(name);
90 m_layers = new ArrayList();
91 m_layers.add(0, Layer.UNASSIGNED);
92 addLayeringListener(this);
93 }
94
95 /***
96 * Add a Layer to this LayerOrder.
97 *
98 * @param layer a <code>Layer</code> value
99 */
100 public void addLayer(Layer layer) {
101 LOG.debug("Layer added: " + layer.getName());
102 m_layers.add(1, layer);
103 }
104
105 /***
106 * Delete all Layers withing this LayerOrder.
107 */
108 public void resetLayers() {
109 m_layers = new ArrayList();
110 }
111
112 /***
113 * Process a graph according to this LayerOrder. This processing
114 * uncovers layering violations. Each time a violation of the
115 * layering is discovered, an instance of this class fires a
116 * LayeringEvent (with the help of LayeringEventSupport).
117 *
118 * @param graph a <code>Graph</code> value
119 * @return a <code>Graph</code> value
120 */
121 public Graph process(Graph graph) {
122
123 LOG.debug("Processing graph: " + graph.getName());
124
125 Hashtable mappings = prepareMappings();
126 Hashtable subgraphs = new Hashtable();
127
128 Node node = null;
129 Subgraph subgraph = null;
130 String nodeName = null;
131 Layer currentLayer = null;
132
133 for (Iterator iter = m_layers.iterator(); iter.hasNext(); ) {
134 Layer layer = (Layer)iter.next();
135 if (!subgraphs.containsKey(layer)) {
136 try {
137 subgraph = SubgraphFactory.createNewSubgraph(graph, layer.getName());
138 subgraph.setAttribute("rank", "same");
139 ((Hashtable)subgraph.object).put(LAYER_NUMBER_KEY, new Integer(m_layers.indexOf(layer)));
140 subgraphs.put(layer, subgraph);
141 } catch (Exception e){
142 for (Enumeration enum = graph.subgraphElements(); enum.hasMoreElements(); ) {
143 Subgraph subg = (Subgraph)enum.nextElement();
144 if (subg.getName().indexOf(layer.getName()) != -1) {
145 subgraphs.put(layer, subg);
146 }
147 }
148 }
149 }
150 }
151
152 for (Enumeration enum = graph.nodeElements(); enum.hasMoreElements(); ) {
153 node = (Node)enum.nextElement();
154
155 // no layer associated with this node
156 //
157 if ((currentLayer = (Layer)mappings.get(node.getName())) == null) {
158
159 // create an extra "unassigned" subgraph
160 //
161 // if (!subgraphs.containsKey(Layer.UNASSIGNED)) {
162 // subgraph = SubgraphFactory.createNewSubgraph(graph, Layer.UNASSIGNED.getName());
163 // subgraph.setAttribute("rank", "same");
164 // ((Hashtable)subgraph.object).put(LAYER_NUMBER_KEY, new Integer(m_layers.indexOf(Layer.UNASSIGNED)));
165 // subgraphs.put(Layer.UNASSIGNED, subgraph);
166 // }
167
168 // assign this node to the UNASSIGNED Layer
169 //
170 subgraph = (Subgraph)subgraphs.get(Layer.UNASSIGNED);
171 node.setSubgraph(subgraph);
172
173 // mark node as unassigned
174 //
175 node.setAttribute(GrappaConstants.STYLE_ATTR, "filled");
176 node.setAttribute(GrappaConstants.COLOR_ATTR, "coral");
177 continue;
178 }
179
180 // was a layer-subgraph already created?
181 //
182 // if (!subgraphs.containsKey(currentLayer)) {
183 // subgraph = SubgraphFactory.createNewSubgraph(graph, currentLayer.getName());
184 // subgraph.setAttribute("rank", "same");
185 // ((Hashtable)subgraph.object).put(LAYER_NUMBER_KEY, new Integer(m_layers.indexOf(currentLayer)));
186 // subgraphs.put(currentLayer, subgraph);
187 // }
188
189 // assign this node to a layer
190 //
191 subgraph = (Subgraph)subgraphs.get(currentLayer);
192 node.setSubgraph(subgraph);
193
194 LOG.debug("Node: " + node.getName() + " Subgraph: " + subgraph.getName() + " " + String.valueOf(((Hashtable)subgraph.object).get(LAYER_NUMBER_KEY)));
195 }
196
197 // now manipulate the graph, so that it will get
198 // displayed correctly
199 //
200
201 graph.setEdgeAttribute("constraint", "false");
202
203 // set constraints of all edges to false
204 //
205 Edge forcingEdge = null;
206 for (Enumeration enum = graph.edgeElements(); enum.hasMoreElements(); ) {
207 forcingEdge = (Edge)enum.nextElement();
208 if (forcingEdge.getHead().getName().indexOf("layer_node") != -1
209 || forcingEdge.getTail().getName().indexOf("layer_node") != -1) {
210 forcingEdge.setAttribute("constraint", "true");
211 }
212 }
213
214 Layer upperLayer = null;
215 Layer lowerLayer = null;
216 Node upperNode = null;
217 Node lowerNode = null;
218 Subgraph upperSubgraph = null;
219 Subgraph lowerSubgraph = null;
220
221 for (int i = m_layers.size()-1; i >= 0; i--) {
222
223 try {
224
225 // upper
226 //
227 if (i == m_layers.size()-1) {
228 upperLayer = (Layer)m_layers.get(i);
229 upperSubgraph = (Subgraph)subgraphs.get(upperLayer);
230 upperNode = NodeFactory.createLayerNode(upperSubgraph, upperSubgraph.getName());
231 } else {
232 upperLayer = lowerLayer;
233 upperSubgraph = lowerSubgraph;
234 upperNode = lowerNode;
235 }
236
237 // lower
238 //
239 lowerLayer = (Layer)m_layers.get(i-1);
240 lowerSubgraph = (Subgraph)subgraphs.get(lowerLayer);
241 lowerNode = NodeFactory.createLayerNode(lowerSubgraph, lowerSubgraph.getName());
242
243 // connecting edge
244 //
245 EdgeFactory.createLayerEdge(graph, upperNode, lowerNode);
246 } catch (Exception e) {
247 // deliberately left empty
248 }
249 }
250
251 // fire an event signalizing a layer violation
252 //
253 Edge edge = null;
254 for (Enumeration enum = graph.edgeElements(); enum.hasMoreElements(); ) {
255 edge = (Edge)enum.nextElement();
256
257 Integer headLayerInt = ((Integer)((Hashtable)edge.getHead().getSubgraph().object).get(LayerOrder.LAYER_NUMBER_KEY));
258 Integer tailLayerInt = ((Integer)((Hashtable)edge.getTail().getSubgraph().object).get(LayerOrder.LAYER_NUMBER_KEY));
259
260 int headLayer = (headLayerInt == null ? 0 : headLayerInt.intValue());
261 int tailLayer = (tailLayerInt == null ? 0 : tailLayerInt.intValue());
262
263 if ( headLayer > tailLayer ) {
264 fireLayeringEvent(edge);
265 }
266 }
267
268 return graph;
269 }
270
271 /***
272 * Prepare package-name (node) to layer (subgraph) mappings and
273 * put them all into a Hashtable.
274 *
275 * @return a <code>Hashtable</code> value
276 */
277 private Hashtable prepareMappings() {
278
279 Hashtable mappings = new Hashtable();
280 Layer layer = null;
281 String[] packages = null;
282
283 for (Iterator iter = m_layers.iterator(); iter.hasNext(); ) {
284
285 layer = (Layer)iter.next();
286 packages = layer.getPackages();
287
288 for (int i = 0; i < packages.length; i++) {
289 mappings.put(packages[i], layer);
290 }
291 }
292
293 return mappings;
294 }
295
296 /***
297 * Handle a event fired when a violation of the layering is
298 * discovered.
299 *
300 * @param event a <code>LayeringEvent</code> value
301 */
302 public void layeringViolated(LayeringEvent event) {
303 Edge edge = event.getEdge();
304 edge.setAttribute(GrappaConstants.COLOR_ATTR, "crimson");
305 edge.setAttribute(GrappaConstants.STYLE_ATTR, "lineWidth(3)");
306 }
307
308 /***
309 * Add a LayeringListener which will receive LayeringEvents.
310 *
311 * @param listener a <code>LayeringListener</code> value
312 */
313 public void addLayeringListener(LayeringListener listener) {
314 m_layeringEventSupport.addLayeringListener(listener);
315 }
316
317 /***
318 * Remove a LayeringListener from the collection of Listeners
319 * receiving LayeringEvents.
320 *
321 * @param listener a <code>LayeringListener</code> value
322 */
323 public void removeLayeringListener(LayeringListener listener) {
324 m_layeringEventSupport.removeLayeringListener(listener);
325 }
326
327 /***
328 * Fire a LayeringEvent with the help of a LayeringEventSupport.
329 *
330 * @param edge an <code>Edge</code> value
331 */
332 private void fireLayeringEvent(Edge edge) {
333 m_layeringEventSupport.fireLayeringEvent(edge);
334 }
335 }
This page was automatically generated by Maven