001: /* ====================================================================
002: * The JRefactory License, Version 1.0
003: *
004: * Copyright (c) 2001 JRefactory. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution,
019: * if any, must include the following acknowledgment:
020: * "This product includes software developed by the
021: * JRefactory (http://www.sourceforge.org/projects/jrefactory)."
022: * Alternately, this acknowledgment may appear in the software itself,
023: * if and wherever such third-party acknowledgments normally appear.
024: *
025: * 4. The names "JRefactory" must not be used to endorse or promote
026: * products derived from this software without prior written
027: * permission. For written permission, please contact seguin@acm.org.
028: *
029: * 5. Products derived from this software may not be called "JRefactory",
030: * nor may "JRefactory" appear in their name, without prior written
031: * permission of Chris Seguin.
032: *
033: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
034: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
035: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
036: * DISCLAIMED. IN NO EVENT SHALL THE CHRIS SEGUIN OR
037: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
038: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
039: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
040: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
041: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
042: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
043: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
044: * SUCH DAMAGE.
045: * ====================================================================
046: *
047: * This software consists of voluntary contributions made by many
048: * individuals on behalf of JRefactory. For more information on
049: * JRefactory, please see
050: * <http://www.sourceforge.org/projects/jrefactory>.
051: */
052: package org.acm.seguin.uml;
053:
054: import java.awt.Dimension;
055: import java.awt.Point;
056: import java.io.BufferedReader;
057: import java.io.File;
058: import java.io.FileNotFoundException;
059: import java.io.FileReader;
060: import java.io.IOException;
061: import java.io.Reader;
062: import java.util.Iterator;
063: import java.util.StringTokenizer;
064: import org.acm.seguin.summary.PackageSummary;
065: import org.acm.seguin.summary.TypeDeclSummary;
066: import org.acm.seguin.summary.TypeSummary;
067: import org.acm.seguin.summary.Summary;
068: import org.acm.seguin.summary.ImportSummary;
069: import org.acm.seguin.summary.FileSummary;
070: import org.acm.seguin.summary.ReflectiveSummaryLoader;
071: import org.acm.seguin.awt.ExceptionPrinter;
072: import org.acm.seguin.ide.common.SummaryLoaderThread;
073: import org.acm.seguin.summary.query.GetTypeSummary;
074: import org.acm.seguin.uml.line.AssociationRelationship;
075: import org.acm.seguin.uml.line.ImplementsRelationship;
076: import org.acm.seguin.uml.line.InheretenceRelationship;
077: import org.acm.seguin.uml.line.SegmentedLine;
078: import org.acm.seguin.util.FileSettings;
079:
080: import org.acm.seguin.project.Project;
081: import org.acm.seguin.project.ProjectClassLoader;
082:
083: /**
084: * Loads a UMLPackage panel from a package summary
085: *
086: *@author Chris Seguin
087: *@author <a href="JRefactory@ladyshot.demon.co.uk">Mike Atkinson</a>
088: *@version $Id: PackageLoader.java,v 1.8 2003/09/11 16:41:17 mikeatkinson Exp $
089: *@created September 12, 2001
090: */
091: public class PackageLoader implements Runnable {
092: private UMLPackage packagePanel;
093: private int defaultX = 20;
094: private int defaultY = 20;
095: private boolean loaded = false;
096:
097: private PackageSummary loadSummary;
098: private File loadFile;
099: private Reader loadStream;
100:
101: /**
102: * Constructor for the PackageLoader object
103: *
104: *@param panel the panel that we are loading
105: */
106: public PackageLoader(UMLPackage panel, Reader input) {
107: packagePanel = panel;
108: loadSummary = null;
109: loadStream = input;
110: loadFile = null;
111: }
112:
113: /**
114: * Constructor for the PackageLoader object
115: *
116: *@param panel the panel that we are loading
117: */
118: public PackageLoader(UMLPackage panel, String filename) {
119: packagePanel = panel;
120: loadSummary = null;
121: loadStream = null;
122: loadFile = new File(filename);
123: }
124:
125: /**
126: * Constructor for the PackageLoader object
127: *
128: *@param panel the panel that we are loading
129: */
130: public PackageLoader(UMLPackage panel, PackageSummary summary) {
131: packagePanel = panel;
132: loadSummary = summary;
133: loadStream = null;
134: loadFile = null;
135: }
136:
137: /**
138: * Main processing method for the PackageLoader object
139: */
140: public void run() {
141: /*
142: * Don't run this until we have completed loading the
143: * summaries from disk
144: */
145: SummaryLoaderThread.waitForLoading();
146:
147: synchronized (PackageLoader.class) {
148: packagePanel.setLoading(true);
149: packagePanel.clear();
150:
151: if (loadSummary != null) {
152: load(loadSummary);
153: }
154: if (loadFile != null) {
155: load(loadFile);
156: }
157: if (loadStream != null) {
158: load(loadStream);
159: }
160:
161: packagePanel.updateClassListPanel();
162: packagePanel.setLoading(false);
163: packagePanel.repaint();
164: }
165: }
166:
167: /**
168: * Gets the File attribute of the PackageLoader object
169: *
170: *@return The File value
171: */
172: public static File getFile(UMLPackage panel) {
173: return getFile(panel.getSummary());
174: }
175:
176: /**
177: * Gets the File attribute of the PackageSummary object
178: *
179: *@return The File value
180: *@since 2.7.04
181: */
182: public static File getFile(PackageSummary summary) {
183: File dir = summary.getDirectory();
184: File inputFile;
185: if (dir == null) {
186: dir = new File(FileSettings.getRefactorySettingsRoot(),
187: "UML");
188: dir.mkdirs();
189: inputFile = new File(dir, summary.getName() + ".uml");
190: } else {
191: inputFile = new File(summary.getDirectory(), "package.uml");
192: }
193:
194: return inputFile;
195: }
196:
197: private ProjectClassLoader pcl = null;
198:
199: /**
200: * Returns the UMLType panel associated with a summary or null if none is
201: * available
202: *
203: *@param summary the type declaration
204: *@return the panel associated with the type
205: */
206: private UMLType getUMLType(TypeSummary current,
207: TypeDeclSummary summary) {
208: if (summary != null) {
209: TypeSummary typeSummary = GetTypeSummary.query(summary);
210: if (typeSummary == null) {
211: if (pcl == null) {
212: pcl = new ProjectClassLoader(Project
213: .getProject("default"));
214: }
215: //System.out.println("package="+summary.getPackage());
216: //System.out.println("name="+summary.getName());
217: //System.out.println("getLongName="+summary.getLongName());
218: String fullName = summary.getLongName();
219: Summary fs = current;
220: while ((fs != null) && !(fs instanceof FileSummary)) {
221: fs = fs.getParent();
222: }
223: FileSummary fileSummary = (FileSummary) fs;
224:
225: if (fileSummary != null) {
226: Iterator i = fileSummary.getImports();
227: if (i != null) {
228: while (i.hasNext()) {
229: ImportSummary is = (ImportSummary) i.next();
230: String type = is.getType();
231: if (summary.getName().equals(type)) {
232: fullName = is.getPackage().getName();
233: break;
234: } else {
235: try {
236: String testName = is.getPackage()
237: .getName()
238: + "." + summary.getName();
239: //System.out.println("testName="+testName);
240: //typeSummary = ReflectiveSummaryLoader.loadType(testName);
241: pcl.loadClass(testName);
242: fullName = testName;
243: break;
244: } catch (ClassNotFoundException e) {
245: }
246: }
247: }
248: }
249: }
250: //System.out.println("fullName="+fullName);
251: try {
252: typeSummary = ReflectiveSummaryLoader.loadType(
253: fullName, pcl);
254: //typeSummary = pcl.loadClass(fullName);
255: } catch (ClassNotFoundException e) {
256: //e.printStackTrace(); // FIXME: don't print stack trace
257: }
258: }
259: if (typeSummary != null) {
260: UMLType typePanel = packagePanel.findType(typeSummary);
261: if (typePanel == null) {
262: typePanel = addType(typeSummary, true);
263: }
264: return typePanel;
265: }
266: }
267:
268: return null;
269: }
270:
271: /**
272: * Returns the location of this class
273: *
274: *@param umlType the type panel
275: *@param summary the type summary
276: *@return the point where this type panel should be located
277: */
278: private Point getLocation(UMLType umlType, TypeSummary summary) {
279: Dimension dim = umlType.getPreferredSize();
280: Point result = new Point(defaultX, defaultY);
281: defaultX += (20 + dim.width);
282: return result;
283: }
284:
285: /**
286: * Reload the summaries
287: *
288: *@param summary the package summary
289: */
290: private void load(PackageSummary summary) {
291: if (summary != null) {
292: defaultPositions(summary);
293: }
294:
295: loadPositions(getFile(packagePanel));
296: }
297:
298: /**
299: * Reload the summaries
300: *
301: *@param file Description of Parameter
302: */
303: private void load(File file) {
304: loadPositions(file);
305: }
306:
307: /**
308: * Reload the summaries
309: *
310: *@param input Description of Parameter
311: */
312: private void load(Reader input) {
313: loadPositions(input);
314: }
315:
316: /**
317: * Loads all the classes into their default positions
318: *
319: *@param summary the package that is being loaded
320: */
321: private void defaultPositions(PackageSummary summary) {
322: // Add all the types
323: Iterator iter = summary.getFileSummaries();
324: if (iter != null) {
325: while (iter.hasNext()) {
326: addFile((FileSummary) iter.next());
327: }
328: }
329:
330: loadInheretence();
331: loadImplements();
332:
333: packagePanel.resetPositions();
334: packagePanel.rearragePositions(2000, 50, 1.0);
335: //rearragePositions(2000, 5);
336: //rearragePositions(1000, 7);
337: //rearragePositions(1000, 7);
338: //rearragePositions(500, 10);
339: //rearragePositions(500, 10);
340: //rearragePositions(250, 10);
341: //rearragePositions(250, 10);
342: //rearragePositions(125, 10);
343: //rearragePositions(125, 40);
344: packagePanel.reset();
345:
346: loaded = true;
347: }
348:
349: /**
350: * Adds all the types in a file
351: *
352: *@param fileSummary the file summary
353: */
354: private void addFile(FileSummary fileSummary) {
355: Iterator iter = fileSummary.getTypes();
356: if (iter != null) {
357: while (iter.hasNext()) {
358: addType((TypeSummary) iter.next(), false);
359: }
360: }
361: }
362:
363: /**
364: * Adds a UML type
365: *
366: *@param typeSummary the type summary being added
367: *@param foreign whether this type is in this package (true means it
368: * is from a different package
369: *@return The panel
370: */
371: private UMLType addType(TypeSummary typeSummary, boolean foreign) {
372: UMLType umlType = new UMLType(packagePanel, typeSummary,
373: foreign);
374: packagePanel.add(umlType);
375: umlType.setLocation(getLocation(umlType, typeSummary));
376:
377: return umlType;
378: }
379:
380: /**
381: * Loads the inheritence relationships
382: */
383: private void loadInheretence() {
384: UMLType[] typeList = packagePanel.getTypes();
385:
386: for (int ndx = 0; ndx < typeList.length; ndx++) {
387: TypeSummary current = typeList[ndx].getSummary();
388: TypeDeclSummary parent = current.getParentClass();
389: UMLType typePanel = getUMLType(current, parent);
390: if (typePanel != null) {
391: packagePanel.add(new InheretenceRelationship(
392: typeList[ndx], typePanel));
393: }
394: }
395: }
396:
397: /**
398: * Loads the inheritence relationships
399: */
400: private void loadImplements() {
401: UMLType[] typeList = packagePanel.getTypes();
402:
403: for (int ndx = 0; ndx < typeList.length; ndx++) {
404: if (typeList[ndx].isForeign()) {
405: continue;
406: }
407:
408: TypeSummary current = typeList[ndx].getSummary();
409: Iterator iter = current.getImplementedInterfaces();
410: if (iter != null) {
411: while (iter.hasNext()) {
412: TypeDeclSummary next = (TypeDeclSummary) iter
413: .next();
414: UMLType typePanel = getUMLType(current, next);
415: if (typePanel != null) {
416: SegmentedLine nextLine;
417: if (current.isInterface()) {
418: nextLine = new InheretenceRelationship(
419: typeList[ndx], typePanel);
420: } else {
421: nextLine = new ImplementsRelationship(
422: typeList[ndx], typePanel);
423: }
424:
425: packagePanel.add(nextLine);
426: }
427: }
428: }
429: }
430: }
431:
432: /**
433: * Loads the package from disk
434: *
435: *@param inputFile Description of Parameter
436: */
437: private void loadPositions(File inputFile) {
438: try {
439: FileReader fr = new FileReader(inputFile);
440: BufferedReader input = new BufferedReader(fr);
441: loadPositions(input);
442: } catch (FileNotFoundException fnfe) {
443: // This is a normal and expected condition
444: } catch (IOException ioe) {
445: ExceptionPrinter.print(ioe, false);
446: }
447: }
448:
449: /**
450: * Loads the package from disk
451: *
452: *@param inputStream Description of Parameter
453: */
454: private void loadPositions(Reader inputStream) {
455: try {
456: if (!(inputStream instanceof BufferedReader)) {
457: inputStream = new BufferedReader(inputStream);
458: }
459: loadPositions(inputStream);
460: inputStream.close();
461: } catch (IOException ioe) {
462: ExceptionPrinter.print(ioe, false);
463: }
464: }
465:
466: /**
467: * Loads the package from disk
468: *
469: *@param input Description of Parameter
470: *@exception IOException Description of Exception
471: */
472: private void loadPositions(BufferedReader input) throws IOException {
473: String line = input.readLine();
474: while (line != null) {
475: // Decide what to do
476: char ch = line.charAt(0);
477: if (ch == 'P') {
478: positionPanel(line);
479: } else if (ch == 'S') {
480: positionLine(line);
481: } else if (ch == 'A') {
482: positionAttribute(line);
483: } else if (ch == 'V') {
484: loadVersion(line);
485: }
486:
487: // Read the next line
488: line = input.readLine();
489: }
490: }
491:
492: /**
493: * position the type in the UMLPackage
494: *
495: *@param buffer the line that describes where to position the type
496: */
497: private void positionPanel(String buffer) {
498: StringTokenizer tok = new StringTokenizer(buffer, "[]{},\n");
499: String code = tok.nextToken();
500: String id = tok.nextToken();
501: String x = tok.nextToken();
502: String y = tok.nextToken();
503:
504: UMLType type = packagePanel.find(id);
505: if (type == null) {
506: return;
507: }
508: Point pt = type.getLocation();
509: int nX = pt.x;
510: int nY = pt.y;
511:
512: try {
513: nX = Integer.parseInt(x);
514: nY = Integer.parseInt(y);
515: } catch (NumberFormatException nfe) {
516: }
517:
518: type.setLocation(nX, nY);
519: }
520:
521: /**
522: * Position the line
523: *
524: *@param buffer the line read from the file
525: */
526: private void positionLine(String buffer) {
527: StringTokenizer tok = new StringTokenizer(buffer, "[]{}\n");
528: String code = tok.nextToken();
529: String pair = tok.nextToken();
530: String position = tok.nextToken();
531:
532: tok = new StringTokenizer(pair, ",");
533: String first = tok.nextToken();
534: String second = tok.nextToken();
535:
536: SegmentedLine line = packagePanel.find(first, second);
537: if (line != null) {
538: line.load(position);
539: }
540: }
541:
542: /**
543: * The attribute
544: *
545: *@param buffer the input string
546: */
547: private void positionAttribute(String buffer) {
548: StringTokenizer tok = new StringTokenizer(buffer, "[]{}\n");
549: String code = tok.nextToken();
550: String pair = tok.nextToken();
551: String position = tok.nextToken();
552: String fieldPosition = tok.nextToken();
553:
554: tok = new StringTokenizer(pair, ",");
555: String first = tok.nextToken();
556: String second = tok.nextToken();
557:
558: UMLType type = packagePanel.find(first);
559: if (type == null) {
560: return;
561: }
562:
563: UMLField field = type.getField(second);
564: if (field == null) {
565: return;
566: }
567:
568: field.setAssociation(true);
569: AssociationRelationship ar = type.convertToAssociation(
570: packagePanel, field);
571: ar.load(position);
572:
573: // Set the field label position
574: tok = new StringTokenizer(fieldPosition, ",");
575: String x = tok.nextToken();
576: String y = tok.nextToken();
577: try {
578: field.setLocation(Integer.parseInt(x), Integer.parseInt(y));
579: } catch (NumberFormatException nfe) {
580: }
581: }
582:
583: /**
584: * Loads a version line
585: *
586: *@param buffer the input line that contains the version number and
587: * package name
588: */
589: private void loadVersion(String buffer) {
590: StringTokenizer tok = new StringTokenizer(buffer, "[]:\n");
591: String key = tok.nextToken();
592:
593: String versionID = tok.nextToken();
594: String packageName = "";
595: if (tok.hasMoreTokens()) {
596: packageName = tok.nextToken();
597: }
598:
599: System.out.println("Loading: " + packageName
600: + " from a file with version " + versionID);
601: if (!loaded) {
602: PackageSummary summary = PackageSummary
603: .getPackageSummary(packageName);
604: packagePanel.setSummary(summary);
605: defaultPositions(summary);
606: }
607: }
608: }
|