Source code: mucode/MuClassLoader.java
1 /* mucode - A lightweight and flexible mobile code toolkit
2 * Copyright (C) 2000, Gian Pietro Picco
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 package mucode;
19
20 import java.io.*;
21 import java.util.*;
22 import java.net.*;
23
24 /** Redefines class loading according to the policy of <i>µ</i>Code. <br>
25 *
26 * When a class name <i>C</I> needs to be resolved during the execution of a
27 * thread <i>t</I>, the class loader that gets invoked is the one that was
28 * used to load <i>t</i>'s class, according to the rules stated by the Java
29 * specification. If the <i>t</i> has been created with a class that comes
30 * from a group, the class loader will be an instance of
31 * <code>MuClassLoader</code>. Otherwise, it will be the system class
32 * loader. <p>
33 *
34 * The class loading policy implemented by <code>MuClassLoader</code> is as
35 * follows. Assuming <i>t</i> is executing within a <i>µ</i>Server
36 * <i>S</i>, the class loader will perform the following steps:
37 *
38 * <OL>
39 *
40 * <LI> Check whether <i>C</i> is a <i>ubiquitous class</I>, i.e. a class
41 * available on every <i>µ</i>Server. The set of ubiquitous classes can
42 * be changed dynamically using the methods in {@link MuServer}. Classes
43 * belonging to the Java API (<code>java.*</code>, <code>javax.*</code>, and
44 * sub-packages) and to <i>µ</i>Code (<code>mucode.*</code> and
45 * sub-packages) are ubiquitous by default. Checking ubiquitous classes first
46 * prevents redefinition of their behavior.
47 *
48 * <LI> Search for <i>C</i> in the private class space associated with
49 * <i>t</i> in <i>S</i>. Threads created directly by applications and not as a
50 * consequence of migration are all associated with the same class space,
51 * managed by the system Java class loader.
52 *
53 * <LI> Search for <i>C</i> in the shared class space associated with
54 * <i>S</i>.
55 *
56 * <LI> If <i>t</i> is allowed to perform dynamic download, <i>C</I> is
57 * retrieved from the remote <i>µ</i>Server specified by the user at
58 * migration time (that can be retrieved using {@link
59 * Group#getDynamicLinkSource()}, and loaded.
60 *
61 * <li> If <i>C</i> cannot be found, throw a
62 * <code>java.lang.ClassNotFoundException</code>.
63 *
64 * </OL>
65 *
66 * Note how classes belonging to the file system are never searched. Those are
67 * accessible only to threads that have been created directly by applications,
68 * because in that case loading is performed by the system class loader.
69 *
70 * @author <a href="mailto:picco@elet.polimi.it">Gian Pietro Picco</a>
71 * @version 1.0
72 *
73 * @see ClassLoader
74 * @see MuConstants */
75 public class MuClassLoader extends ClassLoader implements MuConstants {
76 /** The private class space. */
77 protected ClassSpace classSpace = new ClassSpace();
78 protected MuServer server = null;
79 protected String dynLinkSource = null;
80
81 protected MuClassLoader(MuServer aServer) {
82 server = aServer;
83 }
84
85 MuServer getServer() { return server; }
86
87 public ClassSpace getClassSpace() { return classSpace; }
88
89 /**
90 * Return the class loader associated to the current thread, i.e., the one
91 * that has been used to load the thread's class. If it is the system class
92 * loader, a wrapper to such loader is returned.
93 *
94 * @return a <code>MuClassLoader</code> value */
95 public static MuClassLoader getCurrent() {
96 // Look in the persistency root for loaders.
97 MuClassLoader l = (MuClassLoader)
98 MuServer.loaders.get(Thread.currentThread());
99 // If it's not there then it must be some thread that has been created
100 // within a mobile thread or straight from the VM.
101 if (l == null) {
102 ClassLoader ld = Thread.currentThread().getClass().getClassLoader();
103 if (!(ld instanceof MuClassLoader)) l = MuServer.defaultLoader;
104 else l = (MuClassLoader) ld;
105 }
106 return l;
107 }
108
109 /**
110 * Return the class loader associated with the given class, i.e., the one
111 * that has been used to load it the first time. If the class has been
112 * loaded by the system class loader, a wrapper to such loader is returned.
113 *
114 * @param c a <code>Class</code> value
115 * @return a <code>MuClassLoader</code> value */
116 public static MuClassLoader getClassLoader(Class c) {
117 MuClassLoader ret = null;
118 ClassLoader loader = c.getClassLoader();
119 if (!(loader instanceof MuClassLoader)) ret = MuServer.defaultLoader;
120 else ret = (MuClassLoader) loader;
121 return ret;
122 }
123
124 /** Redefines the behavior of the class loader.
125 *
126 * @param name the name of the desired Class.
127 * @param resolve true if the Class needs to be resolved.
128 * @return the resulting Class, or null if it was not found.
129 * @exception ClassNotFoundException if the class loader cannot find a
130 * definition for the class. */
131 public synchronized Class loadClass(String name, boolean resolve)
132 throws ClassNotFoundException {
133 Class c = null;
134 String id = null;
135 byte[] byteCode = null;
136
137 // First, let's check whether it's one of the system classes.
138 // server == null is the case of the default loader...
139 if (server == null || server.isUbiquitous(name)) {
140 c = findSystemClass(name);
141 if (c == null) throw new ClassNotFoundException();
142 } else {
143 // If not, let's check whether it's already in our class space.
144 c = classSpace.getClass(name);
145 if (c != null) server.D(name + " class retrieved " +
146 "from the thread private class space.");
147 else {
148 // If not, check whether there's the bytecode ready for it.
149 try {
150 byteCode = classSpace.getClassByteCode(name);
151 } catch (IOException e) {
152 throw new ClassNotFoundException(e.toString());
153 }
154 if (byteCode != null) {
155 c = defineClass(name, byteCode, 0, byteCode.length);
156 classSpace.putClass(name, c);
157 server.D(name + " class retrieved from the group's stream.");
158 } else {
159 // If not, check whether it's in the shared class space
160 c = server.sharedSpace.getClass(name);
161 if (c != null)
162 server.D(name + " class retrieved from the shared class space");
163 else if (dynLinkSource != null) {
164 DataInputStream is = null;
165 Socket socket = null;
166 try {
167 InetAddress dest = MuServer.parseHost(dynLinkSource);
168 int port = MuServer.parsePort(dynLinkSource);
169 if (port == -1) port = MuServer.SERVER_PORT;
170 socket = new Socket(dest, port);
171 new Header(MuServer.DYN_LINK, name,
172 server.isCompressionOn()).ship(socket);
173 is = new DataInputStream(socket.getInputStream());
174 int length = is.readInt();
175 if (length == REMOTE_ERROR) {
176 throw new ClassNotFoundException("The bytecode for "+ name +
177 " cannot be retrieved");
178 } else {
179 server.D("Retrieved the bytecode for "+name+" ("+
180 + length + " bytes).");
181 byteCode = new byte[length];
182 is.readFully(byteCode);
183 if (byteCode != null) {
184 c = defineClass(name, byteCode, 0, byteCode.length);
185 classSpace.putClass(name, c);
186 server.D(name + " class retrieved through " +
187 "dynamic linking from " + dynLinkSource);
188 } else throw new ClassNotFoundException();
189 }
190 } catch(IOException e) {
191 throw new ClassNotFoundException(e.toString());
192 } finally {
193 try {
194 is.close();
195 socket.close();
196 } catch(IOException e) {
197 server.Err("Problems in closing the connection." + e, e);
198 }
199 }
200 } else throw new ClassNotFoundException();
201 }
202 }
203 }
204 if (resolve) resolveClass(c);
205 return c;
206 }
207 }
208