1 package org.apache.commons.jcs3.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.InetAddress;
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.Objects;
33 import java.util.Properties;
34 import java.util.concurrent.Executors;
35 import java.util.concurrent.ScheduledExecutorService;
36 import java.util.concurrent.TimeUnit;
37
38 import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheConfigurator;
39 import org.apache.commons.jcs3.auxiliary.remote.RemoteUtils;
40 import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheConstants;
41 import org.apache.commons.jcs3.engine.behavior.ICacheServiceAdmin;
42 import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
43 import org.apache.commons.jcs3.log.Log;
44 import org.apache.commons.jcs3.log.LogManager;
45 import org.apache.commons.jcs3.utils.config.OptionConverter;
46 import org.apache.commons.jcs3.utils.config.PropertySetter;
47 import org.apache.commons.jcs3.utils.threadpool.DaemonThreadFactory;
48
49
50
51
52
53 public class RemoteCacheServerFactory
54 implements IRemoteCacheConstants
55 {
56
57 private static final Log log = LogManager.getLog( RemoteCacheServerFactory.class );
58
59
60 private static RemoteCacheServer<?, ?> remoteCacheServer;
61
62
63 private static String serviceName = IRemoteCacheConstants.REMOTE_CACHE_SERVICE_VAL;
64
65
66 private static ScheduledExecutorService keepAliveDaemon;
67
68
69 private static Registry registry;
70
71
72 private RemoteCacheServerFactory()
73 {
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 public static void startup( String host, final int port, final Properties props)
103 throws IOException
104 {
105 if ( remoteCacheServer != null )
106 {
107 throw new IllegalArgumentException( "Server already started." );
108 }
109
110 synchronized ( RemoteCacheServer.class )
111 {
112 if ( remoteCacheServer != null )
113 {
114 return;
115 }
116
117 final RemoteCacheServerAttributes rcsa = configureRemoteCacheServerAttributes(props);
118
119
120 rcsa.setRemoteLocation( Objects.toString(host, ""), port );
121 log.info( "Creating server with these attributes: {0}", rcsa );
122
123 setServiceName( rcsa.getRemoteServiceName() );
124
125 final RMISocketFactory customRMISocketFactory = configureObjectSpecificCustomFactory( props );
126
127 RemoteUtils.configureGlobalCustomSocketFactory( rcsa.getRmiSocketFactoryTimeoutMillis() );
128
129
130 final ICacheEventLogger cacheEventLogger = configureCacheEventLogger( props );
131
132
133 if ( customRMISocketFactory != null )
134 {
135 remoteCacheServer = new RemoteCacheServer<>( rcsa, props, customRMISocketFactory );
136 }
137 else
138 {
139 remoteCacheServer = new RemoteCacheServer<>( rcsa, props );
140 }
141
142 remoteCacheServer.setCacheEventLogger( cacheEventLogger );
143
144
145 registry = RemoteUtils.createRegistry(port);
146
147
148 registerServer( serviceName, remoteCacheServer );
149
150
151 if ( rcsa.isUseRegistryKeepAlive() )
152 {
153 if ( keepAliveDaemon == null )
154 {
155 keepAliveDaemon = Executors.newScheduledThreadPool(1,
156 new DaemonThreadFactory("JCS-RemoteCacheServerFactory-"));
157 }
158 keepAliveDaemon.scheduleAtFixedRate(() -> keepAlive(host, port, cacheEventLogger),
159 0, rcsa.getRegistryKeepAliveDelayMillis(), TimeUnit.MILLISECONDS);
160 }
161 }
162 }
163
164
165
166
167
168
169
170
171
172
173 protected static void keepAlive(String registryHost, int registryPort, ICacheEventLogger cacheEventLogger)
174 {
175 String namingURL = RemoteUtils.getNamingURL(registryHost, registryPort, serviceName);
176 log.debug( "looking up server {0}", namingURL );
177
178 try
179 {
180 final Object obj = Naming.lookup( namingURL );
181
182
183 final String message = "RMI registry looks fine. Found [" + obj + "] in registry [" + namingURL + "]";
184 if ( cacheEventLogger != null )
185 {
186 cacheEventLogger.logApplicationEvent( "RegistryKeepAliveRunner", "Naming.lookup", message );
187 }
188 log.debug( message );
189 }
190 catch ( final Exception ex )
191 {
192
193 final String message = "Problem finding server at [" + namingURL
194 + "]. Will attempt to start registry and rebind.";
195 log.error( message, ex );
196 if ( cacheEventLogger != null )
197 {
198 cacheEventLogger.logError( "RegistryKeepAliveRunner", "Naming.lookup", message + ":" + ex.getMessage() );
199 }
200
201 registry = RemoteUtils.createRegistry(registryPort);
202
203 if ( cacheEventLogger != null )
204 {
205 if (registry != null)
206 {
207 cacheEventLogger.logApplicationEvent( "RegistryKeepAliveRunner", "createRegistry",
208 "Successfully created registry [" + serviceName + "]." );
209 }
210 else
211 {
212 cacheEventLogger.logError( "RegistryKeepAliveRunner", "createRegistry",
213 "Could not start registry [" + serviceName + "]." );
214 }
215 }
216 }
217
218 try
219 {
220 registerServer(serviceName, remoteCacheServer);
221
222 final String message = "Successfully rebound server to registry [" + serviceName + "].";
223 if ( cacheEventLogger != null )
224 {
225 cacheEventLogger.logApplicationEvent( "RegistryKeepAliveRunner", "registerServer", message );
226 }
227 log.info( message );
228 }
229 catch ( final RemoteException e )
230 {
231 final String message = "Could not rebind server to registry [" + serviceName + "].";
232 log.error( message, e );
233 if ( cacheEventLogger != null )
234 {
235 cacheEventLogger.logError( "RegistryKeepAliveRunner", "registerServer", message + ":"
236 + e.getMessage() );
237 }
238 }
239 }
240
241
242
243
244
245
246
247 protected static ICacheEventLogger configureCacheEventLogger( final Properties props )
248 {
249 return AuxiliaryCacheConfigurator
250 .parseCacheEventLogger( props, IRemoteCacheConstants.CACHE_SERVER_PREFIX );
251 }
252
253
254
255
256
257
258
259
260 protected static RMISocketFactory configureObjectSpecificCustomFactory( final Properties props )
261 {
262 final RMISocketFactory customRMISocketFactory =
263 OptionConverter.instantiateByKey( props, CUSTOM_RMI_SOCKET_FACTORY_PROPERTY_PREFIX, null );
264
265 if ( customRMISocketFactory != null )
266 {
267 PropertySetter.setProperties( customRMISocketFactory, props, CUSTOM_RMI_SOCKET_FACTORY_PROPERTY_PREFIX
268 + "." );
269 log.info( "Will use server specific custom socket factory. {0}",
270 customRMISocketFactory );
271 }
272 else
273 {
274 log.info( "No server specific custom socket factory defined." );
275 }
276 return customRMISocketFactory;
277 }
278
279
280
281
282
283
284
285
286
287 protected static void registerServer(final String serviceName, final Remote server )
288 throws RemoteException
289 {
290 if ( server == null )
291 {
292 throw new RemoteException( "Cannot register the server until it is created." );
293 }
294
295 if ( registry == null )
296 {
297 throw new RemoteException( "Cannot register the server: Registry is null." );
298 }
299
300 log.info( "Binding server to {0}", serviceName );
301
302 registry.rebind( serviceName, server );
303 }
304
305
306
307
308
309
310
311
312
313 protected static RemoteCacheServerAttributes configureRemoteCacheServerAttributes( final Properties prop )
314 {
315 final RemoteCacheServerAttributes rcsa = new RemoteCacheServerAttributes();
316
317
318 PropertySetter.setProperties( rcsa, prop, CACHE_SERVER_ATTRIBUTES_PROPERTY_PREFIX + "." );
319
320 return rcsa;
321 }
322
323
324
325
326
327
328
329
330 static void shutdownImpl( final String host, final int port )
331 throws IOException
332 {
333 synchronized ( RemoteCacheServer.class )
334 {
335 if ( remoteCacheServer == null )
336 {
337 return;
338 }
339 log.info( "Unbinding host={0}, port={1}, serviceName={2}",
340 host, port, getServiceName() );
341 try
342 {
343 Naming.unbind( RemoteUtils.getNamingURL(host, port, getServiceName()) );
344 }
345 catch ( final MalformedURLException ex )
346 {
347
348 throw new IllegalArgumentException( ex.getMessage() + "; host=" + host + ", port=" + port
349 + ", serviceName=" + getServiceName() );
350 }
351 catch ( final NotBoundException ex )
352 {
353
354 }
355 remoteCacheServer.release();
356 remoteCacheServer = null;
357
358
359 if ( keepAliveDaemon != null )
360 {
361 keepAliveDaemon.shutdownNow();
362 keepAliveDaemon = null;
363 }
364
365
366 if (registry != null)
367 {
368 UnicastRemoteObject.unexportObject(registry, true);
369 registry = null;
370 }
371 }
372 }
373
374
375
376
377
378
379
380
381
382
383 public static void main( final String[] args )
384 throws Exception
385 {
386 final Properties prop = args.length > 0 ? RemoteUtils.loadProps( args[args.length - 1] ) : new Properties();
387
388 int port;
389 try
390 {
391 port = Integer.parseInt( prop.getProperty( "registry.port" ) );
392 }
393 catch ( final NumberFormatException ex )
394 {
395 port = Registry.REGISTRY_PORT;
396 }
397
398
399 if ( args.length > 0 && args[0].toLowerCase().indexOf( "-shutdown" ) != -1 )
400 {
401 try
402 {
403 final ICacheServiceAdmin admin = lookupCacheServiceAdmin(prop, port);
404 admin.shutdown();
405 }
406 catch ( final Exception ex )
407 {
408 log.error( "Problem calling shutdown.", ex );
409 }
410 log.debug( "done." );
411 System.exit( 0 );
412 }
413
414
415 if ( args.length > 0 && args[0].toLowerCase().indexOf( "-stats" ) != -1 )
416 {
417 log.debug( "getting cache stats" );
418
419 try
420 {
421 final ICacheServiceAdmin admin = lookupCacheServiceAdmin(prop, port);
422
423 try
424 {
425
426 log.debug( admin.getStats() );
427 }
428 catch ( final IOException es )
429 {
430 log.error( es );
431 }
432 }
433 catch ( final Exception ex )
434 {
435 log.error( "Problem getting stats.", ex );
436 }
437 log.debug( "done." );
438 System.exit( 0 );
439 }
440
441
442 final String hostName = prop.getProperty( "registry.host" );
443 final InetAddress host = InetAddress.getByName(hostName);
444
445 if (host.isLoopbackAddress())
446 {
447 log.debug( "main> creating registry on the localhost" );
448 RemoteUtils.createRegistry( port );
449 }
450 log.debug( "main> starting up RemoteCacheServer" );
451 startup( host.getHostName(), port, prop);
452 log.debug( "main> done" );
453 }
454
455
456
457
458
459
460
461
462
463
464 private static ICacheServiceAdmin lookupCacheServiceAdmin(final Properties config, final int port) throws Exception
465 {
466 final String remoteServiceName = config.getProperty( REMOTE_CACHE_SERVICE_NAME, REMOTE_CACHE_SERVICE_VAL ).trim();
467 final String registry = RemoteUtils.getNamingURL("", port, remoteServiceName);
468
469 log.debug( "looking up server {0}", registry );
470 final Object obj = Naming.lookup( registry );
471 log.debug( "server found" );
472
473 return (ICacheServiceAdmin) obj;
474 }
475
476
477
478
479 protected static void setServiceName( final String serviceName )
480 {
481 RemoteCacheServerFactory.serviceName = serviceName;
482 }
483
484
485
486
487 protected static String getServiceName()
488 {
489 return serviceName;
490 }
491 }