MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MyLoadUnloadTest.java
1 /*
2  Copyright 2010 Sun Microsystems, Inc.
3  All rights reserved. Use is subject to license terms.
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; version 2 of the License.
8 
9  This program 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
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 /*
19  * MyLoadUnloadTest.java
20  */
21 
22 package test;
23 
24 import java.lang.ref.WeakReference;
25 
26 import java.lang.reflect.Method;
27 import java.lang.reflect.InvocationTargetException;
28 
29 import java.io.PrintWriter;
30 import java.io.File;
31 import java.io.FileInputStream;
32 import java.io.IOException;
33 import java.io.FileNotFoundException;
34 
35 import java.net.URL;
36 import java.net.URI;
37 import java.net.MalformedURLException;
38 import java.net.URISyntaxException;
39 import java.net.URLClassLoader;
40 
41 import java.nio.ByteBuffer;
42 import java.nio.channels.FileChannel;
43 
72 public class MyLoadUnloadTest {
73 
77  static protected final PrintWriter out = new PrintWriter(System.out, true);
78 
82  static protected final PrintWriter err = new PrintWriter(System.err, true);
83 
84  // ensure that asserts are enabled
85  static {
86  boolean assertsEnabled = false;
87  assert assertsEnabled = true; // intentional side effect
88  if (!assertsEnabled) {
89  throw new RuntimeException("Asserts must be enabled for this test to be effective!");
90  }
91  }
92 
93  static final String pprefixes_prop
94  = "com.mysql.jtie.test.MyLoadUnloadTest.target_package_prefixes";
95  static final String cname_prop
96  = "com.mysql.jtie.test.MyLoadUnloadTest.target_class_name";
97  static final String mname_prop
98  = "com.mysql.jtie.test.MyLoadUnloadTest.target_method_name";
99 
103  static protected WeakReference<ClassLoader> cl = null;
104 
108  static private final Runtime rt = Runtime.getRuntime();
109 
114  // this loader is only used for debugging this test
115  static class SelfishFileClassLoader extends ClassLoader {
116 
117  public SelfishFileClassLoader() {
118  out.println("--> SelfishFileClassLoader()");
119  out.println(" this = " + this);
120  out.println(" getParent() = " + getParent());
121  out.println("<-- SelfishFileClassLoader()");
122  }
123 
124  private ByteBuffer getClassData(String name)
125  throws ClassNotFoundException {
126  out.println("--> SelfishFileClassLoader.getClassData(String)");
127 
128  // for simplicity of code, only support loading classes from files;
129  // an alternative approach to collect all bytes using
130  // InputStream ClassLoader.getSystemResourceAsStream(String)
131  // ReadableByteChannel Channels.newChannel(InputStream)
132  // int ReadableByteChannel.read(ByteBuffer)
133  // requires multiple copying within nested loops, since the total
134  // number of bytes to be read is not known in advance.
135 
136  String rname = name.replace('.', '/') + ".class";
137 
138  // locate the class data
139  final URL url = ClassLoader.getSystemResource(rname);
140  if (url == null) {
141  final String msg = ("no definition of the class "
142  + rname + " could be found.");
143  throw new ClassNotFoundException(msg);
144  }
145  out.println(" url = " + url);
146 
147  // convert into a URI
148  final URI uri;
149  try {
150  uri = url.toURI();
151  } catch (URISyntaxException ex) {
152  final String msg = ("the URL " + url + " is not formatted"
153  + "strictly according to RFC2396 and "
154  + "cannot be converted to a URI.");
155  throw new ClassNotFoundException(msg, ex);
156  }
157 
158  // convert into a pathname
159  final File f;
160  try {
161  f = new File(uri);
162  } catch (IllegalArgumentException ex) {
163  final String msg = ("the system-dependent URI " + uri
164  + " cannot be converted into a pathname.");
165  throw new ClassNotFoundException(msg, ex);
166  }
167 
168  // check accessibility
169  if (!f.canRead()) {
170  final String msg = ("cannot read file " + f);
171  throw new ClassNotFoundException(msg);
172  }
173  out.println(" can read file " + f);
174  final long nn = f.length();
175  out.println(" f.length = " + nn);
176 
177  // open a FileInputStream
178  final FileInputStream fis;
179  try {
180  fis = new FileInputStream(f);
181  } catch (FileNotFoundException ex) {
182  final String msg = ("the file " + f
183  + " does not exist, is a directory, or"
184  + " cannot be opened for reading.");
185  throw new ClassNotFoundException(msg, ex);
186  }
187 
188  // get the stream's FileChannel
189  final FileChannel fc = fis.getChannel();
190  assert (fc != null);
191  out.println(" fc = " + fc);
192 
193  // allocate a ByteBuffer and read file's content
194  final ByteBuffer bb;
195  try {
196  // not worth mapping file as ByteBuffer
197  // final MappedByteBuffer mbb
198  // = fc.map(MapMode.READ_ONLY, 0, fc.size());
199  // unclear performance gain but platform-dependent behaviour
200 
201  // retrieve the file's size
202  final long n;
203  try {
204  n = fc.size();
205  } catch (IOException ex) {
206  final String msg = ("cannot get size of file " + f);
207  throw new ClassNotFoundException(msg, ex);
208  }
209  assert (n == nn);
210 
211  // allocate a ByteBuffer
212  if (n > Integer.MAX_VALUE) {
213  final String msg = ("size of file " + f
214  + " larger than Integer.MAX_VALUE.");
215  throw new ClassFormatError(msg);
216  }
217  bb = ByteBuffer.allocateDirect((int)n);
218 
219  // read file's content into a ByteBuffer
220  try {
221  int k;
222  while ((k = fc.read(bb)) > 0) {
223  out.println(" read " + k + " bytes");
224  }
225  } catch (IOException ex) {
226  final String msg = ("cannot read file " + f);
227  throw new ClassNotFoundException(msg, ex);
228  }
229  assert (bb.remaining() == 0);
230  bb.rewind();
231  } finally {
232  try {
233  fc.close();
234  } catch (IOException ex) {
235  final String msg = ("cannot close FileChannel " + fc);
236  throw new ClassNotFoundException(msg, ex);
237  }
238  try {
239  fis.close();
240  } catch (IOException ex) {
241  final String msg = ("cannot close FileInputStream " + fis);
242  throw new ClassNotFoundException(msg, ex);
243  }
244  }
245 
246  out.println("<-- SelfishFileClassLoader.getClassData(String)");
247  return bb;
248  }
249 
250  // Under the Java ClassLoader delegation model, subclasses are
251  // encouraged to override findClass(), whose default implementation
252  // throws a ClassNotFoundException, rather than loadClass().
253  // However, for the purpose of ensuring that certain classes are only
254  // loaded by child class loaders, it is not sufficient to override
255  // findClass(), which is invoked by loadClass() only after it has
256  // delegated loading to the parent class loader with no success.
257  protected Class<?> loadClass(String name, boolean resolve)
258  throws ClassNotFoundException {
259  out.println("--> SelfishFileClassLoader.loadClass(String, boolean)");
260 
261  // check if the class has already been loaded
262  Class<?> cls = findLoadedClass(name);
263  if (cls != null) {
264  out.println(" already loaded " + cls);
265  return cls;
266  }
267 
268  //cls = super.findClass(name);
269  //cls = super.loadClass(name, resolve);
270 
271  // load test's classes by this ClassLoader, delegate others
272  if (name.startsWith("test")
273  || name.startsWith("myjapi")
274  || name.startsWith("jtie")) {
275  out.println(" self: loading " + name + " ...");
276  final ByteBuffer bb = getClassData(name);
277  cls = defineClass(name, bb, null);
278  } else {
279  out.println(" parent: loading " + name + " ...");
280  cls = getParent().loadClass(name);
281  }
282  assert (cls != null);
283 
284  out.println(" ... loaded " + cls
285  + " <" + cls.getClassLoader() + ">");
286 
287  // link class if requested
288  if (resolve) {
289  out.println(" linking " + cls + " ...");
290  resolveClass(cls);
291  out.println(" ... linked " + cls);
292  }
293 
294  out.println("<-- SelfishFileClassLoader.loadClass(String, boolean)");
295  return cls;
296  }
297  }
298 
303  static class FilterClassLoader extends ClassLoader {
304 
305  // list of package prefixes not to be loaded by parent class loaders
306  protected final String[] prefixes;
307 
308  public FilterClassLoader(String[] prefixes) {
309  out.println("--> FilterClassLoader()");
310  out.println(" this = " + this);
311  out.println(" getParent() = " + getParent());
312  out.println(" prefixes[] = {");
313  for (int i = 0; i < prefixes.length; i++) {
314  out.println(" \"" + prefixes[i] + "\"");
315  }
316  out.println(" }");
317  this.prefixes = prefixes;
318  out.println("<-- FilterClassLoader()");
319  }
320 
321  // should never be called, since only invoked by loadClass()
322  protected Class<?> findClass(String name)
323  throws ClassNotFoundException {
324  assert (false) : "should never be called";
325  throw new ClassNotFoundException();
326  }
327 
328  // selectively load classes by parent class loaders
329  protected Class<?> loadClass(String name, boolean resolve)
330  throws ClassNotFoundException {
331  out.println("--> FilterClassLoader.loadClass(String, boolean)");
332  Class<?> cls = null;
333 
334  // this loader does not find and load any classes by itself
335  assert (findLoadedClass(name) == null);
336 
337  // give up on loading if class matches any of the prefixes
338  for (int i = prefixes.length - 1; i >= 0; i--) {
339  if (name.startsWith(prefixes[i])) {
340  out.println(" redirect loading " + name);
341  out.println("<<< FilterClassLoader.loadClass(String, boolean)");
342  throw new ClassNotFoundException();
343  }
344  }
345 
346  // delegate loading of class to parent class loaders
347  out.println(" delegate loading " + name);
348  cls = getParent().loadClass(name);
349  assert (cls != null);
350  //out.println(" ... loaded " + cls
351  // + " <" + cls.getClassLoader() + ">");
352 
353  // link class if requested
354  if (resolve) {
355  out.println(" linking " + cls + " ...");
356  resolveClass(cls);
357  out.println(" ... linked " + cls);
358  }
359 
360  out.println("<-- FilterClassLoader.loadClass(String, boolean)");
361  return cls;
362  }
363  }
364 
368  static class MyURLClassLoader extends URLClassLoader {
369 
370  public MyURLClassLoader(URL[] urls, ClassLoader parent) {
371  super(urls, parent);
372  out.println("--> MyURLClassLoader(URL[], ClassLoader)");
373  out.println(" this = " + this);
374  out.println(" getParent() = " + getParent());
375  out.println(" urls[] = {");
376  for (int i = 0; i < urls.length; i++) {
377  out.println(" " + urls[i]);
378  }
379  out.println(" }");
380  out.println("<-- MyURLClassLoader(URL[], ClassLoader)");
381  }
382 
383  protected Class<?> findClass(String name)
384  throws ClassNotFoundException {
385  out.println("--> MyURLClassFinder.findClass(String, boolean)");
386  out.println(" finding " + name + " ...");
387  Class<?> cls = super.findClass(name);
388  out.println(" ... found " + cls
389  + " <" + cls.getClassLoader() + ">");
390  out.println("<-- MyURLClassFinder.findClass(String, boolean)");
391  return cls;
392  }
393 
394  protected Class<?> loadClass(String name, boolean resolve)
395  throws ClassNotFoundException {
396  out.println("--> MyURLClassLoader.loadClass(String, boolean)");
397  out.println(" loading " + name + " ...");
398  Class<?> cls = super.loadClass(name, resolve);
399  out.println(" ... loaded " + cls
400  + " <" + cls.getClassLoader() + ">");
401  out.println("<-- MyURLClassLoader.loadClass(String, boolean)");
402  return cls;
403  }
404  }
405 
409  static private URL[] classPathURLs() throws MalformedURLException {
410  final String cp = System.getProperty("java.class.path");
411  assert (cp != null) : ("classpath = '" + cp + "'");
412  final String[] s = cp.split(File.pathSeparator);
413  final URL[] urls = new URL[s.length];
414  for (int i = 0; i < s.length; i++) {
415  urls[i] = new File(s[i]).toURI().toURL();
416  }
417  return urls;
418  }
419 
420  static public void test0()
421  throws ClassNotFoundException, NoSuchMethodException,
422  IllegalAccessException, InvocationTargetException,
423  MalformedURLException, InstantiationException {
424  out.flush();
425  out.println("--> MyLoadUnloadTest.test0()");
426 
427  out.println();
428  out.println(" MyLoadUnloadTest.class.getClassLoader() = "
429  + MyLoadUnloadTest.class.getClassLoader());
430  out.println(" ClassLoader.getSystemClassLoader() = "
431  + ClassLoader.getSystemClassLoader());
432 
433  // read properties specifying the test to run
434  final String pprefixes = System.getProperty(pprefixes_prop,
435  "test.,myjapi.");
436  final String[] pprefix = pprefixes.split(",");
437  final String cname = System.getProperty(cname_prop, "test.MyJapiTest");
438  final String mname = System.getProperty(mname_prop, "test");
439  out.println();
440  out.println(" using properties");
441  out.println(" pprefixes = '" + pprefixes + "'");
442  out.println(" cname = '" + cname + "'");
443  out.println(" mname = '" + mname + "'");
444 
445  // set up class loaders
446  out.println();
447  out.println(" create FilterClassLoader ...");
448  final ClassLoader fcl = new FilterClassLoader(pprefix);
449  out.println(" ... created " + fcl);
450 
451  out.println();
452  out.println(" create URLClassLoader ...");
453  final URL[] urls = classPathURLs();
454  //final ClassLoader ucl = new MyURLClassLoader(urls, fcl);
455  final ClassLoader ucl = new URLClassLoader(urls, fcl);
456  out.println(" ... created " + ucl);
457 
458  // store class loader in a global but weak reference
459  cl = new WeakReference<ClassLoader>(ucl);
460 
461  // run test
462  out.println();
463  out.println(" load class ...");
464  Class cls = ucl.loadClass(cname);
465  out.println(" ... loaded " + cls
466  + " <" + cls.getClassLoader() + ">");
467 
468  out.println();
469  out.println(" get method: " + mname + " ...");
470  Method m = cls.getMethod("test");
471  out.println(" ... got method: " + m);
472 
473  out.println();
474  out.println(" create instance: ...");
475  Object o = cls.newInstance();
476  out.println(" ... created instance: " + o);
477 
478  out.println();
479  out.println(" invoke method: " + m + " ...");
480  m.invoke(o);
481  out.println(" ... invoked method: " + m);
482 
483  out.println();
484  out.println("<-- MyLoadUnloadTest.test0()");
485  out.flush();
486  }
487 
491  static private void gc() {
492  out.println("--> MyLoadUnloadTest.gc()");
493  out.println(" jvm mem: " + (rt.totalMemory() - rt.freeMemory())/1024
494  + " KiB [" + rt.totalMemory()/1024 + " KiB]");
495  // empirically determined limit after which no further
496  // reduction in memory usage has been observed
497  final int nFullGCs = 100;
498  //final int nFullGCs = 10;
499  for (int i = 0; i < nFullGCs; i++) {
500  long oldfree;
501  long newfree = rt.freeMemory();
502  do {
503  // help I/O appear in sync between Java/native
504  synchronized (MyLoadUnloadTest.class) {
505  oldfree = newfree;
506  out.println(" rt.gc()");
507  out.flush();
508  err.flush();
509 
510  rt.runFinalization();
511  rt.gc();
512  newfree = rt.freeMemory();
513  }
514  } while (newfree > oldfree);
515  }
516  out.println(" jvm mem: " + (rt.totalMemory() - rt.freeMemory())/1024
517  + " KiB [" + rt.totalMemory()/1024 + " KiB]");
518  out.println("<-- MyLoadUnloadTest.gc()");
519  }
520 
521  static public void test()
522  throws ClassNotFoundException, NoSuchMethodException,
523  IllegalAccessException, InvocationTargetException,
524  MalformedURLException, InstantiationException {
525  out.flush();
526  out.println("--> MyLoadUnloadTest.test()");
527 
528  for (int i = 0; i < 3; i++) {
529  // create a class loader, load native library, and run test
530  test0();
531 
532  // garbage collect class loader that loaded native library
533  gc();
534 
535  // if the class loader with the native library has not been
536  // garbage collected, for instance, due to a strong caching
537  // reference, the next test invocation will fail with, e.g.:
538  // java.lang.UnsatisfiedLinkError: Native Library <libmyjapi>
539  // already loaded in another classloader
540  if (cl.get() != null) {
541  out.println("!!! the class loader with the native library"
542  + " has not been garbage collected (for instance,"
543  + " due to a strong caching reference)!");
544  break;
545  }
546  }
547 
548  out.println();
549  out.println("<-- MyLoadUnloadTest.test()");
550  out.flush();
551  }
552 
553  static public void main(String[] args)
554  throws Exception {
555  out.println("--> MyLoadUnloadTest.main()");
556 
557  test();
558 
559  // help I/O appear in sync between Java/native
560  synchronized (MyLoadUnloadTest.class) {
561  //try {
562  // MyLoadUnloadTest.class.wait(1000);
563  //} catch (InterruptedException ex) {
564  // // ignore
565  //}
566  out.flush();
567  err.flush();
568  }
569 
570  out.println();
571  out.println("<-- MyLoadUnloadTest.main()");
572  }
573 }