fixed bug with some attributes
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / builder / IdentifierIndexManager.java
1 package net.sourceforge.phpeclipse.builder;
2
3 import java.io.BufferedInputStream;
4 import java.io.BufferedReader;
5 import java.io.FileNotFoundException;
6 import java.io.FileReader;
7 import java.io.FileWriter;
8 import java.io.IOException;
9 import java.io.InputStream;
10 import java.util.ArrayList;
11 import java.util.Collection;
12 import java.util.Comparator;
13 import java.util.HashMap;
14 import java.util.Iterator;
15 import java.util.List;
16 import java.util.Set;
17 import java.util.SortedMap;
18 import java.util.StringTokenizer;
19 import java.util.TreeMap;
20
21 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
22 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
23 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
24 import net.sourceforge.phpdt.internal.compiler.parser.SyntaxError;
25 import net.sourceforge.phpdt.internal.compiler.util.Util;
26 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
27 import net.sourceforge.phpeclipse.obfuscator.PHPIdentifier;
28
29 import org.eclipse.core.resources.IFile;
30 import org.eclipse.core.runtime.CoreException;
31 import org.eclipse.core.runtime.IStatus;
32
33 /**
34  * Manages the identifer index information for a specific project
35  *  
36  */
37 public class IdentifierIndexManager {
38   public class LineCreator implements ITerminalSymbols {
39     private Scanner fScanner;
40
41     private int fToken;
42
43     public LineCreator() {
44       fScanner = new Scanner(true, false, false, false, true, null, null, true /* taskCaseSensitive */);
45     }
46
47     /**
48      * Add the information of the current identifier to the line
49      * 
50      * @param typeOfIdentifier
51      *          the type of the identifier ('c'lass, 'd'efine, 'f'unction, 'm'ethod(class), 'v'ariable(class) 'g'lobal variable)
52      * @param identifier
53      *          current identifier
54      * @param line
55      *          Buffer for the current index line
56      * @param phpdocOffset
57      *          the offset of the PHPdoc comment if available
58      * @param phpdocLength
59      *          the length of the PHPdoc comment if available
60      */
61     private void addIdentifierInformation(char typeOfIdentifier, char[] identifier, StringBuffer line, int phpdocOffset,
62         int phpdocLength) {
63       line.append('\t');
64       line.append(typeOfIdentifier);
65       line.append(identifier);
66       line.append("\to"); // Offset
67       line.append(fScanner.getCurrentTokenStartPosition());
68       if (phpdocOffset >= 0) {
69         line.append("\tp"); // phpdoc offset
70         line.append(phpdocOffset);
71         line.append("\tl"); // phpdoc length
72         line.append(phpdocLength);
73       }
74     }
75
76     private void addClassVariableInformation(char typeOfIdentifier, char[] identifier, StringBuffer line, int phpdocOffset,
77         int phpdocLength) {
78       line.append('\t');
79       line.append(typeOfIdentifier);
80       line.append(identifier);
81       line.append("\to"); // Offset
82       // we don't store the '$' in the index for class variables:
83       line.append(fScanner.getCurrentTokenStartPosition() + 1);
84       if (phpdocOffset >= 0) {
85         line.append("\tp"); // phpdoc offset
86         line.append(phpdocOffset);
87         line.append("\tl"); // phpdoc length
88         line.append(phpdocLength);
89       }
90     }
91
92     /**
93      * Get the next token from input
94      */
95     private void getNextToken() {
96       try {
97         fToken = fScanner.getNextToken();
98         if (Scanner.DEBUG) {
99           int currentEndPosition = fScanner.getCurrentTokenEndPosition();
100           int currentStartPosition = fScanner.getCurrentTokenStartPosition();
101           System.out.print(currentStartPosition + "," + currentEndPosition + ": ");
102           System.out.println(fScanner.toStringAction(fToken));
103         }
104         return;
105       } catch (InvalidInputException e) {
106         // ignore errors
107         //        e.printStackTrace();
108       }
109       fToken = TokenNameERROR;
110     }
111
112     private void parseDeclarations(char[] parent, StringBuffer buf, boolean goBack) {
113       char[] ident;
114       char[] classVariable;
115       int counter = 0;
116       boolean hasModifiers = false;
117       int phpdocOffset = -1;
118       int phpdocLength = -1;
119       try {
120         while (fToken != TokenNameEOF && fToken != TokenNameERROR) {
121           phpdocOffset = -1;
122           hasModifiers = false;
123           if (fToken == TokenNameCOMMENT_PHPDOC) {
124             phpdocOffset = fScanner.getCurrentTokenStartPosition();
125             phpdocLength = fScanner.getCurrentTokenEndPosition() - fScanner.getCurrentTokenStartPosition() + 1;
126             getNextToken();
127             while (fToken == TokenNamestatic || fToken == TokenNamefinal || fToken == TokenNamepublic
128                 || fToken == TokenNameprotected || fToken == TokenNameprivate || fToken == TokenNameabstract) {
129               hasModifiers = true;
130               getNextToken();
131             }
132             if (fToken == TokenNameEOF || fToken == TokenNameERROR) {
133               break;
134             }
135           }
136           if (fToken == TokenNamefunction) {
137             getNextToken();
138             if (fToken == TokenNameAND) {
139               getNextToken();
140             }
141             if (fToken == TokenNameIdentifier) {
142               ident = fScanner.getCurrentIdentifierSource();
143               if (parent != null && equalCharArrays(parent, ident)) {
144                 // constructor function
145                 addIdentifierInformation('k', ident, buf, phpdocOffset, phpdocLength);
146               } else {
147                 if (parent != null) {
148                   // class method function
149                   addIdentifierInformation('m', ident, buf, phpdocOffset, phpdocLength);
150                 } else {
151                   // nested function ?!
152                   addIdentifierInformation('f', ident, buf, phpdocOffset, phpdocLength);
153                 }
154               }
155               getNextToken();
156               parseDeclarations(null, buf, true);
157             }
158           } else if (fToken == TokenNameclass || fToken == TokenNameinterface) {
159             getNextToken();
160             if (fToken == TokenNameIdentifier) {
161               ident = fScanner.getCurrentIdentifierSource();
162               addIdentifierInformation('c', ident, buf, phpdocOffset, phpdocLength);
163               getNextToken();
164               //skip tokens for classname, extends and others until we have
165               // the opening '{'
166               while (fToken != TokenNameLBRACE && fToken != TokenNameEOF && fToken != TokenNameERROR) {
167                 getNextToken();
168               }
169               parseDeclarations(ident, buf, true);
170             }
171           } else if (fToken == TokenNamevar || hasModifiers || fToken == TokenNamestatic || fToken == TokenNamefinal
172               || fToken == TokenNamepublic || fToken == TokenNameprotected || fToken == TokenNameprivate) {
173             while (fToken == TokenNamevar || fToken == TokenNamestatic || fToken == TokenNamefinal || fToken == TokenNamepublic
174                 || fToken == TokenNameprotected || fToken == TokenNameprivate) {
175               getNextToken();
176             }
177             while (fToken == TokenNameVariable) {
178               ident = fScanner.getCurrentIdentifierSource();
179               classVariable = new char[ident.length - 1];
180               System.arraycopy(ident, 1, classVariable, 0, ident.length - 1);
181               addClassVariableInformation('v', classVariable, buf, phpdocOffset, phpdocLength);
182               getNextToken();
183               if (fToken == TokenNameCOMMA) {
184                 getNextToken();
185               }
186             }
187           } else if (!hasModifiers && fToken == TokenNameIdentifier) {
188             ident = fScanner.getCurrentIdentifierSource();
189             getNextToken();
190             if (ident.length == 6 && ident[0] == 'd' && ident[1] == 'e' && ident[2] == 'f' && ident[3] == 'i' && ident[4] == 'n'
191                 && ident[5] == 'e') {
192               if (fToken == TokenNameLPAREN) {
193                 getNextToken();
194                 if (fToken == TokenNameStringDoubleQuote) {
195                   ident = fScanner.getCurrentStringLiteralSource();
196                   addIdentifierInformation('d', ident, buf, phpdocOffset, phpdocLength);
197                   getNextToken();
198                 } else if (fToken == TokenNameStringSingleQuote) {
199                   ident = fScanner.getCurrentStringLiteralSource();
200                   addIdentifierInformation('d', ident, buf, phpdocOffset, phpdocLength);
201                   getNextToken();
202                 }
203               }
204             }
205           } else if (fToken == TokenNameglobal) {
206             // global variable
207             while (fToken != TokenNameEOF && fToken != TokenNameERROR && fToken != TokenNameSEMICOLON && fToken != TokenNameLBRACE
208                 && fToken != TokenNameRBRACE) {
209               getNextToken();
210               if (fToken == TokenNameVariable) {
211                 ident = fScanner.getCurrentIdentifierSource();
212                 addIdentifierInformation('g', ident, buf, phpdocOffset, phpdocLength);
213               }
214             }
215           } else if (fToken == TokenNameLBRACE) {
216             getNextToken();
217             counter++;
218           } else if (fToken == TokenNameRBRACE) {
219             getNextToken();
220             --counter;
221             if (counter == 0 && goBack) {
222               return;
223             }
224           } else {
225             getNextToken();
226           }
227         }
228       } catch (SyntaxError e) {
229         // TODO Auto-generated catch block
230         e.printStackTrace();
231       }
232     }
233
234     synchronized public void parseIdentifiers(char[] charArray, StringBuffer buf) {
235       char[] ident;
236       String identifier;
237       int counter = 0;
238       boolean hasModifiers = false;
239       int phpdocOffset = -1;
240       int phpdocLength = -1;
241       fScanner.setSource(charArray);
242       fScanner.setPHPMode(false);
243       fToken = TokenNameEOF;
244       getNextToken();
245       try {
246         while (fToken != TokenNameEOF) { // && fToken != TokenNameERROR) {
247           phpdocOffset = -1;
248           hasModifiers = false;
249           if (fToken == TokenNameCOMMENT_PHPDOC) {
250             phpdocOffset = fScanner.getCurrentTokenStartPosition();
251             phpdocLength = fScanner.getCurrentTokenEndPosition() - fScanner.getCurrentTokenStartPosition() + 1;
252             getNextToken();
253             while (fToken == TokenNamestatic || fToken == TokenNamefinal || fToken == TokenNamepublic
254                 || fToken == TokenNameprotected || fToken == TokenNameprivate || fToken == TokenNameabstract) {
255               hasModifiers = true;
256               getNextToken();
257             }
258             if (fToken == TokenNameEOF || fToken == TokenNameERROR) {
259               break;
260             }
261           }
262           if (fToken == TokenNamefunction) {
263             getNextToken();
264             if (fToken == TokenNameAND) {
265               getNextToken();
266             }
267             if (fToken == TokenNameIdentifier) {
268               ident = fScanner.getCurrentIdentifierSource();
269               addIdentifierInformation('f', ident, buf, phpdocOffset, phpdocLength);
270               getNextToken();
271               parseDeclarations(null, buf, true);
272             }
273           } else if (fToken == TokenNameclass || fToken == TokenNameinterface) {
274             getNextToken();
275             if (fToken == TokenNameIdentifier) {
276               ident = fScanner.getCurrentIdentifierSource();
277               addIdentifierInformation('c', ident, buf, phpdocOffset, phpdocLength);
278               getNextToken();
279               //skip fTokens for classname, extends and others until we have
280               // the opening '{'
281               while (fToken != TokenNameLBRACE && fToken != TokenNameEOF && fToken != TokenNameERROR) {
282                 getNextToken();
283               }
284               parseDeclarations(ident, buf, true);
285             }
286           } else if (fToken == TokenNameVariable) {
287             // global variable
288             ident = fScanner.getCurrentIdentifierSource();
289             addIdentifierInformation('g', ident, buf, phpdocOffset, phpdocLength);
290             getNextToken();
291           } else if (!hasModifiers && fToken == TokenNameIdentifier) {
292             ident = fScanner.getCurrentIdentifierSource();
293             getNextToken();
294             if (ident.length == 6 && ident[0] == 'd' && ident[1] == 'e' && ident[2] == 'f' && ident[3] == 'i' && ident[4] == 'n'
295                 && ident[5] == 'e') {
296               if (fToken == TokenNameLPAREN) {
297                 getNextToken();
298                 if (fToken == TokenNameStringDoubleQuote) {
299                   ident = fScanner.getCurrentStringLiteralSource();
300                   addIdentifierInformation('d', ident, buf, phpdocOffset, phpdocLength);
301                   getNextToken();
302                 } else if (fToken == TokenNameStringSingleQuote) {
303                   ident = fScanner.getCurrentStringLiteralSource();
304                   addIdentifierInformation('d', ident, buf, phpdocOffset, phpdocLength);
305                   getNextToken();
306                 }
307               }
308             }
309           } else {
310             getNextToken();
311           }
312         }
313       } catch (SyntaxError e) {
314         // TODO Auto-generated catch block
315         e.printStackTrace();
316       }
317     }
318   }
319
320   class StringComparator implements Comparator {
321     public int compare(Object o1, Object o2) {
322       String s1 = (String) o1;
323       String s2 = (String) o2;
324       return s1.compareTo(s2);
325       //        return s1.toUpperCase().compareTo(s2.toUpperCase());
326     }
327
328     public boolean equals(Object o) {
329       String s = (String) o;
330       return compare(this, o) == 0;
331     }
332   }
333
334   private HashMap fFileMap;
335
336   private String fFilename;
337
338   private TreeMap fIndentifierMap;
339
340   public IdentifierIndexManager(String filename) {
341     fFilename = filename;
342     initialize();
343     readFile();
344   }
345
346   /**
347    * Check if 2 char arrays are equal
348    * 
349    * @param a
350    * @param b
351    * @return
352    */
353   private static boolean equalCharArrays(char[] a, char[] b) {
354     if (a.length != b.length) {
355       return false;
356     }
357     for (int i = 0; i < b.length; i++) {
358       if (a[i] != b[i]) {
359         return false;
360       }
361     }
362     return true;
363   }
364
365   public LineCreator createLineCreator() {
366     return new LineCreator();
367   }
368
369   /**
370    * Add the information for a given IFile resource
371    *  
372    */
373   public void addFile(IFile fileToParse) {
374     //    InputStream iStream;
375     LineCreator lineCreator = createLineCreator();
376     try {
377       addInputStream(new BufferedInputStream(fileToParse.getContents()), fileToParse.getProjectRelativePath().toString(),
378           lineCreator);
379     } catch (CoreException e1) {
380       // TODO Auto-generated catch block
381       e1.printStackTrace();
382     }
383   }
384
385   /**
386    * @param fileToParse
387    * @param lineCreator
388    * @throws CoreException
389    */
390   public void addInputStream(InputStream stream, String filePath, LineCreator lineCreator) throws CoreException {
391     try {
392       StringBuffer lineBuffer = new StringBuffer();
393       lineBuffer.append(filePath);
394       int lineLength = lineBuffer.length();
395       lineCreator.parseIdentifiers(Util.getInputStreamAsCharArray(stream, -1, null), lineBuffer);
396       //      if (lineLength != lineBuffer.length()) {
397       // always add the file for Open Include Action
398       addLine(lineBuffer.toString());
399       //      }
400     } catch (IOException e) {
401       e.printStackTrace();
402     } finally {
403       try {
404         if (stream != null) {
405           stream.close();
406         }
407       } catch (IOException e) {
408       }
409     }
410   }
411
412   /**
413    * Adds a line of the index file for function, class, class-method and class-variable names
414    * 
415    * @param line
416    */
417   private void addLine(String line) {
418     StringTokenizer tokenizer;
419     String phpFileName = null;
420     String token;
421     String identifier = null;
422     String classname = null;
423     String offset = null;
424     PHPIdentifierLocation phpIdentifier = null;
425     boolean tokenExists = false;
426     tokenizer = new StringTokenizer(line, "\t");
427     // first token contains the filename:
428     try {
429       if (tokenizer.hasMoreTokens()) {
430         phpFileName = tokenizer.nextToken();
431         //System.out.println(token);
432       } else {
433         return;
434       }
435       // all the other tokens are identifiers:
436       while (tokenizer.hasMoreTokens()) {
437         token = tokenizer.nextToken();
438         //System.out.println(token);
439         switch (token.charAt(0)) {
440         case 'c':
441           // class name
442           identifier = token.substring(1);
443           classname = identifier;
444           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.CLASS, phpFileName);
445           break;
446         case 'd':
447           // define
448           identifier = token.substring(1);
449           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.DEFINE, phpFileName);
450           break;
451         case 'f':
452           // function name
453           identifier = token.substring(1);
454           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.FUNCTION, phpFileName);
455           break;
456         case 'g':
457           // global variable
458           identifier = token.substring(1);
459           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.GLOBAL_VARIABLE, phpFileName);
460           break;
461         case 'k':
462           // constructor function name
463           identifier = token.substring(1);
464           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.CONSTRUCTOR, phpFileName);
465           break;
466         case 'm':
467           //method inside a class
468           identifier = token.substring(1);
469           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.METHOD, phpFileName, classname);
470           break;
471         case 'v':
472           // variable inside a class
473           identifier = token.substring(1);
474           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.VARIABLE, phpFileName, classname);
475           break;
476         case 'o':
477           // offset information
478           identifier = null;
479           if (phpIdentifier != null) {
480             offset = token.substring(1);
481             phpIdentifier.setOffset(Integer.parseInt(offset));
482           }
483           break;
484         case 'p':
485           // PHPdoc offset information
486           identifier = null;
487           if (phpIdentifier != null) {
488             offset = token.substring(1);
489             phpIdentifier.setPHPDocOffset(Integer.parseInt(offset));
490           }
491           break;
492         case 'l':
493           // PHPdoc length information
494           identifier = null;
495           if (phpIdentifier != null) {
496             offset = token.substring(1);
497             phpIdentifier.setPHPDocLength(Integer.parseInt(offset));
498           }
499           break;
500         default:
501           PHPeclipsePlugin.log(IStatus.ERROR, "Unknown token character in IdentifierIndexManager: " + token.charAt(0));
502           identifier = null;
503           phpIdentifier = null;
504           classname = null;
505         }
506         if (identifier != null && phpIdentifier != null) {
507           tokenExists = true;
508           ArrayList list = (ArrayList) fIndentifierMap.get(identifier);
509           if (list == null) {
510             list = new ArrayList();
511             list.add(phpIdentifier);
512             fIndentifierMap.put(identifier, list);
513           } else {
514             boolean flag = false;
515             for (int i = 0; i < list.size(); i++) {
516               if (list.get(i).equals(phpIdentifier)) {
517                 flag = true;
518                 break;
519               }
520             }
521             if (flag == false) {
522               list.add(phpIdentifier);
523             }
524           }
525         }
526       }
527       fFileMap.put(phpFileName, line);
528     } catch (Throwable e) {
529       // write to workspace/.metadata/.log file
530       PHPeclipsePlugin.log(e);
531     }
532     //    if (tokenExists) {
533     
534     //    }
535   }
536
537   /**
538    * Change the information for a given IFile resource
539    *  
540    */
541   public void changeFile(IFile fileToParse) {
542     removeFile(fileToParse);
543     addFile(fileToParse);
544   }
545
546   /**
547    * Get a list of all PHPIdentifierLocation object's associated with an identifier
548    * 
549    * @param identifier
550    * @return
551    */
552   public List getLocations(String identifier) {
553     return (List) fIndentifierMap.get(identifier);
554   }
555
556   /**
557    * Initialize (i.e. clear) the current index information
558    *  
559    */
560   public void initialize() {
561     fIndentifierMap = new TreeMap(new StringComparator());
562     fFileMap = new HashMap();
563   }
564
565   private void readFile() {
566     FileReader fileReader;
567     try {
568       fileReader = new FileReader(fFilename);
569       BufferedReader bufferedReader = new BufferedReader(fileReader);
570       String line;
571       while (bufferedReader.ready()) {
572         // all entries for one file are in a line
573         // separated by tabs !
574         line = bufferedReader.readLine();
575         addLine(line);
576       }
577       fileReader.close();
578     } catch (FileNotFoundException e) {
579       // ignore this
580       // TODO DialogBox which asks the user if she/he likes to build new index?
581     } catch (IOException e) {
582       // TODO Auto-generated catch block
583       e.printStackTrace();
584     }
585   }
586
587   /**
588    * Remove the information for a given IFile resource
589    *  
590    */
591   public void removeFile(IFile fileToParse) {
592     //    String line = (String)
593     // fFileMap.get(fileToParse.getLocation().toString());
594     String line = (String) fFileMap.get(fileToParse.getProjectRelativePath().toString());
595     if (line != null) {
596       removeLine(line);
597     }
598   }
599
600   /**
601    * Removes a line of the index file for function, class, class-method and class-variable names
602    * 
603    * @param line
604    */
605   private void removeLine(String line) {
606     StringTokenizer tokenizer;
607     String phpFileName = null;
608     String token;
609     String identifier = null;
610     String classname = null;
611     PHPIdentifier phpIdentifier = null;
612     boolean tokenExists = false;
613     tokenizer = new StringTokenizer(line, "\t");
614     // first token contains the filename:
615     if (tokenizer.hasMoreTokens()) {
616       phpFileName = tokenizer.nextToken();
617       //System.out.println(token);
618     } else {
619       return;
620     }
621     int offset = -1;
622     // all the other tokens are identifiers:
623     while (tokenizer.hasMoreTokens()) {
624       token = tokenizer.nextToken();
625       //System.out.println(token);
626       switch (token.charAt(0)) {
627       case 'c':
628         // class name
629         identifier = token.substring(1);
630         classname = identifier;
631         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.CLASS, phpFileName);
632         break;
633       case 'd':
634         // define
635         identifier = token.substring(1);
636         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.DEFINE, phpFileName);
637         break;
638       case 'f':
639         // function name
640         identifier = token.substring(1);
641         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.FUNCTION, phpFileName);
642         break;
643       case 'g':
644         // global variable
645         identifier = token.substring(1);
646         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.GLOBAL_VARIABLE, phpFileName);
647         break;
648       case 'k':
649         // constructor function name
650         identifier = token.substring(1);
651         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.CONSTRUCTOR, phpFileName);
652         break;
653       case 'm':
654         //method inside a class
655         identifier = token.substring(1);
656         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.METHOD, phpFileName, classname);
657         break;
658       case 'o':
659         // offset information
660         identifier = null;
661         break;
662       case 'p':
663         // PHPdoc offset information
664         identifier = null;
665         break;
666       case 'l':
667         // PHPdoc length information
668         identifier = null;
669         break;
670       case 'v':
671         // variable inside a class
672         identifier = token.substring(1);
673         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.VARIABLE, phpFileName, classname);
674         break;
675       default:
676         PHPeclipsePlugin.log(IStatus.ERROR, "Unknown token character in IdentifierIndexManager: " + token.charAt(0));
677         identifier = null;
678         phpIdentifier = null;
679         classname = null;
680       }
681       if (identifier != null && phpIdentifier != null) {
682         ArrayList list = (ArrayList) fIndentifierMap.get(identifier);
683         if (list == null) {
684         } else {
685           for (int i = 0; i < list.size(); i++) {
686             if (list.get(i).equals(phpIdentifier)) {
687               list.remove(i);
688               break;
689             }
690           }
691           if (list.size() == 0) {
692             fIndentifierMap.remove(identifier);
693           }
694         }
695       }
696     }
697     fFileMap.remove(phpFileName);
698   }
699
700   /**
701    * Save the current index information in the projects index file
702    *  
703    */
704   public void writeFile() {
705     FileWriter fileWriter;
706     try {
707       fileWriter = new FileWriter(fFilename);
708       String line;
709       Collection collection = fFileMap.values();
710       Iterator iterator = collection.iterator();
711       while (iterator.hasNext()) {
712         line = (String) iterator.next();
713         fileWriter.write(line + '\n');
714       }
715       fileWriter.close();
716     } catch (FileNotFoundException e) {
717       // ignore exception; project is deleted by user
718     } catch (IOException e) {
719       // TODO Auto-generated catch block
720       e.printStackTrace();
721     }
722   }
723
724   /**
725    * @param fromKey
726    * @param toKey
727    * @return
728    */
729   public SortedMap getIdentifierMap() {
730     return fIndentifierMap;
731   }
732
733   synchronized public List getFileList(String filePattern) {
734     Set set = fFileMap.keySet();
735     if (set.isEmpty()) {
736       return null;
737     }
738     Iterator iter = set.iterator();
739     ArrayList list = new ArrayList();
740     String fileName;
741     int index;
742     while (iter.hasNext()) {
743       fileName = (String) iter.next();
744       if ((index = fileName.indexOf(filePattern)) != -1 && fileName.length() == (index + filePattern.length())) {
745         list.add(fileName);
746       }
747     }
748     return list;
749   }
750 }