1 package org.apache.commons.jcs.auxiliary.remote.http.server;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.ObjectInputStream;
25 import java.io.OutputStream;
26 import java.io.Serializable;
27 import java.util.HashMap;
28 import java.util.Map;
29 import java.util.Properties;
30 import java.util.Set;
31
32 import javax.servlet.ServletConfig;
33 import javax.servlet.ServletException;
34 import javax.servlet.http.HttpServlet;
35 import javax.servlet.http.HttpServletRequest;
36 import javax.servlet.http.HttpServletResponse;
37
38 import org.apache.commons.jcs.access.exception.CacheException;
39 import org.apache.commons.jcs.auxiliary.AuxiliaryCacheConfigurator;
40 import org.apache.commons.jcs.auxiliary.remote.http.behavior.IRemoteHttpCacheConstants;
41 import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheRequest;
42 import org.apache.commons.jcs.auxiliary.remote.value.RemoteCacheResponse;
43 import org.apache.commons.jcs.engine.behavior.ICacheElement;
44 import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal;
45 import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
46 import org.apache.commons.jcs.engine.control.CompositeCacheManager;
47 import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
48 import org.apache.commons.jcs.io.ObjectInputStreamClassLoaderAware;
49 import org.apache.commons.jcs.utils.config.PropertySetter;
50 import org.apache.commons.jcs.utils.serialization.StandardSerializer;
51 import org.apache.commons.logging.Log;
52 import org.apache.commons.logging.LogFactory;
53
54
55
56
57
58 public class RemoteHttpCacheServlet
59 extends HttpServlet
60 {
61
62 private static final long serialVersionUID = 8752849397531933346L;
63
64
65 private static final Log log = LogFactory.getLog( RemoteHttpCacheServlet.class );
66
67
68 private static CompositeCacheManager cacheMgr;
69
70
71 private static ICacheServiceNonLocal<Serializable, Serializable> remoteCacheService;
72
73
74 private final StandardSerializer serializer = new StandardSerializer();
75
76
77 private int serviceCalls = 0;
78
79
80 private final int logInterval = 100;
81
82
83
84
85
86
87
88
89
90 @Override
91 public void init( ServletConfig config )
92 throws ServletException
93 {
94 try
95 {
96 cacheMgr = CompositeCacheManager.getInstance();
97 }
98 catch (CacheException e)
99 {
100 throw new ServletException(e);
101 }
102
103 remoteCacheService = createRemoteHttpCacheService( cacheMgr );
104
105 super.init( config );
106 }
107
108
109
110
111
112
113
114
115
116 @Override
117 public void service( HttpServletRequest request, HttpServletResponse response )
118 throws ServletException, IOException
119 {
120 incrementServiceCallCount();
121 if ( log.isDebugEnabled() )
122 {
123 log.debug( "Servicing a request. " + request );
124 }
125
126 RemoteCacheRequest<Serializable, Serializable> remoteRequest = readRequest( request );
127 RemoteCacheResponse<Object> cacheResponse = processRequest( remoteRequest );
128
129 writeResponse( response, cacheResponse );
130 }
131
132
133
134
135
136
137
138 protected RemoteCacheRequest<Serializable, Serializable> readRequest( HttpServletRequest request )
139 {
140 RemoteCacheRequest<Serializable, Serializable> remoteRequest = null;
141 try
142 {
143 InputStream inputStream = request.getInputStream();
144 if ( log.isDebugEnabled() )
145 {
146 log.debug( "After getting input stream and before reading it" );
147 }
148
149 remoteRequest = readRequestFromStream( inputStream );
150 }
151 catch ( Exception e )
152 {
153 log.error( "Could not get a RemoteHttpCacheRequest object from the input stream.", e );
154 }
155 return remoteRequest;
156 }
157
158
159
160
161
162
163
164
165
166 protected RemoteCacheRequest<Serializable, Serializable> readRequestFromStream( InputStream inputStream )
167 throws IOException, ClassNotFoundException
168 {
169 ObjectInputStream ois = new ObjectInputStreamClassLoaderAware( inputStream, null );
170
171 @SuppressWarnings("unchecked")
172 RemoteCacheRequest<Serializable, Serializable> remoteRequest
173 = (RemoteCacheRequest<Serializable, Serializable>) ois.readObject();
174 ois.close();
175 return remoteRequest;
176 }
177
178
179
180
181
182
183
184 protected void writeResponse( HttpServletResponse response, RemoteCacheResponse<Object> cacheResponse )
185 {
186 try
187 {
188 response.setContentType( "application/octet-stream" );
189
190 byte[] responseAsByteAray = serializer.serialize( cacheResponse );
191 response.setContentLength( responseAsByteAray.length );
192
193 OutputStream outputStream = response.getOutputStream();
194 if ( log.isDebugEnabled() )
195 {
196 log.debug( "Opened output stream. Response size: " + responseAsByteAray.length );
197 }
198
199 outputStream.write( responseAsByteAray );
200 outputStream.flush();
201 outputStream.close();
202 }
203 catch ( IOException e )
204 {
205 log.error( "Problem writing response. " + cacheResponse, e );
206 }
207 }
208
209
210
211
212
213
214
215 protected RemoteCacheResponse<Object> processRequest( RemoteCacheRequest<Serializable, Serializable> request )
216 {
217 RemoteCacheResponse<Object> response = new RemoteCacheResponse<Object>();
218
219 if ( request == null )
220 {
221 String message = "The request is null. Cannot process";
222 log.warn( message );
223 response.setSuccess( false );
224 response.setErrorMessage( message );
225 }
226 else
227 {
228 try
229 {
230 switch ( request.getRequestType() )
231 {
232 case GET:
233 ICacheElement<Serializable, Serializable> element =
234 remoteCacheService.get( request.getCacheName(), request.getKey(), request.getRequesterId() );
235 response.setPayload(element);
236 break;
237 case GET_MULTIPLE:
238 Map<Serializable, ICacheElement<Serializable, Serializable>> elementMap =
239 remoteCacheService.getMultiple( request.getCacheName(), request.getKeySet(), request.getRequesterId() );
240 if ( elementMap != null )
241 {
242 Map<Serializable, ICacheElement<Serializable, Serializable>> map = new HashMap<Serializable, ICacheElement<Serializable, Serializable>>();
243 map.putAll(elementMap);
244 response.setPayload(map);
245 }
246 break;
247 case GET_MATCHING:
248 Map<Serializable, ICacheElement<Serializable, Serializable>> elementMapMatching =
249 remoteCacheService.getMatching( request.getCacheName(), request.getPattern(), request.getRequesterId() );
250 if ( elementMapMatching != null )
251 {
252 Map<Serializable, ICacheElement<Serializable, Serializable>> map = new HashMap<Serializable, ICacheElement<Serializable, Serializable>>();
253 map.putAll(elementMapMatching);
254 response.setPayload(map);
255 }
256 break;
257 case REMOVE:
258 remoteCacheService.remove( request.getCacheName(), request.getKey(), request.getRequesterId() );
259 break;
260 case REMOVE_ALL:
261 remoteCacheService.removeAll( request.getCacheName(), request.getRequesterId() );
262 break;
263 case UPDATE:
264 remoteCacheService.update( request.getCacheElement(), request.getRequesterId() );
265 break;
266 case ALIVE_CHECK:
267 case DISPOSE:
268 response.setSuccess( true );
269
270 break;
271 case GET_KEYSET:
272 Set<Serializable> keys = remoteCacheService.getKeySet( request.getCacheName() );
273 response.setPayload( keys );
274 break;
275 default:
276 String message = "Unknown event type. Cannot process " + request;
277 log.warn( message );
278 response.setSuccess( false );
279 response.setErrorMessage( message );
280 break;
281 }
282 }
283 catch ( IOException e )
284 {
285 String message = "Problem processing request. " + request + " Error: " + e.getMessage();
286 log.error( message, e );
287 response.setSuccess( false );
288 response.setErrorMessage( message );
289 }
290 }
291
292 return response;
293 }
294
295
296
297
298
299
300
301 protected <K, V> RemoteHttpCacheService<K, V> createRemoteHttpCacheService( ICompositeCacheManager cacheManager )
302 {
303 Properties props = cacheManager.getConfigurationProperties();
304 ICacheEventLogger cacheEventLogger = configureCacheEventLogger( props );
305 RemoteHttpCacheServerAttributes attributes = configureRemoteHttpCacheServerAttributes( props );
306
307 RemoteHttpCacheService<K, V> service = new RemoteHttpCacheService<K, V>( cacheManager, attributes, cacheEventLogger );
308 if ( log.isInfoEnabled() )
309 {
310 log.info( "Created new RemoteHttpCacheService " + service );
311 }
312 return service;
313 }
314
315
316
317
318
319
320
321 protected ICacheEventLogger configureCacheEventLogger( Properties props )
322 {
323 ICacheEventLogger cacheEventLogger = AuxiliaryCacheConfigurator
324 .parseCacheEventLogger( props, IRemoteHttpCacheConstants.HTTP_CACHE_SERVER_PREFIX );
325
326 return cacheEventLogger;
327 }
328
329
330
331
332
333
334
335
336
337 protected RemoteHttpCacheServerAttributes configureRemoteHttpCacheServerAttributes( Properties prop )
338 {
339 RemoteHttpCacheServerAttributes rcsa = new RemoteHttpCacheServerAttributes();
340
341
342 PropertySetter.setProperties( rcsa, prop,
343 IRemoteHttpCacheConstants.HTTP_CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX + "." );
344
345 return rcsa;
346 }
347
348
349
350
351 protected void setRemoteCacheService(ICacheServiceNonLocal<Serializable, Serializable> rcs)
352 {
353 remoteCacheService = rcs;
354 }
355
356
357
358
359 private void incrementServiceCallCount()
360 {
361
362 serviceCalls++;
363 if ( log.isInfoEnabled() )
364 {
365 if ( serviceCalls % logInterval == 0 )
366 {
367 log.info( "serviceCalls = " + serviceCalls );
368 }
369 }
370 }
371
372
373 @Override
374 public void destroy()
375 {
376 if ( log.isInfoEnabled() )
377 {
378 log.info( "Servlet Destroyed, shutting down JCS." );
379 }
380
381 cacheMgr.shutDown();
382 }
383
384
385
386
387
388
389 @Override
390 public String getServletInfo()
391 {
392 return "RemoteHttpCacheServlet";
393 }
394 }