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