1 /***
2 * DependencyModel.java
3 *
4 * Project: Dependency Tool
5 *
6 * WHEN WHO WHAT
7 * 06.06.2003 pko initial public release
8 * 20.01.2003 pko modification
9 * 18.04.2002 ctr modification
10 * 22.01.2002 ctr modification
11 * 08.01.2002 ctr creation
12 *
13 * Copyright 2003 ELCA Informatique SA
14 * Av. de la Harpe 22-24, 1000 Lausanne 13, Switzerland
15 * www.elca.ch
16 *
17 * This library is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU Lesser General Public License
19 * as published by the Free Software Foundation; either version 2.1 of
20 * the License, or (at your option) any later version.
21 *
22 * This library is distributed in the hope that it will be useful, but
23 * WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * Lesser General Public License for more details.
26 *
27 * You should have received a copy of the GNU Lesser General Public
28 * License along with this library; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
30 * USA
31 */
32
33 package ch.elca.dependency.core;
34
35 import java.io.File;
36 import java.io.IOException;
37 import java.util.Hashtable;
38 import java.util.HashMap;
39 import java.util.HashSet;
40 import java.util.Enumeration;
41 import java.util.ListIterator;
42 import java.util.ArrayList;
43
44 import att.grappa.Edge;
45 import att.grappa.Graph;
46 import att.grappa.Node;
47
48 import ch.elca.dependency.exception.AnalyseException;
49 import ch.elca.dependency.graph.Perspective;
50 import ch.elca.dependency.graph.PerspectiveManager;
51
52 /***
53 * It's the model in the MVC Design Pattern.
54 *
55 * This class contains the filtered graph model as well as the statistic data
56 * and the lists for generating the corresponding views. For every kind of data
57 * there are methods for getting this data to the view.<br>
58 *
59 * A set of observers are there for updating all the views attached to this
60 * model. Every time the model is changed by the controller, automatically all
61 * the views registred as an <code>Observer</code> are updated with the changed
62 * data.<br>
63 * If there are very serious changes performed on the model there is the
64 * possibility for disable the automated update mechanismus. This makes sense
65 * for example at startup when the whole model must be created or when a new
66 * filter is applicated which causes the model to change a lot.
67 *
68 * @see ch.elca.dependency.view.View
69 * @see ch.elca.dependency.rawmodel.RawModel
70 *
71 * @author Christoph Trutmann
72 * @author Pawel Kowalski
73 * @version 1.0-beta
74 */
75 public class DependencyModel extends Hashtable implements Selection {
76
77 //****************************************************************************************/
78 // static part of the model
79 //****************************************************************************************/
80
81 private static DependencyModel s_dependencyModel = null;
82
83 /***
84 * Get an instance of the <code>DependencyModel</code>, which is
85 * an singletong and must be creaated by the means of this method
86 * only.
87 *
88 * @return a <code>DependencyModel</code> value
89 */
90 public static DependencyModel getDependencyModel() {
91 return s_dependencyModel;
92 }
93
94 //****************************************************************************************/
95 // dynamic part of the model
96 //****************************************************************************************/
97
98 /***
99 * A key used to store and retrieve the MainFrame.
100 */
101 public static final String MAIN_FRAME_KEY = "main-frame-key";
102
103 /***
104 * The list with all the Classinfo objects
105 */
106 private HashMap m_filteredClassInfos;
107
108 /***
109 * The graph component of the <code>DependencyModel</code>.
110 */
111 private Graph m_filteredGraph;
112
113 /***
114 * The Statistic component of the <code>DependencyModel</code>.
115 */
116 private Statistic m_filteredStatistic;
117
118 /***
119 * All the registred observer implementations are within this list.<br>
120 * I.e. all the existing views of this project.
121 */
122 private ArrayList m_setOfObservers = new ArrayList();
123
124 /***
125 * This flag can be set false if the model should not notify the observer
126 * after each change in the model. This is useful in the case of an
127 * application of a new filter. Then a lot changes in the model and an
128 * actualisation after each of these changes would be not very good for the
129 * performance.
130 */
131 private boolean m_notifyEnabled = true;
132
133 /***
134 * Set containing all the <code>Edges</code> which are removed from the
135 * <code>Graph</code>.
136 */
137 private HashSet m_removedEdges = new HashSet();
138
139 /***
140 * HashTable containing all the <code>Node</code> which are
141 * removed from the <code>Graph<code>. The name of the node
142 * element is the key for the hash map. Like this each node can
143 * be retrieved by using its name.
144 */
145 private HashMap m_removedNodes = new HashMap();
146
147 /***
148 * Set containing all the packages of the last selection.
149 */
150 private HashSet m_lastSelection = new HashSet();
151
152 /***
153 * A <code>DependencyContext</code> used to create this <code>DependencyModel</code>.
154 */
155 private DependencyContext m_dependencyCtx = null;
156
157 /***
158 * Support for StatusListeners.
159 */
160 protected StatusListenerSupport m_statusListenerSupport = new StatusListenerSupport();
161
162 /***
163 * Available Perspectives.
164 */
165 protected Perspective[] m_perspectives = null;
166
167 /***
168 * A boolean indicating whether this model has been created already.
169 */
170 private boolean m_created = false;
171
172 /***
173 * The RawModel associated with this DependencyModel.
174 */
175 private RawModel m_rawModel = null;
176
177 /***
178 * Creates a new <code>DependencyModel</code> instance. Notice
179 * that altough an DependencyModel instance is created here, the
180 * DependencyModel is not created. Use isCreated() to check,
181 * whether this DependencyModel has really been created.
182 */
183 public DependencyModel() {
184 }
185
186 /***
187 * Creates a new <code>DependencyModel</code> instance. The
188 * specified DependencyContext will be used to create this
189 * DependencyModel.
190 *
191 * @param dependencyContext a <code>DependencyContext</code> value
192 * @exception AnalyseException if an error occurs
193 * @exception CloneNotSupportedException if an error occurs
194 * @exception IOException if an error occurs
195 * @exception ClassNotFoundException if an error occurs
196 */
197 public DependencyModel(DependencyContext dependencyContext)
198 throws AnalyseException, CloneNotSupportedException, IOException, ClassNotFoundException {
199 create(dependencyContext);
200 }
201
202 /***
203 * Create this DependencyModel accordingly to the specified DependencyContext.
204 *
205 * @param dependencyContext a <code>DependencyContext</code> value
206 * @exception AnalyseException if an error occurs
207 * @exception CloneNotSupportedException if an error occurs
208 * @exception IOException if an error occurs
209 * @exception ClassNotFoundException if an error occurs
210 */
211 public void create(DependencyContext dependencyContext)
212 throws AnalyseException, CloneNotSupportedException, IOException, ClassNotFoundException {
213 m_dependencyCtx = dependencyContext;
214
215 File rootFile = (File)dependencyContext.get(DependencyContext.ROOT_FILE_KEY);
216 Filter basicFilter = (Filter)dependencyContext.get(DependencyContext.BASIC_FILTER_KEY);
217
218 m_statusListenerSupport.postMessage("analysing...");
219
220 Analyzer analyzer = new Analyzer(rootFile, basicFilter);
221
222 m_statusListenerSupport.postMessage("creating model...");
223 m_rawModel = new RawModel(analyzer);
224
225 // initialize the ClassInfo list
226 //
227 m_filteredClassInfos = (HashMap)m_rawModel.getRawClassInfos().clone();
228
229 // initialize the statistic from the RawModel
230 //
231 m_filteredStatistic = (Statistic)m_rawModel.getRawStatistic().clone();
232
233 // take the same graph object as initialized in the raw model
234 // the removed nodes are put in a separate list.
235 //
236 m_filteredGraph = m_rawModel.getRawGraph();
237
238 m_created = true;
239 s_dependencyModel = this;
240 m_statusListenerSupport.postMessage("");
241 }
242
243 /***
244 * Is this DependencyModel created already? It might be possible
245 * that this DependencyModel is created as an Object, but is not
246 * really created. Such a DependencyModel cann't be used to
247 * retrieve information about the analyzed project. If a
248 * DependencyModel has been created successfully, this method will
249 * return <code>true</code>.
250 *
251 * @return a <code>boolean</code> value
252 */
253 public boolean isCreated() {
254 return m_created;
255 }
256
257 /***
258 * Get the DependencyContext which was used to create this DependencyModel.
259 *
260 * @return a <code>DependencyContext</code> value
261 */
262 public DependencyContext getDependencyContext() {
263 return m_dependencyCtx;
264 }
265
266 /***
267 * Get all Perspectives specified in a perspectives config file.
268 *
269 * @return a <code>Perspective[]</code> value
270 */
271 public Perspective[] getPerspectives() {
272
273 // perspectives not yet loaded
274 //
275 if (m_perspectives == null) {
276 File perspectiveConfig = (File)m_dependencyCtx.get(DependencyContext.PERSPECTIVES_KEY);
277 if (perspectiveConfig != null) {
278 m_perspectives = PerspectiveManager.loadPerspectives(perspectiveConfig);
279 } else {
280 m_perspectives = new Perspective[] { Perspective.DEFAULT_PERSPECTIVE };
281 }
282 }
283
284 return m_perspectives;
285 }
286
287 /***
288 * Attaches the observers to the model.
289 *
290 * @param observer <code>Observer</code> Interface which is implemented by
291 * all the views ofthe DependencyTool.
292 */
293 public void attach(Observer observer) {
294 m_setOfObservers.add(observer);
295 }
296
297 /***
298 * Detaches the observers from the model.
299 *
300 * @param observer <code>Observer</code> Interface which is implemented by
301 * all the views ofthe DependencyTool.
302 */
303 public void detach(Observer observer) {
304 m_setOfObservers.remove(observer);
305 }
306
307 /***
308 * Gets the filtered <code>ClassInfo</code> objects.
309 *
310 * @return Filtered <code>ClassInfo</code> objects.
311 */
312 public HashMap getFilteredClassInfos(){
313 return m_filteredClassInfos;
314 }
315
316 /***
317 * Gets the filtered <code>Graph</code> object.
318 *
319 * @return Filtered <code>Graph</code> object.
320 */
321 public Graph getFilteredGraph() {
322 return m_filteredGraph;
323 }
324
325 /***
326 * Gets the filtered <code>Statistic</code> object.
327 *
328 * @return Filtered <code>Statistic</code> object.
329 */
330 public Statistic getFilteredStatistic(){
331 return m_filteredStatistic;
332 }
333
334 /***
335 * Select the same packages in each view.
336 *
337 * @param selectList List containing all the selected packages.
338 */
339 public void selectPackages(ArrayList selectList){
340
341 // the same is selected twice
342 //
343 if ( m_lastSelection.containsAll(selectList) ) {
344 return;
345 }
346
347 // select the apckages in all the views
348 //
349 ListIterator iter = m_setOfObservers.listIterator();
350 while ( iter.hasNext() ) {
351 ((Observer)iter.next()).select(selectList);
352 }
353
354 // clear the list with the last packages
355 //
356 m_lastSelection.clear();
357
358 // add the current selected packages
359 //
360 m_lastSelection.addAll(selectList);
361 }
362
363 /***
364 * Clears all the selections in all the views.
365 */
366 public void clearSelection(){
367 // clear the selection in all the views
368 ListIterator iter = m_setOfObservers.listIterator();
369 while ( iter.hasNext() ) {
370 ((Observer)iter.next()).clearSelection();
371 }
372 // clear the list with the last packages
373 m_lastSelection.clear();
374 }
375
376 /***
377 * Gets the list with the last selected packages.
378 *
379 * @return a <code>HashSet</code> value
380 */
381 public HashSet getLastSelection() {
382 return m_lastSelection;
383 }
384
385 /***
386 * Iterates over all the observer objects and calls the update method.
387 */
388 public void notifyObserver() {
389 if( ! m_notifyEnabled ) {
390 return;
391 }
392
393 ListIterator iter = m_setOfObservers.listIterator();
394 while( iter.hasNext() ) {
395 ((Observer)iter.next()).update(this);
396 }
397 }
398
399 /***
400 * Sets the notification flag false. I.e. the model is not updated until
401 * this flag is not set true.
402 */
403 public void disableNotification() {
404 m_notifyEnabled = false;
405 }
406
407 /***
408 * Sets the notification flag true and notifies the observer.
409 */
410 public void enableNotification() {
411 m_notifyEnabled = true;
412 notifyObserver();
413 }
414
415 /***
416 * Clears all the <code>ClassInfo</code> objects in the list of the
417 * <code>DependencyModel</code>.
418 */
419 public void clearClassInfos(){
420 m_filteredClassInfos.clear();
421 notifyObserver();
422 }
423
424 /***
425 * Clears all the <code>Vertices</code> and <code>Edges</code> from the
426 * current <code>DependencyModel</code>.
427 */
428 public void clearGraph() {
429
430 // remove all the nodes in the graph and add them to the HashMap.
431 //
432 Enumeration nodeEnum = m_filteredGraph.nodeElements();
433 while ( nodeEnum.hasMoreElements() ) {
434 String nodeName = ((Node)nodeEnum.nextElement()).getName();
435 Node nodeTmp = m_filteredGraph.removeNode(nodeName);
436
437 m_removedNodes.put(nodeName, nodeTmp);
438 }
439
440 // remove all the edges in the graph and add them to the HashMap.
441 //
442 Enumeration edgeEnum = m_filteredGraph.edgeElements();
443 while ( edgeEnum.hasMoreElements() ) {
444 String edgeName = ((Edge)edgeEnum.nextElement()).getName();
445 Edge edgeTmp = m_filteredGraph.removeEdge(edgeName);
446 if ( edgeTmp == null ) {
447 System.out.println("Edge '" + edgeName + "' is not removed!!");
448 }
449 m_removedEdges.add(edgeTmp);
450 }
451 notifyObserver();
452 }
453
454 /***
455 * Adds the specified <code>Classinfo</code> to the model.
456 *
457 * @param classInfoList Information object of one class of the project.
458 * @param pack a <code>String</code> value
459 */
460 public void add(ArrayList classInfoList, String pack) {
461 m_filteredClassInfos.put(pack, classInfoList);
462 notifyObserver();
463 }
464
465 /***
466 * Adds the specified <code>Node</code> to the model.
467 *
468 * @param node Node to be added.
469 */
470 public void add(Node node) {
471
472 // remove node in the removed hash map
473 //
474 String nodeName = node.getName();
475 if ( m_removedNodes.containsKey(nodeName) ) {
476 m_removedNodes.remove(nodeName);
477 }
478
479 // add node to the graph
480 //
481 m_filteredGraph.addNode(node);
482 notifyObserver();
483 }
484
485 /***
486 * Adds the specified <code>Edge</code> to the model.
487 *
488 * @param edge Edge to add to the model.
489 */
490 public void add(Edge edge) {
491
492 // remove edge in the removed hash set
493 //
494 if ( m_removedEdges.contains(edge) ) {
495 m_removedEdges.remove(edge);
496 }
497
498 // add edge to the graph
499 //
500 m_filteredGraph.addEdge(edge);
501 notifyObserver();
502 }
503
504 /***
505 * Get the Set with the removed <code>Edges</code>.
506 *
507 * @return HashSet with the removed <code>Edge</code> elements.
508 */
509 public HashSet getRemovedEdges(){
510 return m_removedEdges;
511 }
512
513 /***
514 * Get the <code>HashTable</code> with the removed <code>Node</code>.
515 *
516 * @return HashSet with the removed <code>Node</code> elements.
517 */
518 public HashMap getRemovedNodes(){
519 return m_removedNodes;
520 }
521
522 /***
523 * Append a StatusListeners to this DependencyModel. A
524 * StatusListener will be noticed in case a StatusEvent occurs.
525 *
526 * @param statusListener a <code>StatusListener</code> value
527 */
528 public void setStatusListener(StatusListener statusListener) {
529 m_statusListenerSupport.setStatusListener(statusListener);
530 }
531
532 /***
533 * Get RawClassInfos from this DependencyModel.
534 *
535 * @return a <code>HashMap</code> value
536 */
537 public HashMap getRawClassInfos(){
538 return m_rawModel.getRawClassInfos();
539 }
540
541 /***
542 * Get the RawGraph from this DependencyModel.
543 *
544 * @return a <code>Graph</code> value
545 */
546 public Graph getRawGraph() {
547 return m_rawModel.getRawGraph();
548 }
549
550 /***
551 * Get all Package dependencies from this DependencyModel.
552 *
553 * @return a <code>HashMap</code> value
554 */
555 public HashMap getPackDepend() {
556 return m_rawModel.getPackDepend();
557 }
558
559 /***
560 * Get the Project Root.
561 *
562 * @return a <code>File</code> value
563 */
564 public File getProjectRoot() {
565 return m_rawModel.getProjectRoot();
566 }
567
568 /***
569 * Get the list of all nodes representing packages in the analyzed project.
570 *
571 * @return an <code>ArrayList</code> value
572 */
573 public ArrayList getNodeList() {
574 return m_rawModel.getNodeList();
575 }
576
577 /***
578 * Get the RawModel from this DependencyModel.
579 *
580 * @return a <code>RawModel</code> value
581 */
582 public RawModel getRawModel() {
583 return m_rawModel;
584 }
585 }
This page was automatically generated by Maven