Friday, February 11, 2011

Class Loader

Class Loader

Class loader is responsible for loading the class. ClassLoader finds and loads the byte codes for the class definitions. Once loaded, they are verified before the ClassLoader can create actual classes. Now one question may arise who loads this classloader class, it is bootstrap also know as Primordial Class Loader.

Primordial Class Loader uses the native library to open and read Java class files from the disk into byte arrays and are platform depended. This class loader will load the core java class whose package starts with java.*. Once the core java classes are loaded it will try to load the extension classes which starts with javax.* and then finally application classes. All these loading works under delegate method one delegating to others.

Lets start writing our own class loader which will load the class from particular directory from the disk.

In order to write our own classloader we need to extend it from ClassLoader object

public class MyClassLoader extends ClassLoader

we had one method to load the class

protected synchronized Class loadClass(String dirName, String className, boolean resolve)
throws ClassNotFoundException {

Step 1: We need to find out whether that class is already loaded or not if loaded then just return that class.

Class cls = findLoadedClass(className);
if (cls != null) {
return cls;
}
Step 2: Getting the full fledge class name
String clsFile = className.replace('.', '/') + ".class";
clsFile = dirName+clsFile;

Step 3 : Security Checks.
Now here is the important step by default java runs with security manager disabled so if you want to run by enabling the security Manger you need to pass the following commands as arguments to java -Djava.security.manager -Djava.security.policy==/home/milind/.java.policy

Classloader should call the security manager to check whether particular classes are to be loaded or defined. So we will first call checkPackageDefinition() method of the security manager so that the security manager can prevent an untrusted class from defining classes in a particular package. and then we will call checkPackageAccess() method of the security manager so that the security manager can prevent certain classes from being loaded. By this way you can ensure that untrusted classes do not directly call classes in that package by placing the appropriate logic into the checkPackageAccess() method of your SecurityManager and also prevent an untrusted class from loading a new class into the java.lang package.

Classic example are Applet browser runs with own security manger and grants the correct access.

SecurityManager securityManager = System.getSecurityManager();
if( securityManager !=null) {
securityManager.checkPackageDefinition(packageName);
securityManager.checkPackageAccess(packageName);
}

Note securtiyManager can be null if you run the code without security manage enabled.


Step4: Getting the ByteStream of the .class file.

Step5: Converting the bytestream to java class and resolving it by calling the Classloader Methods.
cls = defineClass(className, classBytes, 0, classBytes.length);
if (resolve) {
resolveClass(cls);
}


Complete Code:
public class MyClassLoader extends ClassLoader {
private static final int BUFFER_SIZE = 8192;
protected synchronized Class loadClass(String className, boolean resolve)
throws ClassNotFoundException {
return loadClass(null, className, resolve);
}
protected synchronized Class loadClass(String dirName, String className, boolean resolve)
throws ClassNotFoundException {
// 1. is this class already loaded?
Class cls = findLoadedClass(className);
if (cls != null) {
return cls;
}
// get class file name from class name
String clsFile = className.replace('.', '/') + ".class";
if(dirName !=null) {
clsFile = dirName+clsFile;
}
String packageName = className.substring(0,className.lastIndexOf("."));
// Checking for the security
SecurityManager securityManager = System.getSecurityManager();
if( securityManager !=null) {
securityManager.checkPackageDefinition(packageName);
securityManager.checkPackageAccess(packageName);
}
// get bytes for class
byte[] classBytes = null;
try {
InputStream in=null;
if(dirName == null){
in = getResourceAsStream(clsFile);
}else {
in = new BufferedInputStream(new FileInputStream(clsFile));
}
byte[] buffer = new byte[BUFFER_SIZE];
ByteArrayOutputStream out = new ByteArrayOutputStream();
int n = -1;
while ((n = in.read(buffer, 0, BUFFER_SIZE)) != -1) {
out.write(buffer, 0, n);
}
classBytes = out.toByteArray();
}
catch (IOException e) {
}
if (classBytes == null) {
throw new ClassNotFoundException("Cannot load class: " + className);
}
// turn the byte array into a Class
try {
cls = defineClass(className, classBytes, 0, classBytes.length);
if (resolve) {
resolveClass(cls);
}
}
catch (SecurityException e) {
// loading core java classes such as java.lang.String
// is prohibited, throws java.lang.SecurityException.
// delegate to parent if not allowed to load class
cls = super.loadClass(className, resolve);
}
return cls;
}
}

Calling:

public static void main(String[] args) throws Exception {
MyClassLoader my = new MyClassLoader();
Class cls = my.loadClass("/media/disk/milind/MyCode/classloadingtest/", "com.milind.ClassTest", false);
Object obj = cls.newInstance();
Method method = cls.getMethod("getDesc");
Object returnObj = method.invoke(obj,null);
System.out.println(returnObj);
}









No comments:

Post a Comment