summaryrefslogtreecommitdiff
path: root/java/src/ServiceRepository.java
blob: e284679f4581682171546b5dfb9d501a536da4ed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
/*************************************************
 *
 * = PACKAGE
 *    ACE.ServiceConfigurator
 *
 * = FILENAME
 *    ServiceRepository.java
 *
 *@author Prashant Jain
 *
 *************************************************/
package ACE.ServiceConfigurator;

import java.io.*;
import java.util.*;
import java.net.*;
import ACE.OS.*;

/**
 * <hr>
 * <h2>SYNOPSIS</h2>
 *<blockquote>
 *     Provides a repository for loaded Java classes
 *</blockquote>
 *
 * <h2>DESCRIPTION</h2>
 *<blockquote>
 * This class provides a means to load Java classes explicitly at
 * runtime. Note that since the class makes use of the Java
 * ClassLoader, this class can not be used in a Java applet.
 *</blockquote>
 */
public class ServiceRepository
{
  /**
   * Create a Service Repository.
   */
  public ServiceRepository ()
  {
    this.loader_ = new ServiceLoader (null);
  }

  /**
   * Create a Service Repository passing in the context. Note that
   * this can cause problems for the default system loader since it will
   * try to load all the system classes using the context specified.
   *@param context Context to use when loading classes.
   */
  public ServiceRepository (String context)
  {
    this.loader_ = new ServiceLoader (context);
  }

  /**
   * Set the context
   *@param context Context to use when loading classes.
   */
  public void context (String c)
  {
    this.loader_.context (c);
  }

  /**
   * Load a Java Class. This method first checks if the class is
   * already in the repository. If it is not, it checks if the class
   * is a system class and can be found on the local system. If both
   * these fail, the method tries to load the bytes for the class and
   * then create the Class from these bytes.
   *@param name name of the class to find in the repository
   *@return Class corresponding to name
   */
  public Class load (String name) throws ClassNotFoundException
  {
    return this.loader_.loadClass (name, true);
  }

  /**
   * Load a Java Class across the network. The method tries to load
   * the bytes for the class and then create the Class from these
   * bytes. 
   *@param url URL of the class to load
   *@return Class corresponding to the url
   */
  public Class load (URL url) throws ClassNotFoundException
  {
    return this.loader_.loadClass (url, true);
  }

  private ServiceLoader loader_;
}

class ServiceLoader extends ClassLoader
{
  public ServiceLoader (String context)
  {
    super ();
    if (context == null)
      this.getClassPath ();
    else
      this.context_ = context;
  }

  public void context (String c)
  {
    this.context_ = c;
  }

  // Load a compiled class file into runtime
  public Class loadClass (String name, boolean resolve) throws ClassNotFoundException
  {
    Class newClass;
    if (this.context_ == null)
      {
	try
	  {
	    // Try to load it the class by reading in the bytes.
	    // Note that we are not catching ClassNotFoundException here
	    // since our caller will catch it.
	    try
	      {
		byte[] buf = bytesForClass (name);
		newClass = defineClass (buf, 0, buf.length);
		//	    ACE.DEBUG ("Loaded class: "+ name);
	    
		// Check if we need to load other classes referred to by this class.
		if (resolve)
		  resolveClass (newClass);
	      }
	    catch (ClassNotFoundException e)
	      {
		//	    ACE.DEBUG ("Using default loader for class: "+ name);
		// Try default system loader
		if ((newClass = findSystemClass (name)) != null)
		  return newClass;
		else 
		  throw (e);   // Rethrow the exception
	      }
	  }
	catch (IOException e)
	  {
	    throw new ClassNotFoundException (e.toString ());
	  }
      }
    else
      {
	System.out.println ("Fetching over the net");
	System.out.println ("Context: " + this.context_);
	// Try to load it the class by reading in the bytes.
	// Note that we are not catching ClassNotFoundException here
	// since our caller will catch it.
	try
	  {
	    URL url = new URL (this.context_ + name);
	    URLConnection urlConnection = url.openConnection ();

	    // Get the input stream associated with the URL connection and
	    // pipe it to a newly created DataInputStream
	    DataInputStream i = new DataInputStream (urlConnection.getInputStream ());

	    // Allocate a buffer big enough to hold the contents of the
	    // data we are about to read
	    byte [] buf = new byte [urlConnection.getContentLength ()];

	    // Now read all the data into the buffer
	    i.readFully (buf);

	    newClass = defineClass (buf, 0, buf.length);
	    //	    ACE.DEBUG ("Loaded class: "+ name);
	    
	    // Check if we need to load other classes referred to by this class.
	    if (resolve)
	      resolveClass (newClass);
	  }
	catch (IOException e)
	  {
	    throw new ClassNotFoundException (e.toString ());
	  }
      }
    return newClass;
  }

