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.summary;
053:
054: import java.io.File;
055: import java.io.IOException;
056: import java.io.Reader;
057: import java.util.ArrayList;
058: import java.util.Date;
059: import java.util.HashMap;
060: import java.util.Iterator;
061: import java.util.LinkedList;
062: import net.sourceforge.jrefactory.ast.ASTTypeDeclaration;
063: import net.sourceforge.jrefactory.ast.SimpleNode;
064: import net.sourceforge.jrefactory.factory.BufferParserFactory;
065: import net.sourceforge.jrefactory.factory.FileParserFactory;
066: import net.sourceforge.jrefactory.factory.InputStreamParserFactory;
067: import net.sourceforge.jrefactory.factory.ParserFactory;
068: import org.acm.seguin.awt.ExceptionPrinter;
069:
070: import net.sourceforge.jrefactory.parser.JavaParser;
071: import org.acm.seguin.util.FileSettings;
072:
073: /**
074: * Stores a summary of a java file
075: *
076: *@author Chris Seguin
077: *@author <a href="JRefactory@ladyshot.demon.co.uk">Mike Atkinson</a>
078: *@version $Id: FileSummary.java,v 1.7 2004/05/04 15:46:54 mikeatkinson Exp $
079: *@created June 6, 1999
080: *@since 2.6.31
081: */
082: public class FileSummary extends Summary {
083: private boolean delete;
084:
085: // Class Variables
086: private static HashMap fileMap;
087: private ArrayList importList;
088: private boolean isMoving;
089: private Date lastModified;
090: // Instance Variables
091: private File theFile;
092: private LinkedList typeList;
093:
094: /**
095: * Creates a file map
096: *
097: *@since 2.6.31
098: *@param parentSummary the parent summary
099: *@param initFile the file
100: */
101: protected FileSummary(Summary parentSummary, File initFile) {
102: // Initialize parent class
103: super (parentSummary);
104:
105: // Set instance Variables
106: theFile = initFile;
107: importList = null;
108: typeList = null;
109: isMoving = false;
110: delete = false;
111: lastModified = new Date();
112: }
113:
114: /**
115: * Mark whether this file should be deleted
116: *
117: *@since 2.6.31
118: *@param way the way that this parameter is changing
119: */
120: public void setDeleted(boolean way) {
121: delete = way;
122: }
123:
124: /**
125: * Change whether this file is moving or not
126: *
127: *@since 2.6.31
128: *@param way the way that this parameter is changing
129: */
130: public void setMoving(boolean way) {
131: isMoving = way;
132: }
133:
134: /**
135: * Return the file
136: *
137: *@since 2.6.31
138: *@return the file object
139: */
140: public File getFile() {
141: return theFile;
142: }
143:
144: /**
145: * Get the file summary for a particular file
146: *
147: *@since 2.6.31
148: *@param file the file we are looking up
149: *@return the file summary
150: */
151: public static FileSummary getFileSummary(File file) {
152: if (fileMap == null) {
153: init();
154: }
155:
156: FileSummary result = (FileSummary) fileMap.get(getKey(file));
157: if (result == null) {
158: SummaryLoaderState state = loadNewFileSummary(file);
159: result = linkFileSummary(state, file);
160: } else {
161: Date currentModificationTime = new Date(file.lastModified());
162: if (currentModificationTime.after(result.lastModified)) {
163: resetFileSummary(file, result);
164: result.lastModified = new Date(file.lastModified());
165:
166: // Create a new file summary object
167: ParserFactory factory = new FileParserFactory(file);
168: SimpleNode root = factory.getAbstractSyntaxTree(false,
169: ExceptionPrinter.getInstance());
170: if (root == null) {
171: return null;
172: }
173: reloadFileSummary(file, result, root);
174: }
175: }
176:
177: return result;
178: }
179:
180: /**
181: * Get the file summary for a particular file
182: *
183: *@since 2.6.31
184: *@param buffer the buffer that is used to load the summary
185: *@return the file summary
186: */
187: public static FileSummary getFileSummary(String buffer) {
188: // Create a new file summary object
189: ParserFactory factory = new BufferParserFactory(buffer);
190: SimpleNode root = null;
191: try {
192: root = factory.getAbstractSyntaxTree(false,
193: ExceptionPrinter.getInstance());
194: } catch (Exception e) {
195: //e.printStackTrace();
196: try {
197: FileSettings bundle = FileSettings
198: .getRefactoryPrettySettings();
199: String jdk = bundle.getString("jdk");
200: if (jdk.indexOf("1.4") >= 0) {
201: JavaParser.setTargetJDK("1.5.0");
202: } else {
203: JavaParser.setTargetJDK("1.4.2");
204: }
205: root = factory.getAbstractSyntaxTree(false,
206: ExceptionPrinter.getInstance());
207: } catch (Exception ex) {
208: ex.printStackTrace();
209: }
210:
211: }
212: if ((root == null) || (!hasType(root))) {
213: return null;
214: }
215:
216: // Start the summary
217: SummaryLoaderState state = new SummaryLoaderState();
218: state.setFile(null);
219: root.jjtAccept(new SummaryLoadVisitor(), state);
220:
221: // Associate them together
222: FileSummary result = (FileSummary) state.getCurrentSummary();
223: ((PackageSummary) result.getParent()).addFileSummary(result);
224:
225: return result;
226: }
227:
228: /**
229: * Return the list of imports
230: *
231: *@since 2.6.31
232: *@return an iterator containing the imports
233: */
234: public Iterator getImports() {
235: if (importList == null) {
236: return null;
237: }
238:
239: return importList.iterator();
240: }
241:
242: /**
243: * Get the key that is used to index the files
244: *
245: *@since 2.6.31
246: *@param file the file we are using to find the key
247: *@return the key
248: */
249: protected static String getKey(File file) {
250: try {
251: return file.getCanonicalPath();
252: } catch (IOException ioe) {
253: return "Unknown";
254: }
255: }
256:
257: /**
258: * Return the name of the file
259: *
260: *@since 2.6.31
261: *@return a string containing the name
262: */
263: public String getName() {
264: if (theFile == null) {
265: return "";
266: }
267:
268: return theFile.getName();
269: }
270:
271: /**
272: * Counts the types stored in the file
273: *
274: *@since 2.6.31
275: *@return the number of types in this file
276: */
277: public int getTypeCount() {
278: if (typeList == null) {
279: return 0;
280: }
281:
282: return typeList.size();
283: }
284:
285: /**
286: * Get the list of types stored in this file
287: *
288: *@since 2.6.31
289: *@return an iterator over the types
290: */
291: public Iterator getTypes() {
292: if (typeList == null) {
293: return null;
294: }
295:
296: return typeList.iterator();
297: }
298:
299: /**
300: * Has this file been deleted
301: *
302: *@since 2.6.31
303: *@return true if the file is deleted
304: */
305: public boolean isDeleted() {
306: return delete;
307: }
308:
309: /**
310: * Is this file moving to a new package
311: *
312: *@since 2.6.31
313: *@return true if the file is moving
314: */
315: public boolean isMoving() {
316: return isMoving;
317: }
318:
319: /**
320: * Provide method to visit a node
321: *
322: *@since 2.6.31
323: *@param visitor the visitor
324: *@param data the data for the visit
325: *@return some new data
326: */
327: public Object accept(SummaryVisitor visitor, Object data) {
328: return visitor.visit(this , data);
329: }
330:
331: /**
332: * Add an import summary
333: *
334: *@since 2.6.31
335: *@param importSummary the summary of what was imported
336: */
337: protected void add(ImportSummary importSummary) {
338: if (importSummary != null) {
339: // Initialize the import list
340: if (importList == null) {
341: initImportList();
342: }
343:
344: // Add it in
345: importList.add(importSummary);
346: }
347: }
348:
349: /**
350: * Add an type summary
351: *
352: *@since 2.6.31
353: *@param typeSummary the summary of the type
354: */
355: protected void add(TypeSummary typeSummary) {
356: if (typeSummary != null) {
357: // Initialize the type list
358: if (typeList == null) {
359: initTypeList();
360: }
361:
362: // Add it to the list
363: typeList.add(typeSummary);
364: }
365: }
366:
367: /**
368: * Scans through the tree looking for a type declaration
369: *
370: *@since 2.6.31
371: *@param root the root of the abstract syntax tree
372: *@return true if there is a type node present
373: */
374: private static boolean hasType(SimpleNode root) {
375: int last = root.jjtGetNumChildren();
376: for (int ndx = 0; ndx < last; ndx++) {
377: if (root.jjtGetChild(ndx) instanceof ASTTypeDeclaration) {
378: return true;
379: }
380: }
381: return false;
382: }
383:
384: /**
385: * Initialization method
386: *
387: *@since 2.6.31
388: */
389: private static void init() {
390: if (fileMap == null) {
391: fileMap = new HashMap();
392: }
393: }
394:
395: /**
396: * Initialize the import list
397: *
398: *@since 2.6.31
399: */
400: private void initImportList() {
401: importList = new ArrayList();
402: }
403:
404: /**
405: * Initialize the type list
406: *
407: *@since 2.6.31
408: */
409: private void initTypeList() {
410: typeList = new LinkedList();
411: }
412:
413: /**
414: * Description of the Method
415: *
416: *@since 2.6.31
417: *@param state Description of Parameter
418: *@param file Description of Parameter
419: *@return Description of the Returned Value
420: */
421: private static FileSummary linkFileSummary(
422: SummaryLoaderState state, File file) {
423: FileSummary result;
424:
425: // Associate them together
426: result = (FileSummary) state.getCurrentSummary();
427: ((PackageSummary) result.getParent()).addFileSummary(result);
428:
429: // Store it away
430: fileMap.put(getKey(file), result);
431:
432: return result;
433: }
434:
435: /**
436: * Description of the Method
437: *
438: *@since 2.6.31
439: *@param file Description of Parameter
440: *@return Description of the Returned Value
441: */
442: private static SummaryLoaderState loadNewFileSummary(File file) {
443: // Create a new file summary object
444: ParserFactory factory = new FileParserFactory(file);
445: SimpleNode root = factory.getAbstractSyntaxTree(false,
446: ExceptionPrinter.getInstance());
447: if (root == null) {
448: return null;
449: }
450:
451: // Start the summary
452: SummaryLoaderState state = new SummaryLoaderState();
453: state.setFile(file);
454: root.jjtAccept(new SummaryLoadVisitor(), state);
455: return state;
456: }
457:
458: /**
459: * Registers a single new file. This method is used by the rapid metadata
460: * reloader
461: *
462: *@since 2.6.31
463: *@param summary Description of Parameter
464: */
465: static void register(FileSummary summary) {
466: if (fileMap == null) {
467: init();
468: }
469:
470: File file = summary.getFile();
471: if (file == null) {
472: return;
473: }
474:
475: fileMap.put(getKey(file), summary);
476: }
477:
478: /**
479: * Description of the Method
480: *
481: *@since 2.6.31
482: *@param file Description of Parameter
483: *@param result Description of Parameter
484: *@param root Description of Parameter
485: */
486: private static void reloadFileSummary(File file,
487: FileSummary result, SimpleNode root) {
488: SummaryLoaderState state = new SummaryLoaderState();
489: state.setFile(file);
490: state.startSummary(result);
491: state.setCode(SummaryLoaderState.LOAD_FILE);
492: root.jjtAccept(new SummaryLoadVisitor(), state);
493: }
494:
495: /**
496: * This method allows JBuilder to load a file summary from the buffer
497: *
498: *@since 2.6.31
499: *@param file the file
500: *@param input the input stream
501: *@return the file summary loaded
502: */
503: public static FileSummary reloadFromBuffer(File file, Reader input) {
504: if (fileMap == null) {
505: init();
506: }
507:
508: if (file == null) {
509: System.out.println("No file!");
510: return null;
511: }
512:
513: String key = getKey(file);
514: if (key == null) {
515: System.out.println("No key: " + file.toString());
516: return null;
517: }
518:
519: FileSummary result = (FileSummary) fileMap.get(key);
520:
521: if (result == null) {
522: System.out.println("No initial file summary");
523: SummaryLoaderState state = loadNewFileSummary(file);
524: result = linkFileSummary(state, file);
525:
526: // If you still can't get something that makes sense abort
527: if (result == null) {
528: System.out
529: .println("Unable to load the file summary from the file");
530: return null;
531: }
532: }
533:
534: resetFileSummary(file, result);
535: result.lastModified = new Date(file.lastModified());
536:
537: // Create a new file summary object
538: ParserFactory factory;
539: if (input == null) {
540: factory = new FileParserFactory(file);
541: } else {
542: factory = new InputStreamParserFactory(input, key);
543: }
544: SimpleNode root = factory.getAbstractSyntaxTree(false,
545: ExceptionPrinter.getInstance());
546: if (root == null) {
547: System.out
548: .println("Unable to get a parse tree for this file: Using existing file summary");
549: return result;
550: }
551: reloadFileSummary(file, result, root);
552:
553: return result;
554: }
555:
556: /**
557: * Removes all the files from the system
558: *
559: *@since 2.6.31
560: */
561: public static void removeAll() {
562: fileMap = null;
563: init();
564: }
565:
566: /**
567: * Remove any file summaries that have been deleted
568: *
569: *@since 2.6.31
570: */
571: public static void removeDeletedSummaries() {
572: if (fileMap == null) {
573: init();
574: return;
575: }
576:
577: LinkedList temp = new LinkedList();
578: Iterator keys = fileMap.values().iterator();
579: while (keys.hasNext()) {
580: FileSummary next = (FileSummary) keys.next();
581: File file = next.getFile();
582: if ((file != null) && !file.exists()) {
583: temp.add(file);
584: }
585: }
586:
587: Iterator iter = temp.iterator();
588: while (iter.hasNext()) {
589: File next = (File) iter.next();
590: removeFileSummary(next);
591: }
592: }
593:
594: /**
595: * Remove the file summary for a particular file
596: *
597: *@since 2.6.31
598: *@param file the file we are looking up
599: */
600: public static void removeFileSummary(File file) {
601: if (fileMap == null) {
602: init();
603: }
604:
605: String key = getKey(file);
606: FileSummary fileSummary = (FileSummary) fileMap.get(key);
607: if (fileSummary != null) {
608: // There is something to remove
609: fileMap.remove(key);
610:
611: // Get the parent
612: PackageSummary parent = (PackageSummary) fileSummary
613: .getParent();
614: parent.deleteFileSummary(fileSummary);
615: }
616: }
617:
618: /**
619: * Description of the Method
620: *
621: *@since 2.6.31
622: *@param file Description of Parameter
623: *@param result Description of the Parameter
624: */
625: private static void resetFileSummary(File file, FileSummary result) {
626: if (result == null) {
627: return;
628: }
629:
630: result.theFile = file;
631: result.importList = null;
632: result.typeList = null;
633: result.isMoving = false;
634: result.delete = false;
635: }
636:
637: /**
638: * Description of the Method
639: *
640: *@since 2.6.31
641: *@return Description of the Returned Value
642: */
643: public String toString() {
644: if (theFile == null) {
645: return "FileSummary<Framework File>";
646: }
647: return "FileSummary<" + theFile.getName() + ">";
648: }
649: }
650: // EOF
|