1/*
2 * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/*
25 * @test
26 * @bug 6222961
27 * @summary Test that the counter/gauge/string monitors
28 *          support attributes of arbitrary data types.
29 * @author Luis-Miguel Alventosa
30 * @modules java.desktop
31 *          java.management
32 * @run clean AttributeArbitraryDataTypeTest
33 * @run build AttributeArbitraryDataTypeTest
34 * @run main AttributeArbitraryDataTypeTest
35 */
36
37import java.beans.BeanInfo;
38import java.beans.IntrospectionException;
39import java.beans.PropertyDescriptor;
40import java.beans.SimpleBeanInfo;
41import java.lang.reflect.Array;
42import java.lang.reflect.InvocationTargetException;
43import javax.management.AttributeNotFoundException;
44import javax.management.MBeanServer;
45import javax.management.MBeanServerFactory;
46import javax.management.Notification;
47import javax.management.NotificationListener;
48import javax.management.ObjectName;
49import javax.management.monitor.CounterMonitor;
50import javax.management.monitor.GaugeMonitor;
51import javax.management.monitor.MonitorNotification;
52import javax.management.monitor.StringMonitor;
53import javax.management.openmbean.CompositeData;
54import javax.management.openmbean.CompositeDataSupport;
55import javax.management.openmbean.CompositeType;
56import javax.management.openmbean.OpenDataException;
57import javax.management.openmbean.OpenType;
58import javax.management.openmbean.SimpleType;
59
60public class AttributeArbitraryDataTypeTest implements NotificationListener {
61
62    // Flag to notify that a message has been received
63    private volatile boolean counterMessageReceived = false;
64    private volatile boolean gaugeMessageReceived = false;
65    private volatile boolean stringMessageReceived = false;
66
67    // Match enum
68    public enum Match { do_not_match_0,
69                        do_not_match_1,
70                        do_not_match_2,
71                        do_match_now };
72
73    // MatchBeanInfo class
74    public static class MatchBeanInfo extends SimpleBeanInfo {
75        public PropertyDescriptor[] getPropertyDescriptors() {
76            try {
77                return new PropertyDescriptor[] {
78                    new PropertyDescriptor("name", Match.class, "name", null) };
79            } catch (IntrospectionException e ) {
80                e.printStackTrace();
81                return null;
82            }
83        }
84    }
85
86    // ComplexAttribute class
87    public class ComplexAttribute {
88
89        public Integer getIntegerAttribute() {
90            return i;
91        }
92
93        public void setIntegerAttribute(Integer i) {
94            this.i = i;
95        }
96
97        public Double getDoubleAttribute() {
98            return d;
99        }
100
101        public void setDoubleAttribute(Double d) {
102            this.d = d;
103        }
104
105        public String getStringAttribute() {
106            return s;
107        }
108
109        public void setStringAttribute(String s) {
110            this.s = s;
111        }
112
113        public Integer[] getArrayAttribute() {
114            return a;
115        }
116
117        public void setArrayAttribute(Integer[] a) {
118            this.a = a;
119        }
120
121        public Match getEnumAttribute() {
122            return e;
123        }
124
125        public void setEnumAttribute(Match e) {
126            this.e = e;
127        }
128
129        private Integer i;
130        private Double d;
131        private String s;
132        private Integer[] a;
133        private Match e;
134    }
135
136    // MBean class
137    public class ObservedObject implements ObservedObjectMBean {
138
139        // Simple type buried in complex getter
140        //
141        public ComplexAttribute getComplexAttribute() {
142            return ca;
143        }
144
145        public void setComplexAttribute(ComplexAttribute ca) {
146            this.ca = ca;
147        }
148
149        private ComplexAttribute ca = null;
150
151        // Simple type buried in CompositeData
152        //
153        public CompositeData getCompositeDataAttribute()
154            throws OpenDataException {
155            CompositeType ct = new CompositeType("CompositeDataAttribute",
156                                                 "Composite Data Attribute",
157                                                 itemNames,
158                                                 itemDescriptions,
159                                                 itemTypes);
160            Object itemValues[] = { ia, da, sa };
161            return new CompositeDataSupport(ct, itemNames, itemValues);
162        }
163
164        public Integer ia;
165        public Double da;
166        public String sa;
167
168        private String itemNames[] = { "IntegerAttribute",
169                                       "DoubleAttribute",
170                                       "StringAttribute" };
171        private String itemDescriptions[] = { "Integer Attribute",
172                                              "Double Attribute",
173                                              "String Attribute" };
174        private OpenType itemTypes[] = { SimpleType.INTEGER,
175                                         SimpleType.DOUBLE,
176                                         SimpleType.STRING };
177    }
178
179    // MBean interface
180    public interface ObservedObjectMBean {
181        public ComplexAttribute getComplexAttribute();
182        public void setComplexAttribute(ComplexAttribute ca);
183        public CompositeData getCompositeDataAttribute()
184            throws OpenDataException;
185    }
186
187    // Notification handler
188    public void handleNotification(Notification notification,
189                                   Object handback) {
190        MonitorNotification n = (MonitorNotification) notification;
191        echo("\tInside handleNotification...");
192        String type = n.getType();
193        try {
194            if (type.equals(MonitorNotification.
195                            THRESHOLD_VALUE_EXCEEDED)) {
196                echo("\t\t" + n.getObservedAttribute() +
197                     " has reached or exceeded the threshold");
198                echo("\t\tDerived Gauge = " + n.getDerivedGauge());
199                echo("\t\tTrigger = " + n.getTrigger());
200
201                synchronized (this) {
202                    counterMessageReceived = true;
203                    notifyAll();
204                }
205            } else if (type.equals(MonitorNotification.
206                                   THRESHOLD_HIGH_VALUE_EXCEEDED)) {
207                echo("\t\t" + n.getObservedAttribute() +
208                     " has reached or exceeded the high threshold");
209                echo("\t\tDerived Gauge = " + n.getDerivedGauge());
210                echo("\t\tTrigger = " + n.getTrigger());
211
212                synchronized (this) {
213                    gaugeMessageReceived = true;
214                    notifyAll();
215                }
216            } else if (type.equals(MonitorNotification.
217                                   STRING_TO_COMPARE_VALUE_MATCHED)) {
218                echo("\t\t" + n.getObservedAttribute() +
219                     " matches the string-to-compare value");
220                echo("\t\tDerived Gauge = " + n.getDerivedGauge());
221                echo("\t\tTrigger = " + n.getTrigger());
222
223                synchronized (this) {
224                    stringMessageReceived = true;
225                    notifyAll();
226                }
227            } else {
228                echo("\t\tSkipping notification of type: " + type);
229            }
230        } catch (Exception e) {
231            echo("\tError in handleNotification!");
232            e.printStackTrace(System.out);
233        }
234    }
235
236    /**
237     * Update the counter and check for notifications
238     */
239    public int counterMonitorNotification(int testCase)
240        throws Exception {
241
242        counterMessageReceived = false;
243        CounterMonitor counterMonitor = null;
244        try {
245            MBeanServer server = MBeanServerFactory.newMBeanServer();
246
247            String domain = server.getDefaultDomain();
248
249            // Create a new CounterMonitor MBean and add it to the MBeanServer.
250            //
251            echo(">>> CREATE a new CounterMonitor MBean");
252            ObjectName counterMonitorName = new ObjectName(
253                            domain + ":type=" + CounterMonitor.class.getName());
254            counterMonitor = new CounterMonitor();
255            server.registerMBean(counterMonitor, counterMonitorName);
256
257            echo(">>> ADD a listener to the CounterMonitor");
258            counterMonitor.addNotificationListener(this, null, null);
259
260            //
261            // MANAGEMENT OF A STANDARD MBEAN
262            //
263
264            echo(">>> CREATE a new ObservedObject MBean");
265
266            ObjectName obsObjName =
267                ObjectName.getInstance(domain + ":type=ObservedObject");
268            ObservedObject obsObj = new ObservedObject();
269            ComplexAttribute ca = new ComplexAttribute();
270            switch (testCase) {
271                case 1:
272                    obsObj.ia = 0;
273                    break;
274                case 2:
275                    ca.setIntegerAttribute(0);
276                    obsObj.setComplexAttribute(ca);
277                    break;
278                case 3:
279                    ca.setArrayAttribute(new Integer[0]);
280                    obsObj.setComplexAttribute(ca);
281                    break;
282            }
283            server.registerMBean(obsObj, obsObjName);
284
285            echo(">>> SET the attributes of the CounterMonitor:");
286
287            counterMonitor.addObservedObject(obsObjName);
288            echo("\tATTRIBUTE \"ObservedObject\"    = " + obsObjName);
289
290            switch (testCase) {
291                case 1:
292                    counterMonitor.setObservedAttribute(
293                         "CompositeDataAttribute.IntegerAttribute");
294                    echo("\tATTRIBUTE \"ObservedAttribute\" = " +
295                         "CompositeDataAttribute.IntegerAttribute");
296                    break;
297                case 2:
298                    counterMonitor.setObservedAttribute(
299                         "ComplexAttribute.integerAttribute");
300                    echo("\tATTRIBUTE \"ObservedAttribute\" = " +
301                         "ComplexAttribute.integerAttribute");
302                    break;
303                case 3:
304                    counterMonitor.setObservedAttribute(
305                         "ComplexAttribute.arrayAttribute.length");
306                    echo("\tATTRIBUTE \"ObservedAttribute\" = " +
307                         "ComplexAttribute.arrayAttribute.length");
308                    break;
309            }
310
311            counterMonitor.setNotify(true);
312            echo("\tATTRIBUTE \"NotifyFlag\"        = true");
313
314            Integer threshold = 2;
315            counterMonitor.setInitThreshold(threshold);
316            echo("\tATTRIBUTE \"Threshold\"         = " + threshold);
317
318            int granularityperiod = 500;
319            counterMonitor.setGranularityPeriod(granularityperiod);
320            echo("\tATTRIBUTE \"GranularityPeriod\" = " + granularityperiod);
321
322            echo(">>> START the CounterMonitor");
323            counterMonitor.start();
324
325            // Wait for granularity period (multiplied by 2 for sure)
326            //
327            Thread.sleep(granularityperiod * 2);
328
329            switch (testCase) {
330                case 1:
331                    obsObj.ia = 1;
332                    break;
333                case 2:
334                    ca.setIntegerAttribute(1);
335                    break;
336                case 3:
337                    ca.setArrayAttribute(new Integer[1]);
338                    break;
339            }
340
341            // Wait for granularity period (multiplied by 2 for sure)
342            //
343            Thread.sleep(granularityperiod * 2);
344
345            switch (testCase) {
346                case 1:
347                    obsObj.ia = 2;
348                    break;
349                case 2:
350                    ca.setIntegerAttribute(2);
351                    break;
352                case 3:
353                    ca.setArrayAttribute(new Integer[2]);
354                    break;
355            }
356
357            // Wait for granularity period (multiplied by 2 for sure)
358            //
359            Thread.sleep(granularityperiod * 2);
360
361            switch (testCase) {
362                case 1:
363                    obsObj.ia = 3;
364                    break;
365                case 2:
366                    ca.setIntegerAttribute(3);
367                    break;
368                case 3:
369                    ca.setArrayAttribute(new Integer[3]);
370                    break;
371            }
372
373            // Check if notification was received
374            //
375            synchronized (this) {
376                while (!counterMessageReceived) {
377                    try {
378                        wait();
379                    } catch (InterruptedException e) {
380                        System.err.println("Got unexpected exception: " + e);
381                        e.printStackTrace();
382                        break;
383                    }
384                }
385            }
386            if (counterMessageReceived) {
387                echo("\tOK: CounterMonitor notification received");
388            } else {
389                echo("\tKO: CounterMonitor notification missed or not emitted");
390                return 1;
391            }
392        } finally {
393            if (counterMonitor != null)
394                counterMonitor.stop();
395        }
396
397        return 0;
398    }
399
400    /**
401     * Update the gauge and check for notifications
402     */
403    public int gaugeMonitorNotification(int testCase)
404        throws Exception {
405
406        gaugeMessageReceived = false;
407        GaugeMonitor gaugeMonitor = null;
408        try {
409            MBeanServer server = MBeanServerFactory.newMBeanServer();
410
411            String domain = server.getDefaultDomain();
412
413            // Create a new GaugeMonitor MBean and add it to the MBeanServer.
414            //
415            echo(">>> CREATE a new GaugeMonitor MBean");
416            ObjectName gaugeMonitorName = new ObjectName(
417                            domain + ":type=" + GaugeMonitor.class.getName());
418            gaugeMonitor = new GaugeMonitor();
419            server.registerMBean(gaugeMonitor, gaugeMonitorName);
420
421            echo(">>> ADD a listener to the GaugeMonitor");
422            gaugeMonitor.addNotificationListener(this, null, null);
423
424            //
425            // MANAGEMENT OF A STANDARD MBEAN
426            //
427
428            echo(">>> CREATE a new ObservedObject MBean");
429
430            ObjectName obsObjName =
431                ObjectName.getInstance(domain + ":type=ObservedObject");
432            ObservedObject obsObj = new ObservedObject();
433            ComplexAttribute ca = new ComplexAttribute();
434            switch (testCase) {
435                case 1:
436                    obsObj.da = 0.0;
437                    break;
438                case 2:
439                    ca.setDoubleAttribute(0.0);
440                    obsObj.setComplexAttribute(ca);
441                    break;
442                case 3:
443                    ca.setArrayAttribute(new Integer[0]);
444                    obsObj.setComplexAttribute(ca);
445                    break;
446            }
447            server.registerMBean(obsObj, obsObjName);
448
449            echo(">>> SET the attributes of the GaugeMonitor:");
450
451            gaugeMonitor.addObservedObject(obsObjName);
452            echo("\tATTRIBUTE \"ObservedObject\"    = " + obsObjName);
453
454            switch (testCase) {
455                case 1:
456                    gaugeMonitor.setObservedAttribute(
457                         "CompositeDataAttribute.DoubleAttribute");
458                    echo("\tATTRIBUTE \"ObservedAttribute\" = " +
459                         "CompositeDataAttribute.DoubleAttribute");
460                    break;
461                case 2:
462                    gaugeMonitor.setObservedAttribute(
463                         "ComplexAttribute.doubleAttribute");
464                    echo("\tATTRIBUTE \"ObservedAttribute\" = " +
465                         "ComplexAttribute.doubleAttribute");
466                    break;
467                case 3:
468                    gaugeMonitor.setObservedAttribute(
469                         "ComplexAttribute.arrayAttribute.length");
470                    echo("\tATTRIBUTE \"ObservedAttribute\" = " +
471                         "ComplexAttribute.arrayAttribute.length");
472                    break;
473            }
474
475            gaugeMonitor.setNotifyLow(false);
476            gaugeMonitor.setNotifyHigh(true);
477            echo("\tATTRIBUTE \"Notify Low  Flag\"  = false");
478            echo("\tATTRIBUTE \"Notify High Flag\"  = true");
479
480            switch (testCase) {
481                case 1:
482                case 2:
483                    Double highThresholdD = 3.0, lowThresholdD = 2.5;
484                    gaugeMonitor.setThresholds(highThresholdD, lowThresholdD);
485                    echo("\tATTRIBUTE \"Low  Threshold\"    = " + lowThresholdD);
486                    echo("\tATTRIBUTE \"High Threshold\"    = " + highThresholdD);
487                    break;
488                case 3:
489                    Integer highThreshold = 2, lowThreshold = 1;
490                    gaugeMonitor.setThresholds(highThreshold, lowThreshold);
491                    echo("\tATTRIBUTE \"Low  Threshold\"    = " + lowThreshold);
492                    echo("\tATTRIBUTE \"High Threshold\"    = " + highThreshold);
493                    break;
494            }
495
496            int granularityperiod = 500;
497            gaugeMonitor.setGranularityPeriod(granularityperiod);
498            echo("\tATTRIBUTE \"GranularityPeriod\" = " + granularityperiod);
499
500            echo(">>> START the GaugeMonitor");
501            gaugeMonitor.start();
502
503            // Wait for granularity period (multiplied by 2 for sure)
504            //
505            Thread.sleep(granularityperiod * 2);
506
507            switch (testCase) {
508                case 1:
509                    obsObj.da = 2.0;
510                    break;
511                case 2:
512                    ca.setDoubleAttribute(2.0);
513                    break;
514                case 3:
515                    ca.setArrayAttribute(new Integer[2]);
516                    break;
517            }
518
519            // Wait for granularity period (multiplied by 2 for sure)
520            //
521            Thread.sleep(granularityperiod * 2);
522
523            switch (testCase) {
524                case 1:
525                    obsObj.da = 4.0;
526                    break;
527                case 2:
528                    ca.setDoubleAttribute(4.0);
529                    break;
530                case 3:
531                    ca.setArrayAttribute(new Integer[4]);
532                    break;
533            }
534
535            // Wait for granularity period (multiplied by 2 for sure)
536            //
537            Thread.sleep(granularityperiod * 2);
538
539            switch (testCase) {
540                case 1:
541                    obsObj.da = 6.0;
542                    break;
543                case 2:
544                    ca.setDoubleAttribute(6.0);
545                    break;
546                case 3:
547                    ca.setArrayAttribute(new Integer[6]);
548                    break;
549            }
550
551            // Check if notification was received
552            //
553            synchronized (this) {
554                while (!gaugeMessageReceived) {
555                    try {
556                        wait();
557                    } catch (InterruptedException e) {
558                        System.err.println("Got unexpected exception: " + e);
559                        e.printStackTrace();
560                        break;
561                    }
562                }
563            }
564            if (gaugeMessageReceived) {
565                echo("\tOK: GaugeMonitor notification received");
566            } else {
567                echo("\tKO: GaugeMonitor notification missed or not emitted");
568                return 1;
569            }
570        } finally {
571            if (gaugeMonitor != null)
572                gaugeMonitor.stop();
573        }
574
575        return 0;
576    }
577
578    /**
579     * Update the string and check for notifications
580     */
581    public int stringMonitorNotification(int testCase)
582        throws Exception {
583
584        stringMessageReceived = false;
585        StringMonitor stringMonitor = null;
586        try {
587            MBeanServer server = MBeanServerFactory.newMBeanServer();
588
589            String domain = server.getDefaultDomain();
590
591            // Create a new StringMonitor MBean and add it to the MBeanServer.
592            //
593            echo(">>> CREATE a new StringMonitor MBean");
594            ObjectName stringMonitorName = new ObjectName(
595                            domain + ":type=" + StringMonitor.class.getName());
596            stringMonitor = new StringMonitor();
597            server.registerMBean(stringMonitor, stringMonitorName);
598
599            echo(">>> ADD a listener to the StringMonitor");
600            stringMonitor.addNotificationListener(this, null, null);
601
602            //
603            // MANAGEMENT OF A STANDARD MBEAN
604            //
605
606            echo(">>> CREATE a new ObservedObject MBean");
607
608            ObjectName obsObjName =
609                ObjectName.getInstance(domain + ":type=ObservedObject");
610            ObservedObject obsObj = new ObservedObject();
611            ComplexAttribute ca = new ComplexAttribute();
612            switch (testCase) {
613                case 1:
614                    obsObj.sa = "do_not_match_0";
615                    break;
616                case 2:
617                    ca.setStringAttribute("do_not_match_0");
618                    obsObj.setComplexAttribute(ca);
619                    break;
620                case 3:
621                    ca.setEnumAttribute(Match.do_not_match_0);
622                    obsObj.setComplexAttribute(ca);
623                    break;
624            }
625            server.registerMBean(obsObj, obsObjName);
626
627            echo(">>> SET the attributes of the StringMonitor:");
628
629            stringMonitor.addObservedObject(obsObjName);
630            echo("\tATTRIBUTE \"ObservedObject\"    = " + obsObjName);
631
632            switch (testCase) {
633                case 1:
634                    stringMonitor.setObservedAttribute(
635                         "CompositeDataAttribute.StringAttribute");
636                    echo("\tATTRIBUTE \"ObservedAttribute\" = " +
637                         "CompositeDataAttribute.StringAttribute");
638                    break;
639                case 2:
640                    stringMonitor.setObservedAttribute(
641                         "ComplexAttribute.stringAttribute");
642                    echo("\tATTRIBUTE \"ObservedAttribute\" = " +
643                         "ComplexAttribute.stringAttribute");
644                    break;
645                case 3:
646                    stringMonitor.setObservedAttribute(
647                         "ComplexAttribute.enumAttribute.name");
648                    echo("\tATTRIBUTE \"ObservedAttribute\" = " +
649                         "ComplexAttribute.enumAttribute.name");
650                    break;
651            }
652
653            stringMonitor.setNotifyMatch(true);
654            echo("\tATTRIBUTE \"NotifyMatch\"       = true");
655
656            stringMonitor.setNotifyDiffer(false);
657            echo("\tATTRIBUTE \"NotifyDiffer\"      = false");
658
659            stringMonitor.setStringToCompare("do_match_now");
660            echo("\tATTRIBUTE \"StringToCompare\"   = \"do_match_now\"");
661
662            int granularityperiod = 500;
663            stringMonitor.setGranularityPeriod(granularityperiod);
664            echo("\tATTRIBUTE \"GranularityPeriod\" = " + granularityperiod);
665
666            echo(">>> START the StringMonitor");
667            stringMonitor.start();
668
669            // Wait for granularity period (multiplied by 2 for sure)
670            //
671            Thread.sleep(granularityperiod * 2);
672
673            switch (testCase) {
674                case 1:
675                    obsObj.sa = "do_not_match_1";
676                    break;
677                case 2:
678                    ca.setStringAttribute("do_not_match_1");
679                    break;
680                case 3:
681                    ca.setEnumAttribute(Match.do_not_match_1);
682                    break;
683            }
684
685            // Wait for granularity period (multiplied by 2 for sure)
686            //
687            Thread.sleep(granularityperiod * 2);
688
689            switch (testCase) {
690                case 1:
691                    obsObj.sa = "do_match_now";
692                    break;
693                case 2:
694                    ca.setStringAttribute("do_match_now");
695                    break;
696                case 3:
697                    ca.setEnumAttribute(Match.do_match_now);
698                    break;
699            }
700
701            // Wait for granularity period (multiplied by 2 for sure)
702            //
703            Thread.sleep(granularityperiod * 2);
704
705            switch (testCase) {
706                case 1:
707                    obsObj.sa = "do_not_match_2";
708                    break;
709                case 2:
710                    ca.setStringAttribute("do_not_match_2");
711                    break;
712                case 3:
713                    ca.setEnumAttribute(Match.do_not_match_2);
714                    break;
715            }
716
717            // Check if notification was received
718            //
719            synchronized (this) {
720                while (!stringMessageReceived) {
721                    try {
722                        wait();
723                    } catch (InterruptedException e) {
724                        System.err.println("Got unexpected exception: " + e);
725                        e.printStackTrace();
726                        break;
727                    }
728                }
729            }
730            if (stringMessageReceived) {
731                echo("\tOK: StringMonitor notification received");
732            } else {
733                echo("\tKO: StringMonitor notification missed or not emitted");
734                return 1;
735            }
736        } finally {
737            if (stringMonitor != null)
738                stringMonitor.stop();
739        }
740
741        return 0;
742    }
743
744    /**
745     * Test the monitor notifications.
746     */
747    public int monitorNotifications() throws Exception {
748        echo(">>> ----------------------------------------");
749        int error = counterMonitorNotification(1);
750        echo(">>> ----------------------------------------");
751        error += counterMonitorNotification(2);
752        echo(">>> ----------------------------------------");
753        error += counterMonitorNotification(3);
754        echo(">>> ----------------------------------------");
755        error += gaugeMonitorNotification(1);
756        echo(">>> ----------------------------------------");
757        error += gaugeMonitorNotification(2);
758        echo(">>> ----------------------------------------");
759        error += gaugeMonitorNotification(3);
760        echo(">>> ----------------------------------------");
761        error += stringMonitorNotification(1);
762        echo(">>> ----------------------------------------");
763        error += stringMonitorNotification(2);
764        echo(">>> ----------------------------------------");
765        error += stringMonitorNotification(3);
766        echo(">>> ----------------------------------------");
767        return error;
768    }
769
770    /*
771     * Print message
772     */
773    private static void echo(String message) {
774        System.out.println(message);
775    }
776
777    public static Object elementFromComplex(Object complex, String element)
778    throws AttributeNotFoundException {
779        try {
780            if (complex.getClass().isArray() && element.equals("length")) {
781                return Array.getLength(complex);
782            } else if (complex instanceof CompositeData) {
783                return ((CompositeData) complex).get(element);
784            } else {
785                // Java Beans introspection
786                //
787                BeanInfo bi = java.beans.Introspector.getBeanInfo(complex.getClass());
788                PropertyDescriptor[] pds = bi.getPropertyDescriptors();
789                System.out.println("PDs: " + pds.length);
790                for (PropertyDescriptor pd : pds) {
791                    System.out.println("Property: " + pd.getName());
792                    if (pd.getName().equals(element))
793                        return pd.getReadMethod().invoke(complex);
794                }
795                throw new AttributeNotFoundException(
796                    "Could not find the getter method for the property " +
797                    element + " using the Java Beans introspector");
798            }
799        } catch (InvocationTargetException e) {
800            throw new IllegalArgumentException(e);
801        } catch (AttributeNotFoundException e) {
802            throw e;
803        } catch (Exception e) {
804            AttributeNotFoundException anfe =
805                new AttributeNotFoundException(e.getMessage());
806            anfe.initCause(e);
807            throw anfe;
808        }
809    }
810
811    /*
812     * Standalone entry point.
813     *
814     * Run the test and report to stdout.
815     */
816    public static void main (String args[]) throws Exception {
817        Match match = Match.do_match_now;
818        String name = (String) elementFromComplex(match, "name");
819        System.out.println("name: " + name);
820        AttributeArbitraryDataTypeTest test =
821            new AttributeArbitraryDataTypeTest();
822        int error = test.monitorNotifications();
823        if (error > 0) {
824            echo(">>> Unhappy Bye, Bye!");
825            throw new IllegalStateException("Test FAILED: Didn't get all " +
826                                            "the notifications that were " +
827                                            "expected by the test!");
828        } else {
829            echo(">>> Happy Bye, Bye!");
830        }
831    }
832}
833