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
104
105
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
119 try
120 {
121 clazz = super.findSystemClass( name );
122 return clazz;
123 }
124 catch ( ClassNotFoundException e )
125 {
126
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
143
144
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 }