/*********************************************************************
* EJClassLoader.java
* created on 08.08.2004 by netseeker
* $Source: /cvsroot/ejoe/EJOE/src/de/netseeker/ejoe/EJClassLoader.java,v $
* $Date: 2007/03/22 21:01:35 $
* $Revision: 1.28 $
*
* ====================================================================
*
* Copyright 2005-2006 netseeker aka Michael Manske
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*
* This file is part of the ejoe framework.
* For more information on the author, please see
* <http://www.manskes.de/>.
*
*********************************************************************/
package de.netseeker.ejoe;
import java.io.IOException;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import de.netseeker.ejoe.adapter.ObjectStreamAdapter;
import de.netseeker.ejoe.cache.LRUMap;
import de.netseeker.ejoe.request.ClassloaderRequest;
/**
* A remote classloader using an EJClient instance (shared per EJServer) to retrieve class definitions from an EJServer.
* The last thousand retrieved classes are cached global over all instances of EJClassLoader. The used cache uses soft
* references.
*
* @author netseeker aka Michael Manske
* @since 0.3.0
*/
public class EJClassLoader extends ClassLoader implements Serializable
{
private static final long serialVersionUID = 1L;
transient private static Map _classCache = new LRUMap();
private static Map _clients = Collections.synchronizedMap( new HashMap() );
private String _clientKey;
/**
* Creates a new instance of this classloader using the EJOE server on the given host and port for loading unknown
* class definitions.
*
* @param host ip address or dns name where the EJOE classloader server is running
* @param port port to which the EJOE classloader serve is listening
*/
public EJClassLoader(String host, int port)
{
super();
initEJClient( host, port );
}
/**
* Creates a new instance of this classloader using the EJOE server on the given host and port for loading unknown
* class definitions. The classloader will delegate calls first to the given parent classloader.
*
* @param parent parent classloader
* @param host ip address or dns name where the EJOE classloader server is running
* @param port port to which the EJOE classloader serve is listening
*/
public EJClassLoader(ClassLoader parent, String host, int port)
{
super( parent );
initEJClient( host, port );
}
/**
* @param host
* @param port
*/
private void initEJClient( String host, int port )
{
_clientKey = host + ':' + port;
if ( !_clients.containsKey( _clientKey ) )
{
_clients.put( _clientKey, new EJClient( host, port, new ObjectStreamAdapter() ) );
}
}
/*
* (non-Javadoc)
*
* @see java.lang.ClassLoader#loadClass(java.lang.String, boolean)
*/
protected synchronized Class loadClass( String name, boolean resolve ) throws ClassNotFoundException
{
if ( _classCache == null )
{
_classCache = new LRUMap();
}
Class clazz = (Class) _classCache.get( name );
if ( clazz == null )
{
// ----- Check with the primordial class loader
try
{
clazz = super.findSystemClass( name );
return clazz;
}
catch ( ClassNotFoundException e )
{
// do nothing, it's just not a system class
}
clazz = loadRemoteClass( name );
_classCache.put( name, clazz );
if ( resolve )
{
resolveClass( clazz );
}
}
return clazz;
}
/*
* (non-Javadoc)
*
* @see java.lang.ClassLoader#loadClass(java.lang.String)
*/
public Class loadClass( String name ) throws ClassNotFoundException
{
return loadClass( name, true );
}
/**
* @param name
* @return
* @throws IOException
*/
private Class loadRemoteClass( String name ) throws ClassNotFoundException
{
Class result = null;
EJClient client = (EJClient) _clients.get( _clientKey );
try
{
byte[] classRaw = (byte[]) client.execute( new ClassloaderRequest( name ) );
if ( classRaw == null )
{
throw new ClassNotFoundException( "Class " + name + " not found!" );
}
result = defineClass( name, classRaw, 0, classRaw.length );
}
catch ( Throwable e )
{
throw new ClassNotFoundException( e.getMessage(), e );
}
return result;
}
}