  // Load a compiled class file across the network
  public Class loadClass (URL url, boolean resolve) throws ClassNotFoundException
  {
    Class newClass = null;
    // Try to load it the class by reading in the bytes.
    // Note that we are not catching ClassNotFoundException here
    // since our caller will catch it.
    try
      {
	URLConnection urlConnection = url.openConnection ();

	// Get the input stream associated with the URL connection and
	// pipe it to a newly created DataInputStream
	DataInputStream i = new DataInputStream (urlConnection.getInputStream ());

	// Allocate a buffer big enough to hold the contents of the
	// data we are about to read
	byte [] buf = new byte [urlConnection.getContentLength ()];

	// Now read all the data into the buffer
	i.readFully (buf);

	newClass = defineClass (buf, 0, buf.length);
	//	    ACE.DEBUG ("Loaded class: "+ name);
	    
	// Check if we need to load other classes referred to by this class.
	if (resolve)
	  resolveClass (newClass);
      }
    catch (IOException e)
      {
	throw new ClassNotFoundException (e.toString ());
      }
    return newClass;
  }

  private void getClassPath ()
  {
    // Cache system properties that are needed when trying to find a
    // class file
    this.classPath_     = System.getProperty ("java.class.path", ".");
    this.pathSeparator_ = System.getProperty ("path.separator", ":");
    this.fileSeparator_ = System.getProperty ("file.separator", "/");
  }

  // Read a file into a byte array
  private byte[] bytesForClass (String name) throws IOException, ClassNotFoundException
  {
    // Break up the CLASSPATH to check for existence of file in each
    // sub-path. Note that we use the path_separator to extract every
    // sub-path and use that to check if the class file exists.
    StringTokenizer tokens = new StringTokenizer (this.classPath_, 
						  this.pathSeparator_);
    while (tokens.hasMoreTokens ())
      {
	// Create a File object which can then be used to see if the
	// class file actually exists
	File classFile = new File (tokens.nextToken () + 
				    this.fileSeparator_ + 
				    name + 
				    ".class");

	// Check if file exists, is a normal file and is readable
	if (true) /*classFile.exists () && 
	    classFile.isFile () &&
	    classFile.canRead ()) */
	  {    
	    // Set up the stream
	    FileInputStream in = new FileInputStream (classFile);

	    // Get byte count
	    int length = in.available ();
	    
	    if (length == 0)
	      throw new ClassNotFoundException (name);

	    // Create an array of bytes to read the file in
	    byte[] buf = new byte[length];

	    // Read the file
	    in.read (buf);

	    // Return byte array
	    return buf;
	  }
      }
    // File was not found so throw an exception.
    throw new ClassNotFoundException ("Class file " + name + " not found");
  }

  private String classPath_;
  // Class path that is loaded at construction

  private String pathSeparator_;
  // Platform-dependent path separator (e.g., : or ;)

  private String fileSeparator_;
  // Platform-dependent file separator (e.g., / or \)

  private String context_ = null;
}