View Javadoc

1   package org.naftulin.classpathexplorer.dublicate.imlp;
2   
3   import java.io.File;
4   import java.io.IOException;
5   import java.util.HashMap;
6   import java.util.Iterator;
7   import java.util.LinkedList;
8   import java.util.List;
9   import java.util.Map;
10  
11  import org.naftulin.classpathexplorer.AccessibleResource;
12  import org.naftulin.logwrapper.LogAdapter;
13  import org.naftulin.logwrapper.LogLevelAdaptor;
14  import org.naftulin.timespan.TimeSpan;
15  
16  
17  
18  /***
19   * Resource registry, singleton.
20   *  
21   * @author henry naftulin
22   * @version 1.0
23   */
24  class ResourceRegistry {
25  	private static final LogAdapter log = LogAdapter.getLogger(ResourceRegistry.class);
26  	private static final AccessibleResource[] EMPTY_ARRAY = new AccessibleResource[0];
27  	
28  	private static ResourceRegistry registry;
29  	private Map resources = new HashMap(2000);
30  	private List dublicatedResourceKeyList = new LinkedList();
31  	private String[] path;
32  	
33  	private ResourceRegistry() {}
34  	/***
35  	 * Returns resource registry, which is created if needed. 
36  	 * Based on GOF singleton pattern. 
37  	 * @return resource registry, which is created if needed.
38  	 */
39  	static synchronized ResourceRegistry getInstance() {
40  		if (registry == null) {
41  			registry = new ResourceRegistry();
42  		}
43  		return registry;
44  	}
45  	
46  	/***
47  	 * Returns resources based on the path sepcified.
48  	 * @param path
49  	 * @return resources based on the path sepcified.
50  	 */
51  	synchronized AccessibleResource[] getResourcesByFullName(String path) {
52  		AccessibleResource[] retArray = EMPTY_ARRAY;
53  		AccessibleResource temp = (AccessibleResource) resources.get(path);
54  		if (temp != null) { 		
55  			if (temp instanceof AccessibleResourceListDecorator) {
56  				List resourceList = new LinkedList();
57  				AccessibleResourceListDecorator dec = (AccessibleResourceListDecorator) temp;
58  				resourceList.add(temp);
59  				while(temp instanceof AccessibleResourceListDecorator) {
60  					dec = (AccessibleResourceListDecorator) temp;
61  					temp = dec.getNextResource();
62  					resourceList.add(temp);
63  				}
64  				retArray = new AccessibleResource[resourceList.size()];
65  				retArray = (AccessibleResource[]) resourceList.toArray(retArray);
66  			} else {
67  				retArray = new AccessibleResource[1];
68  				retArray[0] = temp;
69  			}
70  		}
71  		return retArray;
72  	}
73  	
74  	/***
75  	 * Returns all resources with the specified name.
76  	 * @param name 
77  	 * @return all resources with the specified name.
78  	 */
79  	synchronized AccessibleResource[] getResroucesByName(String name) { 
80  		TimeSpan span = new TimeSpan("ResourceRegistry.getResourcesByName()");
81  		span.start();
82  		List resourceList = new LinkedList(resources.values());
83  		List found = new LinkedList();
84  		Iterator it = resourceList.iterator();
85  		AccessibleResource temp;
86  		while(it.hasNext()) {
87  			temp = (AccessibleResource) it.next();
88  			if (temp.getName().equals(name)) {
89  				found.add(temp);
90  				if (temp instanceof AccessibleResourceListDecorator) {
91  					AccessibleResourceListDecorator dups= (AccessibleResourceListDecorator) temp;
92  					//leaving original resource in the list and dups in separate list
93  					while(temp instanceof AccessibleResourceListDecorator) {
94  						dups =(AccessibleResourceListDecorator) temp;
95  						temp = dups.getNextResource();
96  						found.add(temp);	
97  					}
98  				} 
99  			}
100 			
101 		}
102 		AccessibleResource[] arr = new AccessibleResource[found.size()];
103 		arr = (AccessibleResource[]) found.toArray(arr);
104 		span.stop();
105 		span.log(log, LogLevelAdaptor.INFO);
106 		return arr;
107 	}
108 	
109 	/***
110 	 * Returns all resources from the registry.
111 	 * @return all resources from the registry.
112 	 */
113 	synchronized AccessibleResource[] getResrouces() {
114 		TimeSpan span = new TimeSpan("ResourceRegistry.getResources()");
115 		span.start();
116 		List resourceList = new LinkedList(resources.values());
117 		List duplicates = new LinkedList();
118 		Iterator it = resourceList.iterator();
119 		AccessibleResource temp;
120 		while(it.hasNext()) {
121 			temp = (AccessibleResource) it.next();
122 			if (temp instanceof AccessibleResourceListDecorator) {
123 				AccessibleResourceListDecorator dups= (AccessibleResourceListDecorator) temp;
124 				//leaving original resource in the list and dups in separate list
125 				while(temp instanceof AccessibleResourceListDecorator && dups.getNextResource()!= null) {
126 					dups =(AccessibleResourceListDecorator) temp;
127 					temp = dups.getNextResource();
128 					duplicates.add(temp);	
129 				}
130 			}
131 		}
132 		resourceList.addAll(duplicates);
133 		AccessibleResource[] arr = new AccessibleResource[resourceList.size()];
134 		arr = (AccessibleResource[]) resourceList.toArray(arr);
135 		span.stop();
136 		span.log(log, LogLevelAdaptor.INFO);
137 		return arr;
138 	}
139 	
140 	/***
141 	 * Returns all the resources accessible from the archive. 
142 	 * @param archive not null.
143 	 * @return all the resources accessible from the archive.
144 	 * @throws IOException if error occurs while reading resource.
145 	 * @exception IllegalArgumentException if archive is null
146 	 */
147 	synchronized AccessibleResource[] getResrouces(AccessibleArchive archive) throws IOException {
148 		if (archive == null) {
149 			throw new IllegalArgumentException("archive cannot be null");
150 		}
151 		return archive.getAccessibleResources(); 
152 	}
153 	
154 	/***
155 	 * Returns dublicated resources.
156 	 * @return dublicated resources.
157 	 */
158 	synchronized AccessibleResource[] getDublicatedResources() { 
159 		Iterator it = dublicatedResourceKeyList.iterator();
160 		List resourceList = new LinkedList();
161 		AccessibleResource resource;
162 		while(it.hasNext()) {
163 			resource = (AccessibleResource) resources.get(it.next());
164 			while (resource instanceof AccessibleResourceListDecorator) {
165 				resourceList.add(resource);
166 				resource = ((AccessibleResourceListDecorator) resource).getNextResource();
167 			}
168 			if (resource != null) {
169 				resourceList.add(resource);
170 			}
171 		}
172 		AccessibleResource[] arr = new AccessibleResource[resourceList.size()];
173 		arr = (AccessibleResource[]) resourceList.toArray(arr);
174 		return arr;
175 	}
176 	
177 	/***
178 	 * Returns true if a resource is dublicated.
179 	 * @param resource not null. 
180 	 * @return true if a resource is dublicated.
181 	 * @exception IllegalArgumentException if resource is null
182 	 */
183 	synchronized boolean isResourceDublicated(AccessibleResource resource) {
184 		if (resource == null) {
185 			throw new IllegalArgumentException("resource cannot be null");
186 		}
187 		String key = resource.getKey();
188 		return dublicatedResourceKeyList.contains(key);
189 	}
190 	
191 	/***
192 	 * Returns true if any resource is dublicated in the resource registry.
193 	 * @return true if any resource is dublicated in the resource registry.
194 	 */
195 	synchronized boolean isAnyResourceDublicated() {
196 		return dublicatedResourceKeyList.size() > 0;
197 	}
198 	
199 	/***
200 	 * Returns the number resource dublicate resources.
201 	 * @return the number resource dublicate resources.
202 	 */
203 	synchronized int numResourceDublicated() {
204 		return dublicatedResourceKeyList.size();
205 	}
206 	
207 	/***
208 	 * Clears the registry.
209 	 */
210 	synchronized void clearRegistry() { 
211 		resources.clear(); 
212 		dublicatedResourceKeyList.clear();
213 	}
214 	
215 	/***
216 	 * Returns the size of regustry. All resources are counted, dublicated or not.
217 	 * @return the size of regustry.
218 	 */
219 	synchronized int registrySize() { return resources.size(); }
220 	
221 	/***
222 	 * Adds a resource to the resource registry. The resource is added
223 	 * based on it's {@link AccessibleResource#getKey() key}.
224 	 * @param resource to be added to the registry, not null.
225 	 * @exception IllegalArgumentException if resource is null
226 	 */
227 	synchronized void addResource(AccessibleResource resource) {
228 		if (resource == null) {
229 			throw new IllegalArgumentException("resource cannot be null");
230 		}
231 		String key = resource.getKey();
232 		if (resources.containsKey(key)) {
233 			AccessibleResource next = (AccessibleResource) resources.get(key);			
234 			resources.put(key, new AccessibleResourceListDecorator(resource, next));
235 			if (!dublicatedResourceKeyList.contains(key)) {
236 				dublicatedResourceKeyList.add(key);
237 			}
238 		} else {
239 			resources.put(key, resource);
240 		}		
241 	}
242 	
243 	/***
244 	 * Given path (path from class path) creates accessible archive resources for
245 	 * all the path that were not scanned already. If the path was scanned already,
246 	 * for example class path contains an entry twice, the path is not rescanned. 
247 	 * Null entries are returned for the dublicate archives
248 	 * @param accessiblePath path from class path - either directories or archives. 
249 	 * @return an array of accessible archives, with either archives or null entries.
250 	 */
251 	private AccessibleArchive[] getAccessibleArcives(String[] accessiblePath) {
252 		AccessibleArchive[] archives = new AccessibleArchive[accessiblePath.length];
253 		for (int i=0; i < archives.length; ++i) {
254 			archives[i] = ArchiveFactory.createArchive(new File(accessiblePath[i]));
255 			if (!resources.containsKey(archives[i].getKey())) {
256 				log.log(LogLevelAdaptor.DEBUG,"added accessible arcive: " + archives[i]);
257 				addResource(archives[i]);
258 			} else {
259 				//dublicate archive, we are not going to rescan it
260 				archives[i]=null;
261 			}
262 		}
263 		return archives;
264 	}
265 	
266 	/***
267 	 * Discovers resources. Archive is scanned only once, even if path contains entries pointing to the same
268 	 * archive. To re-scan the archive we first need to clear the registry.
269 	 * @param paths
270 	 */
271 	protected synchronized void discoverResources(String[] paths) {
272 		this.path = paths;
273 		TimeSpan timeSpan = new TimeSpan("ResourceRegistry.discoverResources()");
274 		timeSpan.start();
275 		AccessibleArchive[] archives = getAccessibleArcives(paths);
276 		for(int i=0; i < archives.length; ++i) {
277 			if (archives[i]!= null) { //dups would be nulls, so need to skip them
278 				try {
279 					AccessibleResource[] resources = archives[i].getAccessibleResources();
280 					if (resources != null) {
281 						for(int j=0; j < resources.length; ++j) {
282 							addResource(resources[j]);
283 						}
284 					}
285 				} catch(IOException e) {
286 					log.log(LogLevelAdaptor.WARN, "Cannot get resources for archive: " + archives[i] + ". Skipping the archive.", e);
287 				}
288 			}
289 		}
290 		timeSpan.stop();
291 		timeSpan.log(log, LogLevelAdaptor.DEBUG);
292 	}
293 	
294 	/***
295 	 * Returns the paths that were considered for discovering resources
296 	 * @return the paths that were considered for discovering resources
297 	 */
298 	public String[] getPath() { return path; }
299 }