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.ObjectInputStream; 30import java.io.ObjectOutputStream; 31import java.io.Serializable; 32import java.io.StreamCorruptedException; 33import java.util.Objects; 34 35/** 36 * <p>Provides general information for an MBean descriptor object. 37 * The feature described can be an attribute, an operation, a 38 * parameter, or a notification. Instances of this class are 39 * immutable. Subclasses may be mutable but this is not 40 * recommended.</p> 41 * 42 * @since 1.5 43 */ 44public class MBeanFeatureInfo implements Serializable, DescriptorRead { 45 46 47 /* Serial version */ 48 static final long serialVersionUID = 3952882688968447265L; 49 50 /** 51 * The name of the feature. It is recommended that subclasses call 52 * {@link #getName} rather than reading this field, and that they 53 * not change it. 54 * 55 * @serial The name of the feature. 56 */ 57 protected String name; 58 59 /** 60 * The human-readable description of the feature. It is 61 * recommended that subclasses call {@link #getDescription} rather 62 * than reading this field, and that they not change it. 63 * 64 * @serial The human-readable description of the feature. 65 */ 66 protected String description; 67 68 /** 69 * @serial The Descriptor for this MBeanFeatureInfo. This field 70 * can be null, which is equivalent to an empty Descriptor. 71 */ 72 private transient Descriptor descriptor; 73 74 75 /** 76 * Constructs an <CODE>MBeanFeatureInfo</CODE> object. This 77 * constructor is equivalent to {@code MBeanFeatureInfo(name, 78 * description, (Descriptor) null}. 79 * 80 * @param name The name of the feature. 81 * @param description A human readable description of the feature. 82 */ 83 public MBeanFeatureInfo(String name, String description) { 84 this(name, description, null); 85 } 86 87 /** 88 * Constructs an <CODE>MBeanFeatureInfo</CODE> object. 89 * 90 * @param name The name of the feature. 91 * @param description A human readable description of the feature. 92 * @param descriptor The descriptor for the feature. This may be null 93 * which is equivalent to an empty descriptor. 94 * 95 * @since 1.6 96 */ 97 public MBeanFeatureInfo(String name, String description, 98 Descriptor descriptor) { 99 this.name = name; 100 this.description = description; 101 this.descriptor = descriptor; 102 } 103 104 /** 105 * Returns the name of the feature. 106 * 107 * @return the name of the feature. 108 */ 109 public String getName() { 110 return name; 111 } 112 113 /** 114 * Returns the human-readable description of the feature. 115 * 116 * @return the human-readable description of the feature. 117 */ 118 public String getDescription() { 119 return description; 120 } 121 122 /** 123 * Returns the descriptor for the feature. Changing the returned value 124 * will have no affect on the original descriptor. 125 * 126 * @return a descriptor that is either immutable or a copy of the original. 127 * 128 * @since 1.6 129 */ 130 public Descriptor getDescriptor() { 131 return (Descriptor) ImmutableDescriptor.nonNullDescriptor(descriptor).clone(); 132 } 133 134 /** 135 * Compare this MBeanFeatureInfo to another. 136 * 137 * @param o the object to compare to. 138 * 139 * @return true if and only if <code>o</code> is an MBeanFeatureInfo such 140 * that its {@link #getName()}, {@link #getDescription()}, and 141 * {@link #getDescriptor()} 142 * values are equal (not necessarily identical) to those of this 143 * MBeanFeatureInfo. 144 */ 145 public boolean equals(Object o) { 146 if (o == this) 147 return true; 148 if (!(o instanceof MBeanFeatureInfo)) 149 return false; 150 MBeanFeatureInfo p = (MBeanFeatureInfo) o; 151 return (Objects.equals(p.getName(), getName()) && 152 Objects.equals(p.getDescription(), getDescription()) && 153 Objects.equals(p.getDescriptor(), getDescriptor())); 154 } 155 156 public int hashCode() { 157 return getName().hashCode() ^ getDescription().hashCode() ^ 158 getDescriptor().hashCode(); 159 } 160 161 /** 162 * Serializes an {@link MBeanFeatureInfo} to an {@link ObjectOutputStream}. 163 * @serialData 164 * For compatibility reasons, an object of this class is serialized as follows. 165 * <p> 166 * The method {@link ObjectOutputStream#defaultWriteObject defaultWriteObject()} 167 * is called first to serialize the object except the field {@code descriptor} 168 * which is declared as transient. The field {@code descriptor} is serialized 169 * as follows: 170 * <ul> 171 * <li>If {@code descriptor} is an instance of the class 172 * {@link ImmutableDescriptor}, the method {@link ObjectOutputStream#write 173 * write(int val)} is called to write a byte with the value {@code 1}, 174 * then the method {@link ObjectOutputStream#writeObject writeObject(Object obj)} 175 * is called twice to serialize the field names and the field values of the 176 * {@code descriptor}, respectively as a {@code String[]} and an 177 * {@code Object[]};</li> 178 * <li>Otherwise, the method {@link ObjectOutputStream#write write(int val)} 179 * is called to write a byte with the value {@code 0}, then the method 180 * {@link ObjectOutputStream#writeObject writeObject(Object obj)} is called 181 * to serialize directly the field {@code descriptor}. 182 * </ul> 183 * 184 * @since 1.6 185 */ 186 private void writeObject(ObjectOutputStream out) throws IOException { 187 out.defaultWriteObject(); 188 189 if (descriptor != null && 190 descriptor.getClass() == ImmutableDescriptor.class) { 191 192 out.write(1); 193 194 final String[] names = descriptor.getFieldNames(); 195 196 out.writeObject(names); 197 out.writeObject(descriptor.getFieldValues(names)); 198 } else { 199 out.write(0); 200 201 out.writeObject(descriptor); 202 } 203 } 204 205 /** 206 * Deserializes an {@link MBeanFeatureInfo} from an {@link ObjectInputStream}. 207 * @serialData 208 * For compatibility reasons, an object of this class is deserialized as follows. 209 * <p> 210 * The method {@link ObjectInputStream#defaultReadObject defaultReadObject()} 211 * is called first to deserialize the object except the field 212 * {@code descriptor}, which is not serialized in the default way. Then the method 213 * {@link ObjectInputStream#read read()} is called to read a byte, the field 214 * {@code descriptor} is deserialized according to the value of the byte value: 215 * <ul> 216 * <li>1. The method {@link ObjectInputStream#readObject readObject()} 217 * is called twice to obtain the field names (a {@code String[]}) and 218 * the field values (an {@code Object[]}) of the {@code descriptor}. 219 * The two obtained values then are used to construct 220 * an {@link ImmutableDescriptor} instance for the field 221 * {@code descriptor};</li> 222 * <li>0. The value for the field {@code descriptor} is obtained directly 223 * by calling the method {@link ObjectInputStream#readObject readObject()}. 224 * If the obtained value is null, the field {@code descriptor} is set to 225 * {@link ImmutableDescriptor#EMPTY_DESCRIPTOR EMPTY_DESCRIPTOR};</li> 226 * <li>-1. This means that there is no byte to read and that the object is from 227 * an earlier version of the JMX API. The field {@code descriptor} is set 228 * to {@link ImmutableDescriptor#EMPTY_DESCRIPTOR EMPTY_DESCRIPTOR}</li> 229 * <li>Any other value. A {@link StreamCorruptedException} is thrown.</li> 230 * </ul> 231 * 232 * @since 1.6 233 */ 234 private void readObject(ObjectInputStream in) 235 throws IOException, ClassNotFoundException { 236 237 in.defaultReadObject(); 238 239 switch (in.read()) { 240 case 1: 241 final String[] names = (String[])in.readObject(); 242 243 final Object[] values = (Object[]) in.readObject(); 244 descriptor = (names.length == 0) ? 245 ImmutableDescriptor.EMPTY_DESCRIPTOR : 246 new ImmutableDescriptor(names, values); 247 248 break; 249 case 0: 250 descriptor = (Descriptor)in.readObject(); 251 252 if (descriptor == null) { 253 descriptor = ImmutableDescriptor.EMPTY_DESCRIPTOR; 254 } 255 256 break; 257 case -1: // from an earlier version of the JMX API 258 descriptor = ImmutableDescriptor.EMPTY_DESCRIPTOR; 259 260 break; 261 default: 262 throw new StreamCorruptedException("Got unexpected byte."); 263 } 264 } 265} 266