View Javadoc
1   package org.apache.commons.jcs.auxiliary.remote;
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.File;
23  import java.io.FileInputStream;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.net.InetSocketAddress;
27  import java.net.ServerSocket;
28  import java.net.Socket;
29  import java.net.URL;
30  import java.rmi.RemoteException;
31  import java.rmi.registry.LocateRegistry;
32  import java.rmi.registry.Registry;
33  import java.rmi.server.RMISocketFactory;
34  import java.util.Enumeration;
35  import java.util.Properties;
36  
37  import org.apache.commons.logging.Log;
38  import org.apache.commons.logging.LogFactory;
39  
40  /**
41   * This class provides some basic utilities for doing things such as starting
42   * the registry properly.
43   */
44  public class RemoteUtils
45  {
46      /** The logger. */
47      private static final Log log = LogFactory.getLog(RemoteUtils.class);
48  
49      /** No instances please. */
50      private RemoteUtils()
51      {
52          super();
53      }
54  
55      /**
56       * Creates and exports a registry on the specified port of the local host.
57       * <p>
58       *
59       * @param port
60       * @return the registry
61       */
62      public static Registry createRegistry(int port)
63      {
64          Registry registry = null;
65  
66          // if ( log.isInfoEnabled() )
67          // {
68          // log.info( "createRegistry> Setting security manager" );
69          // }
70          //
71          // System.setSecurityManager( new RMISecurityManager() );
72  
73          if (port < 1024)
74          {
75              if (log.isWarnEnabled())
76              {
77                  log.warn("createRegistry> Port chosen was less than 1024, will use default [" + Registry.REGISTRY_PORT + "] instead.");
78              }
79              port = Registry.REGISTRY_PORT;
80          }
81  
82          try
83          {
84              registry = LocateRegistry.createRegistry(port);
85              log.info("createRegistry> Created the registry on port " + port);
86          }
87          catch (RemoteException e)
88          {
89              log.warn("createRegistry> Problem creating registry. It may already be started. " + e.getMessage());
90          }
91          catch (Throwable t)
92          {
93              log.error("createRegistry> Problem creating registry.", t);
94          }
95  
96          if (registry == null)
97          {
98              try
99              {
100                 registry = LocateRegistry.getRegistry(port);
101             }
102             catch (RemoteException e)
103             {
104                 log.error("createRegistry> Problem getting a registry reference.", e);
105             }
106         }
107 
108         return registry;
109     }
110 
111     /**
112      * Loads properties for the named props file.
113      * First tries class path, then file, then URL
114      * <p>
115      *
116      * @param propFile
117      * @return The properties object for the file
118      * @throws IOException
119      */
120     public static Properties loadProps(String propFile)
121             throws IOException
122     {
123         InputStream is = RemoteUtils.class.getResourceAsStream(propFile);
124 
125         if (null == is) // not found in class path
126         {
127             // Try root of class path
128             if (propFile != null && !propFile.startsWith("/"))
129             {
130                 is = RemoteUtils.class.getResourceAsStream("/" + propFile);
131             }
132         }
133         
134         if (null == is) // not found in class path
135         {
136             if (new File(propFile).exists())
137             {
138                 // file found
139                 is = new FileInputStream(propFile);
140             }
141             else
142             {
143                 // try URL
144                 is = new URL(propFile).openStream();
145             }
146         }
147 
148         Properties props = new Properties();
149         try
150         {
151             props.load(is);
152             if (log.isDebugEnabled())
153             {
154                 log.debug("props.size=" + props.size());
155             }
156 
157             if (log.isDebugEnabled())
158             {
159                 Enumeration<Object> en = props.keys();
160                 StringBuilder buf = new StringBuilder();
161                 while (en.hasMoreElements())
162                 {
163                     String key = (String) en.nextElement();
164                     buf.append("\n" + key + " = " + props.getProperty(key));
165                 }
166                 log.debug(buf.toString());
167             }
168 
169         }
170         catch (Exception ex)
171         {
172             log.error("Error loading remote properties, for file name [" + propFile + "]", ex);
173         }
174         finally
175         {
176             if (is != null)
177             {
178                 is.close();
179             }
180         }
181         return props;
182     }
183 
184     /**
185      * Configure a custom socket factory to set the timeout value. This sets the
186      * global socket factory. It's used only if a custom factory is not
187      * configured for the specific object.
188      * <p>
189      *
190      * @param timeoutMillis
191      */
192     public static void configureGlobalCustomSocketFactory(final int timeoutMillis)
193     {
194         try
195         {
196             // Don't set a socket factory if the setting is -1
197             if (timeoutMillis > 0)
198             {
199                 if (log.isInfoEnabled())
200                 {
201                     log.info("RmiSocketFactoryTimeoutMillis [" + timeoutMillis + "]. "
202                             + " Configuring a custom socket factory.");
203                 }
204 
205                 // use this socket factory to add a timeout.
206                 RMISocketFactory.setSocketFactory(new RMISocketFactory()
207                 {
208                     @Override
209                     public Socket createSocket(String host, int port)
210                             throws IOException
211                     {
212                         Socket socket = new Socket();
213                         socket.setSoTimeout(timeoutMillis);
214                         socket.setSoLinger(false, 0);
215                         socket.connect(new InetSocketAddress(host, port), timeoutMillis);
216                         return socket;
217                     }
218 
219                     @Override
220                     public ServerSocket createServerSocket(int port)
221                             throws IOException
222                     {
223                         return new ServerSocket(port);
224                     }
225                 });
226             }
227         }
228         catch (IOException e)
229         {
230             // Only try to do it once. Otherwise we
231             // Generate errors for each region on construction.
232             RMISocketFactory factoryInUse = RMISocketFactory.getSocketFactory();
233             if (factoryInUse != null && !factoryInUse.getClass().getName().startsWith("org.apache.commons.jcs"))
234             {
235                 log.info("Could not create new custom socket factory. " + e.getMessage() + " Factory in use = "
236                         + RMISocketFactory.getSocketFactory());
237             }
238         }
239     }
240 
241     /**
242      * Get the naming url used for RMI registration
243      *
244      * @param location
245      *            the remote location
246      * @param serviceName
247      *            the remote service name
248      * @return the URL for RMI lookup
249      */
250     public static String getNamingURL(final RemoteLocation location, final String serviceName)
251     {
252         return getNamingURL(location.getHost(), location.getPort(), serviceName);
253     }
254 
255     /**
256      * Get the naming url used for RMI registration
257      *
258      * @param registryHost
259      *            the remote host
260      * @param registryPort
261      *            the remote port
262      * @param serviceName
263      *            the remote service name
264      * @return the URL for RMI lookup
265      */
266     public static String getNamingURL(final String registryHost, final int registryPort, final String serviceName)
267     {
268         if (registryHost.contains(":"))
269         { // TODO improve this check? See also JCS-133
270             return "//[" + registryHost.replaceFirst("%", "%25") + "]:" + registryPort + "/" + serviceName;
271         }
272         final String registryURL = "//" + registryHost + ":" + registryPort + "/" + serviceName;
273         return registryURL;
274     }
275 }