/* * JBoss, Home of Professional Open Source. * Copyright 2008, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.test.mx.remoting.pingpong; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Timer; import java.util.TimerTask; import javax.management.AttributeChangeNotification; import javax.management.ListenerNotFoundException; import javax.management.MBeanException; import javax.management.MBeanNotificationInfo; import javax.management.MBeanRegistration; import javax.management.MBeanServer; import javax.management.Notification; import javax.management.NotificationFilter; import javax.management.NotificationListener; import javax.management.ObjectName; import org.jboss.logging.Logger; import org.jboss.mx.remoting.MBeanLocator; import org.jboss.mx.remoting.tracker.MBeanTracker; import org.jboss.mx.remoting.tracker.MBeanTrackerAction; import org.jboss.mx.util.JBossNotificationBroadcasterSupport; import org.jboss.remoting.ConnectionFailedException; import org.jboss.remoting.ident.Identity; /** * PingPong is a simple test mbean that will call ping on other peers * in the JBoss remoting network and will fire a notification and * an attribute change notification when ping is invoked back to listeners. * * @author <a href="mailto:jhaynie@vocalocity.net">Jeff Haynie</a> * @version $Revision: 81023 $ */ public class PingPong implements PingPongMBean, MBeanTrackerAction, MBeanRegistration { private static final transient Logger log = Logger.getLogger(PingPong.class.getName()); private MBeanTracker tracker; private Timer timer=new Timer(false); private Map friends=new HashMap(); private MBeanServer server; private ObjectName objectName; private JBossNotificationBroadcasterSupport broadcaster=new JBossNotificationBroadcasterSupport(); public Object ping (Object pong) { Notification notification = new Notification("pong",objectName,System.currentTimeMillis()); broadcaster.sendNotification(notification); log.debug("ping called: "+pong+", sending notification: "+notification+" for objectName: "+objectName); Notification stateChange = new AttributeChangeNotification(objectName,System.currentTimeMillis(),System.currentTimeMillis(),"State Changed","State",Integer.class.getName(),new Integer(1),new Integer(2)); broadcaster.sendNotification(stateChange); return pong; } /** * Add a listener to an MBean. * * @param listener implementation of the listener object * @param filter implementation of the filter object or <tt>null</tt> * if no filtering is required * @param handback A handback object associated with each notification * sent by this notification broadcaster. * * @throws IllegalArgumentException if listener is <tt>null</tt> */ public void addNotificationListener ( NotificationListener listener, NotificationFilter filter, Object handback ) throws IllegalArgumentException { log.debug("addNotificationListener - listener: "+listener); broadcaster.addNotificationListener(listener,filter,handback); } /** * Removes a listener from an MBean. * * @param listener the listener object to remove * * @throws ListenerNotFoundException if the listener was not found */ public void removeNotificationListener ( NotificationListener listener ) throws ListenerNotFoundException { log.debug("removeNotificationListener - listener: "+listener); broadcaster.removeNotificationListener(listener); } /** * Returns the notification metadata associated with the MBean. * * @see MBeanNotificationInfo * * @return MBean's notification metadata */ public MBeanNotificationInfo[] getNotificationInfo () { return new MBeanNotificationInfo[0]; } /** * This method is called by the MBeanServer after deregistration takes * place. */ public void postDeregister () { } /** * This method is called by the MBeanServer after registration takes * place or when registration fails. * * @param registrationDone the MBeanServer passes true when the * MBean was registered, false otherwise. */ public void postRegister (Boolean registrationDone) { } /** * This method is called by the MBeanServer before deregistration takes * place.<p> * * The MBean can throw an exception, this will stop the deregistration. * The exception is forwarded to the invoker wrapped in * an MBeanRegistrationException. */ public void preDeregister () throws Exception { stop(); } /** * This method is called by the MBeanServer before registration takes * place. The MBean is passed a reference of the MBeanServer it is * about to be registered with. The MBean must return the ObjectName it * will be registered with. The MBeanServer can pass a suggested object * depending upon how the MBean is registered.<p> * * The MBean can stop the registration by throwing an exception.The * exception is forwarded to the invoker wrapped in an * MBeanRegistrationException. * * @param MBeanServer the MBeanServer the MBean is about to be * registered with. * @param ObjectName the suggested ObjectName supplied by the * MBeanServer. * @return the actual ObjectName to register this MBean with. * @exception Exception for any error, the MBean is not registered. */ public ObjectName preRegister (MBeanServer server, ObjectName name) throws Exception { this.server = server; this.objectName = name; start(); return name; } /** * Describe <code>start</code> method here. * * @jmx.managed-operation description="Second lifecycle method called after mbeans attributes are set. During this method declared mbean dependencies are available and may be used. After completion the mbean should be completely usable." * impact="ACTION" */ public void start () throws Exception { tracker = new MBeanTracker(server,new Class[]{PingPongMBean.class},null,false,null,true,this); timer.scheduleAtFixedRate(new Pinger(),5000L,5000L); } /** * Describe <code>stop</code> method here. * * @jmx.managed-operation description="First shutdown lifecycle method. This method should undo the effects of start" * impact="ACTION" */ public void stop () { if (tracker!=null) { tracker.destroy(); tracker=null; } } /** * called when a mbean notification is fired * * @param locator * @param notification * @param handback */ public void mbeanNotification (MBeanLocator locator, Notification notification, Object handback) { log.info("received notification from: "+locator+", notification: "+notification); } /** * called when an MBean is registered with the MBeanServer * * @param locator */ public void mbeanRegistered (MBeanLocator locator) { if (Identity.get(server).equals(locator.getIdentity())) { // ignore myself return; } log.info("found a new friend to play ping pong with: "+locator); PingPongMBean friend=null; try { friend=(PingPongMBean)locator.narrow(PingPongMBean.class); } catch (Exception e) { log.error("error casting my friend to PingPongMBean - his locator is: "+locator,e); return; } synchronized(friends) { friends.put(locator,friend); } } /** * called when the mbean state changes. Note: this method will only be called on MBeans that have a * <tt>State</tt> attribute and where state change attribute notifications are fired * * @param locator * @param oldState * @param newState */ public void mbeanStateChanged (MBeanLocator locator, int oldState, int newState) { log.info("one of my partners ("+locator+") changed its state from: "+oldState+" to: "+newState); } /** * called when an MBean is unregistered with the MBeanServer * * @param locator */ public void mbeanUnregistered (MBeanLocator locator) { log.info("I lost a friend, "+locator); friends.remove(locator); } final class Pinger extends TimerTask { /** * The action to be performed by this timer task. */ public void run () { Map copy = null; synchronized (friends) { copy = new HashMap(friends); } if (copy.isEmpty()) { log.info("I don't have any friends on the network, how boring..."); return; } Iterator iter = copy.keySet().iterator(); Integer myhash=new Integer(hashCode()); while(iter.hasNext()) { MBeanLocator l=(MBeanLocator)iter.next(); try { Object obj = l.getServerLocator().getMBeanServer().invoke(l.getObjectName(),"ping",new Object[]{myhash},new String[]{Object.class.getName()}); //PingPongMBean friend=(PingPongMBean)copy.get(l); log.info("pinging my friend at: "+l+", with: "+myhash); // send my friend a ping //Object obj = friend.ping(myhash); if (!obj.equals(myhash)) { log.warn("My friend passed me back something I don't understand?! I passed him: "+myhash+", I received: "+obj); } } catch (Throwable ex) { if (ex instanceof MBeanException) { MBeanException mbe=(MBeanException)ex; if (mbe.getTargetException() instanceof ConnectionFailedException) { log.info("my friend died during a ping, "+l); return; } } log.warn("My friend doesn't like me, he gave me an exception back",ex); } } copy=null; } } }