Java tutorial
/* * Copyright 2002-2011 Greg Hinkle * * 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.mc4j.ems.impl.jmx.connection; import java.util.ArrayList; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedMap; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; import javax.management.MBeanException; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.ObjectInstance; import javax.management.ObjectName; import javax.management.OperationsException; import javax.management.QueryExp; import javax.management.ReflectionException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.mc4j.ems.connection.ConnectionTracker; import org.mc4j.ems.connection.EmsConnection; import org.mc4j.ems.connection.EmsException; import org.mc4j.ems.connection.EmsMalformedObjectNameException; import org.mc4j.ems.connection.EmsUnsupportedTypeException; import org.mc4j.ems.connection.MBeanRegistrationEvent; import org.mc4j.ems.connection.MBeanRegistrationListener; import org.mc4j.ems.connection.bean.EmsBean; import org.mc4j.ems.connection.support.ConnectionProvider; import org.mc4j.ems.impl.jmx.connection.bean.DAdvancedBean; import org.mc4j.ems.impl.jmx.connection.bean.DMBean; import org.mc4j.ems.impl.jmx.connection.support.providers.AbstractConnectionProvider; /** * TODO GH: Decide exception handling strategy (runtime?) * * @author Greg Hinkle (ghinkle@users.sourceforge.net), Apr 4, 2005 * @version $Revision: 629 $($Author: ianpspringer $ / $Date: 2011-10-28 23:44:26 +0200 (Fr, 28 Okt 2011) $) */ public class DConnection implements EmsConnection { private static Log log = LogFactory.getLog(DConnection.class); protected String connectionName; protected AbstractConnectionProvider connectionProvider; protected SortedMap<DObjectName, EmsBean> beanMap; protected boolean loaded; // TODO Do this with 1.4 support // protected PooledConnectionTracker tracker; protected List<MBeanRegistrationListener> registrationListeners = new ArrayList<MBeanRegistrationListener>(); public DConnection(String connectionName, ConnectionProvider connectionProvider) { this.connectionName = connectionName; this.connectionProvider = (AbstractConnectionProvider) connectionProvider; beanMap = new TreeMap<DObjectName, EmsBean>(new DObjectNameComparator()); // this.tracker = new PooledConnectionTracker(this); } public void setConnectionProvider(AbstractConnectionProvider connectionProvider) { this.connectionProvider = connectionProvider; } public ConnectionTracker getTracker() { // return tracker; return null; } public void refresh() { try { loadSynchronous(false); } catch (Exception e) { log.warn("Could not refresh connection [" + connectionProvider.getConnectionSettings().getServerUrl() + "] " + e.toString(), e); } } public void close() { // tracker.stopTracker(); connectionProvider.disconnect(); LogFactory.release(connectionProvider.getClass().getClassLoader()); } /* TODO: Check WebLogic <= 8.1 This was how mc4j worked since weblogic <= 8.1 won't allow a null search on queryNames, but will on queryMBeans if (connectionSettings.getConnectionType() instanceof WeblogicConnectionTypeDescriptor) { Set objectInstances = server.queryMBeans(null,null); objectNames = new HashSet(); for (Iterator iterator = objectInstances.iterator(); iterator.hasNext();) { ObjectInstance objectInstance = (ObjectInstance) iterator.next(); objectNames.add(objectInstance.getObjectName()); } } else { objectNames = server.queryNames(null,null); }*/ @SuppressWarnings({ "unchecked" }) public synchronized void loadSynchronous(boolean deep) { if (!connectionProvider.isConnected()) connectionProvider.connect(); log.info("Querying MBeanServer for all MBeans..."); MBeanServer mBeanServer = connectionProvider.getMBeanServer(); Set<ObjectName> objectNames = null; try { objectNames = (Set<ObjectName>) mBeanServer.queryNames(new ObjectName("*:*"), null); } catch (MalformedObjectNameException e) { /* Should never happen */ } SortedMap<ObjectName, DMBean> retrievedBeansMap = new TreeMap<ObjectName, DMBean>( new ObjectNameComparator()); if (!loaded) { log.info("Found " + objectNames.size() + " MBeans - starting load..."); } Set<DObjectName> currentKeys = new HashSet<DObjectName>(this.beanMap.keySet()); for (ObjectName objectName : objectNames) { // TODO: We're loading the beans on every run here i think... only load it if its not in the beanMap DMBean bean = mapBean(objectName, deep); retrievedBeansMap.put(objectName, bean); } Set<EmsBean> newBeans = new HashSet<EmsBean>(); Set<EmsBean> removedBeans = new HashSet<EmsBean>(); for (Map.Entry<ObjectName, DMBean> entry : retrievedBeansMap.entrySet()) { if (!currentKeys.contains(entry.getKey())) { newBeans.add(entry.getValue()); } } for (DObjectName name : currentKeys) { if (!retrievedBeansMap.containsKey(name.getObjectName())) { removedBeans.add(beanMap.remove(name)); } } if (loaded && log.isDebugEnabled()) { log.debug("Added " + newBeans.size() + " and removed " + removedBeans.size() + " since previous load."); } loaded = true; fireRegistrationEvent(newBeans, removedBeans); } public void unload() { for (EmsBean bean : beanMap.values()) { bean.unload(); } } static boolean isJMX12 = false; static { try { Class.forName("javax.management.MBeanServerInvocationHandler"); isJMX12 = true; } catch (ClassNotFoundException e) { } } private DMBean mapBean(ObjectName objectName, boolean loadSynchronous) { DMBean bean = null; DObjectName dObjectName = new DObjectName(objectName); // If the bean is unknown to the internal map, create our local representation and add it synchronized (this) { if (!this.beanMap.keySet().contains(dObjectName)) { if (isJMX12) { bean = new DAdvancedBean(connectionProvider, objectName); } else { bean = new DMBean(connectionProvider, objectName); } beanMap.put(dObjectName, bean); } } // If the bean was just created then optional load its metadata synchronously // Do this outside the synchronized block if (bean != null && loadSynchronous) { try { bean.loadSynchronous(); } catch (EmsUnsupportedTypeException e) { // Keep loading other beans even if one has an unsupported type log.info("Bean metadata not loaded, unsupported type on [" + objectName.toString() + "]", e); } } if (bean == null) { return (DMBean) this.beanMap.get(dObjectName); } else { return bean; } } private void fireRegistrationEvent(Set<EmsBean> added, Set<EmsBean> removed) { if (!registrationListeners.isEmpty()) { MBeanRegistrationEvent event = new MBeanRegistrationEvent(added, removed); for (MBeanRegistrationListener listener : registrationListeners) { listener.registrationChanged(event); } } } public synchronized void addRegistrationListener(MBeanRegistrationListener registrationListener) { registrationListeners.add(registrationListener); } public synchronized void removeRegistrationListener(MBeanRegistrationListener registrationListener) { registrationListeners.remove(registrationListener); } /** * This will register a new MBean, but that may not be immediately recognized * * @param className * @param objectName */ public void createMBean(String className, String objectName) throws EmsException { ObjectName on = null; try { on = new ObjectName(objectName); connectionProvider.getMBeanServer().createMBean(className, on); } catch (Exception e) { throw new EmsException("Could not create MBean", e); } // TODO: Shouldn't we add the MBean to our map too? } public void removeMBean(String objectName) throws EmsException { ObjectName on = null; try { on = new ObjectName(objectName); connectionProvider.getMBeanServer().unregisterMBean(on); } catch (Exception e) { throw new EmsException("Could not remove MBean", e); } // TODO: Shouldn't we remove the MBean from our map too? } public synchronized SortedSet<EmsBean> getBeans() { if (!loaded) { refresh(); } return new TreeSet<EmsBean>(beanMap.values()); } protected EmsBean getBean(ObjectName objectName) { return this.beanMap.get(new DObjectName(objectName)); } public EmsBean getBean(String objectName) { try { ObjectName name = new ObjectName(objectName); return getBean(name); } catch (MalformedObjectNameException e) { throw new EmsMalformedObjectNameException("Invalid ObjectName [" + objectName + "]", e); } } /** * This will run the query, creating our internal bean representation * as needed and return the full list of both previously and newly * mapped beans from the corresponding query. * * @param objectName * @param query * @return The list of EmsBeans representing mbeans that match the query */ @SuppressWarnings({ "unchecked" }) public List<EmsBean> queryBeans(ObjectName objectName, QueryExp query) { Set<ObjectName> objectNames = (Set<ObjectName>) connectionProvider.getMBeanServer().queryNames(objectName, query); List<EmsBean> results = new ArrayList<EmsBean>(); for (ObjectName name : objectNames) { results.add(mapBean(name, false)); } return results; } /** * Utility to perform a query without ObjectName in your classpath * * @param objectName * @return the list of EmsBeans matching your query * @throws RuntimeException when the ObjectName is not valid */ public List<EmsBean> queryBeans(String objectName) { try { ObjectName name = null; if (objectName != null) name = new ObjectName(objectName); return queryBeans(name, null); } catch (MalformedObjectNameException e) { throw new RuntimeException("Illegal ObjectName " + objectName, e); } } public EmsBean registerBean(String className, String objectName) { try { ObjectName objName = new ObjectName(objectName); ObjectInstance instance = connectionProvider.getMBeanServer().createMBean(className, objName); return mapBean(instance.getObjectName(), false); } catch (MBeanException e) { e.printStackTrace(); throw new EmsException("Couldn't create MBean", e); } catch (OperationsException e) { throw new EmsException("Couldn't create MBean", e); } catch (ReflectionException e) { throw new EmsException("Couldn't create MBean", e); } } public EmsBean registerBean(String className, String objectName, Object[] params, String[] signature) { try { ObjectName objName = new ObjectName(objectName); ObjectInstance instance = connectionProvider.getMBeanServer().createMBean(className, objName, params, signature); return mapBean(instance.getObjectName(), false); } catch (MBeanException e) { e.printStackTrace(); throw new EmsException("Couldn't create MBean", e); } catch (OperationsException e) { throw new EmsException("Couldn't create MBean", e); } catch (ReflectionException e) { throw new EmsException("Couldn't create MBean", e); } } public long getRoundTrips() { return connectionProvider.getRoundTrips(); } public long getFailures() { return connectionProvider.getFailures(); } public Object buildObjectName(String objectName) throws EmsMalformedObjectNameException { try { return new ObjectName(objectName); } catch (MalformedObjectNameException e) { throw new EmsMalformedObjectNameException("Object Name not valid [" + objectName + "]", e); } } private static class ObjectNameComparator implements Comparator { public int compare(Object o1, Object o2) { return o1.toString().compareTo(o2.toString()); } } public ConnectionProvider getConnectionProvider() { return connectionProvider; } /** * Some object name implementations are not equal if the properties are in different orders. * The RI compares cannonical property forms as expected, JBoss is broken. * * This class is a key to search and get around that potential issue by always key on * the cannoical form, but ordering by the default form. */ public static class DObjectName { private ObjectName objectName; public DObjectName(ObjectName objectName) { this.objectName = objectName; } public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; final DObjectName that = (DObjectName) o; return objectName.getCanonicalName().equals(that.objectName.getCanonicalName()); } public int hashCode() { return objectName.getCanonicalName().hashCode(); } public int compareTo(DObjectName o) { return toString().compareTo(o.toString()); } public String toString() { return objectName.toString(); } public ObjectName getObjectName() { return objectName; } } public static class DObjectNameComparator implements Comparator<DObjectName> { public int compare(DObjectName o1, DObjectName o2) { return o1.getObjectName().getCanonicalName().compareTo(o2.getObjectName().getCanonicalName()); } } }