Java tutorial
/* * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * * [Additional notices, if required by prior licensing conditions] * */ 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; } } }