1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.jk.common;
19
20
21 import org.apache.jk.core.JkHandler;
22
23 import javax.management.MBeanServer;
24 import javax.management.ObjectName;
25 import javax.management.Attribute;
26 import javax.management.MBeanServerFactory;
27 import java.io.IOException;
28
29 /**
30 * Load the HTTP or RMI adapters for MX4J and JMXRI.
31 *
32 * Add "mx.enabled=true" in jk2.properties to enable it.
33 * You could also select http and/or jrmp protocol,
34 * with mx.httpPort, mx.httpHost, mxjrmpPort and mx.jrmpPort.
35 * <p />
36 * If you run into an error message like
37 * "SystemId Unknown; Line #12; Column #81; Cannot add attribute name after
38 * child nodes or before an element is produced. Attribute will be ignored."
39 * after setting mx.enabled to true, you probably need a newer version
40 * of Xalan. See the RELEASE-NOTES document section on XML Parsers for
41 * more information.
42 *
43 */
44 public class JkMX extends JkHandler
45 {
46 MBeanServer mserver;
47 private boolean enabled=false;
48 private boolean log4jEnabled=true;
49 private int httpport=-1;
50 private String httphost="localhost";
51 private String authmode="none";
52 private String authuser=null;
53 private String authpassword=null;
54 private int jrmpport=-1;
55 private String jrmphost="localhost";
56 private boolean useXSLTProcessor = true;
57
58 public JkMX() {
59 }
60
61 /* -------------------- Public methods -------------------- */
62
63 /** Enable the MX4J adapters (new way)
64 */
65 public void setEnabled(boolean b) {
66 enabled=b;
67 }
68
69 public boolean getEnabled() {
70 return enabled;
71 }
72
73 /** Enable the Log4j MBean)
74 */
75 public void setLog4jEnabled(boolean b) {
76 log4jEnabled=b;
77 }
78
79 public boolean getLog4jEnabled() {
80 return log4jEnabled;
81 }
82
83 /** Enable the MX4J adapters (old way, compatible)
84 */
85 public void setPort(int i) {
86 enabled=(i != -1);
87 }
88
89 public int getPort() {
90 return ((httpport != -1) ? httpport : jrmpport);
91 }
92
93 /** Enable the MX4J HTTP internal adapter
94 */
95 public void setHttpPort( int i ) {
96 httpport=i;
97 }
98
99 public int getHttpPort() {
100 return httpport;
101 }
102
103 public void setHttpHost(String host ) {
104 this.httphost=host;
105 }
106
107 public String getHttpHost() {
108 return httphost;
109 }
110
111 public void setAuthMode(String mode) {
112 authmode=mode;
113 }
114
115 public String getAuthMode() {
116 return authmode;
117 }
118
119 public void setAuthUser(String user) {
120 authuser=user;
121 }
122
123 public String getAuthUser() {
124 return authuser;
125 }
126
127 public void setAuthPassword(String password) {
128 authpassword=password;
129 }
130
131 public String getAuthPassword() {
132 return authpassword;
133 }
134
135 /** Enable the MX4J JRMP internal adapter
136 */
137 public void setJrmpPort( int i ) {
138 jrmpport=i;
139 }
140
141 public int getJrmpPort() {
142 return jrmpport;
143 }
144
145 public void setJrmpHost(String host ) {
146 this.jrmphost=host;
147 }
148
149 public String getJrmpHost() {
150 return jrmphost;
151 }
152
153 public boolean getUseXSLTProcessor() {
154 return useXSLTProcessor;
155 }
156
157 public void setUseXSLTProcessor(boolean uxsltp) {
158 useXSLTProcessor = uxsltp;
159 }
160
161 /* ==================== Start/stop ==================== */
162 ObjectName httpServerName=null;
163 ObjectName jrmpServerName=null;
164
165 /** Initialize the worker. After this call the worker will be
166 * ready to accept new requests.
167 */
168 public void loadAdapter() throws IOException {
169 boolean httpAdapterLoaded = false;
170 boolean jrmpAdapterLoaded = false;
171
172 if ((httpport != -1) && classExists("mx4j.adaptor.http.HttpAdaptor")) {
173 try {
174 httpServerName = registerObject("mx4j.adaptor.http.HttpAdaptor",
175 "Http:name=HttpAdaptor");
176
177
178 if( httphost!=null )
179 mserver.setAttribute(httpServerName, new Attribute("Host", httphost));
180 mserver.setAttribute(httpServerName, new Attribute("Port", new Integer(httpport)));
181
182 if( "none".equals(authmode) || "basic".equals(authmode) || "digest".equals(authmode) )
183 mserver.setAttribute(httpServerName, new Attribute("AuthenticationMethod", authmode));
184
185 if( authuser!=null && authpassword!=null )
186 mserver.invoke(httpServerName, "addAuthorization",
187 new Object[] {
188 authuser,
189 authpassword},
190 new String[] { "java.lang.String", "java.lang.String" });
191
192 if(useXSLTProcessor) {
193 ObjectName processorName = registerObject("mx4j.adaptor.http.XSLTProcessor",
194 "Http:name=XSLTProcessor");
195 mserver.setAttribute(httpServerName, new Attribute("ProcessorName", processorName));
196 }
197
198 // starts the server
199 mserver.invoke(httpServerName, "start", null, null);
200
201 log.info( "Started MX4J console on host " + httphost + " at port " + httpport);
202
203 httpAdapterLoaded = true;
204
205 } catch( Throwable t ) {
206 httpServerName=null;
207 log.error( "Can't load the MX4J http adapter ", t );
208 }
209 }
210
211 if ((httpport != -1) && (!httpAdapterLoaded) && classExists("mx4j.tools.adaptor.http.HttpAdaptor")) {
212 try {
213 httpServerName = registerObject("mx4j.tools.adaptor.http.HttpAdaptor",
214 "Http:name=HttpAdaptor");
215
216
217 if( httphost!=null )
218 mserver.setAttribute(httpServerName, new Attribute("Host", httphost));
219 mserver.setAttribute(httpServerName, new Attribute("Port", new Integer(httpport)));
220
221 if( "none".equals(authmode) || "basic".equals(authmode) || "digest".equals(authmode) )
222 mserver.setAttribute(httpServerName, new Attribute("AuthenticationMethod", authmode));
223
224 if( authuser!=null && authpassword!=null )
225 mserver.invoke(httpServerName, "addAuthorization",
226 new Object[] {
227 authuser,
228 authpassword},
229 new String[] { "java.lang.String", "java.lang.String" });
230
231 if(useXSLTProcessor) {
232 ObjectName processorName = registerObject("mx4j.tools.adaptor.http.XSLTProcessor",
233 "Http:name=XSLTProcessor");
234 mserver.setAttribute(httpServerName, new Attribute("ProcessorName", processorName));
235 }
236 // starts the server
237 mserver.invoke(httpServerName, "start", null, null);
238 if(log.isInfoEnabled())
239 log.info( "Started MX4J console on host " + httphost + " at port " + httpport);
240
241 httpAdapterLoaded = true;
242
243 } catch( Throwable t ) {
244 httpServerName=null;
245 log.error( "Can't load the MX4J http adapter ", t );
246 }
247 }
248
249 if ((jrmpport != -1) && classExists("mx4j.tools.naming.NamingService")) {
250 try {
251 jrmpServerName = registerObject("mx4j.tools.naming.NamingService",
252 "Naming:name=rmiregistry");
253 mserver.setAttribute(jrmpServerName, new Attribute("Port",
254 new Integer(jrmpport)));
255 mserver.invoke(jrmpServerName, "start", null, null);
256 if(log.isInfoEnabled())
257 log.info( "Creating " + jrmpServerName );
258
259 // Create the JRMP adaptor
260 ObjectName adaptor = registerObject("mx4j.adaptor.rmi.jrmp.JRMPAdaptor",
261 "Adaptor:protocol=jrmp");
262
263
264 mserver.setAttribute(adaptor, new Attribute("JNDIName", "jrmp"));
265
266 mserver.invoke( adaptor, "putNamingProperty",
267 new Object[] {
268 javax.naming.Context.INITIAL_CONTEXT_FACTORY,
269 "com.sun.jndi.rmi.registry.RegistryContextFactory"},
270 new String[] { "java.lang.Object", "java.lang.Object" });
271
272 String jrpmurl = "rmi://" + jrmphost + ":" + Integer.toString(jrmpport) ;
273
274 mserver.invoke( adaptor, "putNamingProperty",
275 new Object[] {
276 javax.naming.Context.PROVIDER_URL,
277 jrpmurl},
278 new String[] { "java.lang.Object", "java.lang.Object" });
279
280 // Registers the JRMP adaptor in JNDI and starts it
281 mserver.invoke(adaptor, "start", null, null);
282 if(log.isInfoEnabled())
283 log.info( "Creating " + adaptor + " on host " + jrmphost + " at port " + jrmpport);
284
285 jrmpAdapterLoaded = true;
286
287 } catch( Exception ex ) {
288 jrmpServerName = null;
289 log.error( "MX4j RMI adapter not loaded: " + ex.toString());
290 }
291 }
292
293 if ((httpport != -1) && (! httpAdapterLoaded) && classExists("com.sun.jdmk.comm.HtmlAdaptorServer")) {
294 try {
295 httpServerName=registerObject("com.sun.jdmk.comm.HtmlAdaptorServer",
296 "Adaptor:name=html,port=" + httpport);
297 if(log.isInfoEnabled())
298 log.info("Registering the JMX_RI html adapter " + httpServerName + " at port " + httpport);
299
300 mserver.setAttribute(httpServerName,
301 new Attribute("Port", new Integer(httpport)));
302
303 mserver.invoke(httpServerName, "start", null, null);
304
305 httpAdapterLoaded = true;
306 } catch( Throwable t ) {
307 httpServerName = null;
308 log.error( "Can't load the JMX_RI http adapter " + t.toString() );
309 }
310 }
311
312 if ((!httpAdapterLoaded) && (!jrmpAdapterLoaded))
313 log.warn( "No adaptors were loaded but mx.enabled was defined.");
314
315 }
316
317 public void destroy() {
318 try {
319 if(log.isInfoEnabled())
320 log.info("Stoping JMX ");
321
322 if( httpServerName!=null ) {
323 mserver.invoke(httpServerName, "stop", null, null);
324 }
325 if( jrmpServerName!=null ) {
326 mserver.invoke(jrmpServerName, "stop", null, null);
327 }
328 } catch( Throwable t ) {
329 log.error( "Destroy error" + t );
330 }
331 }
332
333 public void init() throws IOException {
334 try {
335 mserver = getMBeanServer();
336
337 if( enabled ) {
338 loadAdapter();
339 }
340 if( log4jEnabled) {
341 try {
342 registerObject("org.apache.log4j.jmx.HierarchyDynamicMBean" ,
343 "log4j:hierarchy=default");
344 if(log.isInfoEnabled())
345 log.info("Registering the JMX hierarchy for Log4J ");
346 } catch( Throwable t ) {
347 if(log.isInfoEnabled())
348 log.info("Can't enable log4j mx: ",t);
349 }
350 }
351 } catch( Throwable t ) {
352 log.error( "Init error", t );
353 }
354 }
355
356 public void addHandlerCallback( JkHandler w ) {
357 }
358
359 MBeanServer getMBeanServer() {
360 MBeanServer server;
361 if( MBeanServerFactory.findMBeanServer(null).size() > 0 ) {
362 server=(MBeanServer)MBeanServerFactory.findMBeanServer(null).get(0);
363 } else {
364 server=MBeanServerFactory.createMBeanServer();
365 }
366 return (server);
367 }
368
369
370 private static boolean classExists(String className) {
371 try {
372 Thread.currentThread().getContextClassLoader().loadClass(className);
373 return true;
374 } catch(Throwable e) {
375 if (log.isInfoEnabled())
376 log.info( "className [" + className + "] does not exist");
377 return false;
378 }
379 }
380
381 private ObjectName registerObject(String className, String oName)
382 throws Exception {
383 Class c = Class.forName(className);
384 Object o = c.newInstance();
385 ObjectName objN = new ObjectName(oName);
386 mserver.registerMBean(o, objN);
387 return objN;
388 }
389
390 private static org.apache.juli.logging.Log log=
391 org.apache.juli.logging.LogFactory.getLog( JkMX.class );
392
393
394 }
395