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