/*
* Sun Public License
*
* The contents of this file are subject to the Sun Public License Version
* 1.0 (the "License"). You may not use this file except in compliance with
* the License. A copy of the License is available at http://www.sun.com/
*
* The Original Code is the SLAMD Distributed Load Generation Engine.
* The Initial Developer of the Original Code is Neil A. Wilson.
* Portions created by Neil A. Wilson are Copyright (C) 2004-2010.
* Some preexisting portions Copyright (C) 2002-2006 Sun Microsystems, Inc.
* All Rights Reserved.
*
* Contributor(s): Neil A. Wilson
*/
package com.slamd.common;
import java.io.File;
import java.io.FileInputStream;
import com.slamd.job.JobClass;
/**
* This class defines a class loader that will be used to load SLAMD job
* classes. Defining a custom class loader for job classes makes it possible to
* unload them if necessary to replace them on the fly in a running VM.
*
*
* @author Neil A. Wilson
*/
public class JobClassLoader
extends ClassLoader
{
// The parent class loader associated with this loader.
ClassLoader parent;
// The filesystem path that indicates where the classes may be found.
String classPath;
/**
* Creates a new instance of this job class loader.
*
* @param parentClassLoader The class loader that should be used if this
* class loader cannot create the class.
* @param classPath The path to the root of the hierarchy for the
* class files to be loaded.
*/
public JobClassLoader(ClassLoader parentClassLoader, String classPath)
{
super(parentClassLoader);
this.parent = parentClassLoader;
this.classPath = classPath;
}
/**
* Retrieves the job class with the specified name.
*
* @param className The fully-qualified name of the Java class to retrieve.
*
* @return The requested job class.
*
* @throws SLAMDException If a problem occurs while trying to load the
* requested class.
*/
public JobClass getJobClass(String className)
throws SLAMDException
{
String filePath = classPath + '/' + className.replace('.', '/') + ".class";
File classFile = new File(filePath);
if (! (classFile.exists() && classFile.isFile()))
{
try
{
return (JobClass) Constants.classForName(className).newInstance();
}
catch (Exception e)
{
throw new SLAMDException("File " + classFile + " associated with job " +
"class " + className +
" either does not exist or is not a file.", e);
}
}
byte[] fileBytes;
try
{
int fileSize = (int) classFile.length();
fileBytes = new byte[fileSize];
FileInputStream inputStream = new FileInputStream(classFile);
int totalBytesRead = inputStream.read(fileBytes);
while (totalBytesRead < fileSize)
{
totalBytesRead += inputStream.read(fileBytes, totalBytesRead,
(fileSize - totalBytesRead));
}
inputStream.close();
}
catch (Exception e)
{
throw new SLAMDException("Error loading class file " + filePath +
" for job class " + className + ": " + e, e);
}
Class jobClass;
try
{
jobClass = defineClass(className, fileBytes, 0, fileBytes.length);
resolveClass(jobClass);
}
catch (Exception e)
{
throw new SLAMDException("Error parsing file " + filePath +
" as a Java class: " + e, e);
}
try
{
return (JobClass) jobClass.newInstance();
}
catch (Exception e)
{
e.printStackTrace();
throw new SLAMDException("Unable to instantiate class " + className +
" as a job class: " + e, e);
}
}
/**
* Retrieves the binary representation of the specified job class.
*
* @param className The fully-qualified name of the Java class to retrieve.
*
* @return The bytes contained in the job class file.
*
* @throws SLAMDException If a problem occurs while trying to load the
* requested class.
*/
public byte[] getJobClassBytes(String className)
throws SLAMDException
{
String filePath = classPath + '/' + className.replace('.', '/') + ".class";
File classFile = new File(filePath);
if (! (classFile.exists() && classFile.isFile()))
{
throw new SLAMDException("File " + classFile + " associated with job " +
"class " + className +
" either does not exist or is not a file.");
}
try
{
int fileSize = (int) classFile.length();
byte[] fileBytes = new byte[fileSize];
FileInputStream inputStream = new FileInputStream(classFile);
int totalBytesRead = inputStream.read(fileBytes);
while (totalBytesRead < fileSize)
{
totalBytesRead += inputStream.read(fileBytes, totalBytesRead,
(fileSize - totalBytesRead));
}
inputStream.close();
return fileBytes;
}
catch (Exception e)
{
throw new SLAMDException("Error loading class file " + filePath +
" for job class " + className + ": " + e, e);
}
}
}