提交 2cc2b4c2 编写于 作者: J jbachorik

8014085: Better serialization support in JMX classes

Reviewed-by: alanb, dfuchs, skoivu
上级 db5bee27
...@@ -25,6 +25,9 @@ ...@@ -25,6 +25,9 @@
package javax.management; package javax.management;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.util.Arrays; import java.util.Arrays;
/** /**
...@@ -67,7 +70,7 @@ public class MBeanNotificationInfo extends MBeanFeatureInfo implements Cloneable ...@@ -67,7 +70,7 @@ public class MBeanNotificationInfo extends MBeanFeatureInfo implements Cloneable
/** /**
* @serial The different types of the notification. * @serial The different types of the notification.
*/ */
private final String[] types; private String[] types;
/** @see MBeanInfo#arrayGettersSafe */ /** @see MBeanInfo#arrayGettersSafe */
private final transient boolean arrayGettersSafe; private final transient boolean arrayGettersSafe;
...@@ -114,9 +117,8 @@ public class MBeanNotificationInfo extends MBeanFeatureInfo implements Cloneable ...@@ -114,9 +117,8 @@ public class MBeanNotificationInfo extends MBeanFeatureInfo implements Cloneable
notifType, though it doesn't explicitly allow it notifType, though it doesn't explicitly allow it
either. */ either. */
if (notifTypes == null) this.types = (notifTypes != null && notifTypes.length > 0) ?
notifTypes = NO_TYPES; notifTypes.clone() : NO_TYPES;
this.types = notifTypes;
this.arrayGettersSafe = this.arrayGettersSafe =
MBeanInfo.arrayGettersSafe(this.getClass(), MBeanInfo.arrayGettersSafe(this.getClass(),
MBeanNotificationInfo.class); MBeanNotificationInfo.class);
...@@ -203,4 +205,16 @@ public class MBeanNotificationInfo extends MBeanFeatureInfo implements Cloneable ...@@ -203,4 +205,16 @@ public class MBeanNotificationInfo extends MBeanFeatureInfo implements Cloneable
hash ^= types[i].hashCode(); hash ^= types[i].hashCode();
return hash; return hash;
} }
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ObjectInputStream.GetField gf = ois.readFields();
String[] t = (String[])gf.get("types", null);
if (t == null) {
throw new InvalidObjectException("Trying to deserialize an invalid " +
"instance of " + MBeanNotificationInfo.class +
"[types=null]");
}
types = t.length == 0 ? t : t.clone();
}
} }
...@@ -26,6 +26,9 @@ ...@@ -26,6 +26,9 @@
package javax.management.remote; package javax.management.remote;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.Serializable; import java.io.Serializable;
import java.security.Principal; import java.security.Principal;
...@@ -64,9 +67,7 @@ public class JMXPrincipal implements Principal, Serializable { ...@@ -64,9 +67,7 @@ public class JMXPrincipal implements Principal, Serializable {
* <code>null</code>. * <code>null</code>.
*/ */
public JMXPrincipal(String name) { public JMXPrincipal(String name) {
if (name == null) validate(name);
throw new NullPointerException("illegal null input");
this.name = name; this.name = name;
} }
...@@ -130,4 +131,20 @@ public class JMXPrincipal implements Principal, Serializable { ...@@ -130,4 +131,20 @@ public class JMXPrincipal implements Principal, Serializable {
public int hashCode() { public int hashCode() {
return name.hashCode(); return name.hashCode();
} }
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ObjectInputStream.GetField gf = ois.readFields();
String principalName = (String)gf.get("name", null);
try {
validate(principalName);
this.name = principalName;
} catch (NullPointerException e) {
throw new InvalidObjectException(e.getMessage());
}
}
private static void validate(String name) throws NullPointerException {
if (name == null)
throw new NullPointerException("illegal null input");
}
} }
...@@ -29,6 +29,9 @@ package javax.management.remote; ...@@ -29,6 +29,9 @@ package javax.management.remote;
import com.sun.jmx.remote.util.ClassLogger; import com.sun.jmx.remote.util.ClassLogger;
import com.sun.jmx.remote.util.EnvHelp; import com.sun.jmx.remote.util.EnvHelp;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.Serializable; import java.io.Serializable;
import java.net.InetAddress; import java.net.InetAddress;
...@@ -297,7 +300,7 @@ public class JMXServiceURL implements Serializable { ...@@ -297,7 +300,7 @@ public class JMXServiceURL implements Serializable {
If we're given an explicit host name that is illegal we If we're given an explicit host name that is illegal we
have to reject it. (Bug 5057532.) */ have to reject it. (Bug 5057532.) */
try { try {
validateHost(host); validateHost(host, port);
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
if (logger.fineOn()) { if (logger.fineOn()) {
logger.fine("JMXServiceURL", logger.fine("JMXServiceURL",
...@@ -336,36 +339,82 @@ public class JMXServiceURL implements Serializable { ...@@ -336,36 +339,82 @@ public class JMXServiceURL implements Serializable {
validate(); validate();
} }
private void validate() throws MalformedURLException { private static final String INVALID_INSTANCE_MSG =
"Trying to deserialize an invalid instance of JMXServiceURL";
private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
ObjectInputStream.GetField gf = inputStream.readFields();
String h = (String)gf.get("host", null);
int p = (int)gf.get("port", -1);
String proto = (String)gf.get("protocol", null);
String url = (String)gf.get("urlPath", null);
if (proto == null || url == null || h == null) {
StringBuilder sb = new StringBuilder(INVALID_INSTANCE_MSG).append('[');
boolean empty = true;
if (proto == null) {
sb.append("protocol=null");
empty = false;
}
if (h == null) {
sb.append(empty ? "" : ",").append("host=null");
empty = false;
}
if (url == null) {
sb.append(empty ? "" : ",").append("urlPath=null");
}
sb.append(']');
throw new InvalidObjectException(sb.toString());
}
// Check protocol if (h.contains("[") || h.contains("]")) {
throw new InvalidObjectException("Invalid host name: " + h);
}
try {
validate(proto, h, p, url);
this.protocol = proto;
this.host = h;
this.port = p;
this.urlPath = url;
} catch (MalformedURLException e) {
throw new InvalidObjectException(INVALID_INSTANCE_MSG + ": " +
e.getMessage());
}
final int protoEnd = indexOfFirstNotInSet(protocol, protocolBitSet, 0); }
if (protoEnd == 0 || protoEnd < protocol.length()
|| !alphaBitSet.get(protocol.charAt(0))) { private void validate(String proto, String h, int p, String url)
throws MalformedURLException {
// Check protocol
final int protoEnd = indexOfFirstNotInSet(proto, protocolBitSet, 0);
if (protoEnd == 0 || protoEnd < proto.length()
|| !alphaBitSet.get(proto.charAt(0))) {
throw new MalformedURLException("Missing or invalid protocol " + throw new MalformedURLException("Missing or invalid protocol " +
"name: \"" + protocol + "\""); "name: \"" + proto + "\"");
} }
// Check host // Check host
validateHost(h, p);
validateHost();
// Check port // Check port
if (p < 0)
if (port < 0) throw new MalformedURLException("Bad port: " + p);
throw new MalformedURLException("Bad port: " + port);
// Check URL path // Check URL path
if (url.length() > 0) {
if (urlPath.length() > 0) { if (!url.startsWith("/") && !url.startsWith(";"))
if (!urlPath.startsWith("/") && !urlPath.startsWith(";")) throw new MalformedURLException("Bad URL path: " + url);
throw new MalformedURLException("Bad URL path: " + urlPath);
} }
} }
private void validateHost() throws MalformedURLException { private void validate() throws MalformedURLException {
if (host.length() == 0) { validate(this.protocol, this.host, this.port, this.urlPath);
}
private static void validateHost(String h, int port)
throws MalformedURLException {
if (h.length() == 0) {
if (port != 0) { if (port != 0) {
throw new MalformedURLException("Cannot give port number " + throw new MalformedURLException("Cannot give port number " +
"without host name"); "without host name");
...@@ -373,12 +422,6 @@ public class JMXServiceURL implements Serializable { ...@@ -373,12 +422,6 @@ public class JMXServiceURL implements Serializable {
return; return;
} }
validateHost(host);
}
private static void validateHost(String h)
throws MalformedURLException {
if (isNumericIPv6Address(h)) { if (isNumericIPv6Address(h)) {
/* We assume J2SE >= 1.4 here. Otherwise you can't /* We assume J2SE >= 1.4 here. Otherwise you can't
use the address anyway. We can't call use the address anyway. We can't call
...@@ -663,22 +706,22 @@ public class JMXServiceURL implements Serializable { ...@@ -663,22 +706,22 @@ public class JMXServiceURL implements Serializable {
/** /**
* The value returned by {@link #getProtocol()}. * The value returned by {@link #getProtocol()}.
*/ */
private final String protocol; private String protocol;
/** /**
* The value returned by {@link #getHost()}. * The value returned by {@link #getHost()}.
*/ */
private final String host; private String host;
/** /**
* The value returned by {@link #getPort()}. * The value returned by {@link #getPort()}.
*/ */
private final int port; private int port;
/** /**
* The value returned by {@link #getURLPath()}. * The value returned by {@link #getURLPath()}.
*/ */
private final String urlPath; private String urlPath;
/** /**
* Cached result of {@link #toString()}. * Cached result of {@link #toString()}.
......
...@@ -25,6 +25,9 @@ ...@@ -25,6 +25,9 @@
package javax.management.remote; package javax.management.remote;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.Serializable; import java.io.Serializable;
/** /**
...@@ -76,17 +79,7 @@ public class NotificationResult implements Serializable { ...@@ -76,17 +79,7 @@ public class NotificationResult implements Serializable {
public NotificationResult(long earliestSequenceNumber, public NotificationResult(long earliestSequenceNumber,
long nextSequenceNumber, long nextSequenceNumber,
TargetedNotification[] targetedNotifications) { TargetedNotification[] targetedNotifications) {
if (targetedNotifications == null) { validate(targetedNotifications, earliestSequenceNumber, nextSequenceNumber);
final String msg = "Notifications null";
throw new IllegalArgumentException(msg);
}
if (earliestSequenceNumber < 0 || nextSequenceNumber < 0)
throw new IllegalArgumentException("Bad sequence numbers");
/* We used to check nextSequenceNumber >= earliestSequenceNumber
here. But in fact the opposite can legitimately be true if
notifications have been lost. */
this.earliestSequenceNumber = earliestSequenceNumber; this.earliestSequenceNumber = earliestSequenceNumber;
this.nextSequenceNumber = nextSequenceNumber; this.nextSequenceNumber = nextSequenceNumber;
this.targetedNotifications = (targetedNotifications.length == 0 ? targetedNotifications : targetedNotifications.clone()); this.targetedNotifications = (targetedNotifications.length == 0 ? targetedNotifications : targetedNotifications.clone());
...@@ -138,7 +131,39 @@ public class NotificationResult implements Serializable { ...@@ -138,7 +131,39 @@ public class NotificationResult implements Serializable {
getTargetedNotifications().length; getTargetedNotifications().length;
} }
private final long earliestSequenceNumber; private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
private final long nextSequenceNumber; ObjectInputStream.GetField gf = ois.readFields();
private final TargetedNotification[] targetedNotifications; TargetedNotification[] tNotifs = (TargetedNotification[])gf.get("targetedNotifications", null);
long snStart = gf.get("earliestSequenceNumber", -1L);
long snNext = gf.get("nextSequenceNumber", -1L);
try {
validate(tNotifs, snStart, snNext);
this.targetedNotifications = tNotifs.length == 0 ? tNotifs : tNotifs.clone();
this.earliestSequenceNumber = snStart;
this.nextSequenceNumber = snNext;
} catch (IllegalArgumentException e) {
throw new InvalidObjectException(e.getMessage());
}
}
private long earliestSequenceNumber;
private long nextSequenceNumber;
private TargetedNotification[] targetedNotifications;
private static void validate(TargetedNotification[] targetedNotifications,
long earliestSequenceNumber,
long nextSequenceNumber)
throws IllegalArgumentException {
if (targetedNotifications == null) {
final String msg = "Notifications null";
throw new IllegalArgumentException(msg);
}
if (earliestSequenceNumber < 0 || nextSequenceNumber < 0)
throw new IllegalArgumentException("Bad sequence numbers");
/* We used to check nextSequenceNumber >= earliestSequenceNumber
here. But in fact the opposite can legitimately be true if
notifications have been lost. */
}
} }
...@@ -26,6 +26,9 @@ ...@@ -26,6 +26,9 @@
package javax.management.remote; package javax.management.remote;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.Serializable; import java.io.Serializable;
import javax.management.Notification; import javax.management.Notification;
...@@ -73,12 +76,9 @@ public class TargetedNotification implements Serializable { ...@@ -73,12 +76,9 @@ public class TargetedNotification implements Serializable {
*/ */
public TargetedNotification(Notification notification, public TargetedNotification(Notification notification,
Integer listenerID) { Integer listenerID) {
validate(notification, listenerID);
// If we replace integer with int... // If we replace integer with int...
// this(notification,intValue(listenerID)); // this(notification,intValue(listenerID));
if (notification == null) throw new
IllegalArgumentException("Invalid notification: null");
if (listenerID == null) throw new
IllegalArgumentException("Invalid listener ID: null");
this.notif = notification; this.notif = notification;
this.id = listenerID; this.id = listenerID;
} }
...@@ -115,13 +115,13 @@ public class TargetedNotification implements Serializable { ...@@ -115,13 +115,13 @@ public class TargetedNotification implements Serializable {
* @serial A notification to transmit to the other side. * @serial A notification to transmit to the other side.
* @see #getNotification() * @see #getNotification()
**/ **/
private final Notification notif; private Notification notif;
/** /**
* @serial The ID of the listener to which the notification is * @serial The ID of the listener to which the notification is
* targeted. * targeted.
* @see #getListenerID() * @see #getListenerID()
**/ **/
private final Integer id; private Integer id;
//private final int id; //private final int id;
// Needed if we use int instead of Integer... // Needed if we use int instead of Integer...
...@@ -130,4 +130,26 @@ public class TargetedNotification implements Serializable { ...@@ -130,4 +130,26 @@ public class TargetedNotification implements Serializable {
// IllegalArgumentException("Invalid listener ID: null"); // IllegalArgumentException("Invalid listener ID: null");
// return id.intValue(); // return id.intValue();
// } // }
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ObjectInputStream.GetField gf = ois.readFields();
Notification notification = (Notification)gf.get("notif", null);
Integer listenerId = (Integer)gf.get("id", null);
try {
validate(notification, listenerId);
this.notif = notification;
this.id = listenerId;
} catch (IllegalArgumentException e) {
throw new InvalidObjectException(e.getMessage());
}
}
private static void validate(Notification notif, Integer id) throws IllegalArgumentException {
if (notif == null) {
throw new IllegalArgumentException("Invalid notification: null");
}
if (id == null) {
throw new IllegalArgumentException("Invalid listener ID: null");
}
}
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册