| 1 | // jademx - JADE management using JMX |
| 2 | // Copyright 2005 Caboodle Networks, Inc. |
| 3 | // |
| 4 | // This library is free software; you can redistribute it and/or |
| 5 | // modify it under the terms of the GNU Lesser General Public |
| 6 | // License as published by the Free Software Foundation; either |
| 7 | // version 2.1 of the License, or (at your option) any later version. |
| 8 | // |
| 9 | // This library is distributed in the hope that it will be useful, |
| 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 12 | // Lesser General Public License for more details. |
| 13 | // |
| 14 | // You should have received a copy of the GNU Lesser General Public |
| 15 | // License along with this library; if not, write to the Free Software |
| 16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
| 17 | package jade.jademx.server; |
| 18 | |
| 19 | import java.util.Enumeration; |
| 20 | import java.util.Hashtable; |
| 21 | import java.util.logging.Level; |
| 22 | import java.util.logging.Logger; |
| 23 | |
| 24 | //import jade.util.Logger; |
| 25 | |
| 26 | import javax.servlet.ServletContext; |
| 27 | import javax.servlet.ServletContextEvent; |
| 28 | import javax.servlet.ServletContextListener; |
| 29 | |
| 30 | /** |
| 31 | * Let JADE be installed using JMX in servlet context, e.g. under J2EE as a WAR. |
| 32 | * The class is then described as a <code>listener</code> in the |
| 33 | * <code>web.xml</code> file. |
| 34 | * <p>The following context parameters are understood: |
| 35 | * <table> |
| 36 | * <tr><th>name</th><th>needed</th></tr> |
| 37 | * <tr><td><a href="#PARAMETER_JADEMX_SERVER_CLASS_NAME"> |
| 38 | * <code>{@value #PARAMETER_JADEMX_SERVER_CLASS_NAME}</code></a></td> |
| 39 | * <td>required</td></tr> |
| 40 | * <tr><td><a href="#PARAMETER_JADE_SERVICE_JNDI_NAME"> |
| 41 | * <code>{@value #PARAMETER_JADE_SERVICE_JNDI_NAME}</code></a></td> |
| 42 | * <td>optional</td></tr> |
| 43 | * <tr><td><a href="#PARAMETER_JADE_SERVICE_CONFIG_DOC_URL"> |
| 44 | * <code>{@value #PARAMETER_JADE_SERVICE_CONFIG_DOC_URL}</code></a></td> |
| 45 | * <td>optional</td></tr> |
| 46 | * <tr><td><a href="#PARAMETER_JADE_SERVICE_CONFIG_DOC_RESOURCE"> |
| 47 | * <code>{@value #PARAMETER_JADE_SERVICE_CONFIG_DOC_RESOURCE}</code></a></td> |
| 48 | * <td>optional</td></tr> |
| 49 | * <tr><td><a href="#PARAMETER_JADE_SERVICE_OBJECT_NAME_DOMAIN"> |
| 50 | * <code>{@value #PARAMETER_JADE_SERVICE_OBJECT_NAME_DOMAIN}</code></a></td> |
| 51 | * <td>optional</td></tr> |
| 52 | * </table> |
| 53 | * </p> |
| 54 | * @author David Bernstein, <a href="http://www.caboodlenetworks.com" |
| 55 | * >Caboodle Networks, Inc.</a> |
| 56 | */ |
| 57 | public class JadeServletContextListener implements ServletContextListener { |
| 58 | |
| 59 | // CONTEXT PARAMETER NAMES |
| 60 | |
| 61 | /** prefix for <code>PARAMETER_JADE_SERVICE_</code> parameters */ |
| 62 | private final static String JADE_SERVICE_PARM_PREFIX = "jade.service."; |
| 63 | |
| 64 | /** prefix for JNDI environment parameters */ |
| 65 | private final static String JNDI_ENV_PARM_PREFIX = |
| 66 | JADE_SERVICE_PARM_PREFIX + "jndi.env."; |
| 67 | |
| 68 | /** fragment for configuration document name parameters */ |
| 69 | private final static String CONFIG_DOC_PARM_FRAGMENT = "config.doc."; |
| 70 | |
| 71 | /** |
| 72 | * Name of <b>required</b> context paramter with name of class implementing |
| 73 | * <code>JadeMXServer</code> to instantiate |
| 74 | * with no-argument constructor retrieving MBeanServer. |
| 75 | * Value: <code>{@value #PARAMETER_JADEMX_SERVER_CLASS_NAME}</code>. |
| 76 | */ |
| 77 | public final static String PARAMETER_JADEMX_SERVER_CLASS_NAME = |
| 78 | "jademx.server.class.name"; |
| 79 | |
| 80 | /** |
| 81 | * Name of <b>optional</b> context parameter with JNDI name to register |
| 82 | * JadeService as. |
| 83 | * Value: <code>{@value #PARAMETER_JADE_SERVICE_JNDI_NAME}</code>. |
| 84 | * Setting this to <code>null</code> will turn off JNDI registration. |
| 85 | */ |
| 86 | public final static String PARAMETER_JADE_SERVICE_JNDI_NAME = |
| 87 | JADE_SERVICE_PARM_PREFIX + "jndi.name"; |
| 88 | |
| 89 | /** |
| 90 | * Name of <b>optional</b> context parameter with URL to find |
| 91 | * JadeService configuration doc. |
| 92 | * Value: <code>{@value #PARAMETER_JADE_SERVICE_CONFIG_DOC_URL}</code>. |
| 93 | * Mutually exclusive with |
| 94 | * {@link #PARAMETER_JADE_SERVICE_CONFIG_DOC_RESOURCE}. |
| 95 | */ |
| 96 | public final static String PARAMETER_JADE_SERVICE_CONFIG_DOC_URL = |
| 97 | JADE_SERVICE_PARM_PREFIX + CONFIG_DOC_PARM_FRAGMENT + "url"; |
| 98 | |
| 99 | /** |
| 100 | * Name of <b>optional</b> context parameter with resource to find |
| 101 | * JadeService configuration doc. |
| 102 | * Value: <code>{@value #PARAMETER_JADE_SERVICE_CONFIG_DOC_RESOURCE}</code>. |
| 103 | * Mutually exclusive with |
| 104 | * {@link #PARAMETER_JADE_SERVICE_CONFIG_DOC_URL}. |
| 105 | */ |
| 106 | public final static String PARAMETER_JADE_SERVICE_CONFIG_DOC_RESOURCE = |
| 107 | JADE_SERVICE_PARM_PREFIX + CONFIG_DOC_PARM_FRAGMENT + "resource"; |
| 108 | |
| 109 | /** |
| 110 | * Name of <b>optional</b> context parameter with JMX ObjectName |
| 111 | * domain to use. |
| 112 | * Value: <code>{@value #PARAMETER_JADE_SERVICE_OBJECT_NAME_DOMAIN}</code>. |
| 113 | */ |
| 114 | public final static String PARAMETER_JADE_SERVICE_OBJECT_NAME_DOMAIN = |
| 115 | JADE_SERVICE_PARM_PREFIX + "object.name.domain"; |
| 116 | |
| 117 | /** local copy of service implementation */ |
| 118 | private JadeService service; |
| 119 | |
| 120 | /** my logger */ |
| 121 | private final Logger logger = |
| 122 | Logger.getLogger(JadeServletContextListener.class.getName()); |
| 123 | // Logger.getMyLogger(JadeServletContextListener.class.getName()); |
| 124 | |
| 125 | |
| 126 | // use the default constructor |
| 127 | |
| 128 | /* (non-Javadoc) |
| 129 | * @see javax.servlet.ServletContextListener#contextInitialized( |
| 130 | * javax.servlet.ServletContextEvent) |
| 131 | */ |
| 132 | public void contextInitialized( ServletContextEvent servletContextEvent ) { |
| 133 | |
| 134 | if ( logger.isLoggable( Level.FINE ) ) { |
| 135 | //System.getProperties().list( System.out );//this version truncates |
| 136 | logger.log( Level.FINE, "system properties:"); |
| 137 | java.util.Properties sysProps = System.getProperties(); |
| 138 | java.util.Enumeration sysPropNames = sysProps.propertyNames(); |
| 139 | while ( sysPropNames.hasMoreElements() ) { |
| 140 | String sysPropName = (String)sysPropNames.nextElement(); |
| 141 | logger.log( Level.FINE, sysPropName + "=" + |
| 142 | sysProps.getProperty( sysPropName ) ); |
| 143 | } |
| 144 | } |
| 145 | |
| 146 | try { |
| 147 | |
| 148 | try { |
| 149 | // construct the service instance, which will perform the work |
| 150 | // and register self as an MBean and register self with JNDI |
| 151 | service = new JadeService(); |
| 152 | } |
| 153 | catch ( Exception e ) { |
| 154 | e.printStackTrace(); |
| 155 | throw new RuntimeException( |
| 156 | "exception constructing JadeService", e ); |
| 157 | } |
| 158 | |
| 159 | |
| 160 | try { |
| 161 | |
| 162 | // servlet context lets us look at our environment |
| 163 | ServletContext servletContext = |
| 164 | servletContextEvent.getServletContext(); |
| 165 | |
| 166 | // JadeMXServer class name is required context parameter |
| 167 | String parmJadeMXServerClassName = |
| 168 | servletContext.getInitParameter( |
| 169 | PARAMETER_JADEMX_SERVER_CLASS_NAME ); |
| 170 | if ( null == parmJadeMXServerClassName ) { |
| 171 | throw new RuntimeException("required context parameter \""+ |
| 172 | PARAMETER_JADEMX_SERVER_CLASS_NAME+ |
| 173 | "\" not specified"); |
| 174 | } |
| 175 | service.setJadeMXServerClassName( parmJadeMXServerClassName ); |
| 176 | |
| 177 | // check for specification of JNDI name for JADE service |
| 178 | String parmJadeServiceJndiName = |
| 179 | servletContext.getInitParameter( |
| 180 | PARAMETER_JADE_SERVICE_JNDI_NAME ); |
| 181 | if ( null != parmJadeServiceJndiName ) { |
| 182 | service.setJndiName( parmJadeServiceJndiName ); |
| 183 | } |
| 184 | |
| 185 | // check for specification of config doc as url |
| 186 | String parmJadeServiceConfigDocUrl = |
| 187 | servletContext.getInitParameter( |
| 188 | PARAMETER_JADE_SERVICE_CONFIG_DOC_URL ); |
| 189 | if ( null != parmJadeServiceConfigDocUrl ) { |
| 190 | service.setConfigDocUrl( parmJadeServiceConfigDocUrl ); |
| 191 | } |
| 192 | |
| 193 | // check for specification of config doc as resource |
| 194 | String parmJadeServiceConfigDocResource = |
| 195 | servletContext.getInitParameter( |
| 196 | PARAMETER_JADE_SERVICE_CONFIG_DOC_RESOURCE ); |
| 197 | if ( null != parmJadeServiceConfigDocResource ) { |
| 198 | service.setConfigDocResource( |
| 199 | parmJadeServiceConfigDocResource); |
| 200 | } |
| 201 | |
| 202 | // check for specification of ObjectName domain |
| 203 | String parmJadeServiceObjectNameDomain = |
| 204 | servletContext.getInitParameter( |
| 205 | PARAMETER_JADE_SERVICE_OBJECT_NAME_DOMAIN ); |
| 206 | if ( null != parmJadeServiceObjectNameDomain ) { |
| 207 | if ( "null".equals( parmJadeServiceObjectNameDomain ) ) { |
| 208 | // this can be used to turn off registration with JNDI |
| 209 | parmJadeServiceObjectNameDomain = null; |
| 210 | } |
| 211 | service.setObjectNameDomain( |
| 212 | parmJadeServiceObjectNameDomain ); |
| 213 | } |
| 214 | |
| 215 | // check for JNDI environment InitialContext properties |
| 216 | Hashtable contextProps = new Hashtable(); |
| 217 | Enumeration initParmNamesE = |
| 218 | servletContext.getInitParameterNames(); |
| 219 | while ( initParmNamesE.hasMoreElements() ) { |
| 220 | String parmName = (String)initParmNamesE.nextElement(); |
| 221 | if ( parmName.startsWith( JNDI_ENV_PARM_PREFIX ) ) { |
| 222 | String envPropName = |
| 223 | parmName.substring( JNDI_ENV_PARM_PREFIX.length() ); |
| 224 | String envPropVal = |
| 225 | servletContext.getInitParameter( parmName ); |
| 226 | if ( logger.isLoggable( Level.FINE ) ) { |
| 227 | logger.log( Level.FINE, |
| 228 | "JNDI env prop:"+envPropName+"="+envPropVal); |
| 229 | } |
| 230 | contextProps.put( envPropName, envPropVal ); |
| 231 | } |
| 232 | } |
| 233 | service.setJndiInitialContextProperties( contextProps ); |
| 234 | |
| 235 | //logger.log(Logger.INFO, "configured "+service ); |
| 236 | |
| 237 | } |
| 238 | catch ( Exception e ) { |
| 239 | e.printStackTrace(); |
| 240 | throw new RuntimeException( |
| 241 | "exception configuring JadeService "+service, e ); |
| 242 | } |
| 243 | |
| 244 | // register the JadeServiceMBean with the MBeanServer |
| 245 | JadeMXServer jadeMXServer = null; |
| 246 | try { |
| 247 | jadeMXServer = (JadeMXServer) |
| 248 | Class.forName(service.getJadeMXServerClassName()).newInstance(); |
| 249 | } |
| 250 | catch ( Exception e ) { |
| 251 | e.printStackTrace(); |
| 252 | throw new RuntimeException( |
| 253 | "exception instantiating JadeMXServer class"+ |
| 254 | service.getJadeMXServerClassName(), e ); |
| 255 | } |
| 256 | try { |
| 257 | jadeMXServer.getMBeanServer().registerMBean( service, null ); |
| 258 | } |
| 259 | catch ( Exception e ) { |
| 260 | e.printStackTrace(); |
| 261 | throw new RuntimeException( |
| 262 | "exception registering JadeMXServer "+jadeMXServer+ |
| 263 | " with MBeanServer", e ); |
| 264 | } |
| 265 | |
| 266 | // create the service |
| 267 | try { |
| 268 | service.create(); |
| 269 | } |
| 270 | catch ( Exception e ) { |
| 271 | e.printStackTrace(); |
| 272 | throw new RuntimeException("exception creating "+service, e ); |
| 273 | } |
| 274 | |
| 275 | // start the service |
| 276 | try { |
| 277 | service.start(); |
| 278 | } |
| 279 | catch ( Exception e ) { |
| 280 | e.printStackTrace(); |
| 281 | throw new RuntimeException("exception starting "+service, e ); |
| 282 | } |
| 283 | |
| 284 | } |
| 285 | catch ( Throwable t ) { |
| 286 | logger.log( Level.SEVERE, "caught throwable", t); |
| 287 | System.err.println( |
| 288 | "JadeServletContextListener.contextInitialized():"+ |
| 289 | "caught throwable: "); |
| 290 | t.printStackTrace(); |
| 291 | throw new RuntimeException( |
| 292 | "JadeServletContextListener.contextInitialized():"+ |
| 293 | "caught throwable: ", t ); |
| 294 | } |
| 295 | |
| 296 | } |
| 297 | |
| 298 | |
| 299 | /* (non-Javadoc) |
| 300 | * @see javax.servlet.ServletContextListener#contextDestroyed( |
| 301 | * javax.servlet.ServletContextEvent) |
| 302 | */ |
| 303 | public void contextDestroyed( ServletContextEvent servletContextEvent ) { |
| 304 | logger.log( Level.INFO, "destroying servlet context..."); |
| 305 | // stop the service |
| 306 | service.stop(); |
| 307 | // unregister from MBeanServer |
| 308 | service.unregister(); |
| 309 | // destroy the service |
| 310 | service.destroy(); |
| 311 | } |
| 312 | |
| 313 | } |