View Javadoc

1   package org.apache.jcs.auxiliary.remote.server;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.IOException;
23  import java.net.MalformedURLException;
24  import java.net.ServerSocket;
25  import java.net.Socket;
26  import java.rmi.Naming;
27  import java.rmi.NotBoundException;
28  import java.rmi.registry.Registry;
29  import java.rmi.server.RMISocketFactory;
30  import java.util.Properties;
31  
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  import org.apache.jcs.auxiliary.remote.RemoteUtils;
35  import org.apache.jcs.auxiliary.remote.behavior.IRemoteCacheConstants;
36  import org.apache.jcs.auxiliary.remote.behavior.IRemoteCacheServiceAdmin;
37  
38  /***
39   * Provides remote cache services. This creates remote cache servers and can proxy command line
40   * requests to a running server.
41   */
42  public class RemoteCacheServerFactory
43      implements IRemoteCacheConstants
44  {
45      private final static Log log = LogFactory.getLog( RemoteCacheServerFactory.class );
46  
47      /*** The single instance of the RemoteCacheServer object. */
48      private static RemoteCacheServer remoteCacheServer;
49  
50      private static String serviceName;
51  
52      private static int DEFAULT_RMI_SOCKET_FACTORY_TIMEOUT_MS = 10000;
53  
54      /*** Constructor for the RemoteCacheServerFactory object. */
55      private RemoteCacheServerFactory()
56      {
57          super();
58      }
59  
60      /***
61       * This will allow you to get stats from the server, etc. Perhaps we should provide methods on
62       * the factory to do this instead.
63       * A remote cache is either a local cache or a cluster cache
64       * @return Returns the remoteCacheServer.
65       */
66      public static RemoteCacheServer getRemoteCacheServer()
67      {
68          return remoteCacheServer;
69      }
70  
71      // ///////////////////// Statup/shutdown methods. //////////////////
72      /***
73       * Starts up the remote cache server on this JVM, and binds it to the registry on the given host
74       * and port.
75       * A remote cache is either a local cache or a cluster cache
76       * @param host
77       * @param port
78       * @param propFile
79       * @throws IOException
80       */
81      public static void startup( String host, int port, String propFile )
82          throws IOException
83      {
84          if ( remoteCacheServer != null )
85          {
86              throw new IllegalArgumentException( "Server already started." );
87          }
88  
89          synchronized ( RemoteCacheServer.class )
90          {
91              if ( remoteCacheServer != null )
92              {
93                  return;
94              }
95  
96              if ( log.isInfoEnabled() )
97              {
98                  log.info( "ConfigFileName = [" + propFile + "]" );
99              }
100 
101             try
102             {
103                 // TODO make configurable.
104                 // use this socket factory to add a timeout.
105                 RMISocketFactory.setSocketFactory( new RMISocketFactory()
106                 {
107                     public Socket createSocket( String host, int port )
108                         throws IOException
109                     {
110                         Socket socket = new Socket( host, port );
111                         socket.setSoTimeout( DEFAULT_RMI_SOCKET_FACTORY_TIMEOUT_MS );
112                         socket.setSoLinger( false, 0 );
113                         return socket;
114                     }
115 
116                     public ServerSocket createServerSocket( int port )
117                         throws IOException
118                     {
119                         return new ServerSocket( port );
120                     }
121                 } );
122             }
123             catch ( Exception e )
124             {
125                 log.error( "Problem setting custom RMI Socket Factory.", e );
126             }
127 
128             // TODO: make automatic
129             RemoteCacheServerAttributes rcsa = new RemoteCacheServerAttributes();
130             rcsa.setConfigFileName( propFile );
131 
132             Properties prop = RemoteUtils.loadProps( propFile );
133             // Properties prop = PropertyLoader.loadProperties( propFile );
134 
135             String servicePortStr = prop.getProperty( REMOTE_CACHE_SERVICE_PORT );
136             int servicePort = -1;
137             try
138             {
139                 servicePort = Integer.parseInt( servicePortStr );
140 
141                 rcsa.setServicePort( servicePort );
142                 log.debug( "Remote cache service uses port number " + servicePort + "." );
143             }
144             catch ( NumberFormatException ignore )
145             {
146                 log.debug( "Remote cache service port property " + REMOTE_CACHE_SERVICE_PORT
147                     + " not specified.  An anonymous port will be used." );
148             }
149 
150             String lccStr = prop.getProperty( REMOTE_LOCAL_CLUSTER_CONSISTENCY );
151             if ( lccStr == null )
152             {
153                 lccStr = "true";
154             }
155             boolean lcc = Boolean.valueOf( lccStr ).booleanValue();
156             rcsa.setLocalClusterConsistency( lcc );
157 
158             String acgStr = prop.getProperty( REMOTE_ALLOW_CLUSTER_GET );
159             if ( acgStr == null )
160             {
161                 acgStr = "true";
162             }
163             boolean acg = Boolean.valueOf( acgStr ).booleanValue();
164             rcsa.setAllowClusterGet( acg );
165 
166             if ( log.isInfoEnabled() )
167             {
168                 log.info( "Creating server with these attributes " + rcsa );
169             }
170 
171             // CREATE SERVER
172             remoteCacheServer = new RemoteCacheServer( rcsa );
173 
174             if ( host == null )
175             {
176                 host = "";
177             }
178             // Register the RemoteCacheServer remote object in the registry.
179             serviceName = prop.getProperty( REMOTE_CACHE_SERVICE_NAME, REMOTE_CACHE_SERVICE_VAL ).trim();
180 
181             if ( log.isInfoEnabled() )
182             {
183                 log.info( "Binding server to " + host + ":" + port + " with the name " + serviceName );
184             }
185             try
186             {
187                 Naming.rebind( "//" + host + ":" + port + "/" + serviceName, remoteCacheServer );
188             }
189             catch ( MalformedURLException ex )
190             {
191                 // impossible case.
192                 throw new IllegalArgumentException( ex.getMessage() + "; host=" + host + ", port=" + port );
193             }
194         }
195     }
196 
197     /***
198      * Unbinds the remote server.
199      * <p>
200      * @param host
201      * @param port
202      * @exception IOException
203      */
204     static void shutdownImpl( String host, int port )
205         throws IOException
206     {
207         if ( remoteCacheServer == null )
208         {
209             return;
210         }
211         synchronized ( RemoteCacheServer.class )
212         {
213             if ( remoteCacheServer == null )
214             {
215                 return;
216             }
217             log.info( "Unbinding host=" + host + ", port=" + port + ", serviceName=" + serviceName );
218             try
219             {
220                 Naming.unbind( "//" + host + ":" + port + "/" + serviceName );
221             }
222             catch ( MalformedURLException ex )
223             {
224                 // impossible case.
225                 throw new IllegalArgumentException( ex.getMessage() + "; host=" + host + ", port=" + port
226                     + ", serviceName=" + serviceName );
227             }
228             catch ( NotBoundException ex )
229             {
230                 // ignore.
231             }
232             remoteCacheServer.release();
233             remoteCacheServer = null;
234             // TODO: safer exit ?
235             try
236             {
237                 Thread.sleep( 2000 );
238             }
239             catch ( InterruptedException ex )
240             {
241                 // swallow
242             }
243             System.exit( 0 );
244         }
245     }
246 
247     /***
248      * Creates an local RMI registry on the default port, starts up the remote cache server, and
249      * binds it to the registry.
250      * A remote cache is either a local cache or a cluster cache
251      * @param args The command line arguments
252      * @throws Exception
253      */
254     public static void main( String[] args )
255         throws Exception
256     {
257         Properties prop = args.length > 0 ? RemoteUtils.loadProps( args[args.length - 1] ) : new Properties();
258 
259         int port;
260         try
261         {
262             port = Integer.parseInt( prop.getProperty( "registry.port" ) );
263         }
264         catch ( NumberFormatException ex )
265         {
266             port = Registry.REGISTRY_PORT;
267         }
268 
269         // shutdown
270         if ( args.length > 0 && args[0].toLowerCase().indexOf( "-shutdown" ) != -1 )
271         {
272             String serviceName = prop.getProperty( REMOTE_CACHE_SERVICE_NAME, REMOTE_CACHE_SERVICE_VAL ).trim();
273             String registry = "//:" + port + "/" + serviceName;
274 
275             if ( log.isDebugEnabled() )
276             {
277                 log.debug( "looking up server " + registry );
278             }
279             Object obj = Naming.lookup( registry );
280             if ( log.isDebugEnabled() )
281             {
282                 log.debug( "server found" );
283             }
284             IRemoteCacheServiceAdmin admin = (IRemoteCacheServiceAdmin) obj;
285             try
286             {
287                 admin.shutdown();
288             }
289             catch ( Exception ex )
290             {
291                 log.error( "Problem calling shutdown.", ex );
292             }
293             log.debug( "done." );
294             System.exit( 0 );
295         }
296 
297         // STATS
298         if ( args.length > 0 && args[0].toLowerCase().indexOf( "-stats" ) != -1 )
299         {
300 
301             log.debug( "getting cache stats" );
302 
303             try
304             {
305                 String serviceName = prop.getProperty( REMOTE_CACHE_SERVICE_NAME, REMOTE_CACHE_SERVICE_VAL ).trim();
306                 String registry = "//:" + port + "/" + serviceName;
307                 log.debug( "looking up server " + registry );
308                 Object obj = Naming.lookup( registry );
309                 log.debug( "server found" );
310 
311                 log.debug( "obj = " + obj );
312                 IRemoteCacheServiceAdmin admin = (IRemoteCacheServiceAdmin) obj;
313 
314                 try
315                 {
316                     System.out.println( admin.getStats().toString() );
317                     log.debug( admin.getStats() );
318                 }
319                 catch ( Exception es )
320                 {
321                     log.error( es );
322                 }
323 
324             }
325             catch ( Exception ex )
326             {
327                 log.error( "Problem getting stats.", ex );
328             }
329             log.debug( "done." );
330             System.exit( 0 );
331         }
332 
333         // startup.
334         String host = prop.getProperty( "registry.host" );
335 
336         if ( host == null || host.trim().equals( "" ) || host.trim().equals( "localhost" ) )
337         {
338             log.debug( "main> creating registry on the localhost" );
339             port = RemoteUtils.createRegistry( port );
340         }
341         log.debug( "main> starting up RemoteCacheServer" );
342         RemoteCacheServerFactory.startup( host, port, args.length > 0 ? args[0] : null );
343         log.debug( "main> done" );
344     }
345 }