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 import java.util.Collection;
25 import java.util.Date;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.concurrent.Callable;
31 import java.util.concurrent.ExecutorService;
32 import java.util.concurrent.Executors;
33 import java.util.concurrent.Future;
34 import javax.management.Descriptor;
35 import javax.management.ImmutableDescriptor;
36 import javax.management.ListenerNotFoundException;
37 import javax.management.MBeanNotificationInfo;
38 import javax.management.MBeanRegistration;
39 import javax.management.MBeanServer;
40 import javax.management.Notification;
41 import javax.management.NotificationBroadcasterSupport;
42 import javax.management.NotificationEmitter;
43 import javax.management.NotificationFilter;
44 import javax.management.NotificationListener;
45 import javax.management.ObjectName;
46 
47 /**
48  * Class Basic
49  * Basic Description
50  */
51 public class Basic implements BasicMXBean, NotificationEmitter,
52                               MBeanRegistration {
53 
54     public static final String EXCEPTION_MESSAGE = "from Basic";
55     public static final String NOTIFICATION_MESSAGE = "from Basic";
56     /** Attribute : IntAtt */
57     private int intAtt = 0;
58     /** Attribute : IntegerAtt */
59     private Integer integerAtt = 0;
60     /** Attribute : BoolAtt */
61     private boolean boolAtt = false;
62     /** Attribute : BooleanAtt */
63     private Boolean booleanAtt = false;
64     /** Attribute : StringAtt */
65     private String stringAtt = null;
66     /** Attribute : DateAtt */
67     private Date dateAtt = null;
68     /** Attribute : ObjectNameAtt */
69     private ObjectName objectNameAtt = null;
70     /** Attribute : NotifDescriptorAsMapAtt */
71     private Map<String, String> notifDescriptorAsMapAtt = null;
72     /** Attribute : NotifDescriptorAtt */
73     private Descriptor notifDescriptorAtt = null;
74     /** Attribute : SqeParameter */
75     private SqeParameter sqeParameterAtt = null;
76 
77     /* Creates a new instance of Basic */
78     @SqeDescriptorKey("CONSTRUCTOR Basic")
Basic()79     public Basic() {
80     }
81 
82     /* Creates a new instance of Basic */
83     @SqeDescriptorKey("CONSTRUCTOR Basic")
Basic( @qeDescriptorKeyR) SqeParameter param)84     public Basic(
85             @SqeDescriptorKey("CONSTRUCTOR PARAMETER SqeParameter") SqeParameter param) {
86     }
87 
88     /**
89      * Get int attribute
90      */
getIntAtt()91     public int getIntAtt() {
92         return intAtt;
93     }
94 
95     /**
96      * Set int attribute
97      */
setIntAtt(int value)98     public void setIntAtt(int value) {
99         intAtt = value;
100     }
101 
102     /**
103      * Get Integer attribute
104      */
getIntegerAtt()105     public Integer getIntegerAtt() {
106         return integerAtt;
107     }
108 
109     /**
110      * Set Integer attribute
111      */
setIntegerAtt(Integer value)112     public void setIntegerAtt(Integer value) {
113         integerAtt = value;
114     }
115 
116     /**
117      * Get boolean attribute
118      */
getBoolAtt()119     public boolean getBoolAtt() {
120         return boolAtt;
121     }
122 
123     /**
124      * Set boolean attribute
125      */
setBoolAtt(boolean value)126     public void setBoolAtt(boolean value) {
127         boolAtt = value;
128     }
129 
130     /**
131      * Get Boolean attribute
132      */
getBooleanAtt()133     public Boolean getBooleanAtt() {
134         return booleanAtt;
135     }
136 
137     /**
138      * Set Boolean attribute
139      */
setBooleanAtt(Boolean value)140     public void setBooleanAtt(Boolean value) {
141         booleanAtt = value;
142     }
143 
144     /**
145      * Get String attribute
146      */
getStringAtt()147     public String getStringAtt() {
148         return stringAtt;
149     }
150 
151     /**
152      * Set String attribute
153      */
setStringAtt(String value)154     public void setStringAtt(String value) {
155         stringAtt = value;
156     }
157 
158     /**
159      * Get Date attribute
160      */
getDateAtt()161     public Date getDateAtt() {
162         return dateAtt;
163     }
164 
165     /**
166      * Set Date attribute
167      */
setDateAtt(Date value)168     public void setDateAtt(Date value) {
169         dateAtt = value;
170     }
171 
172     /**
173      * Get ObjectName attribute
174      */
getObjectNameAtt()175     public ObjectName getObjectNameAtt() {
176         return objectNameAtt;
177     }
178 
179     /**
180      * Set ObjectName attribute
181      */
setObjectNameAtt(ObjectName value)182     public void setObjectNameAtt(ObjectName value) {
183         objectNameAtt = value;
184     }
185 
186     /**
187      * Get SqeParameter attribute
188      */
getSqeParameterAtt()189     public SqeParameter getSqeParameterAtt() throws Exception {
190         if (sqeParameterAtt == null) {
191             sqeParameterAtt = new SqeParameter();
192             sqeParameterAtt.setGlop("INITIALIZED");
193         }
194 
195         return sqeParameterAtt;
196     }
197 
198     /**
199      * Set SqeParameter attribute
200      */
setSqeParameterAtt(SqeParameter value)201     public void setSqeParameterAtt(SqeParameter value) {
202         sqeParameterAtt = value;
203     }
204 
205     /**
206      * Get the Descriptor used to build the NotificationInfo
207      * of emitted notifications.
208      */
getNotifDescriptorAsMapAtt()209     public Map<String, String> getNotifDescriptorAsMapAtt() {
210         if (notifDescriptorAsMapAtt == null) {
211             initNotifDescriptorAtt();
212         }
213 
214         return notifDescriptorAsMapAtt;
215     }
216 
217     /**
218      * Set the Descriptor used to build the NotificationInfo
219      * of emitted notifications.
220      * <br>A Map<String, Object> would better fit Descriptor needs but then
221      * it is not convertible according the MXBean specification so the MBean
222      * registration fails.
223      * As we plan to test our custom Descriptor finds its way into
224      * the metadata of emitted notifications, String is good enough.
225      */
setNotifDescriptorAsMapAtt(Map<String, String> value)226     public void setNotifDescriptorAsMapAtt(Map<String, String> value) {
227         notifDescriptorAsMapAtt = new HashMap<String, String>(value);
228         notifDescriptorAtt = new ImmutableDescriptor(value);
229     }
230 
231     /**
232      * Do nothing
233      */
doNothing()234     public void doNothing() {
235         // I said NOTHING !
236     }
237 
238     /**
239      * Do take SqeParameter as a parameter
240      */
doWeird(SqeParameter param)241     public void doWeird(SqeParameter param) {
242     }
243 
244     /**
245      * Throw an Exception
246      */
throwException()247     public void throwException() throws Exception {
248         throw new Exception(EXCEPTION_MESSAGE);
249     }
250 
251     /**
252      * Throw an Error
253      */
throwError()254     public void throwError() {
255         throw new InternalError(EXCEPTION_MESSAGE);
256     }
257 
258     /**
259      * Reset all attributes
260      */
reset()261     public void reset() {
262         intAtt = 0;
263         integerAtt = 0;
264         boolAtt = false;
265         booleanAtt = Boolean.FALSE;
266         stringAtt = null;
267         dateAtt = null;
268         objectNameAtt = null;
269     }
270 
271     /**
272      * Returns the weather for the coming days
273      * @param verbose <code>boolean</code> verbosity
274      * @throws java.lang.Exception <code>storm</code>
275      * @return <code>ObjectName</code>
276      */
getWeather(boolean verbose)277     public Weather getWeather(boolean verbose)
278             throws java.lang.Exception {
279         return Weather.SUNNY;
280     }
281 
282     // Starting here are the 4 methods of MBeanRegistration interface.
283     // We use that to grab the ObjectName the MBean is registered with.
284     //
preRegister(MBeanServer server, ObjectName name)285     public ObjectName preRegister(MBeanServer server, ObjectName name)
286             throws Exception {
287         // Grab a reference on the MBeanServer we're registered in.
288         mbs = server;
289         // Compute the name we're registered with.
290         if (name != null) {
291             mbeanName = name;
292             return name;
293         } else {
294             mbeanName =
295                 new ObjectName("sqe:type=" + Basic.class.getName());
296             return mbeanName;
297         }
298     }
299 
postRegister(Boolean registrationDone)300     public void postRegister(Boolean registrationDone) {
301         // Do nothing
302     }
303 
preDeregister()304     public void preDeregister() throws Exception {
305         // Do nothing
306     }
307 
postDeregister()308     public void postDeregister() {
309         // Do nothing
310     }
311 
312     /**
313      * Send one Notification of the provided notifType type.
314      */
sendNotification(String notifType)315     public void sendNotification(String notifType) {
316         Notification notification = null;
317 
318         if (notifType.equals(NOTIF_TYPE_0)) {
319             notification = new Notification(NOTIF_TYPE_0,
320                     mbeanName,
321                     seqNumber,
322                     NOTIFICATION_MESSAGE);
323         } else if (notifType.equals(NOTIF_TYPE_1)) {
324             notification = new SqeNotification(NOTIF_TYPE_1,
325                     mbeanName,
326                     seqNumber,
327                     NOTIFICATION_MESSAGE);
328         }
329 
330         seqNumber++;
331         broadcaster.sendNotification(notification);
332     }
333 
334     /**
335      * That method starts a set of threads, each thread sends a given number of
336      * notifications.
337      * The number of threads can be set via the attribute numOfNotificationSenders.
338      * The number of notification sent by each thread can be set via
339      * the attribute numOfNotificationSenderLoops.
340      * Depending on the parameter customNotification we send either custom
341      * notification(s) or MBeanServer registration and unregistration notification(s).
342      * When customNotification=true the total number of notification(s) sent is
343      * (numOfNotificationSenders * numOfNotificationSenderLoops). They are
344      * sequentially of type NOTIF_TYPE_0 then NOTIF_TYPE_1 and so on.
345      *
346      * When customNotification=false the total number of notification(s) sent is
347      * (numOfNotificationSenders * numOfNotificationSenderLoops) registration
348      * notification(s)
349      * +
350      * (numOfNotificationSenders * numOfNotificationSenderLoops) unregistration
351      * notification(s)
352      *
353      * @throws java.lang.Exception
354      */
sendNotificationWave(boolean customNotification)355     public void sendNotificationWave(boolean customNotification) throws
356             Exception {
357         // Build the set of notification sender.
358         Collection<Callable<Integer>> tasks =
359                 new HashSet<Callable<Integer>>(numOfNotificationSenders);
360 
361         for (int i = 1; i <= numOfNotificationSenders; i++) {
362             tasks.add(new NotifSender(numOfNotificationSenderLoops,
363                     customNotification, i));
364         }
365 
366         // Start all notification sender in parallel.
367         ExecutorService execServ = null;
368         try {
369             execServ = Executors.newFixedThreadPool(numOfNotificationSenders);
370             List<Future<Integer>> taskHandlers = execServ.invokeAll(tasks);
371             checkNotifSenderThreadStatus(taskHandlers);
372         } finally {
373             if (!execServ.isShutdown()) {
374                 execServ.shutdown();
375             }
376         }
377     }
378 
setNumOfNotificationSenders(int value)379     public void setNumOfNotificationSenders(int value) {
380         numOfNotificationSenders = value;
381     }
382 
setNumOfNotificationSenderLoops(int value)383     public void setNumOfNotificationSenderLoops(int value) {
384         numOfNotificationSenderLoops = value;
385     }
386 
387     /**
388      * MBean Notification support
389      * You shouldn't update these methods
390      */
391     // <editor-fold defaultstate="collapsed" desc=" Generated Code ">
addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback)392     public void addNotificationListener(NotificationListener listener,
393                                         NotificationFilter filter,
394                                         Object handback)
395             throws IllegalArgumentException {
396         broadcaster.addNotificationListener(listener, filter, handback);
397     }
398 
getNotificationInfo()399     public MBeanNotificationInfo[] getNotificationInfo() {
400         if (notifDescriptorAtt == null) {
401             initNotifDescriptorAtt();
402         }
403 
404         return new MBeanNotificationInfo[]{
405                     new MBeanNotificationInfo(new String[]{
406                         NOTIF_TYPE_0
407                     },
408                     javax.management.Notification.class.getName(),
409                     "Standard JMX Notification",
410                     notifDescriptorAtt),
411                     new MBeanNotificationInfo(new String[]{
412                         NOTIF_TYPE_1
413                     },
414                     SqeNotification.class.getName(),
415                     "SQE Notification",
416                     notifDescriptorAtt)
417                 };
418     }
419 
removeNotificationListener(NotificationListener listener)420     public void removeNotificationListener(NotificationListener listener)
421             throws ListenerNotFoundException {
422         broadcaster.removeNotificationListener(listener);
423     }
424 
removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback)425     public void removeNotificationListener(NotificationListener listener,
426                                            NotificationFilter filter,
427                                            Object handback)
428             throws ListenerNotFoundException {
429         broadcaster.removeNotificationListener(listener, filter, handback);
430     }
431     // </editor-fold>
getNextSeqNumber()432     private synchronized long getNextSeqNumber() {
433         return seqNumber++;
434     }
435 
initNotifDescriptorAtt()436     private void initNotifDescriptorAtt() {
437         String key = "CRABE";
438         String value = "TAMBOUR";
439         notifDescriptorAtt =
440                 new ImmutableDescriptor(new String[]{key + "=" + value});
441         notifDescriptorAsMapAtt =
442                 new HashMap<String, String>();
443         notifDescriptorAsMapAtt.put(key, value);
444     }
445 
checkNotifSenderThreadStatus( List<Future<Integer>> taskHandlers)446     private void checkNotifSenderThreadStatus(
447             List<Future<Integer>> taskHandlers)
448             throws Exception {
449         String msgTag = "Basic::checkNotifSenderThreadStatus: ";
450         // Grab back status of each notification sender.
451         for (Future<Integer> f : taskHandlers) {
452             if (f.isCancelled()) {
453                 String message = msgTag +
454                         "---- ERROR : One thread has been cancelled";
455                 System.out.println(message);
456                 throw new RuntimeException(message);
457             } else {
458                 Integer effectiveNumOfLoops = f.get();
459 
460                 if (effectiveNumOfLoops != numOfNotificationSenderLoops) {
461                     String message = msgTag + "---- ERROR : One thread did " +
462                             effectiveNumOfLoops + " loops in place of " +
463                             numOfNotificationSenderLoops;
464                     System.out.println(message);
465                     throw new RuntimeException(message);
466                 }
467             }
468         }
469     }
470     //
471     private int numOfNotificationSenderLoops = 2;
472     private int numOfNotificationSenders = 13;
473 
474     private class NotifSender implements Callable<Integer> {
475 
476         private int cycles;
477         private boolean customNotification;
478         private int senderID;
479 
NotifSender(int cycles, boolean customNotification, int id)480         public NotifSender(int cycles, boolean customNotification, int id) {
481             this.cycles = cycles;
482             this.customNotification = customNotification;
483             this.senderID = id;
484         }
485 
call()486         public Integer call() throws Exception {
487             int callsDone = 0;
488 
489             try {
490                 for (int i = 1; i <= cycles; i++) {
491                     if (customNotification) {
492                         if (i % 2 == 0) {
493                             sendNotification(NOTIF_TYPE_0);
494                         } else {
495                             sendNotification(NOTIF_TYPE_1);
496                         }
497                     } else {
498                         ObjectName mbeanName = new ObjectName("SQE:type=" +
499                                 mbeanClassName + ",senderID=" + senderID);
500                         mbs.createMBean(mbeanClassName, mbeanName);
501                         mbs.unregisterMBean(mbeanName);
502                     }
503                     callsDone++;
504                 }
505             } catch (Exception e) {
506                 System.out.println("NotifSender::call: (ERROR) Thread [" + senderID +
507                         "] failed after " + callsDone + " cycles");
508                 throw e;
509             }
510 
511             return Integer.valueOf(callsDone);
512         }
513     }
514 
515     //
516     private long seqNumber;
517     private final NotificationBroadcasterSupport broadcaster =
518             new NotificationBroadcasterSupport();
519     private ObjectName mbeanName;
520     private MBeanServer mbs;
521     private String mbeanClassName = "Simple";
522 
523     /**
524      * Notification types definitions. To use when creating JMX Notifications.
525      */
526     public static final String NOTIF_TYPE_0 =
527             "sqe.notification.a.type";
528     public static final String NOTIF_TYPE_1 =
529             "sqe.notification.b.type";
530 }
531