001package org.apache.commons.jcs.auxiliary.remote; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.File; 023import java.io.FileInputStream; 024import java.io.IOException; 025import java.io.InputStream; 026import java.net.InetSocketAddress; 027import java.net.ServerSocket; 028import java.net.Socket; 029import java.net.URL; 030import java.rmi.RemoteException; 031import java.rmi.registry.LocateRegistry; 032import java.rmi.registry.Registry; 033import java.rmi.server.RMISocketFactory; 034import java.util.Enumeration; 035import java.util.Properties; 036 037import org.apache.commons.logging.Log; 038import org.apache.commons.logging.LogFactory; 039 040/** 041 * This class provides some basic utilities for doing things such as starting 042 * the registry properly. 043 */ 044public class RemoteUtils 045{ 046 /** The logger. */ 047 private static final Log log = LogFactory.getLog(RemoteUtils.class); 048 049 /** No instances please. */ 050 private RemoteUtils() 051 { 052 super(); 053 } 054 055 /** 056 * Creates and exports a registry on the specified port of the local host. 057 * <p> 058 * 059 * @param port 060 * @return the registry 061 */ 062 public static Registry createRegistry(int port) 063 { 064 Registry registry = null; 065 066 // if ( log.isInfoEnabled() ) 067 // { 068 // log.info( "createRegistry> Setting security manager" ); 069 // } 070 // 071 // System.setSecurityManager( new RMISecurityManager() ); 072 073 if (port < 1024) 074 { 075 if (log.isWarnEnabled()) 076 { 077 log.warn("createRegistry> Port chosen was less than 1024, will use default [" + Registry.REGISTRY_PORT + "] instead."); 078 } 079 port = Registry.REGISTRY_PORT; 080 } 081 082 try 083 { 084 registry = LocateRegistry.createRegistry(port); 085 log.info("createRegistry> Created the registry on port " + port); 086 } 087 catch (RemoteException e) 088 { 089 log.warn("createRegistry> Problem creating registry. It may already be started. " + e.getMessage()); 090 } 091 catch (Throwable t) 092 { 093 log.error("createRegistry> Problem creating registry.", t); 094 } 095 096 if (registry == null) 097 { 098 try 099 { 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}