View Javadoc
1   package org.apache.commons.jcs3.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.io.OutputStream;
24  import java.net.InetAddress;
25  import java.net.UnknownHostException;
26  import java.nio.charset.StandardCharsets;
27  import java.util.Properties;
28  
29  import javax.servlet.ServletConfig;
30  import javax.servlet.ServletException;
31  import javax.servlet.http.HttpServlet;
32  import javax.servlet.http.HttpServletRequest;
33  import javax.servlet.http.HttpServletResponse;
34  
35  import org.apache.commons.jcs3.access.exception.CacheException;
36  import org.apache.commons.jcs3.auxiliary.remote.RemoteUtils;
37  import org.apache.commons.jcs3.engine.control.CompositeCacheManager;
38  import org.apache.commons.jcs3.log.Log;
39  import org.apache.commons.jcs3.log.LogManager;
40  import org.apache.commons.jcs3.utils.net.HostNameUtil;
41  
42  /**
43   * This servlet can be used to startup the JCS remote cache. It is easy to
44   * deploy the remote server in a tomcat base. This give you an easy way to
45   * monitor its activity.
46   * <p>
47   * <code>
48   *  servlet&gt;
49          &lt;servlet-name&gt;JCSRemoteCacheStartupServlet&lt;/servlet-name&gt;
50          &lt;servlet-class&gt;
51               org.apache.commons.jcs3.auxiliary.remote.server.RemoteCacheStartupServlet
52          &lt;/servlet-class&gt;
53          &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
54      &lt;/servlet&gt;
55  
56  
57      &lt;servlet-mapping&gt;
58          &lt;servlet-name&gt;JCSRemoteCacheStartupServlet&lt;/servlet-name&gt;
59          &lt;url-pattern&gt;/jcs&lt;/url-pattern&gt;
60      &lt;/servlet-mapping&gt;
61   * </code>
62   */
63  public class RemoteCacheStartupServlet
64          extends HttpServlet
65  {
66      /** Don't change */
67      private static final long serialVersionUID = 1L;
68  
69      /** The logger */
70      private static final Log log = LogManager.getLog(RemoteCacheStartupServlet.class);
71  
72      /** The default port to start the registry on. */
73      private static final int DEFAULT_REGISTRY_PORT = 1101;
74  
75      /** properties file name */
76      private static final String DEFAULT_PROPS_FILE_NAME = "/cache.ccf";
77  
78      /** properties file name, must set prior to calling get instance */
79      private String propsFileName = DEFAULT_PROPS_FILE_NAME;
80  
81      /** Configuration properties */
82      private int registryPort = DEFAULT_REGISTRY_PORT;
83  
84      /** Configuration properties */
85      private String registryHost;
86  
87      /**
88       * Starts the registry and then tries to bind to it.
89       * <p>
90       * Gets the port from a props file. Uses the local host name for the
91       * registry host. Tries to start the registry, ignoring failure. Starts the
92       * server.
93       * <p>
94       *
95       * @throws ServletException
96       */
97      @Override
98      public void init()
99              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 }