| /* |
| * Copyright 1999-2004 The Apache Software Foundation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.jk.common; |
| |
| import java.io.IOException; |
| import java.io.BufferedReader; |
| import java.io.InputStreamReader; |
| import java.net.URLConnection; |
| import java.net.URL; |
| import java.util.List; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import javax.management.MBeanServer; |
| import javax.management.AttributeNotFoundException; |
| import javax.management.MBeanException; |
| import javax.management.ReflectionException; |
| import javax.management.Attribute; |
| import javax.management.ObjectName; |
| |
| import org.apache.jk.core.JkHandler; |
| import org.apache.commons.modeler.Registry; |
| import org.apache.commons.modeler.BaseModelMBean; |
| import org.apache.commons.modeler.ManagedBean; |
| import org.apache.commons.modeler.AttributeInfo; |
| import org.apache.commons.modeler.OperationInfo; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| /** |
| * A small mbean that will act as a proxy for mod_jk2. |
| * |
| * For efficiency, it'll get bulk results and cache them - you |
| * can force an update by calling the refreshAttributes and refreshMetadata |
| * operations on this mbean. |
| * |
| * TODO: implement the user/pass auth ( right now you must use IP based security ) |
| * TODO: eventually support https |
| * TODO: support for metadata ( mbean-descriptors ) for description and type conversions |
| * TODO: filter out trivial components ( mutexes, etc ) |
| * |
| * @author Costin Manolache |
| */ |
| public class ModJkMX extends JkHandler |
| { |
| private static Log log = LogFactory.getLog(ModJkMX.class); |
| |
| MBeanServer mserver; |
| String webServerHost="localhost"; |
| int webServerPort=80; |
| String statusPath="/jkstatus"; |
| String user; |
| String pass; |
| Registry reg; |
| |
| HashMap mbeans=new HashMap(); |
| long lastRefresh=0; |
| long updateInterval=5000; // 5 sec - it's min time between updates |
| |
| public ModJkMX() |
| { |
| } |
| |
| /* -------------------- Public methods -------------------- */ |
| |
| public String getWebServerHost() { |
| return webServerHost; |
| } |
| |
| public void setWebServerHost(String webServerHost) { |
| this.webServerHost = webServerHost; |
| } |
| |
| public int getWebServerPort() { |
| return webServerPort; |
| } |
| |
| public void setWebServerPort(int webServerPort) { |
| this.webServerPort = webServerPort; |
| } |
| |
| public long getUpdateInterval() { |
| return updateInterval; |
| } |
| |
| public void setUpdateInterval(long updateInterval) { |
| this.updateInterval = updateInterval; |
| } |
| |
| public String getUser() { |
| return user; |
| } |
| |
| public void setUser(String user) { |
| this.user = user; |
| } |
| |
| public String getPass() { |
| return pass; |
| } |
| |
| public void setPass(String pass) { |
| this.pass = pass; |
| } |
| |
| public String getStatusPath() { |
| return statusPath; |
| } |
| |
| public void setStatusPath(String statusPath) { |
| this.statusPath = statusPath; |
| } |
| /* ==================== Start/stop ==================== */ |
| |
| public void destroy() { |
| try { |
| // We should keep track of loaded beans and call stop. |
| // Modeler should do it... |
| Iterator mbeansIt=mbeans.values().iterator(); |
| MBeanServer mbserver = Registry.getRegistry().getMBeanServer(); |
| while( mbeansIt.hasNext()) { |
| MBeanProxy proxy=(MBeanProxy)mbeansIt.next(); |
| Object ooname = proxy.getObjectName(); |
| if( ooname != null ) { |
| ObjectName oname = null; |
| if(ooname instanceof ObjectName) { |
| oname = (ObjectName)ooname; |
| } else if(ooname instanceof String) { |
| oname = new ObjectName((String)ooname); |
| } |
| if( oname != null ) { |
| mbserver.unregisterMBean(oname); |
| } |
| } |
| } |
| } catch( Throwable t ) { |
| log.error( "Destroy error", t ); |
| } |
| } |
| |
| public void init() throws IOException { |
| try { |
| //if( log.isDebugEnabled() ) |
| log.info("init " + webServerHost + " " + webServerPort); |
| reg=Registry.getRegistry(); |
| refreshMetadata(); |
| refreshAttributes(); |
| } catch( Throwable t ) { |
| log.error( "Init error", t ); |
| } |
| } |
| |
| public void start() throws IOException { |
| if( reg==null) |
| init(); |
| } |
| |
| /** Refresh the proxies, if updateInterval passed |
| * |
| */ |
| public void refresh() { |
| long time=System.currentTimeMillis(); |
| if( time - lastRefresh < updateInterval ) { |
| return; |
| } |
| lastRefresh=time; |
| refreshMetadata(); |
| refreshAttributes(); |
| } |
| |
| public void refreshAttributes() { |
| try { |
| int cnt=0; |
| // connect to apache, get a list of mbeans |
| BufferedReader is=getStream( "dmp=*"); |
| if( is==null ) return; |
| |
| String name=null; |
| String att=null; |
| String val=null; |
| while(true) { |
| String line=is.readLine(); |
| if( line==null ) break; |
| line=line.trim(); |
| if( "".equals(line) || line.startsWith("#") ) continue; |
| |
| // for each mbean, create a proxy |
| if(log.isDebugEnabled()) |
| log.debug("Read " + line); |
| |
| if(line.startsWith( "[")) { |
| name=line.substring(1); |
| if( name.endsWith("]")) { |
| name=name.substring(0, name.length()-1); |
| } |
| } |
| // Name/value pair |
| int idx=line.indexOf('='); |
| if( idx < 0 ) continue; |
| att=line.substring(0, idx ); |
| val=line.substring(idx+1); |
| |
| if( log.isDebugEnabled()) |
| log.debug("name: " + name + " att=" + att + |
| " val=" + val); |
| |
| MBeanProxy proxy=(MBeanProxy)mbeans.get(name); |
| if( proxy==null ) { |
| log.info( "Unknown object " + name); |
| } else { |
| proxy.update(att, val); |
| cnt++; |
| } |
| } |
| log.info( "Refreshing attributes " + cnt); |
| } catch( Exception ex ) { |
| log.info("Error ", ex); |
| } |
| } |
| |
| /** connect to apache, get a list of mbeans |
| */ |
| BufferedReader getStream(String qry) throws Exception { |
| try { |
| String path=statusPath + "?" + qry; |
| URL url=new URL( "http", webServerHost, webServerPort, path); |
| URLConnection urlc=url.openConnection(); |
| BufferedReader is=new BufferedReader(new InputStreamReader(urlc.getInputStream())); |
| return is; |
| } catch (IOException e) { |
| log.info( "Can't connect to jkstatus " + webServerHost + ":" + webServerPort |
| + " " + e.toString()); |
| return null; |
| } |
| } |
| |
| public void refreshMetadata() { |
| try { |
| int cnt=0; |
| int newCnt=0; |
| BufferedReader is=getStream("lst=*"); |
| if( is==null ) return; |
| String name=null; |
| String type=null; |
| ArrayList getters=new ArrayList(); |
| ArrayList setters=new ArrayList(); |
| ArrayList methods=new ArrayList(); |
| while(true) { |
| String line=is.readLine(); |
| if( log.isDebugEnabled()) |
| log.debug("Read " + line); |
| |
| // end of section |
| if( line == null || line.startsWith("[") ) { |
| if( name != null ) { |
| cnt++; |
| if( mbeans.get( name ) ==null ) { |
| // New component |
| newCnt++; |
| MBeanProxy mproxy=new MBeanProxy(this); |
| mproxy.init( name, getters, setters, methods); |
| mbeans.put( name, mproxy ); |
| } |
| if( log.isDebugEnabled()) |
| log.debug("mbean name: " + name + " type=" + type); |
| |
| getters.clear(); |
| setters.clear(); |
| methods.clear(); |
| } |
| } |
| // end of data |
| if( line==null ) break; |
| |
| line=line.trim(); |
| if( "".equals( line ) || line.startsWith("#")) continue; |
| |
| // for each mbean, create a proxy |
| |
| if(line.startsWith( "[") && line.endsWith("]")) { |
| name=line.substring(1, line.length()-1); |
| } |
| if(line.startsWith( "T=")) { |
| type=line.substring(2); |
| } |
| if( line.startsWith("G=")) { |
| getters.add(line.substring(2)); |
| } |
| if( line.startsWith("S=")) { |
| setters.add(line.substring(2)); |
| } |
| if( line.startsWith("M=")) { |
| methods.add(line.substring(2)); |
| } |
| } |
| log.info( "Refreshing metadata " + cnt + " " + newCnt); |
| } catch( Exception ex ) { |
| log.info("Error ", ex); |
| } |
| } |
| |
| /** Use the same metadata, except that we replace the attribute |
| * get/set methods. |
| */ |
| static class MBeanProxy extends BaseModelMBean { |
| private static Log log = LogFactory.getLog(MBeanProxy.class); |
| |
| String jkName; |
| List getAttNames; |
| List setAttNames; |
| HashMap atts=new HashMap(); |
| ModJkMX jkmx; |
| |
| public MBeanProxy(ModJkMX jkmx) throws Exception { |
| this.jkmx=jkmx; |
| } |
| |
| void init( String name, List getters, List setters, List methods ) |
| throws Exception |
| { |
| if(log.isDebugEnabled()) |
| log.debug("Register " + name ); |
| int col=name.indexOf( ':' ); |
| this.jkName=name; |
| String type=name.substring(0, col ); |
| String id=name.substring(col+1); |
| id=id.replace('*','%'); |
| id=id.replace(':', '%'); |
| if( id.length() == 0 ) { |
| id="default"; |
| } |
| ManagedBean mbean= new ManagedBean(); |
| |
| AttributeInfo ai=new AttributeInfo(); |
| ai.setName( "jkName" ); |
| ai.setType( "java.lang.String"); |
| ai.setWriteable(false); |
| mbean.addAttribute(ai); |
| |
| for( int i=0; i<getters.size(); i++ ) { |
| String att=(String)getters.get(i); |
| // Register metadata |
| ai=new AttributeInfo(); |
| ai.setName( att ); |
| ai.setType( "java.lang.String"); |
| if( ! setters.contains(att)) |
| ai.setWriteable(false); |
| mbean.addAttribute(ai); |
| } |
| for( int i=0; i<setters.size(); i++ ) { |
| String att=(String)setters.get(i); |
| if( getters.contains(att)) |
| continue; |
| // Register metadata |
| ai=new AttributeInfo(); |
| ai.setName( att ); |
| ai.setType( "java.lang.String"); |
| ai.setReadable(false); |
| mbean.addAttribute(ai); |
| } |
| for( int i=0; i<methods.size(); i++ ) { |
| String att=(String)methods.get(i); |
| // Register metadata |
| OperationInfo oi=new OperationInfo(); |
| oi.setName( att ); |
| oi.setReturnType("void"); |
| mbean.addOperation(oi); |
| } |
| |
| this.setModelMBeanInfo(mbean.createMBeanInfo()); |
| |
| MBeanServer mserver=Registry.getRegistry().getMBeanServer(); |
| oname=new ObjectName("apache:type=" + type + ",id=" + id); |
| mserver.registerMBean(this, oname); |
| } |
| |
| private void update( String name, String val ) { |
| log.debug( "Updating " + jkName + " " + name + " " + val); |
| atts.put( name, val); |
| } |
| |
| public Object getAttribute(String name) |
| throws AttributeNotFoundException, MBeanException, |
| ReflectionException { |
| if( "jkName".equals( name )) { |
| return jkName; |
| } |
| jkmx.refresh(); |
| return atts.get(name); |
| } |
| |
| public void setAttribute(Attribute attribute) |
| throws AttributeNotFoundException, MBeanException, |
| ReflectionException |
| { |
| try { |
| // we support only string values |
| String val=(String)attribute.getValue(); |
| String name=attribute.getName(); |
| BufferedReader is=jkmx.getStream("set=" + jkName + "|" + |
| name + "|" + val); |
| if( is==null ) return; |
| String res=is.readLine(); |
| if( log.isDebugEnabled()) |
| log.debug( "Setting " + jkName + " " + name + " result " + res); |
| |
| jkmx.refreshMetadata(); |
| jkmx.refreshAttributes(); |
| } catch( Exception ex ) { |
| throw new MBeanException(ex); |
| } |
| } |
| |
| public Object invoke(String name, Object params[], String signature[]) |
| throws MBeanException, ReflectionException { |
| try { |
| // we support only string values |
| BufferedReader is=jkmx.getStream("inv=" + jkName + "|" + |
| name ); |
| if( is==null ) return null; |
| String res=is.readLine(); |
| if( log.isDebugEnabled()) |
| log.debug( "Invoking " + jkName + " " + name + " result " + res); |
| |
| jkmx.refreshMetadata(); |
| jkmx.refreshAttributes(); |
| } catch( Exception ex ) { |
| throw new MBeanException(ex); |
| } |
| return null; |
| } |
| |
| } |
| |
| |
| } |
| |