1 package org.apache.commons.jcs.auxiliary.remote.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.Serializable;
24 import java.net.MalformedURLException;
25 import java.rmi.Naming;
26 import java.rmi.NotBoundException;
27 import java.rmi.Remote;
28 import java.rmi.RemoteException;
29 import java.rmi.registry.Registry;
30 import java.rmi.server.RMISocketFactory;
31 import java.rmi.server.UnicastRemoteObject;
32 import java.util.Properties;
33 import java.util.concurrent.Executors;
34 import java.util.concurrent.ScheduledExecutorService;
35 import java.util.concurrent.TimeUnit;
36
37 import org.apache.commons.jcs.auxiliary.AuxiliaryCacheConfigurator;
38 import org.apache.commons.jcs.auxiliary.remote.RemoteUtils;
39 import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheConstants;
40 import org.apache.commons.jcs.engine.behavior.ICacheServiceAdmin;
41 import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
42 import org.apache.commons.jcs.utils.config.OptionConverter;
43 import org.apache.commons.jcs.utils.config.PropertySetter;
44 import org.apache.commons.jcs.utils.threadpool.DaemonThreadFactory;
45 import org.apache.commons.logging.Log;
46 import org.apache.commons.logging.LogFactory;
47
48
49
50
51
52 public class RemoteCacheServerFactory
53 implements IRemoteCacheConstants
54 {
55
56 private static final Log log = LogFactory.getLog( RemoteCacheServerFactory.class );
57
58
59 private static RemoteCacheServer<?, ?> remoteCacheServer;
60
61
62 private static String serviceName = IRemoteCacheConstants.REMOTE_CACHE_SERVICE_VAL;
63
64
65 private static ScheduledExecutorService keepAliveDaemon;
66
67
68 private static Registry registry = null;
69
70
71 private RemoteCacheServerFactory()
72 {
73 super();
74 }
75
76
77
78
79
80
81
82
83
84 @SuppressWarnings("unchecked")
85 public static <K, V> RemoteCacheServer<K, V> getRemoteCacheServer()
86 {
87 return (RemoteCacheServer<K, V>)remoteCacheServer;
88 }
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 @Deprecated
105 public static void startup( String host, int port, String propFile )
106 throws IOException
107 {
108 if ( log.isInfoEnabled() )
109 {
110 log.info( "ConfigFileName = [" + propFile + "]" );
111 }
112 Properties props = RemoteUtils.loadProps( propFile );
113 startup(host, port, props);
114 }
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130 @Deprecated
131 public static void startup( String host, int port, Properties props, String propFile )
132 throws IOException
133 {
134 if ( log.isWarnEnabled() )
135 {
136 log.warn( "ConfigFileName = [" + propFile + "] ignored" );
137 }
138 startup(host, port, props);
139 }
140
141
142
143
144
145
146
147
148
149
150
151
152 public static void startup( String host, int port, Properties props)
153 throws IOException
154 {
155 if ( remoteCacheServer != null )
156 {
157 throw new IllegalArgumentException( "Server already started." );
158 }
159
160 synchronized ( RemoteCacheServer.class )
161 {
162 if ( remoteCacheServer != null )
163 {
164 return;
165 }
166 if ( host == null )
167 {
168 host = "";
169 }
170
171 RemoteCacheServerAttributes rcsa = configureRemoteCacheServerAttributes(props);
172
173
174 rcsa.setRemoteLocation( host, port );
175 if ( log.isInfoEnabled() )
176 {
177 log.info( "Creating server with these attributes: " + rcsa );
178 }
179
180 setServiceName( rcsa.getRemoteServiceName() );
181
182 RMISocketFactory customRMISocketFactory = configureObjectSpecificCustomFactory( props );
183
184 RemoteUtils.configureGlobalCustomSocketFactory( rcsa.getRmiSocketFactoryTimeoutMillis() );
185
186
187 ICacheEventLogger cacheEventLogger = configureCacheEventLogger( props );
188
189
190 if ( customRMISocketFactory != null )
191 {
192 remoteCacheServer = new RemoteCacheServer<Serializable, Serializable>( rcsa, props, customRMISocketFactory );
193 }
194 else
195 {
196 remoteCacheServer = new RemoteCacheServer<Serializable, Serializable>( rcsa, props );
197 }
198
199 remoteCacheServer.setCacheEventLogger( cacheEventLogger );
200
201
202 registry = RemoteUtils.createRegistry(port);
203
204
205 registerServer( serviceName, remoteCacheServer );
206
207
208 if ( rcsa.isUseRegistryKeepAlive() )
209 {
210 if ( keepAliveDaemon == null )
211 {
212 keepAliveDaemon = Executors.newScheduledThreadPool(1,
213 new DaemonThreadFactory("JCS-RemoteCacheServerFactory-"));
214 }
215 RegistryKeepAliveRunner runner = new RegistryKeepAliveRunner( host, port, serviceName );
216 runner.setCacheEventLogger( cacheEventLogger );
217 keepAliveDaemon.scheduleAtFixedRate(runner, 0, rcsa.getRegistryKeepAliveDelayMillis(), TimeUnit.MILLISECONDS);
218 }
219 }
220 }
221
222
223
224
225
226
227
228 protected static ICacheEventLogger configureCacheEventLogger( Properties props )
229 {
230 ICacheEventLogger cacheEventLogger = AuxiliaryCacheConfigurator
231 .parseCacheEventLogger( props, IRemoteCacheConstants.CACHE_SERVER_PREFIX );
232
233
234 if ( cacheEventLogger == null )
235 {
236 cacheEventLogger = AuxiliaryCacheConfigurator.parseCacheEventLogger( props,
237 IRemoteCacheConstants.PROPERTY_PREFIX );
238 }
239 return cacheEventLogger;
240 }
241
242
243
244
245
246
247
248
249 protected static RMISocketFactory configureObjectSpecificCustomFactory( Properties props )
250 {
251 RMISocketFactory customRMISocketFactory =
252 OptionConverter.instantiateByKey( props, CUSTOM_RMI_SOCKET_FACTORY_PROPERTY_PREFIX, null );
253
254 if ( customRMISocketFactory != null )
255 {
256 PropertySetter.setProperties( customRMISocketFactory, props, CUSTOM_RMI_SOCKET_FACTORY_PROPERTY_PREFIX
257 + "." );
258 if ( log.isInfoEnabled() )
259 {
260 log.info( "Will use server specific custom socket factory. " + customRMISocketFactory );
261 }
262 }
263 else
264 {
265 if ( log.isInfoEnabled() )
266 {
267 log.info( "No server specific custom socket factory defined." );
268 }
269 }
270 return customRMISocketFactory;
271 }
272
273
274
275
276
277
278
279
280
281 protected static void registerServer(String serviceName, Remote server )
282 throws RemoteException
283 {
284 if ( server == null )
285 {
286 throw new RemoteException( "Cannot register the server until it is created." );
287 }
288
289 if ( registry == null )
290 {
291 throw new RemoteException( "Cannot register the server: Registry is null." );
292 }
293
294 if ( log.isInfoEnabled() )
295 {
296 log.info( "Binding server to " + serviceName );
297 }
298
299 registry.rebind( serviceName, server );
300 }
301
302
303
304
305
306
307
308
309
310 protected static RemoteCacheServerAttributes configureRemoteCacheServerAttributes( Properties prop )
311 {
312 RemoteCacheServerAttributes rcsa = new RemoteCacheServerAttributes();
313
314
315 PropertySetter.setProperties( rcsa, prop, CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX + "." );
316
317 configureManuallyIfValuesArePresent( prop, rcsa );
318
319 return rcsa;
320 }
321
322
323
324
325
326
327
328 private static void configureManuallyIfValuesArePresent( Properties prop, RemoteCacheServerAttributes rcsa )
329 {
330
331 String servicePortStr = prop.getProperty( REMOTE_CACHE_SERVICE_PORT );
332 if ( servicePortStr != null )
333 {
334 try
335 {
336 int servicePort = Integer.parseInt( servicePortStr );
337 rcsa.setServicePort( servicePort );
338 log.debug( "Remote cache service uses port number " + servicePort + "." );
339 }
340 catch ( NumberFormatException ignore )
341 {
342 log.debug( "Remote cache service port property " + REMOTE_CACHE_SERVICE_PORT
343 + " not specified. An anonymous port will be used." );
344 }
345 }
346
347 String socketTimeoutMillisStr = prop.getProperty( SOCKET_TIMEOUT_MILLIS );
348 if ( socketTimeoutMillisStr != null )
349 {
350 try
351 {
352 int rmiSocketFactoryTimeoutMillis = Integer.parseInt( socketTimeoutMillisStr );
353 rcsa.setRmiSocketFactoryTimeoutMillis( rmiSocketFactoryTimeoutMillis );
354 log.debug( "Remote cache socket timeout " + rmiSocketFactoryTimeoutMillis + "ms." );
355 }
356 catch ( NumberFormatException ignore )
357 {
358 log.debug( "Remote cache socket timeout property " + SOCKET_TIMEOUT_MILLIS
359 + " not specified. The default will be used." );
360 }
361 }
362
363 String lccStr = prop.getProperty( REMOTE_LOCAL_CLUSTER_CONSISTENCY );
364 if ( lccStr != null )
365 {
366 boolean lcc = Boolean.parseBoolean( lccStr );
367 rcsa.setLocalClusterConsistency( lcc );
368 }
369
370 String acgStr = prop.getProperty( REMOTE_ALLOW_CLUSTER_GET );
371 if ( acgStr != null )
372 {
373 boolean acg = Boolean.parseBoolean( lccStr );
374 rcsa.setAllowClusterGet( acg );
375 }
376
377
378 rcsa.setRemoteServiceName( prop.getProperty( REMOTE_CACHE_SERVICE_NAME, REMOTE_CACHE_SERVICE_VAL ).trim() );
379 }
380
381
382
383
384
385
386
387
388 static void shutdownImpl( String host, int port )
389 throws IOException
390 {
391 synchronized ( RemoteCacheServer.class )
392 {
393 if ( remoteCacheServer == null )
394 {
395 return;
396 }
397 log.info( "Unbinding host=" + host + ", port=" + port + ", serviceName=" + getServiceName() );
398 try
399 {
400 Naming.unbind( RemoteUtils.getNamingURL(host, port, getServiceName()) );
401 }
402 catch ( MalformedURLException ex )
403 {
404
405 throw new IllegalArgumentException( ex.getMessage() + "; host=" + host + ", port=" + port
406 + ", serviceName=" + getServiceName() );
407 }
408 catch ( NotBoundException ex )
409 {
410
411 }
412 remoteCacheServer.release();
413 remoteCacheServer = null;
414
415
416 if ( keepAliveDaemon != null )
417 {
418 keepAliveDaemon.shutdownNow();
419 keepAliveDaemon = null;
420 }
421
422
423 if (registry != null)
424 {
425 UnicastRemoteObject.unexportObject(registry, true);
426 registry = null;
427 }
428 }
429 }
430
431
432
433
434
435
436
437
438
439
440 public static void main( String[] args )
441 throws Exception
442 {
443 Properties prop = args.length > 0 ? RemoteUtils.loadProps( args[args.length - 1] ) : new Properties();
444
445 int port;
446 try
447 {
448 port = Integer.parseInt( prop.getProperty( "registry.port" ) );
449 }
450 catch ( NumberFormatException ex )
451 {
452 port = Registry.REGISTRY_PORT;
453 }
454
455
456 if ( args.length > 0 && args[0].toLowerCase().indexOf( "-shutdown" ) != -1 )
457 {
458 try
459 {
460 ICacheServiceAdmin admin = lookupCacheServiceAdmin(prop, port);
461 admin.shutdown();
462 }
463 catch ( Exception ex )
464 {
465 log.error( "Problem calling shutdown.", ex );
466 }
467 log.debug( "done." );
468 System.exit( 0 );
469 }
470
471
472 if ( args.length > 0 && args[0].toLowerCase().indexOf( "-stats" ) != -1 )
473 {
474 log.debug( "getting cache stats" );
475
476 try
477 {
478 ICacheServiceAdmin admin = lookupCacheServiceAdmin(prop, port);
479
480 try
481 {
482
483 log.debug( admin.getStats() );
484 }
485 catch ( IOException es )
486 {
487 log.error( es );
488 }
489 }
490 catch ( Exception ex )
491 {
492 log.error( "Problem getting stats.", ex );
493 }
494 log.debug( "done." );
495 System.exit( 0 );
496 }
497
498
499 String host = prop.getProperty( "registry.host" );
500
501 if ( host == null || host.trim().equals( "" ) || host.trim().equals( "localhost" ) )
502 {
503 log.debug( "main> creating registry on the localhost" );
504 RemoteUtils.createRegistry( port );
505 }
506 log.debug( "main> starting up RemoteCacheServer" );
507 startup( host, port, prop);
508 log.debug( "main> done" );
509 }
510
511
512
513
514
515
516
517
518
519
520 private static ICacheServiceAdmin lookupCacheServiceAdmin(Properties config, int port) throws Exception
521 {
522 String remoteServiceName = config.getProperty( REMOTE_CACHE_SERVICE_NAME, REMOTE_CACHE_SERVICE_VAL ).trim();
523 String registry = RemoteUtils.getNamingURL("", port, remoteServiceName);
524
525 if ( log.isDebugEnabled() )
526 {
527 log.debug( "looking up server " + registry );
528 }
529 Object obj = Naming.lookup( registry );
530 if ( log.isDebugEnabled() )
531 {
532 log.debug( "server found" );
533 }
534
535 return (ICacheServiceAdmin) obj;
536 }
537
538
539
540
541 protected static void setServiceName( String serviceName )
542 {
543 RemoteCacheServerFactory.serviceName = serviceName;
544 }
545
546
547
548
549 protected static String getServiceName()
550 {
551 return serviceName;
552 }
553 }