001    // jademx - JADE management using JMX
002    // Copyright 2005-2006 Caboodle Networks, Inc.
003    //
004    // This library is free software; you can redistribute it and/or
005    // modify it under the terms of the GNU Lesser General Public
006    // License as published by the Free Software Foundation; either
007    // version 2.1 of the License, or (at your option) any later version.
008    //
009    // This library is distributed in the hope that it will be useful,
010    // but WITHOUT ANY WARRANTY; without even the implied warranty of
011    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
012    // Lesser General Public License for more details.
013    //
014    // You should have received a copy of the GNU Lesser General Public
015    // License along with this library; if not, write to the Free Software
016    // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
017    
018    package jade.jademx.mbean;
019    
020    import java.util.Arrays;
021    import java.util.LinkedList;
022    
023    import javax.management.Attribute;
024    import javax.management.AttributeList;
025    import javax.management.ListenerNotFoundException;
026    import javax.management.MBeanAttributeInfo;
027    import javax.management.MBeanInfo;
028    import javax.management.MBeanNotificationInfo;
029    import javax.management.MBeanOperationInfo;
030    import javax.management.Notification;
031    import javax.management.NotificationListener;
032    import javax.management.ObjectName;
033    import javax.management.ReflectionException;
034    
035    import jade.jademx.JadeMXSuiteTest;
036    import jade.jademx.agent.Arg;
037    import jade.jademx.agent.JademxAgent;
038    import jade.jademx.agent.JademxPingAgent;
039    import jade.jademx.server.JadeMXServer;
040    import jade.jademx.server.JadeMXServerFactory;
041    import jade.wrapper.AgentState;
042    import junit.framework.Test;
043    import junit.framework.TestCase;
044    import junit.framework.TestSuite;
045    
046    /** 
047     * JadeAgent MBean test
048     * @author David Bernstein, <a href="http://www.caboodlenetworks.com"
049     *  >Caboodle Networks, Inc.</a>
050     */
051    public class JadeAgentTest extends TestCase  implements NotificationListener {
052        
053        ///** test(suite) name */
054        //private static String name = 
055        //    JadeMXSuiteTest.nameWithClass( 
056        //            JadePlatformTest.class, 
057        //                  "testing JadeAgent: JADE agent MBean class");
058        
059        
060        /** jadeMXServer we're using */
061        private JadeMXServer jadeMXServer = null;
062        
063        /** runtime for test use */
064        private JadeRuntime jadeRuntime = null;
065    
066        /** mbean for platform under test */
067        JadePlatform platformMBean = null;
068    
069        ///** resource name for configuration of one empty platform */
070        //private static final String EMPTY_PLATFORM_CONFIG_RESOURCE =
071        //    "jade/jademx/config/one-empty-platform.xml";
072        /** resource name for configuration of two ping agents */
073        private static final String TWO_PING_CONFIG_RESOURCE =
074            "jade/jademx/config/two-ping-agents.xml";
075        /** name for 1st ping agent */
076        private static final String AGENT_LOCAL_NAME_PINGER1 = "pinger1";
077        /** name for 2nd ping agent */
078        private static final String AGENT_LOCAL_NAME_PINGER2 = "pinger2";
079    
080        
081        // tests
082        
083        
084        /* (non-Javadoc)
085         * @see junit.framework.TestCase#setUp()
086         */
087        protected void setUp() throws Exception {
088            // first get JadeMXServer
089            jadeMXServer = JadeMXServerFactory.jadeMXServerBySysProp();
090            // now get a factory to use
091            JadeFactory jadeFactory = 
092                new JadeFactory( jadeMXServer );
093            jadeRuntime = (JadeRuntime)jadeFactory.runtimeInstance();
094            //JadeMXSuiteTest.listMBeans(mBeanServer, "at end of setUp()");
095            JadePlatform platformMBeans[] = 
096                jadeRuntime.platformsFromConfigResource( 
097                        TWO_PING_CONFIG_RESOURCE );
098            platformMBean = platformMBeans[0];
099            notificationQueue = new LinkedList();
100        }
101        
102        
103        
104        /* (non-Javadoc)
105         * @see junit.framework.TestCase#tearDown()
106         */
107        protected void tearDown() throws Exception {
108            //JadeMXSuiteTest.listMBeans(mBeanServer,
109            //"at start of JadePlatformTest.tearDown()");
110            if ( null != jadeRuntime ) {
111                jadeRuntime.shutdown();
112            }
113            //JadeMXSuiteTest.listMBeans(mBeanServer,
114            //"at end of JadePlatformTest.tearDown()");
115        }
116        
117        
118        /** a queue for notifications */
119        private LinkedList notificationQueue = null;
120        /* (non-Javadoc)
121         * @see javax.management.NotificationListener#handleNotification(
122         * javax.management.Notification, java.lang.Object)
123         */
124        public void handleNotification(Notification notification, Object handback) {
125            //System.err.println("JadeAgentTest.handleNotification(): "+
126            // "got notification "+notification);        
127            synchronized ( notificationQueue ) {
128                notificationQueue.addLast( notification );
129                notificationQueue.notifyAll();
130            }
131        }
132        /** expected arguments for pinger2 */
133        private final static Object PINGER2_ARGS_AS_OBJ = 
134            new Object[] {"foo","bar",new Arg("baz")};
135        private final static Object PINGER2_ARGS_AS_ARR[] =
136            (Object[])PINGER2_ARGS_AS_OBJ;
137        
138        /**
139         * test getting agent's arguments
140         * @throws JademxException unexpected problems with jademx
141         */
142        public void testGetArguments() throws JademxException {
143            int ARG_COUNT = PINGER2_ARGS_AS_ARR.length;
144            String ARG0 = (String)PINGER2_ARGS_AS_ARR[0];
145            String ARG1 = (String)PINGER2_ARGS_AS_ARR[1];
146            Arg    ARG2 = (Arg)   PINGER2_ARGS_AS_ARR[2];
147            JadeAgent jadeAgent = platformMBean.getAgent( AGENT_LOCAL_NAME_PINGER2);
148            Object args[] = jadeAgent.getArguments();
149            int argLen = args.length;
150            assertEquals("expected 3 arguments but found "+argLen, 
151                    ARG_COUNT, argLen );
152            assertEquals("expected argument 0 to be \""+
153                    ARG0+"\" but it's \""+args[0], ARG0, args[0]);
154            assertEquals("expected argument 1 to be \""+
155                    ARG1+"\" but it's \""+args[1], ARG1, args[1]);
156            assertEquals("expected argument 2 to be "+
157                    ARG2+" but it's \""+args[2], ARG2, args[2]);
158        }
159      
160        /** expected class name for pinger2 agent */
161        private final String PINGER2_CLASS_NAME = 
162            JademxPingAgent.class.getName();
163        
164        /**
165         * test getting agent's classname
166         * @throws JademxException unexpected problems with jademx
167         */
168        public void testGetClassName() throws JademxException  {
169            JadeAgent jadeAgent = platformMBean.getAgent( AGENT_LOCAL_NAME_PINGER2);
170            String actualCN = jadeAgent.getClassName();
171            assertEquals("expected agent class name \""+PINGER2_CLASS_NAME+
172                    "\" but got \""+actualCN+"\"",PINGER2_CLASS_NAME,actualCN);
173        }
174        
175        
176        /**
177         * test getting agent's local name
178         * @throws JademxException unexpected problems with jademx
179         */
180        public void testGetLocalName() throws JademxException  {
181            JadeAgent jadeAgent = platformMBean.getAgent( AGENT_LOCAL_NAME_PINGER2);
182            String actualLN = jadeAgent.getLocalName();
183            assertEquals("expected agent local name \""+AGENT_LOCAL_NAME_PINGER2+
184                    "\" but got \""+actualLN+"\"",
185                    AGENT_LOCAL_NAME_PINGER2,actualLN);
186        }
187        
188        /** expected string MBean name for pinger2 agent */
189        private final static String PINGER2_EXPECTED_PLATFORM_OBJECT_NAME_STRING = 
190            "jade:Name=platform0,Runtime=default,Type=Platform";
191        
192        /**
193         * test getting agent's platform's object name string
194         * @throws JademxException unexpected problems with jademx
195         */
196        public void testGetPlatformObjectNameString() throws JademxException  {
197            JadeAgent jadeAgent = platformMBean.getAgent( AGENT_LOCAL_NAME_PINGER2);
198    
199            String actualPN = jadeAgent.getPlatformObjectNameString();
200            assertEquals("expected platform ObjectName string \""+
201                    PINGER2_EXPECTED_PLATFORM_OBJECT_NAME_STRING+
202                    "\" but got \""+actualPN+"\"",
203                    PINGER2_EXPECTED_PLATFORM_OBJECT_NAME_STRING,actualPN);
204        }
205        
206        /** expected full JADE name name for pinger2 agent */
207        private String pinger2ExpectedFullName() {
208            String platformJadeName = platformMBean.getPlatformName();
209            String expectedFN = AGENT_LOCAL_NAME_PINGER2 + "@" + platformJadeName;
210            return expectedFN;
211        }
212        
213        /**
214         * test getting agent's full JADE name 
215         * @throws JademxException unexpected problems with jademx
216         */
217        public void testGetFullName() throws JademxException {
218            JadeAgent jadeAgent = platformMBean.getAgent( AGENT_LOCAL_NAME_PINGER2);
219            //String platformJadeName = platformMBean.getPlatformName();
220            String agentFullJadeName = jadeAgent.getFullName();
221            String expectedFN = pinger2ExpectedFullName();
222            assertEquals("expected full name \""+expectedFN+"\" but got \""+
223                    agentFullJadeName + "\"", expectedFN, agentFullJadeName );
224        }
225        
226        /**
227         * test getting agent's JADE state code 
228         * @throws JademxException unexpected problems with jademx
229         */
230        public void testGetStateCode() throws JademxException {
231            JadeAgent jadeAgent = platformMBean.getAgent( AGENT_LOCAL_NAME_PINGER2);
232            int actualStateCode = jadeAgent.getStateCode();
233            if ( ( actualStateCode != AgentState.cAGENT_STATE_INITIATED ) &&
234                 ( actualStateCode != AgentState.cAGENT_STATE_ACTIVE    ) &&
235                 ( actualStateCode != AgentState.cAGENT_STATE_IDLE      ) ) {
236                fail("expected state code "+AgentState.cAGENT_STATE_INITIATED+
237                        " or "+AgentState.cAGENT_STATE_ACTIVE+
238                        " or "+AgentState.cAGENT_STATE_IDLE+
239                        " but got "+
240                        actualStateCode);
241            }
242        }    
243        
244        /**
245         * test getting agent's state JADE name 
246         * @throws JademxException unexpected problems with jademx
247         */
248        public void testGetStateName() throws JademxException {
249            JadeAgent jadeAgent = platformMBean.getAgent( AGENT_LOCAL_NAME_PINGER2);
250            String actualStateName = jadeAgent.getStateName();
251            final String initiated = "Initiated";
252            final String active = "Active";
253            final String idle = "Idle";
254            if ( !initiated.equals( actualStateName ) &&
255                 !active.equals( actualStateName    ) &&
256                 !idle.equals( actualStateName      ) ) {
257                fail("expected state name \""+initiated+
258                        "\" or \""+active+
259                        "\" or \""+idle+
260                        "\" but got \""+
261                        actualStateName+"\"");
262            }
263        } 
264        
265        
266        /**
267         * test getting name property for the agent mbean
268         * @throws JademxException unexpected problems with jademx
269         */
270        public void testAgentNameProp() throws JademxException {
271            JadeAgent jadeAgent = platformMBean.getAgent( AGENT_LOCAL_NAME_PINGER2);
272            String nameProp = jadeAgent.getMBeanNamePropVal();
273            assertEquals("expected JadeAgent name property to be local name \""+
274                    AGENT_LOCAL_NAME_PINGER2+"\" but it's \""+
275                    nameProp, 
276                    AGENT_LOCAL_NAME_PINGER2, nameProp );
277        }
278        
279        /**
280         * test killing an agent
281         * @throws JademxException unexpected problems with jademx
282         */
283        public void testAgentKill() throws JademxException {
284            JadeAgent jadeAgent = platformMBean.getAgent( AGENT_LOCAL_NAME_PINGER2);
285            jadeAgent.kill(); 
286            // killing an agent is asynchronous and so may not see evidence
287            // of it immediately
288        }
289        
290        /** string verion of expected MBean name for pinger2 agent */
291        private final static String PINGER2_EXPECTED_MBEAN_NAME_STRING = 
292            "jade:Name=pinger2,Platform=platform0,Runtime=default,Type=Agent";
293        
294        
295        /**
296         * test MBeanInfo for agent
297         * @throws JademxException unexpected problems with jademx
298         */
299        public void testAgentMBeanInfo() throws JademxException {
300            
301            // verify agent binding
302            JadeAgent jadeAgentPinger2 = 
303                platformMBean.getAgent( AGENT_LOCAL_NAME_PINGER2);
304            boolean boundPinger2 = 
305                jadeAgentPinger2.waitForJademxAgentBinding(59*1000/*59sec*/,0);
306            assertTrue("jademx agent didn't bind", boundPinger2);
307            
308            // exercise some other times for waiting
309            boundPinger2 = 
310                jadeAgentPinger2.waitForJademxAgentBinding(61*1000/*61sec*/,0);
311            assertTrue("jademx agent didn't bind", boundPinger2);
312            boundPinger2 = 
313                jadeAgentPinger2.waitForJademxAgentBinding(1,0);
314            assertTrue("jademx agent didn't bind", boundPinger2);
315            boundPinger2 = 
316                jadeAgentPinger2.waitForJademxAgentBinding(0,0);
317            assertTrue("jademx agent didn't bind", boundPinger2);
318            boundPinger2 = 
319                jadeAgentPinger2.waitForJademxAgentBinding(60*1000,1);//1min+1ns
320            assertTrue("jademx agent didn't bind", boundPinger2);
321            boundPinger2 = 
322                jadeAgentPinger2.waitForJademxAgentBinding(1000,1);//1ms+1ns
323            assertTrue("jademx agent didn't bind", boundPinger2);
324            boundPinger2 = 
325                jadeAgentPinger2.waitForJademxAgentBinding(0,1001);
326            assertTrue("jademx agent didn't bind", boundPinger2);
327            boundPinger2 = 
328                jadeAgentPinger2.waitForJademxAgentBinding(0,1);
329            assertTrue("jademx agent didn't bind", boundPinger2);
330            
331            // test bad nanosecond arguments
332            try {
333                jadeAgentPinger2.waitForJademxAgentBinding(0,-1);
334                fail("didn't raise IllegalArgumentException for bad nano -1");
335            }
336            catch ( IllegalArgumentException iae ) {
337                assertTrue(true);
338            }
339            try {
340                jadeAgentPinger2.waitForJademxAgentBinding(0,1000000);
341                fail("didn't raise IllegalArgumentException for bad nano 1000000");
342            }
343            catch ( IllegalArgumentException iae ) {
344                assertTrue(true);
345            }
346            // try nanosecond resolution expecting agent to be already bound
347            boundPinger2 = 
348                jadeAgentPinger2.waitForJademxAgentBinding(0,1);
349            assertTrue("jademx agent didn't bind when already bound with 1ns wait",
350                    boundPinger2);
351            
352            // verify expected feature counts
353            MBeanInfo mbi = jadeAgentPinger2.getMBeanInfo();
354            MBeanAttributeInfo mbais[] = mbi.getAttributes();
355            int aCount = mbais.length;
356            mbi.getDescription();
357            MBeanOperationInfo mbois[] = mbi.getOperations();
358            int oCount = mbois.length;
359            MBeanNotificationInfo mbnis[] = mbi.getNotifications();
360            int nCount = mbnis.length;
361            int nTypeCount = 0;
362            for ( int i = 0; i < nCount; i++ ) {
363                MBeanNotificationInfo mbni = mbnis[i];
364                String notifTypes[] = mbni.getNotifTypes();
365                nTypeCount += notifTypes.length;
366            }
367            final int EXPECTED_ATTR_COUNT = 34;
368            final int EXPECTED_OPER_COUNT = 5;
369            final int EXPECTED_NOTIF_COUNT = 3;
370            // ease future debugging
371            if ( EXPECTED_ATTR_COUNT != aCount ) {
372                for ( int i = 0; i < aCount; i++ ) {
373                    MBeanAttributeInfo mbai = mbais[i];
374                    System.err.println("attribute "+i+": "+mbai.getName()+"("+
375                            "type="+mbai.getType()+
376                            ",readable="+mbai.isReadable()+
377                            ",writable="+mbai.isWritable()+
378                            ")");
379                }
380            }
381            if ( EXPECTED_OPER_COUNT != oCount ) {
382                for ( int i = 0; i < oCount; i++ ) {
383                    MBeanOperationInfo mboi = mbois[i];
384                    System.err.println("operation "+i+": "+mboi.getName()+
385                            "(type="+mboi.getReturnType()+")");
386                }
387            }
388            if ( EXPECTED_NOTIF_COUNT != nTypeCount ) {
389                int nIndex = 0;
390                for ( int i = 0; i < nCount; i++ ) {
391                    MBeanNotificationInfo mbni = mbnis[i];
392                    String notifTypes[] = mbni.getNotifTypes();
393                    int nTypesCount = notifTypes.length;
394                    for ( int j = 0; j < nTypesCount; j++ ) {
395                        System.err.println("notification "+(nIndex++)+": "+mbni.getName()+
396                                ", type \""+notifTypes[j]+"\"");
397                    }
398                }
399            }
400            assertEquals("wrong number of attributes", EXPECTED_ATTR_COUNT, aCount);
401            assertEquals("wrong number of operations", EXPECTED_OPER_COUNT, oCount);
402            assertEquals("wrong number of notifications", EXPECTED_NOTIF_COUNT, 
403                    nTypeCount);
404            
405            // get all the attribute values
406            String aNames[] = new String[aCount];
407            for ( int i = 0; i < aCount; i++ ) {
408                aNames[i] = mbais[i].getName();
409            }
410            AttributeList aList = jadeAgentPinger2.getAttributes( aNames );
411            
412            // verify features, including attribute values
413            verifyAttr( mbi, JadeAgentMBeanDef.ATTR_ARGUMENTS, 
414                    Object[].class.getName(), true, false, aList, 
415                    PINGER2_ARGS_AS_OBJ );
416            verifyAttr( mbi, JadeAgentMBeanDef.ATTR_CLASS_NAME, 
417                    String.class.getName(), true, false, aList, 
418                    PINGER2_CLASS_NAME );
419            verifyAttr( mbi, JadeAgentMBeanDef.ATTR_LOCAL_NAME, 
420                    String.class.getName(), true, false, aList, 
421                    AGENT_LOCAL_NAME_PINGER2 );
422            verifyAttr( mbi, JadeAgentMBeanDef.ATTR_PLATFORM_OBJECT_NAME_STRING, 
423                    String.class.getName(), true, false, aList,
424                    PINGER2_EXPECTED_PLATFORM_OBJECT_NAME_STRING );
425            verifyAttr( mbi, JadeAgentMBeanDef.ATTR_FULL_NAME, 
426                    String.class.getName(), true, false, aList,
427                    pinger2ExpectedFullName() );
428            verifyAttr( mbi, JadeAgentMBeanDef.ATTR_STATE_CODE, 
429                    int.class.getName(), true, false, aList, null );
430            verifyAttr( mbi, JadeAgentMBeanDef.ATTR_STATE_NAME, 
431                    String.class.getName(), true, false, aList, null );
432            verifyAttr( mbi, JadeAgentMBeanDef.ATTR_MBEAN_NAME, 
433                    String.class.getName(), true, false, aList,
434                    PINGER2_EXPECTED_MBEAN_NAME_STRING );
435            ObjectName on = null;
436            try {
437                on = new ObjectName(PINGER2_EXPECTED_MBEAN_NAME_STRING);
438            }
439            catch ( Exception e ) {
440                throw new JademxException( e );
441            }
442            verifyAttr( mbi, JadeAgentMBeanDef.ATTR_OBJECT_NAME, 
443                    ObjectName.class.getName(), true, false, aList, 
444                    on );
445            verifyAttr( mbi, JadeAgentMBeanDef.ATTR_JADE_FACTORY, 
446                    JadeFactory.class.getName(), true, false, aList,
447                    jadeRuntime.getJadeFactory() );
448            verifyAttr( mbi, JadeAgentMBeanDef.ATTR_TYPE, 
449                    String.class.getName(), true, false, aList, 
450                    JadeAgentMBeanDef.TYPE );
451            verifyAttr( mbi, JademxPingAgent.ATTR_RESPONSE_NAME, 
452                    String.class.getName(), true, true, aList, 
453                    JademxPingAgent.DEFAULT_ANSWER );
454            
455            verifyAttr( mbi, JademxAgent.ATTR_UNIT_TEST_CMP_CONTENT_NAME,
456                    boolean.class.getName(), true, true, aList,
457                    Boolean.TRUE );
458            verifyAttr( mbi, JademxAgent.ATTR_UNIT_TEST_CMP_CONVERSATION_ID_NAME,
459                    boolean.class.getName(), true, true, aList,
460                    Boolean.TRUE );
461            verifyAttr( mbi, JademxAgent.ATTR_UNIT_TEST_CMP_ENCODING_NAME,
462                    boolean.class.getName(), true, true, aList,
463                    Boolean.TRUE );
464            verifyAttr( mbi, JademxAgent.ATTR_UNIT_TEST_CMP_ENVELOPE_NAME,
465                    boolean.class.getName(), true, true, aList,
466                    Boolean.FALSE );
467            verifyAttr( mbi, JademxAgent.ATTR_UNIT_TEST_CMP_IN_REPLY_TO_NAME,
468                    boolean.class.getName(), true, true, aList,
469                    Boolean.TRUE );
470            verifyAttr( mbi, JademxAgent.ATTR_UNIT_TEST_CMP_LANGUAGE_NAME,
471                    boolean.class.getName(), true, true, aList,
472                    Boolean.TRUE );
473            verifyAttr( mbi, JademxAgent.ATTR_UNIT_TEST_CMP_ONTOLOGY_NAME,
474                    boolean.class.getName(), true, true, aList,
475                    Boolean.TRUE );
476            verifyAttr( mbi, JademxAgent.ATTR_UNIT_TEST_CMP_PERFORMATIVE_NAME,
477                    boolean.class.getName(), true, true, aList,
478                    Boolean.TRUE );
479            verifyAttr( mbi, JademxAgent.ATTR_UNIT_TEST_CMP_PROTOCOL_NAME,
480                    boolean.class.getName(), true, true, aList,
481                    Boolean.TRUE );
482            verifyAttr( mbi, JademxAgent.ATTR_UNIT_TEST_CMP_RECEIVER_NAME,
483                    boolean.class.getName(), true, true, aList,
484                    Boolean.TRUE );
485            verifyAttr( mbi, JademxAgent.ATTR_UNIT_TEST_CMP_REPLY_BY_NAME,
486                    boolean.class.getName(), true, true, aList,
487                    Boolean.TRUE );
488            verifyAttr( mbi, JademxAgent.ATTR_UNIT_TEST_CMP_REPLY_TO_NAME,
489                    boolean.class.getName(), true, true, aList,
490                    Boolean.TRUE );
491            verifyAttr( mbi, JademxAgent.ATTR_UNIT_TEST_CMP_REPLY_WITH_NAME,
492                    boolean.class.getName(), true, true, aList,
493                    Boolean.TRUE );
494            verifyAttr( mbi, JademxAgent.ATTR_UNIT_TEST_CMP_SENDER_NAME,
495                    boolean.class.getName(), true, true, aList,
496                    Boolean.TRUE );        
497            verifyAttr( mbi, JademxAgent.ATTR_UNIT_TEST_CMP_USER_PROPERTIES_NAME,
498                    boolean.class.getName(), true, true, aList,
499                    Boolean.TRUE );
500            verifyAttr( mbi, JademxAgent.ATTR_UNIT_TEST_IGNORE_CONTENT_AID_ADDRESSES_NAME,
501                    boolean.class.getName(), true, true, aList,
502                    Boolean.TRUE );
503            verifyAttr( mbi, JademxAgent.ATTR_UNIT_TEST_NEWLINES_NORMALIZED_NAME,
504                    boolean.class.getName(), true, true, aList,
505                    Boolean.TRUE );
506    
507            
508            
509            verifyOper( mbi, JadeAgentMBeanDef.OPER_KILL_NAME,
510                    void.class.getName() );
511            verifyOper( mbi, JademxPingAgent.OPER_PING_NAME,
512                    JademxPingAgent.OPER_PING_TYPE );
513            verifyNotif( mbi, JademxPingAgent.NOTIF_PINGED_NAME );
514            
515            // test getting non-existent attribute
516            aNames = new String[] {"NoSuchAttribute"};
517            try {
518                aList = jadeAgentPinger2.getAttributes( aNames );
519                fail("didn't generate expected RuntimeException getting "+
520                        "non-existent attribute \""+aNames[0]+"\"");
521            }
522            catch ( RuntimeException re ) {
523                assertTrue(true);
524            }
525            
526            // test setting non-existent attribute
527            aList = new AttributeList(1);
528            aList.add( new Attribute( "NoSuchAttribute", "fubar" ) );
529            try {
530                jadeAgentPinger2.setAttributes( aList );
531                fail("didn't generate expected RuntimeException setting "+
532                        "non-existent attribute");
533            }
534            catch ( RuntimeException re ) {
535                assertTrue(true);
536            }
537            // verify setting response attribute
538            
539            aList = new AttributeList(1);
540            String NEW_RESPONSE = "hello, world!";
541            aList.add( new Attribute( 
542                    JademxPingAgent.ATTR_RESPONSE_NAME, NEW_RESPONSE ) );
543            jadeAgentPinger2.setAttributes( aList );
544            String crntResponse = null;
545            try {
546                crntResponse = (String)jadeAgentPinger2.getAttribute( 
547                        JademxPingAgent.ATTR_RESPONSE_NAME );
548            } 
549            catch ( Exception e ) {
550                throw new JademxException(e);
551            }
552            assertEquals("expected value of \""+JademxPingAgent.ATTR_RESPONSE_NAME+
553                    "\" attribute to be \""+NEW_RESPONSE+"\" but it's \""+
554                    crntResponse+"\"", 
555                    NEW_RESPONSE, crntResponse );
556            
557            // get notification info.
558            // this is being set asynchrononously so it may or may not yet be
559            // set at this point.
560            //MBeanNotificationInfo nI[] = 
561                jadeAgentPinger2.getNotificationInfo();
562            
563            // verify ping operation and verify pinged notification
564            
565            JadeAgent jadeAgentPinger1 = 
566                platformMBean.getAgent( AGENT_LOCAL_NAME_PINGER1);
567            //boolean boundPinger1 = 
568                jadeAgentPinger1.waitForJademxAgentBinding(59*1000/*59sec*/,0);
569            assertTrue("jademx agent "+AGENT_LOCAL_NAME_PINGER1+" didn't bind", 
570                    boundPinger2);
571            String jadeNamePinger1 = jadeAgentPinger1.getFullName();
572            String jadeNamePinger2 = jadeAgentPinger2.getFullName();
573            
574            //TODO: try with a filter...
575            Object handback = new Object();
576            jadeAgentPinger2.addNotificationListener( this, null, handback );
577            
578            String pingResponse = null;
579            try {
580                pingResponse = (String)jadeAgentPinger1.invoke( 
581                        JademxPingAgent.OPER_PING_NAME, 
582                        new Object[] { jadeNamePinger2 },
583                        JademxPingAgent.OPER_PING_SIGNATURE );
584            } 
585            catch ( Exception e ) {
586                String msg = 
587                    "exception using agent "+AGENT_LOCAL_NAME_PINGER1+
588                    " to ping agent "+AGENT_LOCAL_NAME_PINGER2;
589                System.err.println( msg );
590                e.printStackTrace();
591                throw new JademxException( msg, e );
592            }
593            assertEquals(
594                    "using agent "+AGENT_LOCAL_NAME_PINGER1+
595                    " to ping agent "+AGENT_LOCAL_NAME_PINGER2+
596                    " expected response \""+NEW_RESPONSE+
597                    "\" but got \""+pingResponse+"\"", 
598                    NEW_RESPONSE, pingResponse );
599            Notification notification = null;
600            final long MAX_WAIT_MS = 59 * 1000;
601            long startTimeMs = System.currentTimeMillis();
602            long nowMs = startTimeMs;
603                //Thread myThread = Thread.currentThread();
604            while ( ( null == notification ) && 
605                    ( nowMs < ( startTimeMs + MAX_WAIT_MS ) ) ) {
606                synchronized ( notificationQueue ) {
607                    try {
608                        if ( notificationQueue.size() == 0 ) {
609                            notificationQueue.wait( MAX_WAIT_MS );
610                        }
611                    }
612                    catch ( InterruptedException ie ) {
613                        throw new JademxException(ie);
614                    }
615                    if ( notificationQueue.size() > 0 ) {
616                        notification = 
617                            (Notification)notificationQueue.removeFirst();
618                    }
619                }
620                nowMs = System.currentTimeMillis();
621            }
622            assertNotNull( "never got pinged notification", notification );
623            assertEquals( "expected notification type \""+
624                    JademxPingAgent.NOTIF_PINGED_NAME+"\" but got \""+
625                    notification.getType()+"\"", 
626                    JademxPingAgent.NOTIF_PINGED_NAME, notification.getType() );
627            String expMsgPrefix = "this agent was pinged by pinger1@";
628            assertTrue("expected notification message \""+notification.getMessage()+
629                    "\" to start with \""+expMsgPrefix+"\"", 
630                    notification.getMessage().startsWith(expMsgPrefix));
631            long expMsgSeqNum = 0;
632            assertEquals( "expected notification sequence number "+expMsgSeqNum+
633                    " but got "+notification.getSequenceNumber(), 
634                    expMsgSeqNum, notification.getSequenceNumber() );
635            assertEquals("expected notification user data \""+jadeNamePinger1+
636                    "\" but got \""+notification.getUserData()+"\"",
637                    jadeNamePinger1, notification.getUserData() );
638            assertEquals("expected notification source "+
639                    jadeAgentPinger2.getObjectName()+
640                    " but got "+notification.getSource() , 
641                    jadeAgentPinger2.getObjectName(), notification.getSource() );
642            
643            // remove notification listener using NotificationBroadcaster interface
644            try {
645                jadeAgentPinger2.removeNotificationListener( this );
646            }
647            catch ( Exception e ) {
648                throw new JademxException(
649                        "exception removing self as notification listener "+
650                        "using NotificationBroadcaster interface", e );
651            }
652            // test adding null notification listener
653            try {
654                jadeAgentPinger2.addNotificationListener( null, null, null);
655                fail("didn't raise IllegalArgumentException for null "+
656                        "notification listener");
657            }
658            catch ( IllegalArgumentException iae ) {
659                assertTrue(true);
660            }
661            // remove notification listener using NotificationEmitter interface
662            jadeAgentPinger2.addNotificationListener( this, null, handback );
663            jadeAgentPinger2.addNotificationListener( this, null, handback );//NOP
664            Object handback2 = new Object();
665            jadeAgentPinger2.addNotificationListener( this, null, handback2 );
666            try {
667                jadeAgentPinger2.removeNotificationListener( this, null, handback );
668            }
669            catch ( Exception e ) {
670                throw new JademxException(
671                        "exception removing 1st notification listener "+
672                        "using NotificationEmitter interface", e );
673            }
674            try {
675                jadeAgentPinger2.removeNotificationListener( this, null, handback2 );
676            }
677            catch ( Exception e ) {
678                throw new JademxException(
679                        "exception removing 2nd notification listener "+
680                        "using NotificationEmitter interface", e );
681            }
682            // try removing non-existent listeners
683            try {
684                jadeAgentPinger2.removeNotificationListener( null );
685                fail("didn't raise ListenerNotFoundException removing null "+
686                   "notification listener using NotificationBroadcaster interface");
687            } 
688            catch ( ListenerNotFoundException e ) {
689                assertTrue(true);
690            }
691            try {
692                jadeAgentPinger2.removeNotificationListener( null, null, null );
693                fail("didn't raise ListenerNotFoundException removing null "+
694                   "notification listener using NotificationBroadcaster interface");
695            } 
696            catch ( ListenerNotFoundException e ) {
697                assertTrue(true);
698            }
699            
700            // test operation where arguments/signature wrong
701            try {
702                jadeAgentPinger1.invoke( 
703                        JademxPingAgent.OPER_PING_NAME, 
704                        new Object[0],
705                        new String[0] );
706                fail("didn't raise ReflectionException for bad args/signature");
707            } 
708            catch ( ReflectionException re ) {
709                assertTrue(true);
710            }
711            catch ( Exception e ) {
712                throw new JademxException("unexpected exception raised for "+
713                        "operation with bad args/signature", e );
714            }
715            
716            
717            // verify kill operation
718            try {
719                jadeAgentPinger2.invoke( 
720                        JadeAgentMBeanDef.OPER_KILL_NAME, 
721                        new Object[0],
722                        JadeAgent.OPER_KILL_SIGNATURE );
723            } 
724            catch ( Exception e ) {
725                String msg = 
726                    "exception killing agent "+AGENT_LOCAL_NAME_PINGER2;
727                System.err.println( msg );
728                e.printStackTrace();
729                throw new JademxException( msg, e );
730            }
731            
732            
733        }
734        
735        /**
736         * verify that given attribute in given MBeanInfo
737         * @param mbi MBeanInfo to look in
738         * @param name attribute name
739         * @param type attribute type
740         * @param readable attribute readability
741         * @param writable attribute writability
742         * @param aList attribute list to get actual value from
743         * @param value expected value: if null then don't check
744         */
745        private void verifyAttr( 
746                MBeanInfo mbi, 
747                String name, 
748                String type, 
749                boolean readable, 
750                boolean writable,
751                AttributeList aList,
752                Object value ) {
753            boolean found = false;
754            MBeanAttributeInfo mbais[] = mbi.getAttributes();
755            int aCount = mbais.length;
756            for ( int i = 0; i < aCount; i++ ) {
757                MBeanAttributeInfo mbai = mbais[i];
758                if ( mbai.getName().equals( name ) &&
759                     mbai.getType().equals( type ) &&
760                     ( mbai.isReadable() == readable ) && 
761                     ( mbai.isWritable() == writable ) ) {
762                    found = true;
763                    break;
764                }
765            }
766            // help in future debugging
767            if ( !found ) {
768                System.err.println(aCount+" attributes");
769                for ( int i = 0; i < aCount; i++ ) {
770                    MBeanAttributeInfo mbai = mbais[i];
771                    System.err.println("attribute "+i+": "+mbai.getName()+"("+
772                            "type="+mbai.getType()+
773                            ",readable="+mbai.isReadable()+
774                            ",writable="+mbai.isWritable()+
775                            ")");
776                }
777            }
778            assertTrue("attribute name \""+name+"\", type \""+type+"\""+
779                    ", readable="+readable+", writable="+writable+" not found", 
780                    found );
781            if ( null != value ) {
782                int aListLen = aList.size();
783                for ( int i = 0; i < aListLen; i++ ) {
784                    Attribute a = (Attribute)aList.get( i );
785                    if ( name.equals( a.getName() ) ) {
786                        Object aVal = a.getValue();
787                        assertTrue("expected and actual attribute values must "+
788                                "both be either array or not array: value="+
789                                value.toString()+",aVal="+aVal.toString(), 
790                                value.getClass().isArray()==aVal.getClass().isArray() );
791                        boolean isArray = value.getClass().isArray();
792                        assertTrue("for attribute "+name+" expected value "+value+
793                                " but got "+aVal,
794                                ( isArray
795                                        ? Arrays.deepEquals( (Object[])value, (Object[])aVal )
796                                                : ( value.equals(aVal))
797                                ));
798                    }
799                }
800            }
801        }
802        
803        /**
804         * verify given operation in given MBeanInfo
805         * @param mbi MBeanInfo to look in
806         * @param name operation name
807         * @param type operation type
808         */
809        private void verifyOper( MBeanInfo mbi, 
810                String name, 
811                String type ) {
812            boolean found = false;
813            MBeanOperationInfo mbois[] = mbi.getOperations();
814            int oCount = mbois.length;
815            //System.err.println(oCount+" operations");
816            for ( int i = 0; i < oCount; i++ ) {
817                MBeanOperationInfo mboi = mbois[i];
818                if ( mboi.getName().equals( name ) &&
819                     mboi.getReturnType().equals( type ) ) {
820                         found = true;
821                         break;
822                }
823            }
824            // help in future debugging
825            if ( !found ) {
826                System.err.println(oCount+" operations ");
827                for ( int i = 0; i < oCount; i++ ) {
828                    MBeanOperationInfo mboi = mbois[i];
829                    System.err.println("operation "+i+": "+mboi.getName()+
830                            "(type="+mboi.getReturnType()+")");
831                }
832            }
833            assertTrue("operation name \""+name+"\", type \""+type+"\" not found", 
834                    found );
835        }
836        
837        /**
838         * verify given notification in given MBeanInfo
839         * @param mbi MBeanInfo to look in
840         * @param type notification type
841         */
842        private void verifyNotif( MBeanInfo mbi, String type ) {
843            boolean found = false;
844            MBeanNotificationInfo mbnis[] = mbi.getNotifications();
845            int nCount = mbnis.length;
846            for ( int i = 0; i < nCount; i++ ) {
847                MBeanNotificationInfo mbni = mbnis[i];
848                String notifTypes[] = mbni.getNotifTypes();
849                int nTypeCount = notifTypes.length;
850                for ( int j = 0; j < nTypeCount; j++ ) {
851                    if ( notifTypes[j].equals( type ) ) {
852                        found = true;
853                        break;
854                    }
855                    //System.err.println("JadeAgentTest.verifyNotif():notification "+i+": "+mbni.getName()+
856                    //        ", type \""+notifTypes[j]+"\"");
857                }
858            }
859            // help in future debugging
860            if ( !found ) {
861                for ( int i = 0; i < nCount; i++ ) {
862                    MBeanNotificationInfo mbni = mbnis[i];
863                    String notifTypes[] = mbni.getNotifTypes();
864                    int nTypeCount = notifTypes.length;
865                    for ( int j = 0; j < nTypeCount; j++ ) {
866                        System.err.println("JadeAgentTest.verifyNotif():notification "+i+": "+mbni.getName()+
867                                ", type \""+notifTypes[j]+"\"");
868                    }
869                }
870            }
871            assertTrue("notification type \""+type+"\" not found", found );
872        }
873    
874       
875        // suite
876    
877        /**
878         * return the implicit suite of tests
879         * @return the implicit suite of tests
880         */
881        public static Test suite() {
882            return new TestSuite( 
883                    JadeAgentTest.class, 
884                    JadeMXSuiteTest.nameWithClass( JadeAgentTest.class, 
885                    "testing JadeAgent: jade agent MBean class") );
886        }
887    
888    
889        
890    }