001package org.apache.commons.jcs3.auxiliary.remote.server; 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.IOException; 023import java.io.OutputStream; 024import java.net.InetAddress; 025import java.net.UnknownHostException; 026import java.nio.charset.StandardCharsets; 027import java.util.Properties; 028 029import javax.servlet.ServletConfig; 030import javax.servlet.ServletException; 031import javax.servlet.http.HttpServlet; 032import javax.servlet.http.HttpServletRequest; 033import javax.servlet.http.HttpServletResponse; 034 035import org.apache.commons.jcs3.access.exception.CacheException; 036import org.apache.commons.jcs3.auxiliary.remote.RemoteUtils; 037import org.apache.commons.jcs3.engine.control.CompositeCacheManager; 038import org.apache.commons.jcs3.log.Log; 039import org.apache.commons.jcs3.log.LogManager; 040import org.apache.commons.jcs3.utils.net.HostNameUtil; 041 042/** 043 * This servlet can be used to startup the JCS remote cache. It is easy to 044 * deploy the remote server in a tomcat base. This give you an easy way to 045 * monitor its activity. 046 * <p> 047 * <code> 048 * servlet> 049 <servlet-name>JCSRemoteCacheStartupServlet</servlet-name> 050 <servlet-class> 051 org.apache.commons.jcs3.auxiliary.remote.server.RemoteCacheStartupServlet 052 </servlet-class> 053 <load-on-startup>1</load-on-startup> 054 </servlet> 055 056 057 <servlet-mapping> 058 <servlet-name>JCSRemoteCacheStartupServlet</servlet-name> 059 <url-pattern>/jcs</url-pattern> 060 </servlet-mapping> 061 * </code> 062 */ 063public class RemoteCacheStartupServlet 064 extends HttpServlet 065{ 066 /** Don't change */ 067 private static final long serialVersionUID = 1L; 068 069 /** The logger */ 070 private static final Log log = LogManager.getLog(RemoteCacheStartupServlet.class); 071 072 /** The default port to start the registry on. */ 073 private static final int DEFAULT_REGISTRY_PORT = 1101; 074 075 /** properties file name */ 076 private static final String DEFAULT_PROPS_FILE_NAME = "/cache.ccf"; 077 078 /** properties file name, must set prior to calling get instance */ 079 private String propsFileName = DEFAULT_PROPS_FILE_NAME; 080 081 /** Configuration properties */ 082 private int registryPort = DEFAULT_REGISTRY_PORT; 083 084 /** Configuration properties */ 085 private String registryHost; 086 087 /** 088 * Starts the registry and then tries to bind to it. 089 * <p> 090 * Gets the port from a props file. Uses the local host name for the 091 * registry host. Tries to start the registry, ignoring failure. Starts the 092 * server. 093 * <p> 094 * 095 * @throws ServletException 096 */ 097 @Override 098 public void init() 099 throws ServletException 100 { 101 super.init(); 102 103 loadInitParams(); 104 final Properties props = loadPropertiesFromFile(); 105 106 if (registryHost == null) 107 { 108 // we will always use the local machine for the registry 109 try 110 { 111 registryHost = HostNameUtil.getLocalHostAddress(); 112 } 113 catch (final UnknownHostException e) 114 { 115 log.error("Could not get local address to use for the registry!", e); 116 } 117 } 118 119 log.debug("registryHost = [{0}]", registryHost); 120 121 try 122 { 123 if (InetAddress.getByName(registryHost).isLoopbackAddress()) 124 { 125 log.warn("The local address [{0}] is a loopback address. Other machines must " 126 + "be able to use the address to reach this server.", registryHost); 127 } 128 } 129 catch (final UnknownHostException e) 130 { 131 throw new ServletException("Could not resolve registry host " + registryHost, e); 132 } 133 134 try 135 { 136 if (props == null) 137 { 138 throw new ServletException("Could not load configuration from " + propsFileName); 139 } 140 141 RemoteCacheServerFactory.startup(registryHost, registryPort, props); 142 log.info("Remote JCS Server started with properties from {0}", propsFileName); 143 } 144 catch (final IOException e) 145 { 146 throw new ServletException("Problem starting remote cache server.", e); 147 } 148 } 149 150 /** 151 * It just dumps the stats. 152 * <p> 153 * 154 * @param request 155 * @param response 156 * @throws ServletException 157 * @throws IOException 158 */ 159 @Override 160 protected void service(final HttpServletRequest request, final HttpServletResponse response) 161 throws ServletException, IOException 162 { 163 String stats = ""; 164 165 try 166 { 167 stats = CompositeCacheManager.getInstance().getStats(); 168 } 169 catch (final CacheException e) 170 { 171 throw new ServletException(e); 172 } 173 174 log.info(stats); 175 176 try 177 { 178 String characterEncoding = response.getCharacterEncoding(); 179 if (characterEncoding == null) 180 { 181 characterEncoding = StandardCharsets.UTF_8.name(); 182 response.setCharacterEncoding(characterEncoding); 183 } 184 final OutputStream os = response.getOutputStream(); 185 os.write(stats.getBytes(characterEncoding)); 186 os.close(); 187 } 188 catch (final IOException e) 189 { 190 log.error("Problem writing response.", e); 191 } 192 } 193 194 /** 195 * shuts the cache down. 196 */ 197 @Override 198 public void destroy() 199 { 200 super.destroy(); 201 202 log.info("Shutting down remote cache "); 203 204 try 205 { 206 RemoteCacheServerFactory.shutdownImpl(registryHost, registryPort); 207 } 208 catch (final IOException e) 209 { 210 log.error("Problem shutting down.", e); 211 } 212 213 try 214 { 215 CompositeCacheManager.getInstance().shutDown(); 216 } 217 catch (final CacheException e) 218 { 219 log.error("Could not retrieve cache manager instance", e); 220 } 221 } 222 223 /** 224 * Load configuration values from config file if possible 225 */ 226 private Properties loadPropertiesFromFile() 227 { 228 Properties props = null; 229 230 try 231 { 232 props = RemoteUtils.loadProps(propsFileName); 233 registryHost = props.getProperty("registry.host", registryHost); 234 final String portS = props.getProperty("registry.port", String.valueOf(registryPort)); 235 setRegistryPort(portS); 236 } 237 catch (final IOException e) 238 { 239 log.error("Problem loading props.", e); 240 } 241 242 return props; 243 } 244 245 /** 246 * Load configuration values from init params if possible 247 */ 248 private void loadInitParams() 249 { 250 final ServletConfig config = getServletConfig(); 251 final String _propsFileName = config.getInitParameter("propsFileName"); 252 if (null != _propsFileName) 253 { 254 this.propsFileName = _propsFileName; 255 } 256 final String _registryHost = config.getInitParameter("registryHost"); 257 if (null != _registryHost) 258 { 259 this.registryHost = _registryHost; 260 } 261 final String regPortString = config.getInitParameter("registryPort"); 262 if (null != regPortString) 263 { 264 setRegistryPort(regPortString); 265 } 266 } 267 268 /** 269 * Set registry port from string If the string cannot be parsed, the default 270 * value is used 271 * 272 * @param portS 273 */ 274 private void setRegistryPort(final String portS) 275 { 276 try 277 { 278 this.registryPort = Integer.parseInt(portS); 279 } 280 catch (final NumberFormatException e) 281 { 282 log.error("Problem converting port to an int.", e); 283 this.registryPort = DEFAULT_REGISTRY_PORT; 284 } 285 } 286}