001: package net.xoetrope.optional.resources;
002:
003: import java.io.File;
004: import java.io.FileInputStream;
005: import java.io.FileNotFoundException;
006: import java.io.IOException;
007: import java.io.InputStream;
008: import java.net.MalformedURLException;
009: import java.net.URI;
010: import java.net.URISyntaxException;
011: import java.net.URL;
012: import net.xoetrope.xui.XProjectManager;
013: import net.xoetrope.xui.XResourceManager;
014: import net.xoetrope.xui.build.BuildProperties;
015: import net.xoetrope.debug.DebugLogger;
016: import java.net.URLConnection;
017:
018: /**
019: * Used to locate project files. This classloader is used in the XEditorResourceManager and is initialised when
020: * a project is created or opened. It searches for files within the paths
021: * specified in the paths array.
022: * The paths/URIs can be specified in the startup file as follows:<br>
023: * NumRemoteClassLoaderPaths=2<br>
024: * RemoteClassLoaderPath1=http://localhost:8080/<br>
025: * RemoteClassLoaderPath2=http://localhost:8080/myresources/<br>
026: * <p>Copyright: Copyright (c) Xoetrope Ltd., 1998-2003</p>
027: * $Revision: 1.4 $
028: */
029: public class XRemoteClassLoader extends ClassLoader implements
030: XResourceLoader {
031: protected URI[] uri;
032:
033: /**
034: * Create a new class loader. Initially no search path is set.
035: * @param classLoader the super ClassLoader
036: */
037: public XRemoteClassLoader() {
038: super ();
039:
040: try {
041: XResourceManager rm = XProjectManager.getResourceManager();
042: int numClassLoadersPaths = new Integer(rm
043: .getStartupParam("NumRemoteClassLoaderPaths"))
044: .intValue();
045: String paths[] = new String[numClassLoadersPaths];
046: for (int i = 0; i < numClassLoadersPaths; i++)
047: paths[i] = rm.getStartupParam("RemoteClassLoaderPath"
048: + (i + 1));
049: setSources(paths);
050: } catch (Exception e) {
051: if (BuildProperties.DEBUG)
052: DebugLogger.logError("Unable to load class loader: "
053: + e.getMessage());
054: else
055: System.err.println(e.getMessage());
056: }
057: }
058:
059: /**
060: * Set the URIs for loading files
061: * @param projectUris The String array of URLs for inclusion in the search.
062: */
063: public boolean setSources(String[] projectUris) {
064: try {
065: uri = new URI[projectUris.length];
066: for (int i = 0; i < projectUris.length; i++) {
067: uri[i] = new URI(projectUris[i]);
068: }
069: } catch (URISyntaxException ex) {
070: ex.printStackTrace();
071: return false;
072: }
073:
074: return true;
075: }
076:
077: /**
078: * Overrides the Classloader method and searches for the resource file
079: * specifies by the parameter fileName.
080: * @param fileName The name of the file to be found.
081: * @return An InputStream created by from the filename if found or null if not
082: * found.
083: */
084: public InputStream getResourceAsStream(String fileName) {
085: try {
086: for (int i = 0; i < uri.length; i++) {
087: URL url = new URL(uri[i].toURL(), fileName);
088: URLConnection conn = url.openConnection();
089: conn.setDefaultUseCaches(false);
090: conn.setDoOutput(true);
091: conn.setIfModifiedSince(0);
092:
093: InputStream is = conn.getInputStream();
094: if (is != null)
095: return is;
096: }
097: } catch (IOException ex) {
098: }
099:
100: return null;
101: }
102:
103: /**
104: * Overrides the Classloader method and searches for the resource file
105: * specifies by the parameter fileName.
106: * @param fileName The name of the file to be found.
107: * @return A URL from the filename if found or null if not
108: * found.
109: */
110: public URL findResource(String fileName) {
111: try {
112: for (int i = 0; i < uri.length; i++) {
113: String prefix = (fileName.indexOf("\\") > -1 || fileName
114: .indexOf("/") > -1) ? "" : uri[i].toString()
115: + File.separatorChar;
116: File f = new File(prefix + fileName);
117: if (f.exists()) {
118: return f.toURL();
119: }
120: }
121: } catch (MalformedURLException ex) {
122: } catch (NullPointerException ex) {
123: }
124: return null;
125: }
126:
127: /**
128: * Finds the specified class. This method should be overridden
129: * by class loader implementations that follow the new delegation model
130: * for loading classes, and will be called by the <code>loadClass</code>
131: * method after checking the parent class loader for the requested class.
132: * The default implementation throws <code>ClassNotFoundException</code>.
133: *
134: * @param name the name of the class
135: * @return the resulting <code>Class</code> object
136: * @exception ClassNotFoundException if the class could not be found
137: */
138: public Class findClass(String className)
139: throws ClassNotFoundException {
140: return (findClass(className, true));
141: }
142:
143: /**
144: * Overrides the method from ClassLoader. This method is called auotmatically
145: * if the system classloader cannot find the class it is looking for. We then
146: * have the chance to find, load and return the class.
147: * @param className The name of the class we are being asked to find
148: * @param resolveIt Simply forward the value passed in
149: * @return The newly created Class
150: * @throws ClassNotFoundException
151: */
152: public synchronized Class findClass(String className,
153: boolean resolveIt) throws ClassNotFoundException {
154: Class result;
155: byte[] classBytes;
156:
157: try {
158: result = super .findSystemClass(className);
159: return result;
160: } catch (ClassNotFoundException e) {
161: }
162:
163: classBytes = loadClassBytes(className);
164: if (classBytes == null) {
165: throw new ClassNotFoundException();
166: }
167: // Define it (parse the class file)
168: result = defineClass(classBytes, 0, classBytes.length);
169: if (result == null) {
170: throw new ClassFormatError();
171: }
172: // Resolve if necessary
173: if (resolveIt)
174: resolveClass(result);
175:
176: // Done
177: return result;
178: }
179:
180: /**
181: * Opens the class file specified by the className. If found it opens the file
182: * and loads it into a byte array. The byte array is then returned.
183: * @param className The name of the class we are being asked to load
184: * @return A byte array created from the class file.
185: */
186: private byte[] loadClassBytes(String className) {
187: byte[] classBytes = new byte[0];
188: InputStream is = getResourceAsStream(className + ".class");
189: try {
190: byte[] b = new byte[1000];
191: int i = is.read(b);
192: while (i != -1) {
193: byte[] tempBytes = classBytes;
194: classBytes = new byte[classBytes.length + i];
195: System.arraycopy(b, 0, classBytes, tempBytes.length, i);
196: b = new byte[1000];
197: i = is.read(b);
198: }
199: } catch (IOException ex) {
200: }
201: return classBytes;
202: }
203: }
|