PageRenderTime 112ms CodeModel.GetById 36ms app.highlight 40ms RepoModel.GetById 19ms app.codeStats 1ms

/jEdit/tags/jedit-4-2-pre14/org/gjt/sp/jedit/JARClassLoader.java

#
Java | 342 lines | 221 code | 42 blank | 79 comment | 37 complexity | f5f94298fe2819f029cc390f52965897 MD5 | raw file
  1/*
  2 * JARClassLoader.java - Loads classes from JAR files
  3 * :tabSize=8:indentSize=8:noTabs=false:
  4 * :folding=explicit:collapseFolds=1:
  5 *
  6 * Copyright (C) 1999, 2003 Slava Pestov
  7 * Portions copyright (C) 1999 mike dillon
  8 *
  9 * This program is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU General Public License
 11 * as published by the Free Software Foundation; either version 2
 12 * of the License, or any later version.
 13 *
 14 * This program is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 17 * GNU General Public License for more details.
 18 *
 19 * You should have received a copy of the GNU General Public License
 20 * along with this program; if not, write to the Free Software
 21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 22 */
 23
 24package org.gjt.sp.jedit;
 25
 26//{{{ Imports
 27import java.io.InputStream;
 28import java.io.IOException;
 29import java.net.URL;
 30import java.util.*;
 31import java.util.zip.ZipEntry;
 32import java.util.zip.ZipFile;
 33import org.gjt.sp.util.Log;
 34//}}}
 35
 36/**
 37 * A class loader implementation that loads classes from JAR files. All
 38 * instances share the same set of classes.
 39 * @author Slava Pestov
 40 * @version $Id: JARClassLoader.java 4989 2004-03-11 05:21:00Z spestov $
 41 */
 42public class JARClassLoader extends ClassLoader
 43{
 44	//{{{ JARClassLoader constructor
 45	/**
 46	 * This constructor creates a class loader for loading classes from all
 47	 * plugins. For example BeanShell uses one of these so that scripts can
 48	 * use plugin classes.
 49	 */
 50	public JARClassLoader()
 51	{
 52		// for debugging
 53		id = INDEX++;
 54		live++;
 55	} //}}}
 56
 57	//{{{ loadClass() method
 58	/**
 59	 * @exception ClassNotFoundException if the class could not be found
 60	 */
 61	public Class loadClass(String clazz, boolean resolveIt)
 62		throws ClassNotFoundException
 63	{
 64		// see what JARClassLoader this class is in
 65		Object obj = classHash.get(clazz);
 66		if(obj == NO_CLASS)
 67		{
 68			// we remember which classes we don't exist
 69			// because BeanShell tries loading all possible
 70			// <imported prefix>.<class name> combinations
 71			throw new ClassNotFoundException(clazz);
 72		}
 73		else if(obj instanceof JARClassLoader)
 74		{
 75			JARClassLoader classLoader = (JARClassLoader)obj;
 76			return classLoader._loadClass(clazz,resolveIt);
 77		}
 78
 79		// if it's not in the class hash, and not marked as
 80		// non-existent, try loading it from the CLASSPATH
 81		try
 82		{
 83			Class cls;
 84
 85			/* Defer to whoever loaded us (such as JShell,
 86			 * Echidna, etc) */
 87			ClassLoader parentLoader = getClass().getClassLoader();
 88			if (parentLoader != null)
 89				cls = parentLoader.loadClass(clazz);
 90			else
 91				cls = findSystemClass(clazz);
 92
 93			return cls;
 94		}
 95		catch(ClassNotFoundException cnf)
 96		{
 97			// remember that this class doesn't exist for
 98			// future reference
 99			classHash.put(clazz,NO_CLASS);
100
101			throw cnf;
102		}
103	} //}}}
104
105	//{{{ getResourceAsStream() method
106	public InputStream getResourceAsStream(String name)
107	{
108		if(jar == null)
109			return null;
110
111		try
112		{
113			ZipFile zipFile = jar.getZipFile();
114			ZipEntry entry = zipFile.getEntry(name);
115			if(entry == null)
116				return getSystemResourceAsStream(name);
117			else
118				return zipFile.getInputStream(entry);
119		}
120		catch(IOException io)
121		{
122			Log.log(Log.ERROR,this,io);
123
124			return null;
125		}
126	} //}}}
127
128	//{{{ getResource() method
129	public URL getResource(String name)
130	{
131		if(jar == null)
132			return null;
133
134		try
135		{
136			ZipFile zipFile = jar.getZipFile();
137			ZipEntry entry = zipFile.getEntry(name);
138			if(entry == null)
139				return getSystemResource(name);
140			else
141				return new URL(getResourceAsPath(name));
142		}
143		catch(IOException io)
144		{
145			Log.log(Log.ERROR,this,io);
146			return null;
147		}
148	} //}}}
149
150	//{{{ getResourceAsPath() method
151	public String getResourceAsPath(String name)
152	{
153		if(jar == null)
154			return null;
155
156		if(!name.startsWith("/"))
157			name = "/" + name;
158
159		return "jeditresource:/" + MiscUtilities.getFileName(
160			jar.getPath()) + "!" + name;
161	} //}}}
162
163	//{{{ getZipFile() method
164	/**
165	 * @deprecated Call <code>PluginJAR.getZipFile()</code> instead.
166	 */
167	public ZipFile getZipFile()
168	{
169		try
170		{
171			return jar.getZipFile();
172		}
173		catch(IOException io)
174		{
175			Log.log(Log.ERROR,this,io);
176			return null;
177		}
178	} //}}}
179
180	//{{{ dump() method
181	/**
182	 * For debugging.
183	 */
184	public static void dump()
185	{
186		Log.log(Log.DEBUG,JARClassLoader.class,
187			"Total instances created: " + INDEX);
188		Log.log(Log.DEBUG,JARClassLoader.class,
189			"Live instances: " + live);
190		synchronized(classHash)
191		{
192			Iterator entries = classHash.entrySet().iterator();
193			while(entries.hasNext())
194			{
195				Map.Entry entry = (Map.Entry)entries.next();
196				if(entry.getValue() != NO_CLASS)
197				{
198					Log.log(Log.DEBUG,JARClassLoader.class,
199						entry.getKey() + " ==> "
200						+ entry.getValue());
201				}
202			}
203		}
204	} //}}}
205
206	//{{{ toString() method
207	public String toString()
208	{
209		if(jar == null)
210			return "<anonymous>(" + id + ")";
211		else
212			return jar.getPath() + " (" + id + ")";
213	} //}}}
214
215	//{{{ finalize() method
216	protected void finalize()
217	{
218		live--;
219	} //}}}
220
221	//{{{ Package-private members
222
223	//{{{ JARClassLoader constructor
224	/**
225	 * @since jEdit 4.2pre1
226	 */
227	JARClassLoader(PluginJAR jar)
228	{
229		this();
230		this.jar = jar;
231	} //}}}
232
233	//{{{ activate() method
234	void activate()
235	{
236		String[] classes = jar.getClasses();
237		if(classes != null)
238		{
239			for(int i = 0; i < classes.length; i++)
240			{
241				classHash.put(classes[i],this);
242			}
243		}
244	} //}}}
245
246	//{{{ deactivate() method
247	void deactivate()
248	{
249		String[] classes = jar.getClasses();
250		if(classes == null)
251			return;
252
253		for(int i = 0; i < classes.length; i++)
254		{
255			Object loader = classHash.get(classes[i]);
256			if(loader == this)
257				classHash.remove(classes[i]);
258			else
259				/* two plugins provide same class! */;
260		}
261	} //}}}
262
263	//}}}
264
265	//{{{ Private members
266
267	// used to mark non-existent classes in class hash
268	private static final Object NO_CLASS = new Object();
269
270	private static int INDEX;
271	private static int live;
272	private static Hashtable classHash = new Hashtable();
273
274	private int id;
275	private PluginJAR jar;
276
277	//{{{ _loadClass() method
278	/**
279	 * Load class from this JAR only.
280	 */
281	private synchronized Class _loadClass(String clazz, boolean resolveIt)
282		throws ClassNotFoundException
283	{
284		jar.activatePlugin();
285
286		synchronized(this)
287		{
288			Class cls = findLoadedClass(clazz);
289			if(cls != null)
290			{
291				if(resolveIt)
292					resolveClass(cls);
293				return cls;
294			}
295
296			String name = MiscUtilities.classToFile(clazz);
297
298			try
299			{
300				ZipFile zipFile = jar.getZipFile();
301				ZipEntry entry = zipFile.getEntry(name);
302
303				if(entry == null)
304					throw new ClassNotFoundException(clazz);
305
306				InputStream in = zipFile.getInputStream(entry);
307
308				int len = (int)entry.getSize();
309				byte[] data = new byte[len];
310				int success = 0;
311				int offset = 0;
312				while(success < len)
313				{
314					len -= success;
315					offset += success;
316					success = in.read(data,offset,len);
317					if(success == -1)
318					{
319						Log.log(Log.ERROR,this,"Failed to load class "
320							+ clazz + " from " + zipFile.getName());
321						throw new ClassNotFoundException(clazz);
322					}
323				}
324
325				cls = defineClass(clazz,data,0,data.length);
326
327				if(resolveIt)
328					resolveClass(cls);
329
330				return cls;
331			}
332			catch(IOException io)
333			{
334				Log.log(Log.ERROR,this,io);
335
336				throw new ClassNotFoundException(clazz);
337			}
338		}
339	} //}}}
340
341	//}}}
342}