View Javadoc

1   /**********************************************************************
2    * EJClassLoader.java
3    * created on 08.08.2004 by netseeker
4    * $Source: /cvsroot/ejoe/EJOE/src/de/netseeker/ejoe/EJClassLoader.java,v $
5    * $Date: 2007/03/22 21:01:35 $
6    * $Revision: 1.28 $
7    *
8    * ====================================================================
9    *
10   *  Copyright 2005-2006 netseeker aka Michael Manske
11   *
12   *  Licensed under the Apache License, Version 2.0 (the "License");
13   *  you may not use this file except in compliance with the License.
14   *  You may obtain a copy of the License at
15   *
16   *      http://www.apache.org/licenses/LICENSE-2.0
17   *
18   *  Unless required by applicable law or agreed to in writing, software
19   *  distributed under the License is distributed on an "AS IS" BASIS,
20   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21   *  See the License for the specific language governing permissions and
22   *  limitations under the License.
23   * ====================================================================
24   *
25   * This file is part of the ejoe framework.
26   * For more information on the author, please see
27   * <http://www.manskes.de/>.
28   *
29   *********************************************************************/
30  
31  package de.netseeker.ejoe;
32  
33  import java.io.IOException;
34  import java.io.Serializable;
35  import java.util.Collections;
36  import java.util.HashMap;
37  import java.util.Map;
38  
39  import de.netseeker.ejoe.adapter.ObjectStreamAdapter;
40  import de.netseeker.ejoe.cache.LRUMap;
41  import de.netseeker.ejoe.request.ClassloaderRequest;
42  
43  /***
44   * A remote classloader using an EJClient instance (shared per EJServer) to retrieve class definitions from an EJServer.
45   * The last thousand retrieved classes are cached global over all instances of EJClassLoader. The used cache uses soft
46   * references.
47   * 
48   * @author netseeker aka Michael Manske
49   * @since 0.3.0
50   */
51  public class EJClassLoader extends ClassLoader implements Serializable
52  {
53      private static final long    serialVersionUID = 1L;
54  
55      transient private static Map _classCache      = new LRUMap();
56  
57      private static Map           _clients         = Collections.synchronizedMap( new HashMap() );
58  
59      private String               _clientKey;
60  
61      /***
62       * Creates a new instance of this classloader using the EJOE server on the given host and port for loading unknown
63       * class definitions.
64       * 
65       * @param host ip address or dns name where the EJOE classloader server is running
66       * @param port port to which the EJOE classloader serve is listening
67       */
68      public EJClassLoader(String host, int port)
69      {
70          super();
71          initEJClient( host, port );
72      }
73  
74      /***
75       * Creates a new instance of this classloader using the EJOE server on the given host and port for loading unknown
76       * class definitions. The classloader will delegate calls first to the given parent classloader.
77       * 
78       * @param parent parent classloader
79       * @param host ip address or dns name where the EJOE classloader server is running
80       * @param port port to which the EJOE classloader serve is listening
81       */
82      public EJClassLoader(ClassLoader parent, String host, int port)
83      {
84          super( parent );
85          initEJClient( host, port );
86      }
87  
88      /***
89       * @param host
90       * @param port
91       */
92      private void initEJClient( String host, int port )
93      {
94          _clientKey = host + ':' + port;
95  
96          if ( !_clients.containsKey( _clientKey ) )
97          {
98              _clients.put( _clientKey, new EJClient( host, port, new ObjectStreamAdapter() ) );
99          }
100     }
101 
102     /*
103      * (non-Javadoc)
104      * 
105      * @see java.lang.ClassLoader#loadClass(java.lang.String, boolean)
106      */
107     protected synchronized Class loadClass( String name, boolean resolve ) throws ClassNotFoundException
108     {
109         if ( _classCache == null )
110         {
111             _classCache = new LRUMap();
112         }
113 
114         Class clazz = (Class) _classCache.get( name );
115 
116         if ( clazz == null )
117         {
118             // ----- Check with the primordial class loader
119             try
120             {
121                 clazz = super.findSystemClass( name );
122                 return clazz;
123             }
124             catch ( ClassNotFoundException e )
125             {
126                 // do nothing, it's just not a system class
127             }
128 
129             clazz = loadRemoteClass( name );
130             _classCache.put( name, clazz );
131 
132             if ( resolve )
133             {
134                 resolveClass( clazz );
135             }
136         }
137 
138         return clazz;
139     }
140 
141     /*
142      * (non-Javadoc)
143      * 
144      * @see java.lang.ClassLoader#loadClass(java.lang.String)
145      */
146     public Class loadClass( String name ) throws ClassNotFoundException
147     {
148         return loadClass( name, true );
149     }
150 
151     /***
152      * @param name
153      * @return
154      * @throws IOException
155      */
156     private Class loadRemoteClass( String name ) throws ClassNotFoundException
157     {
158         Class result = null;
159         EJClient client = (EJClient) _clients.get( _clientKey );
160 
161         try
162         {
163             byte[] classRaw = (byte[]) client.execute( new ClassloaderRequest( name ) );
164             if ( classRaw == null )
165             {
166                 throw new ClassNotFoundException( "Class " + name + " not found!" );
167             }
168 
169             result = defineClass( name, classRaw, 0, classRaw.length );
170         }
171         catch ( Throwable e )
172         {
173             throw new ClassNotFoundException( e.getMessage(), e );
174         }
175 
176         return result;
177     }
178 }