1/*
2 * Copyright (c) 1999, 2013, 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.InvalidObjectException;
30import java.io.ObjectInputStream;
31import java.util.Arrays;
32import java.util.Objects;
33
34/**
35 * <p>The {@code MBeanNotificationInfo} class is used to describe the
36 * characteristics of the different notification instances
37 * emitted by an MBean, for a given Java class of notification.
38 * If an MBean emits notifications that can be instances of different Java classes,
39 * then the metadata for that MBean should provide an {@code MBeanNotificationInfo}
40 * object for each of these notification Java classes.</p>
41 *
42 * <p>Instances of this class are immutable.  Subclasses may be
43 * mutable but this is not recommended.</p>
44 *
45 * <p>This class extends {@code javax.management.MBeanFeatureInfo}
46 * and thus provides {@code name} and {@code description} fields.
47 * The {@code name} field should be the fully qualified Java class name of
48 * the notification objects described by this class.</p>
49 *
50 * <p>The {@code getNotifTypes} method returns an array of
51 * strings containing the notification types that the MBean may
52 * emit. The notification type is a dot-notation string which
53 * describes what the emitted notification is about, not the Java
54 * class of the notification.  A single generic notification class can
55 * be used to send notifications of several types.  All of these types
56 * are returned in the string array result of the
57 * {@code getNotifTypes} method.
58 *
59 * @since 1.5
60 */
61public class MBeanNotificationInfo extends MBeanFeatureInfo implements Cloneable {
62
63    /* Serial version */
64    static final long serialVersionUID = -3888371564530107064L;
65
66    private static final String[] NO_TYPES = new String[0];
67
68    static final MBeanNotificationInfo[] NO_NOTIFICATIONS =
69        new MBeanNotificationInfo[0];
70
71    /**
72     * @serial The different types of the notification.
73     */
74    private String[] types;
75
76    /** @see MBeanInfo#arrayGettersSafe */
77    private final transient boolean arrayGettersSafe;
78
79    /**
80     * Constructs an {@code MBeanNotificationInfo} object.
81     *
82     * @param notifTypes The array of strings (in dot notation)
83     * containing the notification types that the MBean may emit.
84     * This may be null with the same effect as a zero-length array.
85     * @param name The fully qualified Java class name of the
86     * described notifications.
87     * @param description A human readable description of the data.
88     */
89    public MBeanNotificationInfo(String[] notifTypes,
90                                 String name,
91                                 String description) {
92        this(notifTypes, name, description, null);
93    }
94
95    /**
96     * Constructs an {@code MBeanNotificationInfo} object.
97     *
98     * @param notifTypes The array of strings (in dot notation)
99     * containing the notification types that the MBean may emit.
100     * This may be null with the same effect as a zero-length array.
101     * @param name The fully qualified Java class name of the
102     * described notifications.
103     * @param description A human readable description of the data.
104     * @param descriptor The descriptor for the notifications.  This may be null
105     * which is equivalent to an empty descriptor.
106     *
107     * @since 1.6
108     */
109    public MBeanNotificationInfo(String[] notifTypes,
110                                 String name,
111                                 String description,
112                                 Descriptor descriptor) {
113        super(name, description, descriptor);
114
115        /* We do not validate the notifTypes, since the spec just says
116           they are dot-separated, not that they must look like Java
117           classes.  E.g. the spec doesn't forbid "sun.prob.25" as a
118           notifType, though it doesn't explicitly allow it
119           either.  */
120
121        this.types = (notifTypes != null && notifTypes.length > 0) ?
122                        notifTypes.clone() : NO_TYPES;
123        this.arrayGettersSafe =
124            MBeanInfo.arrayGettersSafe(this.getClass(),
125                                       MBeanNotificationInfo.class);
126    }
127
128
129    /**
130     * Returns a shallow clone of this instance.
131     * The clone is obtained by simply calling {@code super.clone()},
132     * thus calling the default native shallow cloning mechanism
133     * implemented by {@code Object.clone()}.
134     * No deeper cloning of any internal field is made.
135     */
136     public Object clone () {
137         try {
138             return super.clone() ;
139         } catch (CloneNotSupportedException e) {
140             // should not happen as this class is cloneable
141             return null;
142         }
143     }
144
145
146    /**
147     * Returns the array of strings (in dot notation) containing the
148     * notification types that the MBean may emit.
149     *
150     * @return the array of strings.  Changing the returned array has no
151     * effect on this MBeanNotificationInfo.
152     */
153    public String[] getNotifTypes() {
154        if (types.length == 0)
155            return NO_TYPES;
156        else
157            return types.clone();
158    }
159
160    private String[] fastGetNotifTypes() {
161        if (arrayGettersSafe)
162            return types;
163        else
164            return getNotifTypes();
165    }
166
167    public String toString() {
168        return
169            getClass().getName() + "[" +
170            "description=" + getDescription() + ", " +
171            "name=" + getName() + ", " +
172            "notifTypes=" + Arrays.asList(fastGetNotifTypes()) + ", " +
173            "descriptor=" + getDescriptor() +
174            "]";
175    }
176
177    /**
178     * Compare this MBeanNotificationInfo to another.
179     *
180     * @param o the object to compare to.
181     *
182     * @return true if and only if {@code o} is an MBeanNotificationInfo
183     * such that its {@link #getName()}, {@link #getDescription()},
184     * {@link #getDescriptor()},
185     * and {@link #getNotifTypes()} values are equal (not necessarily
186     * identical) to those of this MBeanNotificationInfo.  Two
187     * notification type arrays are equal if their corresponding
188     * elements are equal.  They are not equal if they have the same
189     * elements but in a different order.
190     */
191    public boolean equals(Object o) {
192        if (o == this)
193            return true;
194        if (!(o instanceof MBeanNotificationInfo))
195            return false;
196        MBeanNotificationInfo p = (MBeanNotificationInfo) o;
197        return (Objects.equals(p.getName(), getName()) &&
198                Objects.equals(p.getDescription(), getDescription()) &&
199                Objects.equals(p.getDescriptor(), getDescriptor()) &&
200                Arrays.equals(p.fastGetNotifTypes(), fastGetNotifTypes()));
201    }
202
203    public int hashCode() {
204        int hash = getName().hashCode();
205        for (int i = 0; i < types.length; i++)
206            hash ^= types[i].hashCode();
207        return hash;
208    }
209
210    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
211        ObjectInputStream.GetField gf = ois.readFields();
212        String[] t = (String[])gf.get("types", null);
213
214        types = (t != null && t.length != 0) ? t.clone() : NO_TYPES;
215    }
216}
217