Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge pull request #1 from mquinson/master
[simgrid.git] / contrib / psg / src / peersim / config / ClassFinder.java
1 /*
2  * Copyright (c) 2003-2005 The BISON Project
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16  *
17  */
18
19 package peersim.config;
20
21 import java.io.*;
22 import java.util.*;
23 import java.util.zip.*;
24
25 /**
26  * Provides static methods to obtain the package-qualified class name
27  * of a class, given just the non-qualified name, and to obtain
28  * the non-qualified name, given the package-qualified class name.
29  * 
30  * Inspired from some code written by David Postill (david@postill.org.uk)
31  * (found in http://groups.google.com).
32  *
33  *
34  * @author Alberto Montresor
35  * @version $Revision: 1.9 $
36  */
37 class ClassFinder 
38 {
39
40 //--------------------------------------------------------------------------
41 //Fields and initialization
42 //--------------------------------------------------------------------------
43         
44         
45 /** Local map containing the associations */
46 private static Map<String,String> map = new TreeMap<String,String>();   
47
48 /** The number of directories that have been touched by the search.
49 This does not include directories in jar files. */
50 private static int visitedDirs = 0;
51
52 private static final int maxDirs;
53
54 static {
55
56         maxDirs = 10000;
57
58         try {
59                 findClasses(map);
60         } catch (IOException e) {
61                 e.printStackTrace();
62         }
63
64         if(visitedDirs >= maxDirs )
65         {
66                 System.err.println("Configuration: some directories in your "+
67                 "classpath probably contain filesystem\nConfiguration: "+
68                 "loops because the number of visited directories "+
69                 "reached "+maxDirs+".\nConfiguration: This means automatic "+
70                 "class lookup might fail and you might have\nConfiguration: "+
71                 "to fully qualify class names in the configuration.");
72         }
73 }
74         
75         
76 //--------------------------------------------------------------------------
77 //Public static methods
78 //--------------------------------------------------------------------------
79         
80 /**
81  * Returns the non-qualified name of a class, removing all the package
82  * information.
83  */
84 public static String getShortName(String className) {
85
86         int index = className.lastIndexOf('.');
87         if (index < 0) {
88                 return className;
89         } else {
90                 return className.substring(index+1);
91         }
92 }
93
94 /**
95  * Returns the package-qualified name associated to the specified
96  * non-qualified name, if exists. Otherwise it returns null.
97  * 
98  * Only classes reachable from the classpath defined by the 
99  * "java.class.path" property are considered. 
100  * Jar files and directories are both parsed.
101  * If multiple classes with the same name but different 
102  * fully-qualified names are present, a comma-separated list
103  * of fully-qualified class names is returned.
104  * 
105  * @param name the non-qualified name of the class to be searched
106  * @return the qualified name, if exists.
107  */
108 public static String getQualifiedName(String name)
109 {
110         return map.get(name);
111 }
112
113 //--------------------------------------------------------------------------
114 //Private static methods
115 //--------------------------------------------------------------------------
116         
117 /**
118  * Finds all the classes reachable from the current classpath;
119  * for each of them, inserts an association (name, fully-qualified 
120  * name) in the specified map. Both names are String objects.
121  * 
122  * Only classes reachable from the classpath defined by the 
123  * "java.class.path" property are considered. 
124  * Jar files and directories are both parsed.
125  * If multiple classes with the same name but different 
126  * fully-qualified names are present, they are inserted
127  * in the map as associations (name, comma-separated list of
128  * fully-qualified names).
129  * 
130  * @param map
131  * @throws IOException
132  */
133 private static void findClasses(Map<String,String> map)
134 throws IOException
135 {
136         String classPath = System.getProperty( "java.class.path" );
137         String separator = System.getProperty( "path.separator"  );
138         String filesep = System.getProperty( "file.separator");
139         StringTokenizer path = new StringTokenizer( classPath, separator );
140
141         while( path.hasMoreTokens() ) {
142                 
143                 String pathElement = path.nextToken();
144                 File pathFile = new File( pathElement );
145                 
146                 if( pathFile.isDirectory() ) {
147                         if (!pathElement.endsWith(filesep)) {
148                                 pathElement = pathElement + filesep;
149                                 pathFile = new File( pathElement);
150                         }
151                         findClassInPathDir( map, pathElement, pathFile );
152                         // Search directories
153                 } else if ( pathFile.exists() ) {
154                         findClassInJar( map, pathFile);
155                 }
156         }
157 }
158
159 //--------------------------------------------------------------------------
160
161 /**
162  * Parses jar file.
163  * 
164  * @param map the map where to insert associations
165  * @param pathFile the file name of the associated jar file
166  * @throws IOException
167  */
168 private static void findClassInJar(Map<String,String> map, File pathFile)
169 throws IOException
170 {
171         ZipFile zipFile = new ZipFile( pathFile );
172         Enumeration entries = zipFile.entries();
173         while( entries.hasMoreElements() ) {
174                 
175                 String entry = entries.nextElement().toString();
176                 if( entry.endsWith( ".class" ) ) {
177                         // File names in ZIP archives (so, also in JARs)
178                         // are separated by forward slashes '/', independently
179                         // of the architecture.
180                         String className = classname( entry, "/" ); 
181                         String shortName = getShortName( className );
182                         if (map.containsKey(shortName)) {
183                                 map.put(shortName,
184                                         map.get(shortName)+","+className);
185                         } else {
186                                 map.put(shortName, className);
187                         }
188                 }
189         }
190 }
191
192 //--------------------------------------------------------------------------
193
194 /**
195  * Recursively parses directories.
196  * 
197  * @param map the map where to insert associations
198  * @param pathElement the path string used for recursion
199  * @param pathFile the file (directory) to be analyzed
200  * @throws IOException
201  */
202 private static void findClassInPathDir( Map<String,String> map,
203         String pathElement, File pathFile )
204 throws IOException
205 {
206         visitedDirs++;
207         if(visitedDirs>=maxDirs) return;
208
209         String[] list = pathFile.list();
210         String filesep = System.getProperty( "file.separator");
211         
212         for( int i = 0; i < list.length; i++ ) {
213                 File file = new File( pathFile, list[i] );
214                 if( file.isDirectory() ) {
215                         findClassInPathDir( map, pathElement, file );
216                 }
217                 else if ( file.exists() && (file.length() != 0) && list[i].endsWith( ".class" ) ) {
218                         String classFile = file.toString().substring( pathElement.length());
219                         String className = classname( classFile, filesep );
220                         String shortName = getShortName( className );
221                         if (map.containsKey(shortName)) {
222                                 map.put(shortName, map.get(shortName)+","+className);
223                         } else {
224                                 map.put(shortName, className);
225                         }
226                 }
227         }
228 }
229
230 //--------------------------------------------------------------------------
231
232 /**
233  * Translates a class file name in a class name using
234  * the specified file separator.
235  */
236 private static String classname(String classFile, String filesep)
237
238         return classFile.replace( filesep, "." ).substring(
239                 0, classFile.length() - ".class".length() ); 
240 }
241
242 //--------------------------------------------------------------------------
243
244 /** 
245  * Testing.
246  * 
247  * @param argv
248  */
249 public static void main( String[] argv )
250 {
251         Iterator i = map.keySet().iterator();
252         while (i.hasNext()) {
253                 String key = (String) i.next();
254                 String name = map.get(key);
255                 System.out.println(key + " --> " + name);
256         }
257 }
258 }