/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.openejb.monitoring.remote; import org.apache.openejb.OpenEJBRuntimeException; import org.apache.openejb.monitoring.LocalMBeanServer; import org.apache.openejb.monitoring.ObjectNameBuilder; import javax.management.Attribute; import javax.management.AttributeList; import javax.management.AttributeNotFoundException; import javax.management.DynamicMBean; import javax.management.InvalidAttributeValueException; import javax.management.MBeanAttributeInfo; import javax.management.MBeanException; import javax.management.MBeanInfo; import javax.management.MBeanNotificationInfo; import javax.management.MBeanOperationInfo; import javax.management.MBeanParameterInfo; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.ReflectionException; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.TimeUnit; public class RemoteResourceMonitor implements DynamicMBean { private static final String PING = "ping"; private static final AttributeList ATTRIBUTE_LIST = new AttributeList(); private static final MBeanAttributeInfo[] EMPTY_ATTRIBUTES = new MBeanAttributeInfo[0]; private static final MBeanNotificationInfo[] EMPTY_NOTIFICATIONS = new MBeanNotificationInfo[0]; private static final MBeanParameterInfo[] EMPTY_PARAMETERS = new MBeanParameterInfo[0]; private static final MBeanOperationInfo PING_INFO = new MBeanOperationInfo("ping", "ping the parameter host", new MBeanParameterInfo[]{ new MBeanParameterInfo("host", String.class.getName(), "the host to ping") }, String.class.getName(), MBeanOperationInfo.INFO); private final Collection<String> hosts = new CopyOnWriteArraySet<String>(); private ObjectName objectName; private MBeanInfo info; public synchronized void addHost(final String host) { hosts.add(host); buildMBeanInfo(); } public synchronized void removeHost(final String host) { hosts.remove(host); buildMBeanInfo(); } public void registerIfNot() { // do it lazily if (objectName != null) { return; } final ObjectNameBuilder jmxName = new ObjectNameBuilder("openejb.management"); jmxName.set("ObjectType", "Related Hosts"); objectName = jmxName.build(); final MBeanServer server = LocalMBeanServer.get(); try { if (server.isRegistered(objectName)) { server.unregisterMBean(objectName); } server.registerMBean(this, objectName); } catch (final Exception e) { throw new OpenEJBRuntimeException(e); } } public void unregister() { try { LocalMBeanServer.get().unregisterMBean(objectName); } catch (final Exception e) { throw new OpenEJBRuntimeException(e); } } @Override public Object invoke(final String actionName, final Object[] params, final String[] signature) throws MBeanException, ReflectionException { if (hosts.contains(actionName)) { return ping(actionName); } else if (PING.equals(actionName) && params != null && params.length == 1) { return ping((String) params[0]); } throw new MBeanException(new IllegalArgumentException(), actionName + " doesn't exist"); } @Override public MBeanInfo getMBeanInfo() { if (info == null) { buildMBeanInfo(); } return info; } @Override public Object getAttribute(final String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException { throw new AttributeNotFoundException(); } @Override public void setAttribute(final Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException { throw new AttributeNotFoundException(); } @Override public AttributeList getAttributes(final String[] attributes) { return ATTRIBUTE_LIST; } @Override public AttributeList setAttributes(final AttributeList attributes) { return ATTRIBUTE_LIST; } private void buildMBeanInfo() { final List<MBeanOperationInfo> operationInfos = new ArrayList<MBeanOperationInfo>(); for (final String host : hosts) { operationInfos.add(new MBeanOperationInfo(host, "ping host " + host, EMPTY_PARAMETERS, String.class.getName(), MBeanOperationInfo.INFO)); } operationInfos.add(PING_INFO); info = new MBeanInfo(RemoteResourceMonitor.class.getName(), "Monitor remote resources", EMPTY_ATTRIBUTES, null, operationInfos.toArray(new MBeanOperationInfo[operationInfos.size()]), EMPTY_NOTIFICATIONS); } private static String ping(final String host) { try { final InetAddress address = InetAddress.getByName(host); boolean ok = address.isReachable(30000); if (ok) { // do it twice since the first one is generally longer final long start = System.nanoTime(); ok = address.isReachable(30000); final long end = System.nanoTime(); if (ok) { final long duration = end - start; final long ms = TimeUnit.NANOSECONDS.toMillis(duration); return "Ping done in " + ms + "." + Long.toString(duration - 1000 * ms) + " ms"; } } return "Can't ping host, timeout (30s)"; } catch (final UnknownHostException e) { return "Can't find host: " + e.getMessage(); } catch (final IOException e) { return "Can't ping host: " + e.getMessage(); } } }