1/*
2 * Copyright (c) 1999, 2008, 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.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package javax.management;
27
28import java.io.IOException;
29import java.io.ObjectInputStream;
30import java.io.ObjectOutputStream;
31import java.io.ObjectStreamField;
32import java.util.EventObject;
33
34import java.security.AccessController;
35
36import com.sun.jmx.mbeanserver.GetPropertyAction;
37
38/**
39 * <p>The Notification class represents a notification emitted by an
40 * MBean.  It contains a reference to the source MBean: if the
41 * notification has been forwarded through the MBean server, and the
42 * original source of the notification was a reference to the emitting
43 * MBean object, then the MBean server replaces it by the MBean's
44 * ObjectName.  If the listener has registered directly with the
45 * MBean, this is either the object name or a direct reference to the
46 * MBean.</p>
47 *
48 * <p>It is strongly recommended that notification senders use the
49 * object name rather than a reference to the MBean object as the
50 * source.</p>
51 *
52 * <p>The <b>serialVersionUID</b> of this class is <code>-7516092053498031989L</code>.
53 *
54 * @since 1.5
55 */
56@SuppressWarnings("serial")  // serialVersionUID is not constant
57public class Notification extends EventObject {
58
59    // Serialization compatibility stuff:
60    // Two serial forms are supported in this class. The selected form depends
61    // on system property "jmx.serial.form":
62    //  - "1.0" for JMX 1.0
63    //  - any other value for JMX 1.1 and higher
64    //
65    // Serial version for old serial form
66    private static final long oldSerialVersionUID = 1716977971058914352L;
67    //
68    // Serial version for new serial form
69    private static final long newSerialVersionUID = -7516092053498031989L;
70    //
71    // Serializable fields in old serial form
72    private static final ObjectStreamField[] oldSerialPersistentFields =
73    {
74        new ObjectStreamField("message", String.class),
75        new ObjectStreamField("sequenceNumber", Long.TYPE),
76        new ObjectStreamField("source", Object.class),
77        new ObjectStreamField("sourceObjectName", ObjectName.class),
78        new ObjectStreamField("timeStamp", Long.TYPE),
79        new ObjectStreamField("type", String.class),
80        new ObjectStreamField("userData", Object.class)
81    };
82    //
83    // Serializable fields in new serial form
84    private static final ObjectStreamField[] newSerialPersistentFields =
85    {
86        new ObjectStreamField("message", String.class),
87        new ObjectStreamField("sequenceNumber", Long.TYPE),
88        new ObjectStreamField("source", Object.class),
89        new ObjectStreamField("timeStamp", Long.TYPE),
90        new ObjectStreamField("type", String.class),
91        new ObjectStreamField("userData", Object.class)
92    };
93    //
94    // Actual serial version and serial form
95    private static final long serialVersionUID;
96    /**
97     * @serialField type String The notification type.
98     *              A string expressed in a dot notation similar to Java properties.
99     *              An example of a notification type is network.alarm.router
100     * @serialField sequenceNumber long The notification sequence number.
101     *              A serial number which identify particular instance
102     *              of notification in the context of the notification source.
103     * @serialField timeStamp long The notification timestamp.
104     *              Indicating when the notification was generated
105     * @serialField userData Object The notification user data.
106     *              Used for whatever other data the notification
107     *              source wishes to communicate to its consumers
108     * @serialField message String The notification message.
109     * @serialField source Object The object on which the notification initially occurred.
110     */
111    private static final ObjectStreamField[] serialPersistentFields;
112    private static boolean compat = false;
113    static {
114        try {
115            GetPropertyAction act = new GetPropertyAction("jmx.serial.form");
116            String form = AccessController.doPrivileged(act);
117            compat = (form != null && form.equals("1.0"));
118        } catch (Exception e) {
119            // OK: exception means no compat with 1.0, too bad
120        }
121        if (compat) {
122            serialPersistentFields = oldSerialPersistentFields;
123            serialVersionUID = oldSerialVersionUID;
124        } else {
125            serialPersistentFields = newSerialPersistentFields;
126            serialVersionUID = newSerialVersionUID;
127        }
128    }
129    //
130    // END Serialization compatibility stuff
131
132    /**
133     * @serial The notification type.
134     *         A string expressed in a dot notation similar to Java properties.
135     *         An example of a notification type is network.alarm.router
136     */
137    private String type;
138
139    /**
140     * @serial The notification sequence number.
141     *         A serial number which identify particular instance
142     *         of notification in the context of the notification source.
143     */
144    private long sequenceNumber;
145
146    /**
147     * @serial The notification timestamp.
148     *         Indicating when the notification was generated
149     */
150    private long timeStamp;
151
152    /**
153     * @serial The notification user data.
154     *         Used for whatever other data the notification
155     *         source wishes to communicate to its consumers
156     */
157    private Object userData = null;
158
159    /**
160     * @serial The notification message.
161     */
162    private String message  = "";
163
164    /**
165     * <p>This field hides the {@link EventObject#source} field in the
166     * parent class to make it non-transient and therefore part of the
167     * serialized form.</p>
168     *
169     * @serial The object on which the notification initially occurred.
170     */
171    protected Object source = null;
172
173
174    /**
175     * Creates a Notification object.
176     * The notification timeStamp is set to the current date.
177     *
178     * @param type The notification type.
179     * @param source The notification source.
180     * @param sequenceNumber The notification sequence number within the source object.
181     *
182     */
183    public Notification(String type, Object source, long sequenceNumber) {
184        super (source) ;
185        this.source = source;
186        this.type = type;
187        this.sequenceNumber = sequenceNumber ;
188        this.timeStamp = (new java.util.Date()).getTime() ;
189    }
190
191    /**
192     * Creates a Notification object.
193     * The notification timeStamp is set to the current date.
194     *
195     * @param type The notification type.
196     * @param source The notification source.
197     * @param sequenceNumber The notification sequence number within the source object.
198     * @param message The detailed message.
199     *
200     */
201    public Notification(String type, Object source, long sequenceNumber, String message) {
202        super (source) ;
203        this.source = source;
204        this.type = type;
205        this.sequenceNumber = sequenceNumber ;
206        this.timeStamp = (new java.util.Date()).getTime() ;
207        this.message = message ;
208    }
209
210    /**
211     * Creates a Notification object.
212     *
213     * @param type The notification type.
214     * @param source The notification source.
215     * @param sequenceNumber The notification sequence number within the source object.
216     * @param timeStamp The notification emission date.
217     *
218     */
219    public Notification(String type, Object source, long sequenceNumber, long timeStamp) {
220        super (source) ;
221        this.source = source;
222        this.type = type ;
223        this.sequenceNumber = sequenceNumber ;
224        this.timeStamp = timeStamp ;
225    }
226
227    /**
228     * Creates a Notification object.
229     *
230     * @param type The notification type.
231     * @param source The notification source.
232     * @param sequenceNumber The notification sequence number within the source object.
233     * @param timeStamp The notification emission date.
234     * @param message The detailed message.
235     *
236     */
237    public Notification(String type, Object source, long sequenceNumber, long timeStamp, String message) {
238        super (source) ;
239        this.source = source;
240        this.type = type ;
241        this.sequenceNumber = sequenceNumber ;
242        this.timeStamp = timeStamp ;
243        this.message = message ;
244    }
245
246    /**
247     * Sets the source.
248     *
249     * @param source the new source for this object.
250     *
251     * @see EventObject#getSource
252     */
253    public void setSource(Object source) {
254        super.source = source;
255        this.source = source;
256    }
257
258    /**
259     * Get the notification sequence number.
260     *
261     * @return The notification sequence number within the source object. It's a serial number
262     * identifying a particular instance of notification in the context of the notification source.
263     * The notification model does not assume that notifications will be received in the same order
264     * that they are sent. The sequence number helps listeners to sort received notifications.
265     *
266     * @see #setSequenceNumber
267     */
268    public long getSequenceNumber() {
269        return sequenceNumber ;
270    }
271
272    /**
273     * Set the notification sequence number.
274     *
275     * @param sequenceNumber The notification sequence number within the source object. It is
276     * a serial number identifying a particular instance of notification in the
277     * context of the notification source.
278     *
279     * @see #getSequenceNumber
280     */
281    public void setSequenceNumber(long sequenceNumber) {
282        this.sequenceNumber = sequenceNumber;
283    }
284
285    /**
286     * Get the notification type.
287     *
288     * @return The notification type. It's a string expressed in a dot notation
289     * similar to Java properties. It is recommended that the notification type
290     * should follow the reverse-domain-name convention used by Java package
291     * names.  An example of a notification type is com.example.alarm.router.
292     */
293    public String getType() {
294        return type ;
295    }
296
297    /**
298     * Get the notification timestamp.
299     *
300     * @return The notification timestamp.
301     *
302     * @see #setTimeStamp
303     */
304    public long getTimeStamp() {
305        return timeStamp ;
306    }
307
308    /**
309     * Set the notification timestamp.
310     *
311     * @param timeStamp The notification timestamp. It indicates when the notification was generated.
312     *
313     * @see #getTimeStamp
314     */
315    public void setTimeStamp(long timeStamp) {
316        this.timeStamp = timeStamp;
317    }
318
319    /**
320     * Get the notification message.
321     *
322     * @return The message string of this notification object.
323     *
324     */
325    public String getMessage() {
326        return message ;
327    }
328
329    /**
330     * Get the user data.
331     *
332     * @return The user data object. It is used for whatever data
333     * the notification source wishes to communicate to its consumers.
334     *
335     * @see #setUserData
336     */
337    public Object getUserData() {
338        return userData ;
339    }
340
341    /**
342     * Set the user data.
343     *
344     * @param userData The user data object. It is used for whatever data
345     * the notification source wishes to communicate to its consumers.
346     *
347     * @see #getUserData
348     */
349    public void setUserData(Object userData) {
350
351        this.userData = userData ;
352    }
353
354    /**
355     * Returns a String representation of this notification.
356     *
357     * @return A String representation of this notification.
358     */
359    @Override
360    public String toString() {
361        return super.toString()+"[type="+type+"][message="+message+"]";
362    }
363
364    /**
365     * Deserializes a {@link Notification} from an {@link ObjectInputStream}.
366     */
367    private void readObject(ObjectInputStream in)
368            throws IOException, ClassNotFoundException {
369      // New serial form ignores extra field "sourceObjectName"
370      in.defaultReadObject();
371      super.source = source;
372    }
373
374
375    /**
376     * Serializes a {@link Notification} to an {@link ObjectOutputStream}.
377     */
378    private void writeObject(ObjectOutputStream out)
379            throws IOException {
380        if (compat) {
381            // Serializes this instance in the old serial form
382            //
383            ObjectOutputStream.PutField fields = out.putFields();
384            fields.put("type", type);
385            fields.put("sequenceNumber", sequenceNumber);
386            fields.put("timeStamp", timeStamp);
387            fields.put("userData", userData);
388            fields.put("message", message);
389            fields.put("source", source);
390            out.writeFields();
391        } else {
392            // Serializes this instance in the new serial form
393            //
394            out.defaultWriteObject();
395        }
396    }
397}
398