提交 2d3a77c8 编写于 作者: T tbell

Merge

...@@ -27,7 +27,6 @@ package com.sun.jmx.event; ...@@ -27,7 +27,6 @@ package com.sun.jmx.event;
import com.sun.jmx.remote.util.ClassLogger; import com.sun.jmx.remote.util.ClassLogger;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
...@@ -115,6 +114,7 @@ public class LeaseManager { ...@@ -115,6 +114,7 @@ public class LeaseManager {
scheduled = null; scheduled = null;
} }
callback.run(); callback.run();
executor.shutdown();
} }
} }
...@@ -131,6 +131,13 @@ public class LeaseManager { ...@@ -131,6 +131,13 @@ public class LeaseManager {
logger.trace("stop", "canceling lease"); logger.trace("stop", "canceling lease");
scheduled.cancel(false); scheduled.cancel(false);
scheduled = null; scheduled = null;
try {
executor.shutdown();
} catch (SecurityException e) {
// OK: caller doesn't have RuntimePermission("modifyThread")
// which is unlikely in reality but triggers a test failure otherwise
logger.trace("stop", "exception from executor.shutdown", e);
}
} }
private final Runnable callback; private final Runnable callback;
...@@ -138,7 +145,7 @@ public class LeaseManager { ...@@ -138,7 +145,7 @@ public class LeaseManager {
private final ScheduledExecutorService executor private final ScheduledExecutorService executor
= Executors.newScheduledThreadPool(1, = Executors.newScheduledThreadPool(1,
new DaemonThreadFactory("LeaseManager")); new DaemonThreadFactory("JMX LeaseManager %d"));
private static final ClassLogger logger = private static final ClassLogger logger =
new ClassLogger("javax.management.event", "LeaseManager"); new ClassLogger("javax.management.event", "LeaseManager");
......
...@@ -95,7 +95,9 @@ public abstract class RepeatedSingletonJob implements Runnable { ...@@ -95,7 +95,9 @@ public abstract class RepeatedSingletonJob implements Runnable {
executor.execute(this); executor.execute(this);
} catch (RejectedExecutionException e) { } catch (RejectedExecutionException e) {
logger.warning( logger.warning(
"setEventReceiver", "Executor threw exception", e); "execute",
"Executor threw exception (" + this.getClass().getName() + ")",
e);
throw new RejectedExecutionException( throw new RejectedExecutionException(
"Executor.execute threw exception -" + "Executor.execute threw exception -" +
"should not be possible", e); "should not be possible", e);
......
...@@ -613,8 +613,7 @@ public class DefaultMBeanServerInterceptor ...@@ -613,8 +613,7 @@ public class DefaultMBeanServerInterceptor
List<String> result = new ArrayList<String>(domains.length); List<String> result = new ArrayList<String>(domains.length);
for (int i = 0; i < domains.length; i++) { for (int i = 0; i < domains.length; i++) {
try { try {
ObjectName dom = ObjectName dom = ObjectName.valueOf(domains[i] + ":x=x");
Util.newObjectName(domains[i] + ":x=x");
checkMBeanPermission(mbeanServerName, (String) null, null, dom, "getDomains"); checkMBeanPermission(mbeanServerName, (String) null, null, dom, "getDomains");
result.add(domains[i]); result.add(domains[i]);
} catch (SecurityException e) { } catch (SecurityException e) {
...@@ -1170,7 +1169,7 @@ public class DefaultMBeanServerInterceptor ...@@ -1170,7 +1169,7 @@ public class DefaultMBeanServerInterceptor
if one is supplied where it shouldn't be). */ if one is supplied where it shouldn't be). */
final String completeName = domain + name; final String completeName = domain + name;
return Util.newObjectName(completeName); return ObjectName.valueOf(completeName);
} }
public String getDefaultDomain() { public String getDefaultDomain() {
...@@ -2021,7 +2020,7 @@ public class DefaultMBeanServerInterceptor ...@@ -2021,7 +2020,7 @@ public class DefaultMBeanServerInterceptor
private void addJMXNamespace(JMXNamespace namespace, private void addJMXNamespace(JMXNamespace namespace,
final ObjectName logicalName, final ObjectName logicalName,
final Queue<Runnable> postQueue) { final Queue<Runnable> postQueue) {
dispatcher.addNamespace(logicalName, namespace, postQueue); dispatcher.addInterceptorFor(logicalName, namespace, postQueue);
} }
/** /**
...@@ -2035,7 +2034,7 @@ public class DefaultMBeanServerInterceptor ...@@ -2035,7 +2034,7 @@ public class DefaultMBeanServerInterceptor
private void removeJMXNamespace(JMXNamespace namespace, private void removeJMXNamespace(JMXNamespace namespace,
final ObjectName logicalName, final ObjectName logicalName,
final Queue<Runnable> postQueue) { final Queue<Runnable> postQueue) {
dispatcher.removeNamespace(logicalName, namespace, postQueue); dispatcher.removeInterceptorFor(logicalName, namespace, postQueue);
} }
/** /**
......
...@@ -194,7 +194,7 @@ public abstract class DispatchInterceptor ...@@ -194,7 +194,7 @@ public abstract class DispatchInterceptor
// found in the handlerMap. Note: there doesn't need to be an interceptor // found in the handlerMap. Note: there doesn't need to be an interceptor
// for that key in the Map. // for that key in the Map.
// //
public abstract String getHandlerKey(ObjectName name); abstract String getHandlerKey(ObjectName name);
// Returns an interceptor for that name, or null if there's no interceptor // Returns an interceptor for that name, or null if there's no interceptor
// for that name. // for that name.
...@@ -277,7 +277,7 @@ public abstract class DispatchInterceptor ...@@ -277,7 +277,7 @@ public abstract class DispatchInterceptor
// of JMXNamespace (or a subclass of it) is registered as an MBean. // of JMXNamespace (or a subclass of it) is registered as an MBean.
// This method is usually invoked from within the repository lock, // This method is usually invoked from within the repository lock,
// hence the necessity of the postRegisterQueue. // hence the necessity of the postRegisterQueue.
public void addNamespace(ObjectName name, N jmxNamespace, public void addInterceptorFor(ObjectName name, N jmxNamespace,
Queue<Runnable> postRegisterQueue) { Queue<Runnable> postRegisterQueue) {
final String key = getHandlerKey(name); final String key = getHandlerKey(name);
validateHandlerNameFor(key,name); validateHandlerNameFor(key,name);
...@@ -298,7 +298,7 @@ public abstract class DispatchInterceptor ...@@ -298,7 +298,7 @@ public abstract class DispatchInterceptor
// of JMXNamespace (or a subclass of it) is deregistered. // of JMXNamespace (or a subclass of it) is deregistered.
// This method is usually invoked from within the repository lock, // This method is usually invoked from within the repository lock,
// hence the necessity of the postDeregisterQueue. // hence the necessity of the postDeregisterQueue.
public void removeNamespace(ObjectName name, N jmxNamespace, public void removeInterceptorFor(ObjectName name, N jmxNamespace,
Queue<Runnable> postDeregisterQueue) { Queue<Runnable> postDeregisterQueue) {
final String key = getHandlerKey(name); final String key = getHandlerKey(name);
final T ns; final T ns;
...@@ -330,7 +330,7 @@ public abstract class DispatchInterceptor ...@@ -330,7 +330,7 @@ public abstract class DispatchInterceptor
} }
// From MBeanServer // From MBeanServer
public ObjectInstance createMBean(String className, ObjectName name) public final ObjectInstance createMBean(String className, ObjectName name)
throws ReflectionException, InstanceAlreadyExistsException, throws ReflectionException, InstanceAlreadyExistsException,
MBeanRegistrationException, MBeanException, MBeanRegistrationException, MBeanException,
NotCompliantMBeanException { NotCompliantMBeanException {
...@@ -338,7 +338,7 @@ public abstract class DispatchInterceptor ...@@ -338,7 +338,7 @@ public abstract class DispatchInterceptor
} }
// From MBeanServer // From MBeanServer
public ObjectInstance createMBean(String className, ObjectName name, public final ObjectInstance createMBean(String className, ObjectName name,
ObjectName loaderName) ObjectName loaderName)
throws ReflectionException, InstanceAlreadyExistsException, throws ReflectionException, InstanceAlreadyExistsException,
MBeanRegistrationException, MBeanException, MBeanRegistrationException, MBeanException,
...@@ -347,7 +347,7 @@ public abstract class DispatchInterceptor ...@@ -347,7 +347,7 @@ public abstract class DispatchInterceptor
} }
// From MBeanServer // From MBeanServer
public ObjectInstance createMBean(String className, ObjectName name, public final ObjectInstance createMBean(String className, ObjectName name,
Object params[], String signature[]) Object params[], String signature[])
throws ReflectionException, InstanceAlreadyExistsException, throws ReflectionException, InstanceAlreadyExistsException,
MBeanRegistrationException, MBeanException, MBeanRegistrationException, MBeanException,
...@@ -357,7 +357,7 @@ public abstract class DispatchInterceptor ...@@ -357,7 +357,7 @@ public abstract class DispatchInterceptor
} }
// From MBeanServer // From MBeanServer
public ObjectInstance createMBean(String className, ObjectName name, public final ObjectInstance createMBean(String className, ObjectName name,
ObjectName loaderName, Object params[], ObjectName loaderName, Object params[],
String signature[]) String signature[])
throws ReflectionException, InstanceAlreadyExistsException, throws ReflectionException, InstanceAlreadyExistsException,
...@@ -368,42 +368,43 @@ public abstract class DispatchInterceptor ...@@ -368,42 +368,43 @@ public abstract class DispatchInterceptor
} }
// From MBeanServer // From MBeanServer
public ObjectInstance registerMBean(Object object, ObjectName name) public final ObjectInstance registerMBean(Object object, ObjectName name)
throws InstanceAlreadyExistsException, MBeanRegistrationException, throws InstanceAlreadyExistsException, MBeanRegistrationException,
NotCompliantMBeanException { NotCompliantMBeanException {
return getInterceptorForCreate(name).registerMBean(object,name); return getInterceptorForCreate(name).registerMBean(object,name);
} }
// From MBeanServer // From MBeanServer
public void unregisterMBean(ObjectName name) public final void unregisterMBean(ObjectName name)
throws InstanceNotFoundException, MBeanRegistrationException { throws InstanceNotFoundException, MBeanRegistrationException {
getInterceptorForInstance(name).unregisterMBean(name); getInterceptorForInstance(name).unregisterMBean(name);
} }
// From MBeanServer // From MBeanServer
public ObjectInstance getObjectInstance(ObjectName name) public final ObjectInstance getObjectInstance(ObjectName name)
throws InstanceNotFoundException { throws InstanceNotFoundException {
return getInterceptorForInstance(name).getObjectInstance(name); return getInterceptorForInstance(name).getObjectInstance(name);
} }
// From MBeanServer // From MBeanServer
public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) { public final Set<ObjectInstance> queryMBeans(ObjectName name,
final QueryInterceptor mbs = QueryExp query) {
final QueryInterceptor queryInvoker =
getInterceptorForQuery(name); getInterceptorForQuery(name);
if (mbs == null) return Collections.emptySet(); if (queryInvoker == null) return Collections.emptySet();
else return mbs.queryMBeans(name,query); else return queryInvoker.queryMBeans(name,query);
} }
// From MBeanServer // From MBeanServer
public Set<ObjectName> queryNames(ObjectName name, QueryExp query) { public final Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
final QueryInterceptor mbs = final QueryInterceptor queryInvoker =
getInterceptorForQuery(name); getInterceptorForQuery(name);
if (mbs == null) return Collections.emptySet(); if (queryInvoker == null) return Collections.emptySet();
else return mbs.queryNames(name,query); else return queryInvoker.queryNames(name,query);
} }
// From MBeanServer // From MBeanServer
public boolean isRegistered(ObjectName name) { public final boolean isRegistered(ObjectName name) {
final MBeanServer mbs = getInterceptorOrNullFor(name); final MBeanServer mbs = getInterceptorOrNullFor(name);
if (mbs == null) return false; if (mbs == null) return false;
else return mbs.isRegistered(name); else return mbs.isRegistered(name);
...@@ -415,20 +416,21 @@ public abstract class DispatchInterceptor ...@@ -415,20 +416,21 @@ public abstract class DispatchInterceptor
} }
// From MBeanServer // From MBeanServer
public Object getAttribute(ObjectName name, String attribute) public final Object getAttribute(ObjectName name, String attribute)
throws MBeanException, AttributeNotFoundException, throws MBeanException, AttributeNotFoundException,
InstanceNotFoundException, ReflectionException { InstanceNotFoundException, ReflectionException {
return getInterceptorForInstance(name).getAttribute(name,attribute); return getInterceptorForInstance(name).getAttribute(name,attribute);
} }
// From MBeanServer // From MBeanServer
public AttributeList getAttributes(ObjectName name, String[] attributes) public final AttributeList getAttributes(ObjectName name,
String[] attributes)
throws InstanceNotFoundException, ReflectionException { throws InstanceNotFoundException, ReflectionException {
return getInterceptorForInstance(name).getAttributes(name,attributes); return getInterceptorForInstance(name).getAttributes(name,attributes);
} }
// From MBeanServer // From MBeanServer
public void setAttribute(ObjectName name, Attribute attribute) public final void setAttribute(ObjectName name, Attribute attribute)
throws InstanceNotFoundException, AttributeNotFoundException, throws InstanceNotFoundException, AttributeNotFoundException,
InvalidAttributeValueException, MBeanException, InvalidAttributeValueException, MBeanException,
ReflectionException { ReflectionException {
...@@ -436,14 +438,14 @@ public abstract class DispatchInterceptor ...@@ -436,14 +438,14 @@ public abstract class DispatchInterceptor
} }
// From MBeanServer // From MBeanServer
public AttributeList setAttributes(ObjectName name, public final AttributeList setAttributes(ObjectName name,
AttributeList attributes) AttributeList attributes)
throws InstanceNotFoundException, ReflectionException { throws InstanceNotFoundException, ReflectionException {
return getInterceptorForInstance(name).setAttributes(name,attributes); return getInterceptorForInstance(name).setAttributes(name,attributes);
} }
// From MBeanServer // From MBeanServer
public Object invoke(ObjectName name, String operationName, public final Object invoke(ObjectName name, String operationName,
Object params[], String signature[]) Object params[], String signature[])
throws InstanceNotFoundException, MBeanException, throws InstanceNotFoundException, MBeanException,
ReflectionException { ReflectionException {
...@@ -463,63 +465,69 @@ public abstract class DispatchInterceptor ...@@ -463,63 +465,69 @@ public abstract class DispatchInterceptor
public abstract String[] getDomains(); public abstract String[] getDomains();
// From MBeanServer // From MBeanServer
public void addNotificationListener(ObjectName name, public final void addNotificationListener(ObjectName name,
NotificationListener listener, NotificationListener listener,
NotificationFilter filter, NotificationFilter filter,
Object handback) Object handback)
throws InstanceNotFoundException { throws InstanceNotFoundException {
getInterceptorForInstance(name).addNotificationListener(name,listener,filter, getInterceptorForInstance(name).
addNotificationListener(name,listener,filter,
handback); handback);
} }
// From MBeanServer // From MBeanServer
public void addNotificationListener(ObjectName name, public final void addNotificationListener(ObjectName name,
ObjectName listener, ObjectName listener,
NotificationFilter filter, NotificationFilter filter,
Object handback) Object handback)
throws InstanceNotFoundException { throws InstanceNotFoundException {
getInterceptorForInstance(name).addNotificationListener(name,listener,filter, getInterceptorForInstance(name).
addNotificationListener(name,listener,filter,
handback); handback);
} }
// From MBeanServer // From MBeanServer
public void removeNotificationListener(ObjectName name, public final void removeNotificationListener(ObjectName name,
ObjectName listener) ObjectName listener)
throws InstanceNotFoundException, ListenerNotFoundException { throws InstanceNotFoundException, ListenerNotFoundException {
getInterceptorForInstance(name).removeNotificationListener(name,listener); getInterceptorForInstance(name).
removeNotificationListener(name,listener);
} }
// From MBeanServer // From MBeanServer
public void removeNotificationListener(ObjectName name, public final void removeNotificationListener(ObjectName name,
ObjectName listener, ObjectName listener,
NotificationFilter filter, NotificationFilter filter,
Object handback) Object handback)
throws InstanceNotFoundException, ListenerNotFoundException { throws InstanceNotFoundException, ListenerNotFoundException {
getInterceptorForInstance(name).removeNotificationListener(name,listener,filter, getInterceptorForInstance(name).
removeNotificationListener(name,listener,filter,
handback); handback);
} }
// From MBeanServer // From MBeanServer
public void removeNotificationListener(ObjectName name, public final void removeNotificationListener(ObjectName name,
NotificationListener listener) NotificationListener listener)
throws InstanceNotFoundException, ListenerNotFoundException { throws InstanceNotFoundException, ListenerNotFoundException {
getInterceptorForInstance(name).removeNotificationListener(name,listener); getInterceptorForInstance(name).
removeNotificationListener(name,listener);
} }
// From MBeanServer // From MBeanServer
public void removeNotificationListener(ObjectName name, public final void removeNotificationListener(ObjectName name,
NotificationListener listener, NotificationListener listener,
NotificationFilter filter, NotificationFilter filter,
Object handback) Object handback)
throws InstanceNotFoundException, ListenerNotFoundException { throws InstanceNotFoundException, ListenerNotFoundException {
getInterceptorForInstance(name).removeNotificationListener(name,listener,filter, getInterceptorForInstance(name).
removeNotificationListener(name,listener,filter,
handback); handback);
} }
// From MBeanServer // From MBeanServer
public MBeanInfo getMBeanInfo(ObjectName name) public final MBeanInfo getMBeanInfo(ObjectName name)
throws InstanceNotFoundException, IntrospectionException, throws InstanceNotFoundException, IntrospectionException,
ReflectionException { ReflectionException {
return getInterceptorForInstance(name).getMBeanInfo(name); return getInterceptorForInstance(name).getMBeanInfo(name);
...@@ -527,21 +535,23 @@ public abstract class DispatchInterceptor ...@@ -527,21 +535,23 @@ public abstract class DispatchInterceptor
// From MBeanServer // From MBeanServer
public boolean isInstanceOf(ObjectName name, String className) public final boolean isInstanceOf(ObjectName name, String className)
throws InstanceNotFoundException { throws InstanceNotFoundException {
return getInterceptorForInstance(name).isInstanceOf(name,className); return getInterceptorForInstance(name).isInstanceOf(name,className);
} }
// From MBeanServer // From MBeanServer
public ClassLoader getClassLoaderFor(ObjectName mbeanName) public final ClassLoader getClassLoaderFor(ObjectName mbeanName)
throws InstanceNotFoundException { throws InstanceNotFoundException {
return getInterceptorForInstance(mbeanName).getClassLoaderFor(mbeanName); return getInterceptorForInstance(mbeanName).
getClassLoaderFor(mbeanName);
} }
// From MBeanServer // From MBeanServer
public ClassLoader getClassLoader(ObjectName loaderName) public final ClassLoader getClassLoader(ObjectName loaderName)
throws InstanceNotFoundException { throws InstanceNotFoundException {
return getInterceptorForInstance(loaderName).getClassLoader(loaderName); return getInterceptorForInstance(loaderName).
getClassLoader(loaderName);
} }
} }
...@@ -75,7 +75,7 @@ class DomainDispatchInterceptor ...@@ -75,7 +75,7 @@ class DomainDispatchInterceptor
private final DomainDispatchInterceptor parent; private final DomainDispatchInterceptor parent;
AggregatingQueryInterceptor(DomainDispatchInterceptor dispatcher) { AggregatingQueryInterceptor(DomainDispatchInterceptor dispatcher) {
super(dispatcher.localNamespace); super(dispatcher.nextInterceptor);
parent = dispatcher; parent = dispatcher;
} }
...@@ -91,9 +91,8 @@ class DomainDispatchInterceptor ...@@ -91,9 +91,8 @@ class DomainDispatchInterceptor
// Add all matching MBeans from local namespace. // Add all matching MBeans from local namespace.
final Set<T> res = Util.cloneSet(local); final Set<T> res = Util.cloneSet(local);
final boolean all = (pattern == null ||
pattern.getDomain().equals("*"));
if (pattern == null) pattern = ObjectName.WILDCARD; if (pattern == null) pattern = ObjectName.WILDCARD;
final boolean all = pattern.getDomain().equals("*");
final String domain = pattern.getDomain(); final String domain = pattern.getDomain();
...@@ -142,7 +141,7 @@ class DomainDispatchInterceptor ...@@ -142,7 +141,7 @@ class DomainDispatchInterceptor
} }
} }
private final DefaultMBeanServerInterceptor localNamespace; private final DefaultMBeanServerInterceptor nextInterceptor;
private final String mbeanServerName; private final String mbeanServerName;
private final MBeanServerDelegate delegate; private final MBeanServerDelegate delegate;
...@@ -165,7 +164,7 @@ class DomainDispatchInterceptor ...@@ -165,7 +164,7 @@ class DomainDispatchInterceptor
MBeanInstantiator instantiator, MBeanInstantiator instantiator,
Repository repository, Repository repository,
NamespaceDispatchInterceptor namespaces) { NamespaceDispatchInterceptor namespaces) {
localNamespace = new DefaultMBeanServerInterceptor(outer, nextInterceptor = new DefaultMBeanServerInterceptor(outer,
delegate, instantiator,repository,namespaces); delegate, instantiator,repository,namespaces);
mbeanServerName = Util.getMBeanServerSecurityName(delegate); mbeanServerName = Util.getMBeanServerSecurityName(delegate);
this.delegate = delegate; this.delegate = delegate;
...@@ -182,7 +181,7 @@ class DomainDispatchInterceptor ...@@ -182,7 +181,7 @@ class DomainDispatchInterceptor
@Override @Override
void validateHandlerNameFor(String key, ObjectName name) { void validateHandlerNameFor(String key, ObjectName name) {
super.validateHandlerNameFor(key,name); super.validateHandlerNameFor(key,name);
final String[] domains = localNamespace.getDomains(); final String[] domains = nextInterceptor.getDomains();
for (int i=0;i<domains.length;i++) { for (int i=0;i<domains.length;i++) {
if (domains[i].equals(key)) if (domains[i].equals(key))
throw new IllegalArgumentException("domain "+key+ throw new IllegalArgumentException("domain "+key+
...@@ -192,37 +191,72 @@ class DomainDispatchInterceptor ...@@ -192,37 +191,72 @@ class DomainDispatchInterceptor
@Override @Override
final MBeanServer getInterceptorOrNullFor(ObjectName name) { final MBeanServer getInterceptorOrNullFor(ObjectName name) {
if (name == null) return localNamespace;
if (name == null) return nextInterceptor;
final String domain = name.getDomain(); final String domain = name.getDomain();
if (domain.endsWith(NAMESPACE_SEPARATOR)) return localNamespace; if (domain.endsWith(NAMESPACE_SEPARATOR))
if (domain.contains(NAMESPACE_SEPARATOR)) return null; return nextInterceptor; // This can be a namespace handler.
final String localDomain = domain; if (domain.contains(NAMESPACE_SEPARATOR))
if (isLocalHandlerNameFor(localDomain,name)) { return null; // shouldn't reach here.
if (isLocalHandlerNameFor(domain,name)) {
// This is the name of a JMXDomain MBean. Return nextInterceptor.
LOG.finer("dispatching to local namespace"); LOG.finer("dispatching to local namespace");
return localNamespace; return nextInterceptor;
} }
final DomainInterceptor ns = getInterceptor(localDomain);
final DomainInterceptor ns = getInterceptor(domain);
if (ns == null) { if (ns == null) {
// no JMXDomain found for that domain - return nextInterceptor.
if (LOG.isLoggable(Level.FINER)) { if (LOG.isLoggable(Level.FINER)) {
LOG.finer("dispatching to local namespace: " + localDomain); LOG.finer("dispatching to local namespace: " + domain);
} }
return getNextInterceptor(); return getNextInterceptor();
} }
if (LOG.isLoggable(Level.FINER)) { if (LOG.isLoggable(Level.FINER)) {
LOG.finer("dispatching to domain: " + localDomain); LOG.finer("dispatching to domain: " + domain);
} }
return ns; return ns;
} }
// This method returns true if the given pattern must be evaluated against
// several interceptors. This happens when either:
//
// a) the pattern can select several domains (it's null, or it's a
// domain pattern)
// or b) it's not a domain pattern, but it might select the name of a
// JMXDomain MBean in charge of that domain. Since the JMXDomain
// MBean is located in the nextInterceptor, the pattern might need
// to be evaluated on two interceptors.
//
// 1. When this method returns false, the query is evaluated on a single
// interceptor:
// The interceptor for pattern.getDomain(), if there is one,
// or the next interceptor, if there is none.
//
// 2. When this method returns true, we loop over all the domain
// interceptors:
// in the list, and if the domain pattern matches the interceptor domain
// we evaluate the query on that interceptor and aggregate the results.
// Eventually we also evaluate the pattern against the next interceptor.
//
// See getInterceptorForQuery below.
//
private boolean multipleQuery(ObjectName pattern) { private boolean multipleQuery(ObjectName pattern) {
// case a) above
if (pattern == null) return true; if (pattern == null) return true;
if (pattern.isDomainPattern()) return true; if (pattern.isDomainPattern()) return true;
try { try {
// case b) above.
//
// This is a bit of a hack. If there's any chance that a JMXDomain // This is a bit of a hack. If there's any chance that a JMXDomain
// MBean name is selected by the given pattern then we must include // MBean name is selected by the given pattern then we must include
// the local namespace in our search. // the local namespace in our search.
// Returning true will have this effect. //
// Returning true will have this effect. see 2. above.
//
if (pattern.apply(ALL_DOMAINS.withDomain(pattern.getDomain()))) if (pattern.apply(ALL_DOMAINS.withDomain(pattern.getDomain())))
return true; return true;
} catch (MalformedObjectNameException x) { } catch (MalformedObjectNameException x) {
...@@ -253,7 +287,7 @@ class DomainDispatchInterceptor ...@@ -253,7 +287,7 @@ class DomainDispatchInterceptor
// We don't have a virtual domain. Send to local domains. // We don't have a virtual domain. Send to local domains.
if (LOG.isLoggable(Level.FINER)) if (LOG.isLoggable(Level.FINER))
LOG.finer("dispatching to local namespace: " + domain); LOG.finer("dispatching to local namespace: " + domain);
return new QueryInterceptor(localNamespace); return new QueryInterceptor(nextInterceptor);
} }
@Override @Override
...@@ -288,7 +322,7 @@ class DomainDispatchInterceptor ...@@ -288,7 +322,7 @@ class DomainDispatchInterceptor
@Override @Override
final DefaultMBeanServerInterceptor getNextInterceptor() { final DefaultMBeanServerInterceptor getNextInterceptor() {
return localNamespace; return nextInterceptor;
} }
/** /**
...@@ -298,11 +332,11 @@ class DomainDispatchInterceptor ...@@ -298,11 +332,11 @@ class DomainDispatchInterceptor
@Override @Override
public String[] getDomains() { public String[] getDomains() {
// A JMXDomain is registered in its own domain. // A JMXDomain is registered in its own domain.
// Therefore, localNamespace.getDomains() contains all domains. // Therefore, nextInterceptor.getDomains() contains all domains.
// In addition, localNamespace will perform the necessary // In addition, nextInterceptor will perform the necessary
// MBeanPermission checks for getDomains(). // MBeanPermission checks for getDomains().
// //
return localNamespace.getDomains(); return nextInterceptor.getDomains();
} }
/** /**
...@@ -310,13 +344,13 @@ class DomainDispatchInterceptor ...@@ -310,13 +344,13 @@ class DomainDispatchInterceptor
*/ */
@Override @Override
public Integer getMBeanCount() { public Integer getMBeanCount() {
int count = getNextInterceptor().getMBeanCount().intValue(); int count = getNextInterceptor().getMBeanCount();
final String[] keys = getKeys(); final String[] keys = getKeys();
for (String key:keys) { for (String key:keys) {
final MBeanServer mbs = getInterceptor(key); final MBeanServer mbs = getInterceptor(key);
if (mbs == null) continue; if (mbs == null) continue;
count += mbs.getMBeanCount().intValue(); count += mbs.getMBeanCount();
} }
return Integer.valueOf(count); return count;
} }
} }
...@@ -61,7 +61,7 @@ public class NamespaceDispatchInterceptor ...@@ -61,7 +61,7 @@ public class NamespaceDispatchInterceptor
private static final int NAMESPACE_SEPARATOR_LENGTH = private static final int NAMESPACE_SEPARATOR_LENGTH =
NAMESPACE_SEPARATOR.length(); NAMESPACE_SEPARATOR.length();
private final DomainDispatchInterceptor localNamespace; private final DomainDispatchInterceptor nextInterceptor;
private final String serverName; private final String serverName;
/** /**
...@@ -84,7 +84,7 @@ public class NamespaceDispatchInterceptor ...@@ -84,7 +84,7 @@ public class NamespaceDispatchInterceptor
MBeanServerDelegate delegate, MBeanServerDelegate delegate,
MBeanInstantiator instantiator, MBeanInstantiator instantiator,
Repository repository) { Repository repository) {
localNamespace = new DomainDispatchInterceptor(outer,delegate, nextInterceptor = new DomainDispatchInterceptor(outer,delegate,
instantiator,repository,this); instantiator,repository,this);
serverName = Util.getMBeanServerSecurityName(delegate); serverName = Util.getMBeanServerSecurityName(delegate);
} }
...@@ -94,21 +94,21 @@ public class NamespaceDispatchInterceptor ...@@ -94,21 +94,21 @@ public class NamespaceDispatchInterceptor
* Get first name space in ObjectName path. Ignore leading namespace * Get first name space in ObjectName path. Ignore leading namespace
* separators. * separators.
**/ **/
public static String getFirstNamespace(ObjectName name) { static String getFirstNamespace(ObjectName name) {
if (name == null) return ""; if (name == null) return "";
final String domain = name.getDomain(); final String domain = name.getDomain();
if (domain.equals("")) return ""; if (domain.equals("")) return "";
// skip leading separators
int first = 0; int first = 0;
int end = domain.indexOf(NAMESPACE_SEPARATOR,first); while (domain.startsWith(NAMESPACE_SEPARATOR,first))
while (end == first) { first += NAMESPACE_SEPARATOR_LENGTH;
first = end+NAMESPACE_SEPARATOR_LENGTH;
end = domain.indexOf(NAMESPACE_SEPARATOR,first);
if (end == -1) break;
}
if (end == -1) return ""; // go to next separator
final int end = domain.indexOf(NAMESPACE_SEPARATOR,first);
if (end == -1) return ""; // no namespace
// This is the first element in the namespace path.
final String namespace = domain.substring(first,end); final String namespace = domain.substring(first,end);
return namespace; return namespace;
...@@ -143,7 +143,7 @@ public class NamespaceDispatchInterceptor ...@@ -143,7 +143,7 @@ public class NamespaceDispatchInterceptor
if (namespace.equals("") || isLocalHandlerNameFor(namespace,name) || if (namespace.equals("") || isLocalHandlerNameFor(namespace,name) ||
name.getDomain().equals(namespace+NAMESPACE_SEPARATOR)) { name.getDomain().equals(namespace+NAMESPACE_SEPARATOR)) {
LOG.finer("dispatching to local name space"); LOG.finer("dispatching to local name space");
return localNamespace; return nextInterceptor;
} }
final NamespaceInterceptor ns = getInterceptor(namespace); final NamespaceInterceptor ns = getInterceptor(namespace);
if (LOG.isLoggable(Level.FINER)) { if (LOG.isLoggable(Level.FINER)) {
...@@ -162,7 +162,7 @@ public class NamespaceDispatchInterceptor ...@@ -162,7 +162,7 @@ public class NamespaceDispatchInterceptor
if (namespace.equals("") || isLocalHandlerNameFor(namespace,pattern) || if (namespace.equals("") || isLocalHandlerNameFor(namespace,pattern) ||
pattern.getDomain().equals(namespace+NAMESPACE_SEPARATOR)) { pattern.getDomain().equals(namespace+NAMESPACE_SEPARATOR)) {
LOG.finer("dispatching to local name space"); LOG.finer("dispatching to local name space");
return new QueryInterceptor(localNamespace); return new QueryInterceptor(nextInterceptor);
} }
final NamespaceInterceptor ns = getInterceptor(namespace); final NamespaceInterceptor ns = getInterceptor(namespace);
if (LOG.isLoggable(Level.FINER)) { if (LOG.isLoggable(Level.FINER)) {
...@@ -202,7 +202,7 @@ public class NamespaceDispatchInterceptor ...@@ -202,7 +202,7 @@ public class NamespaceDispatchInterceptor
@Override @Override
final DomainDispatchInterceptor getNextInterceptor() { final DomainDispatchInterceptor getNextInterceptor() {
return localNamespace; return nextInterceptor;
} }
/** /**
...@@ -211,25 +211,25 @@ public class NamespaceDispatchInterceptor ...@@ -211,25 +211,25 @@ public class NamespaceDispatchInterceptor
*/ */
@Override @Override
public String[] getDomains() { public String[] getDomains() {
return localNamespace.getDomains(); return nextInterceptor.getDomains();
} }
@Override @Override
public void addNamespace(ObjectName name, JMXNamespace handler, public void addInterceptorFor(ObjectName name, JMXNamespace handler,
Queue<Runnable> postRegisterQueue) { Queue<Runnable> postRegisterQueue) {
if (handler instanceof JMXDomain) if (handler instanceof JMXDomain)
localNamespace.addNamespace(name, nextInterceptor.addInterceptorFor(name,
(JMXDomain)handler,postRegisterQueue); (JMXDomain)handler,postRegisterQueue);
else super.addNamespace(name,handler,postRegisterQueue); else super.addInterceptorFor(name,handler,postRegisterQueue);
} }
@Override @Override
public void removeNamespace(ObjectName name, JMXNamespace handler, public void removeInterceptorFor(ObjectName name, JMXNamespace handler,
Queue<Runnable> postDeregisterQueue) { Queue<Runnable> postDeregisterQueue) {
if (handler instanceof JMXDomain) if (handler instanceof JMXDomain)
localNamespace.removeNamespace(name,(JMXDomain)handler, nextInterceptor.removeInterceptorFor(name,(JMXDomain)handler,
postDeregisterQueue); postDeregisterQueue);
else super.removeNamespace(name,handler,postDeregisterQueue); else super.removeInterceptorFor(name,handler,postDeregisterQueue);
} }
......
...@@ -1172,10 +1172,10 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory { ...@@ -1172,10 +1172,10 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
final Class<ConstructorProperties> propertyNamesClass = ConstructorProperties.class; final Class<ConstructorProperties> propertyNamesClass = ConstructorProperties.class;
Class targetClass = getTargetClass(); Class targetClass = getTargetClass();
Constructor[] constrs = targetClass.getConstructors(); Constructor<?>[] constrs = targetClass.getConstructors();
// Applicable if and only if there are any annotated constructors // Applicable if and only if there are any annotated constructors
List<Constructor> annotatedConstrList = newList(); List<Constructor<?>> annotatedConstrList = newList();
for (Constructor<?> constr : constrs) { for (Constructor<?> constr : constrs) {
if (Modifier.isPublic(constr.getModifiers()) if (Modifier.isPublic(constr.getModifiers())
&& constr.getAnnotation(propertyNamesClass) != null) && constr.getAnnotation(propertyNamesClass) != null)
...@@ -1206,7 +1206,7 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory { ...@@ -1206,7 +1206,7 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
// Also remember the set of properties in that constructor // Also remember the set of properties in that constructor
// so we can test unambiguity. // so we can test unambiguity.
Set<BitSet> getterIndexSets = newSet(); Set<BitSet> getterIndexSets = newSet();
for (Constructor constr : annotatedConstrList) { for (Constructor<?> constr : annotatedConstrList) {
String[] propertyNames = String[] propertyNames =
constr.getAnnotation(propertyNamesClass).value(); constr.getAnnotation(propertyNamesClass).value();
...@@ -1363,10 +1363,10 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory { ...@@ -1363,10 +1363,10 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
} }
private static class Constr { private static class Constr {
final Constructor constructor; final Constructor<?> constructor;
final int[] paramIndexes; final int[] paramIndexes;
final BitSet presentParams; final BitSet presentParams;
Constr(Constructor constructor, int[] paramIndexes, Constr(Constructor<?> constructor, int[] paramIndexes,
BitSet presentParams) { BitSet presentParams) {
this.constructor = constructor; this.constructor = constructor;
this.paramIndexes = paramIndexes; this.paramIndexes = paramIndexes;
......
...@@ -623,7 +623,7 @@ abstract class MBeanIntrospector<M> { ...@@ -623,7 +623,7 @@ abstract class MBeanIntrospector<M> {
} }
private static MBeanConstructorInfo[] findConstructors(Class<?> c) { private static MBeanConstructorInfo[] findConstructors(Class<?> c) {
Constructor[] cons = c.getConstructors(); Constructor<?>[] cons = c.getConstructors();
MBeanConstructorInfo[] mbc = new MBeanConstructorInfo[cons.length]; MBeanConstructorInfo[] mbc = new MBeanConstructorInfo[cons.length];
for (int i = 0; i < cons.length; i++) { for (int i = 0; i < cons.length; i++) {
String descr = "Public constructor of the MBean"; String descr = "Public constructor of the MBean";
......
...@@ -396,7 +396,7 @@ public class Repository { ...@@ -396,7 +396,7 @@ public class Repository {
// Set domain to default if domain is empty and not already set // Set domain to default if domain is empty and not already set
if (dom.length() == 0) if (dom.length() == 0)
name = Util.newObjectName(domain + name.toString()); name = ObjectName.valueOf(domain + name.toString());
// Do we have default domain ? // Do we have default domain ?
if (dom == domain) { // ES: OK (dom & domain are interned) if (dom == domain) { // ES: OK (dom & domain are interned)
......
...@@ -57,7 +57,8 @@ import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR; ...@@ -57,7 +57,8 @@ import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR;
public class Util { public class Util {
private final static int NAMESPACE_SEPARATOR_LENGTH = private final static int NAMESPACE_SEPARATOR_LENGTH =
NAMESPACE_SEPARATOR.length(); NAMESPACE_SEPARATOR.length();
public final static String ILLEGAL_MBEANSERVER_NAME_CHARS=";:*?"; public final static char[] ILLEGAL_MBEANSERVER_NAME_CHARS=";:*?".
toCharArray();
static <K, V> Map<K, V> newMap() { static <K, V> Map<K, V> newMap() {
...@@ -109,14 +110,6 @@ public class Util { ...@@ -109,14 +110,6 @@ public class Util {
return new ArrayList<E>(c); return new ArrayList<E>(c);
} }
public static ObjectName newObjectName(String s) {
try {
return new ObjectName(s);
} catch (MalformedObjectNameException e) {
throw new IllegalArgumentException(e);
}
}
/* This method can be used by code that is deliberately violating the /* This method can be used by code that is deliberately violating the
* allowed checked casts. Rather than marking the whole method containing * allowed checked casts. Rather than marking the whole method containing
* the code with @SuppressWarnings, you can use a call to this method for * the code with @SuppressWarnings, you can use a call to this method for
...@@ -621,7 +614,7 @@ public class Util { ...@@ -621,7 +614,7 @@ public class Util {
* is {@code null}. * is {@code null}.
* @throws IllegalArgumentException if mbeanServerName contains illegal * @throws IllegalArgumentException if mbeanServerName contains illegal
* characters, or is empty, or is {@code "-"}. * characters, or is empty, or is {@code "-"}.
* Illegal characters are {@value #ILLEGAL_MBEANSERVER_NAME_CHARS}. * Illegal characters are {@link #ILLEGAL_MBEANSERVER_NAME_CHARS}.
*/ */
public static String checkServerName(String mbeanServerName) { public static String checkServerName(String mbeanServerName) {
if ("".equals(mbeanServerName)) if ("".equals(mbeanServerName))
...@@ -632,7 +625,7 @@ public class Util { ...@@ -632,7 +625,7 @@ public class Util {
"\"-\" is not a valid MBean server name"); "\"-\" is not a valid MBean server name");
if (isMBeanServerNameUndefined(mbeanServerName)) if (isMBeanServerNameUndefined(mbeanServerName))
return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME; return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME;
for (char c : ILLEGAL_MBEANSERVER_NAME_CHARS.toCharArray()) { for (char c : ILLEGAL_MBEANSERVER_NAME_CHARS) {
if (mbeanServerName.indexOf(c) >= 0) if (mbeanServerName.indexOf(c) >= 0)
throw new IllegalArgumentException( throw new IllegalArgumentException(
"invalid character in MBeanServer name: "+c); "invalid character in MBeanServer name: "+c);
...@@ -662,15 +655,15 @@ public class Util { ...@@ -662,15 +655,15 @@ public class Util {
} }
// Log the exception and its causes without logging the stack trace. // Log the exception and its causes without logging the stack trace.
// Use with care - it is usally preferable to log the whole stack trace! // Use with care - it is usually preferable to log the whole stack trace!
// We don't want to log the whole stack trace here: logshort() is // We don't want to log the whole stack trace here: logshort() is
// called in those cases where the exception might not be abnormal. // called in those cases where the exception might not be abnormal.
private static void logshort(String msg, Throwable t) { private static void logshort(String msg, Throwable t) {
if (JmxProperties.MISC_LOGGER.isLoggable(Level.FINE)) { if (JmxProperties.MISC_LOGGER.isLoggable(Level.FINE)) {
StringBuilder toprint = new StringBuilder(msg); StringBuilder toprint = new StringBuilder(msg);
toprint.append("\nCaused By: ").append(String.valueOf(t)); do {
while ((t=t.getCause())!=null) toprint.append("\nCaused By: ").append(String.valueOf(t));
toprint.append("\nCaused By: ").append(String.valueOf(t)); } while ((t=t.getCause())!=null);
JmxProperties.MISC_LOGGER.fine(toprint.toString()); JmxProperties.MISC_LOGGER.fine(toprint.toString());
} }
} }
......
...@@ -85,7 +85,7 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> { ...@@ -85,7 +85,7 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> {
final ObjectName pattern; final ObjectName pattern;
public PatternNotificationFilter(ObjectName pattern) { public PatternNotificationFilter(ObjectName pattern) {
this.pattern = pattern; this.pattern = pattern==null?ObjectName.WILDCARD:pattern;
} }
public boolean isNotificationEnabled(Notification notification) { public boolean isNotificationEnabled(Notification notification) {
...@@ -93,7 +93,7 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> { ...@@ -93,7 +93,7 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> {
return false; return false;
final MBeanServerNotification mbsn = final MBeanServerNotification mbsn =
(MBeanServerNotification) notification; (MBeanServerNotification) notification;
if (pattern == null || pattern.apply(mbsn.getMBeanName())) if (pattern.apply(mbsn.getMBeanName()))
return true; return true;
return false; return false;
} }
...@@ -110,6 +110,7 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> { ...@@ -110,6 +110,7 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> {
super(handler); super(handler);
this.domainName = domainName; this.domainName = domainName;
this.serverName = serverName; this.serverName = serverName;
ALL = ObjectName.valueOf(domainName+":*");
} }
@Override @Override
...@@ -118,27 +119,27 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> { ...@@ -118,27 +119,27 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> {
", domain="+this.domainName+")"; ", domain="+this.domainName+")";
} }
public void connectDelegate(final MBeanServerDelegate delegate) final void connectDelegate(final MBeanServerDelegate delegate)
throws InstanceNotFoundException { throws InstanceNotFoundException {
final NotificationFilter filter = final NotificationFilter filter =
new PatternNotificationFilter(getPatternFor(null)); new PatternNotificationFilter(getPatternFor(null));
synchronized (this) { synchronized (this) {
if (mbsListener == null) if (mbsListener == null) {
mbsListener = new NotificationListener() { mbsListener = new NotificationListener() {
public void handleNotification(Notification notification,
public void handleNotification(Notification notification, Object handback) {
Object handback) { if (filter.isNotificationEnabled(notification))
if (filter.isNotificationEnabled(notification)) delegate.sendNotification(notification);
delegate.sendNotification(notification); }
} };
}; }
} }
getNamespace(). getHandlerInterceptorMBean().
addMBeanServerNotificationListener(mbsListener, filter); addMBeanServerNotificationListener(mbsListener, filter);
} }
public void disconnectDelegate() final void disconnectDelegate()
throws InstanceNotFoundException, ListenerNotFoundException { throws InstanceNotFoundException, ListenerNotFoundException {
final NotificationListener l; final NotificationListener l;
synchronized (this) { synchronized (this) {
...@@ -146,10 +147,10 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> { ...@@ -146,10 +147,10 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> {
if (l == null) return; if (l == null) return;
mbsListener = null; mbsListener = null;
} }
getNamespace().removeMBeanServerNotificationListener(l); getHandlerInterceptorMBean().removeMBeanServerNotificationListener(l);
} }
public void addPostRegisterTask(Queue<Runnable> queue, public final void addPostRegisterTask(Queue<Runnable> queue,
final MBeanServerDelegate delegate) { final MBeanServerDelegate delegate) {
if (queue == null) if (queue == null)
throw new IllegalArgumentException("task queue must not be null"); throw new IllegalArgumentException("task queue must not be null");
...@@ -158,14 +159,15 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> { ...@@ -158,14 +159,15 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> {
try { try {
connectDelegate(delegate); connectDelegate(delegate);
} catch (Exception x) { } catch (Exception x) {
throw new UnsupportedOperationException("notification forwarding",x); throw new UnsupportedOperationException(
"notification forwarding",x);
} }
} }
}; };
queue.add(task1); queue.add(task1);
} }
public void addPostDeregisterTask(Queue<Runnable> queue, public final void addPostDeregisterTask(Queue<Runnable> queue,
final MBeanServerDelegate delegate) { final MBeanServerDelegate delegate) {
if (queue == null) if (queue == null)
throw new IllegalArgumentException("task queue must not be null"); throw new IllegalArgumentException("task queue must not be null");
...@@ -174,17 +176,18 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> { ...@@ -174,17 +176,18 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> {
try { try {
disconnectDelegate(); disconnectDelegate();
} catch (Exception x) { } catch (Exception x) {
throw new UnsupportedOperationException("notification forwarding",x); throw new UnsupportedOperationException(
"notification forwarding",x);
} }
} }
}; };
queue.add(task1); queue.add(task1);
} }
/** // No name conversion for JMXDomains...
* Throws IllegalArgumentException if targetName.getDomain() is not // Throws IllegalArgumentException if targetName.getDomain() is not
* in the domain handled. // in the domain handled.
**/ //
@Override @Override
protected ObjectName toSource(ObjectName targetName) { protected ObjectName toSource(ObjectName targetName) {
if (targetName == null) return null; if (targetName == null) return null;
...@@ -198,6 +201,7 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> { ...@@ -198,6 +201,7 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> {
return targetName; return targetName;
} }
// No name conversion for JMXDomains...
@Override @Override
protected ObjectName toTarget(ObjectName sourceName) { protected ObjectName toTarget(ObjectName sourceName) {
return sourceName; return sourceName;
...@@ -255,16 +259,16 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> { ...@@ -255,16 +259,16 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> {
if (LOG.isLoggable(Level.FINE)) if (LOG.isLoggable(Level.FINE))
LOG.fine("Unexpected exception raised in queryNames: "+x); LOG.fine("Unexpected exception raised in queryNames: "+x);
LOG.log(Level.FINEST,"Unexpected exception raised in queryNames",x); LOG.log(Level.FINEST,"Unexpected exception raised in queryNames",x);
return Collections.emptySet();
} }
// We reach here only when an exception was raised.
//
final Set<ObjectName> empty = Collections.emptySet();
return empty;
} }
// Compute a new pattern which is a sub pattern of 'name' but only selects
// the MBeans in domain 'domainName'
// When we reach here, it has been verified that 'name' matches our domain
// name (done by DomainDispatchInterceptor)
private ObjectName getPatternFor(final ObjectName name) { private ObjectName getPatternFor(final ObjectName name) {
try { try {
if (ALL == null) ALL = ObjectName.getInstance(domainName + ":*");
if (name == null) return ALL; if (name == null) return ALL;
if (name.getDomain().equals(domainName)) return name; if (name.getDomain().equals(domainName)) return name;
return name.withDomain(domainName); return name.withDomain(domainName);
...@@ -284,11 +288,8 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> { ...@@ -284,11 +288,8 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> {
if (LOG.isLoggable(Level.FINE)) if (LOG.isLoggable(Level.FINE))
LOG.fine("Unexpected exception raised in queryNames: "+x); LOG.fine("Unexpected exception raised in queryNames: "+x);
LOG.log(Level.FINEST,"Unexpected exception raised in queryNames",x); LOG.log(Level.FINEST,"Unexpected exception raised in queryNames",x);
return Collections.emptySet();
} }
// We reach here only when an exception was raised.
//
final Set<ObjectInstance> empty = Collections.emptySet();
return empty;
} }
@Override @Override
...@@ -306,7 +307,7 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> { ...@@ -306,7 +307,7 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> {
// in the domain. // in the domain.
@Override @Override
public Integer getMBeanCount() { public Integer getMBeanCount() {
return getNamespace().getMBeanCount(); return getHandlerInterceptorMBean().getMBeanCount();
} }
private boolean checkOn() { private boolean checkOn() {
...@@ -320,8 +321,8 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> { ...@@ -320,8 +321,8 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> {
@Override @Override
void check(ObjectName routingName, String member, String action) { void check(ObjectName routingName, String member, String action) {
if (!checkOn()) return; if (!checkOn()) return;
final String act = (action==null)?"-":action.intern(); final String act = (action==null)?"-":action;
if(act == "queryMBeans" || act == "queryNames") { // ES: OK if("queryMBeans".equals(act) || "queryNames".equals(act)) {
// This is tricky. check with 3 parameters is called // This is tricky. check with 3 parameters is called
// by queryNames/queryMBeans before performing the query. // by queryNames/queryMBeans before performing the query.
// At this point we must check with no class name. // At this point we must check with no class name.
...@@ -355,16 +356,8 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> { ...@@ -355,16 +356,8 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> {
if (!checkOn()) return; if (!checkOn()) return;
final MBeanPermission perm; final MBeanPermission perm;
// action is most probably already an intern string. final String act = (action==null)?"-":action;
// string literals are intern strings. if ("getDomains".equals(act)) { // ES: OK
// we create a new intern string for 'action' - just to be on
// the safe side...
// We intern it in order to be able to use == rather than equals
// below, because if we don't, and if action is not one of the
// 4 literals below, we would have to do a full string comparison.
//
final String act = (action==null)?"-":action.intern();
if (act == "getDomains") { // ES: OK
perm = new MBeanPermission(serverName,"-",member, perm = new MBeanPermission(serverName,"-",member,
routingName,act); routingName,act);
} else { } else {
...@@ -381,7 +374,7 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> { ...@@ -381,7 +374,7 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> {
String getClassName(ObjectName routingName) { String getClassName(ObjectName routingName) {
if (routingName == null || routingName.isPattern()) return "-"; if (routingName == null || routingName.isPattern()) return "-";
try { try {
return getNamespace().getSourceServer(). return getHandlerInterceptorMBean().getSourceServer().
getObjectInstance(routingName).getClassName(); getObjectInstance(routingName).getClassName();
} catch (InstanceNotFoundException ex) { } catch (InstanceNotFoundException ex) {
LOG.finest("Can't get class name for "+routingName+ LOG.finest("Can't get class name for "+routingName+
...@@ -444,7 +437,7 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> { ...@@ -444,7 +437,7 @@ public class DomainInterceptor extends HandlerInterceptor<JMXDomain> {
int count=0; int count=0;
for (int i=0;i<domains.length;i++) { for (int i=0;i<domains.length;i++) {
try { try {
check(Util.newObjectName(domains[i]+":x=x"),"-", check(ObjectName.valueOf(domains[i]+":x=x"),"-",
"-","getDomains"); "-","getDomains");
} catch (SecurityException x) { // DLS: OK } catch (SecurityException x) { // DLS: OK
count++; count++;
......
...@@ -63,8 +63,8 @@ import javax.management.namespace.JMXNamespace; ...@@ -63,8 +63,8 @@ import javax.management.namespace.JMXNamespace;
/** /**
* This interceptor wraps a JMXNamespace, and performs * This interceptor wraps a JMXNamespace, and performs
* {@code ObjectName} rewriting. {@code HandlerInterceptor} are * {@code ObjectName} rewriting. {@code HandlerInterceptor} are
* usually created and managed by a {@link NamespaceDispatcher} or * created and managed by a {@link NamespaceDispatchInterceptor} or a
* {@link DomainDispatcher}. * {@link DomainDispatchInterceptor}.
* <p><b> * <p><b>
* This API is a Sun internal API and is subject to changes without notice. * This API is a Sun internal API and is subject to changes without notice.
* </b></p> * </b></p>
...@@ -90,6 +90,12 @@ public abstract class HandlerInterceptor<T extends JMXNamespace> ...@@ -90,6 +90,12 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
this.handler = handler; this.handler = handler;
} }
//
// The {@code source} connection is a connection to the MBeanServer
// that contains the actual MBeans.
// In the case of cascading, that would be a connection to the sub
// agent. Practically, this is JMXNamespace.getSourceServer();
//
@Override @Override
protected MBeanServer source() { protected MBeanServer source() {
return handler.getSourceServer(); return handler.getSourceServer();
...@@ -105,7 +111,9 @@ public abstract class HandlerInterceptor<T extends JMXNamespace> ...@@ -105,7 +111,9 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
return source(); return source();
} }
T getNamespace() { // The namespace or domain handler - this either a JMXNamespace or a
// a JMXDomain
T getHandlerInterceptorMBean() {
return handler; return handler;
} }
...@@ -122,12 +130,16 @@ public abstract class HandlerInterceptor<T extends JMXNamespace> ...@@ -122,12 +130,16 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
Util.newRuntimeIOException(x)); Util.newRuntimeIOException(x));
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public AttributeList getAttributes(ObjectName name, String[] attributes) public AttributeList getAttributes(ObjectName name, String[] attributes)
throws InstanceNotFoundException, ReflectionException { throws InstanceNotFoundException, ReflectionException {
try { try {
return super.getAttributes(name, attributes); final String[] authorized =
checkAttributes(name,attributes,"getAttribute");
final AttributeList attrList =
super.getAttributes(name,authorized);
return attrList;
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"getAttributes",name,attributes); throw handleIOException(ex,"getAttributes",name,attributes);
} }
...@@ -172,18 +184,19 @@ public abstract class HandlerInterceptor<T extends JMXNamespace> ...@@ -172,18 +184,19 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
} }
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public void removeNotificationListener(ObjectName name, ObjectName listener) public void removeNotificationListener(ObjectName name, ObjectName listener)
throws InstanceNotFoundException, ListenerNotFoundException { throws InstanceNotFoundException, ListenerNotFoundException {
try { try {
super.removeNotificationListener(name, listener); check(name,null,"removeNotificationListener");
super.removeNotificationListener(name,listener);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"removeNotificationListener",name,listener); throw handleIOException(ex,"removeNotificationListener",name,listener);
} }
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public String getDefaultDomain() { public String getDefaultDomain() {
try { try {
...@@ -193,17 +206,19 @@ public abstract class HandlerInterceptor<T extends JMXNamespace> ...@@ -193,17 +206,19 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
} }
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public String[] getDomains() { public String[] getDomains() {
try { try {
return super.getDomains(); check(null,null,"getDomains");
final String[] domains = super.getDomains();
return checkDomains(domains,"getDomains");
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"getDomains"); throw handleIOException(ex,"getDomains");
} }
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public Integer getMBeanCount() { public Integer getMBeanCount() {
try { try {
...@@ -213,64 +228,74 @@ public abstract class HandlerInterceptor<T extends JMXNamespace> ...@@ -213,64 +228,74 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
} }
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public void setAttribute(ObjectName name, Attribute attribute) public void setAttribute(ObjectName name, Attribute attribute)
throws InstanceNotFoundException, AttributeNotFoundException, throws InstanceNotFoundException, AttributeNotFoundException,
InvalidAttributeValueException, MBeanException, InvalidAttributeValueException, MBeanException,
ReflectionException { ReflectionException {
try { try {
super.setAttribute(name, attribute); check(name,
(attribute==null?null:attribute.getName()),
"setAttribute");
super.setAttribute(name,attribute);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"setAttribute",name, attribute); throw handleIOException(ex,"setAttribute",name, attribute);
} }
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public Set<ObjectName> queryNames(ObjectName name, QueryExp query) { public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
if (name == null) name=ObjectName.WILDCARD;
try { try {
return super.queryNames(name, query); checkPattern(name,null,"queryNames");
return super.queryNames(name,query);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"queryNames",name, query); throw handleIOException(ex,"queryNames",name, query);
} }
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) { public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
if (name == null) name=ObjectName.WILDCARD;
try { try {
return super.queryMBeans(name, query); checkPattern(name,null,"queryMBeans");
return super.queryMBeans(name,query);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"queryMBeans",name, query); throw handleIOException(ex,"queryMBeans",name, query);
} }
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public boolean isInstanceOf(ObjectName name, String className) public boolean isInstanceOf(ObjectName name, String className)
throws InstanceNotFoundException { throws InstanceNotFoundException {
try { try {
check(name, null, "isInstanceOf");
return super.isInstanceOf(name, className); return super.isInstanceOf(name, className);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"isInstanceOf",name, className); throw handleIOException(ex,"isInstanceOf",name, className);
} }
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public ObjectInstance createMBean(String className, ObjectName name) public ObjectInstance createMBean(String className, ObjectName name)
throws ReflectionException, InstanceAlreadyExistsException, throws ReflectionException, InstanceAlreadyExistsException,
MBeanRegistrationException, MBeanException, MBeanRegistrationException, MBeanException,
NotCompliantMBeanException { NotCompliantMBeanException {
try { try {
checkCreate(name, className, "instantiate");
checkCreate(name, className, "registerMBean");
return super.createMBean(className, name); return super.createMBean(className, name);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"createMBean",className, name); throw handleIOException(ex,"createMBean",className, name);
} }
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public ObjectInstance createMBean(String className, ObjectName name, public ObjectInstance createMBean(String className, ObjectName name,
ObjectName loaderName) ObjectName loaderName)
...@@ -278,30 +303,34 @@ public abstract class HandlerInterceptor<T extends JMXNamespace> ...@@ -278,30 +303,34 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
MBeanRegistrationException, MBeanException, MBeanRegistrationException, MBeanException,
NotCompliantMBeanException, InstanceNotFoundException { NotCompliantMBeanException, InstanceNotFoundException {
try { try {
checkCreate(name, className, "instantiate");
checkCreate(name, className, "registerMBean");
return super.createMBean(className, name, loaderName); return super.createMBean(className, name, loaderName);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"createMBean",className, name, loaderName); throw handleIOException(ex,"createMBean",className, name, loaderName);
} }
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public Object getAttribute(ObjectName name, String attribute) public Object getAttribute(ObjectName name, String attribute)
throws MBeanException, AttributeNotFoundException, throws MBeanException, AttributeNotFoundException,
InstanceNotFoundException, ReflectionException { InstanceNotFoundException, ReflectionException {
try { try {
check(name, attribute, "getAttribute");
return super.getAttribute(name, attribute); return super.getAttribute(name, attribute);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"getAttribute",name, attribute); throw handleIOException(ex,"getAttribute",name, attribute);
} }
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public void removeNotificationListener(ObjectName name, ObjectName listener, public void removeNotificationListener(ObjectName name, ObjectName listener,
NotificationFilter filter, Object handback) NotificationFilter filter, Object handback)
throws InstanceNotFoundException, ListenerNotFoundException { throws InstanceNotFoundException, ListenerNotFoundException {
try { try {
check(name,null,"removeNotificationListener");
super.removeNotificationListener(name, listener, filter, handback); super.removeNotificationListener(name, listener, filter, handback);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"removeNotificationListener",name, throw handleIOException(ex,"removeNotificationListener",name,
...@@ -309,13 +338,14 @@ public abstract class HandlerInterceptor<T extends JMXNamespace> ...@@ -309,13 +338,14 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
} }
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public void removeNotificationListener(ObjectName name, public void removeNotificationListener(ObjectName name,
NotificationListener listener, NotificationFilter filter, NotificationListener listener, NotificationFilter filter,
Object handback) Object handback)
throws InstanceNotFoundException, ListenerNotFoundException { throws InstanceNotFoundException, ListenerNotFoundException {
try { try {
check(name,null,"removeNotificationListener");
super.removeNotificationListener(name, listener, filter, handback); super.removeNotificationListener(name, listener, filter, handback);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"removeNotificationListener",name, throw handleIOException(ex,"removeNotificationListener",name,
...@@ -323,12 +353,13 @@ public abstract class HandlerInterceptor<T extends JMXNamespace> ...@@ -323,12 +353,13 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
} }
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public void removeNotificationListener(ObjectName name, public void removeNotificationListener(ObjectName name,
NotificationListener listener) NotificationListener listener)
throws InstanceNotFoundException, ListenerNotFoundException { throws InstanceNotFoundException, ListenerNotFoundException {
try { try {
check(name,null,"removeNotificationListener");
super.removeNotificationListener(name, listener); super.removeNotificationListener(name, listener);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"removeNotificationListener",name, throw handleIOException(ex,"removeNotificationListener",name,
...@@ -336,12 +367,13 @@ public abstract class HandlerInterceptor<T extends JMXNamespace> ...@@ -336,12 +367,13 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
} }
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public void addNotificationListener(ObjectName name, public void addNotificationListener(ObjectName name,
NotificationListener listener, NotificationFilter filter, NotificationListener listener, NotificationFilter filter,
Object handback) throws InstanceNotFoundException { Object handback) throws InstanceNotFoundException {
try { try {
check(name,null,"addNotificationListener");
super.addNotificationListener(name, listener, filter, handback); super.addNotificationListener(name, listener, filter, handback);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"addNotificationListener",name, throw handleIOException(ex,"addNotificationListener",name,
...@@ -349,12 +381,13 @@ public abstract class HandlerInterceptor<T extends JMXNamespace> ...@@ -349,12 +381,13 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
} }
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public void addNotificationListener(ObjectName name, ObjectName listener, public void addNotificationListener(ObjectName name, ObjectName listener,
NotificationFilter filter, Object handback) NotificationFilter filter, Object handback)
throws InstanceNotFoundException { throws InstanceNotFoundException {
try { try {
check(name,null,"addNotificationListener");
super.addNotificationListener(name, listener, filter, handback); super.addNotificationListener(name, listener, filter, handback);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"addNotificationListener",name, throw handleIOException(ex,"addNotificationListener",name,
...@@ -362,7 +395,7 @@ public abstract class HandlerInterceptor<T extends JMXNamespace> ...@@ -362,7 +395,7 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
} }
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public boolean isRegistered(ObjectName name) { public boolean isRegistered(ObjectName name) {
try { try {
...@@ -372,41 +405,44 @@ public abstract class HandlerInterceptor<T extends JMXNamespace> ...@@ -372,41 +405,44 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
} }
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public void unregisterMBean(ObjectName name) public void unregisterMBean(ObjectName name)
throws InstanceNotFoundException, MBeanRegistrationException { throws InstanceNotFoundException, MBeanRegistrationException {
try { try {
check(name, null, "unregisterMBean");
super.unregisterMBean(name); super.unregisterMBean(name);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"unregisterMBean",name); throw handleIOException(ex,"unregisterMBean",name);
} }
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public MBeanInfo getMBeanInfo(ObjectName name) public MBeanInfo getMBeanInfo(ObjectName name)
throws InstanceNotFoundException, IntrospectionException, throws InstanceNotFoundException, IntrospectionException,
ReflectionException { ReflectionException {
try { try {
check(name, null, "getMBeanInfo");
return super.getMBeanInfo(name); return super.getMBeanInfo(name);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"getMBeanInfo",name); throw handleIOException(ex,"getMBeanInfo",name);
} }
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public ObjectInstance getObjectInstance(ObjectName name) public ObjectInstance getObjectInstance(ObjectName name)
throws InstanceNotFoundException { throws InstanceNotFoundException {
try { try {
check(name, null, "getObjectInstance");
return super.getObjectInstance(name); return super.getObjectInstance(name);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"getObjectInstance",name); throw handleIOException(ex,"getObjectInstance",name);
} }
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public ObjectInstance createMBean(String className, ObjectName name, public ObjectInstance createMBean(String className, ObjectName name,
Object[] params, String[] signature) Object[] params, String[] signature)
...@@ -414,6 +450,8 @@ public abstract class HandlerInterceptor<T extends JMXNamespace> ...@@ -414,6 +450,8 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
MBeanRegistrationException, MBeanException, MBeanRegistrationException, MBeanException,
NotCompliantMBeanException { NotCompliantMBeanException {
try { try {
checkCreate(name, className, "instantiate");
checkCreate(name, className, "registerMBean");
return super.createMBean(className, name, params, signature); return super.createMBean(className, name, params, signature);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"createMBean",className, name, throw handleIOException(ex,"createMBean",className, name,
...@@ -421,7 +459,7 @@ public abstract class HandlerInterceptor<T extends JMXNamespace> ...@@ -421,7 +459,7 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
} }
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public ObjectInstance createMBean(String className, ObjectName name, public ObjectInstance createMBean(String className, ObjectName name,
ObjectName loaderName, Object[] params, String[] signature) ObjectName loaderName, Object[] params, String[] signature)
...@@ -429,6 +467,8 @@ public abstract class HandlerInterceptor<T extends JMXNamespace> ...@@ -429,6 +467,8 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
MBeanRegistrationException, MBeanException, MBeanRegistrationException, MBeanException,
NotCompliantMBeanException, InstanceNotFoundException { NotCompliantMBeanException, InstanceNotFoundException {
try { try {
checkCreate(name, className, "instantiate");
checkCreate(name, className, "registerMBean");
return super.createMBean(className, name, loaderName, params, return super.createMBean(className, name, loaderName, params,
signature); signature);
} catch (IOException ex) { } catch (IOException ex) {
...@@ -437,23 +477,26 @@ public abstract class HandlerInterceptor<T extends JMXNamespace> ...@@ -437,23 +477,26 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
} }
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public AttributeList setAttributes(ObjectName name,AttributeList attributes) public AttributeList setAttributes(ObjectName name,AttributeList attributes)
throws InstanceNotFoundException, ReflectionException { throws InstanceNotFoundException, ReflectionException {
try { try {
return super.setAttributes(name, attributes); final AttributeList authorized =
checkAttributes(name, attributes, "setAttribute");
return super.setAttributes(name, authorized);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"setAttributes",name, attributes); throw handleIOException(ex,"setAttributes",name, attributes);
} }
} }
// From MBeanServer: catch & handles IOException // From MBeanServerConnection: catch & handles IOException
@Override @Override
public Object invoke(ObjectName name, String operationName, Object[] params, public Object invoke(ObjectName name, String operationName, Object[] params,
String[] signature) String[] signature)
throws InstanceNotFoundException, MBeanException, ReflectionException { throws InstanceNotFoundException, MBeanException, ReflectionException {
try { try {
check(name, operationName, "invoke");
return super.invoke(name, operationName, params, signature); return super.invoke(name, operationName, params, signature);
} catch (IOException ex) { } catch (IOException ex) {
throw handleIOException(ex,"invoke",name, operationName, throw handleIOException(ex,"invoke",name, operationName,
...@@ -574,4 +617,118 @@ public abstract class HandlerInterceptor<T extends JMXNamespace> ...@@ -574,4 +617,118 @@ public abstract class HandlerInterceptor<T extends JMXNamespace>
"Not supported in this namespace: "+namespace)); "Not supported in this namespace: "+namespace));
} }
/**
* A result might be excluded for security reasons.
*/
@Override
boolean excludesFromResult(ObjectName targetName, String queryMethod) {
return !checkQuery(targetName, queryMethod);
}
//----------------------------------------------------------------------
// Hooks for checking permissions
//----------------------------------------------------------------------
/**
* This method is a hook to implement permission checking in subclasses.
* A subclass may override this method and throw a {@link
* SecurityException} if the permission is denied.
*
* @param routingName The name of the MBean in the enclosing context.
* This is of the form {@code <namespace>//<ObjectName>}.
* @param member The {@link
* javax.management.namespace.JMXNamespacePermission#getMember member}
* name.
* @param action The {@link
* javax.management.namespace.JMXNamespacePermission#getActions action}
* name.
* @throws SecurityException if the caller doesn't have the permission
* to perform the given action on the MBean pointed to
* by routingName.
*/
abstract void check(ObjectName routingName,
String member, String action);
// called in createMBean and registerMBean
abstract void checkCreate(ObjectName routingName, String className,
String action);
/**
* This is a hook to implement permission checking in subclasses.
*
* Checks that the caller has sufficient permission for returning
* information about {@code sourceName} in {@code action}.
*
* Subclass may override this method and return false if the caller
* doesn't have sufficient permissions.
*
* @param routingName The name of the MBean to include or exclude from
* the query, expressed in the enclosing context.
* This is of the form {@code <namespace>//<ObjectName>}.
* @param action one of "queryNames" or "queryMBeans"
* @return true if {@code sourceName} can be returned.
*/
abstract boolean checkQuery(ObjectName routingName, String action);
/**
* This method is a hook to implement permission checking in subclasses.
*
* @param routingName The name of the MBean in the enclosing context.
* This is of the form {@code <namespace>//<ObjectName>}.
* @param attributes The list of attributes to check permission for.
* @param action one of "getAttribute" or "setAttribute"
* @return The list of attributes for which the callers has the
* appropriate {@link
* javax.management.namespace.JMXNamespacePermission}.
* @throws SecurityException if the caller doesn't have the permission
* to perform {@code action} on the MBean pointed to by routingName.
*/
abstract String[] checkAttributes(ObjectName routingName,
String[] attributes, String action);
/**
* This method is a hook to implement permission checking in subclasses.
*
* @param routingName The name of the MBean in the enclosing context.
* This is of the form {@code <namespace>//<ObjectName>}.
* @param attributes The list of attributes to check permission for.
* @param action one of "getAttribute" or "setAttribute"
* @return The list of attributes for which the callers has the
* appropriate {@link
* javax.management.namespace.JMXNamespacePermission}.
* @throws SecurityException if the caller doesn't have the permission
* to perform {@code action} on the MBean pointed to by routingName.
*/
abstract AttributeList checkAttributes(ObjectName routingName,
AttributeList attributes, String action);
/**
* This method is a hook to implement permission checking in subclasses.
* Checks that the caller as the necessary permissions to view the
* given domain. If not remove the domains for which the caller doesn't
* have permission from the list.
* <p>
* By default, this method always returns {@code domains}
*
* @param domains The domains to return.
* @param action "getDomains"
* @return a filtered list of domains.
*/
String[] checkDomains(String[] domains, String action) {
return domains;
}
// A priori check for queryNames/queryMBeans/
void checkPattern(ObjectName routingPattern,
String member, String action) {
// pattern is checked only at posteriori by checkQuery.
// checking it a priori usually doesn't work, because ObjectName.apply
// does not work between two patterns.
// We only check that we have the permission requested for 'action'.
check(null,null,action);
}
} }
...@@ -29,7 +29,6 @@ import com.sun.jmx.defaults.JmxProperties; ...@@ -29,7 +29,6 @@ import com.sun.jmx.defaults.JmxProperties;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import java.util.logging.Level; import java.util.logging.Level;
...@@ -40,6 +39,8 @@ import javax.management.MBeanServerConnection; ...@@ -40,6 +39,8 @@ import javax.management.MBeanServerConnection;
import javax.management.NotificationFilter; import javax.management.NotificationFilter;
import javax.management.NotificationListener; import javax.management.NotificationListener;
import javax.management.event.EventClient; import javax.management.event.EventClient;
import javax.management.event.EventClientDelegateMBean;
import javax.management.namespace.JMXNamespace;
import javax.management.namespace.JMXNamespaces; import javax.management.namespace.JMXNamespaces;
import javax.management.remote.JMXAddressable; import javax.management.remote.JMXAddressable;
import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnector;
...@@ -66,26 +67,10 @@ public final class JMXNamespaceUtils { ...@@ -66,26 +67,10 @@ public final class JMXNamespaceUtils {
return new WeakHashMap<K,V>(); return new WeakHashMap<K,V>();
} }
/** Creates a new instance of JMXNamespaces */ /** There are no instances of this class */
private JMXNamespaceUtils() { private JMXNamespaceUtils() {
} }
/**
* Returns an unmodifiable option map in which the given keys have been
* filtered out.
* @param keys keys to filter out from the map.
* @return An unmodifiable option map in which the given keys have been
* filtered out.
*/
public static <K,V> Map<K,V> filterMap(Map<K,V> map, K... keys) {
final Map<K,V> filtered;
filtered=new HashMap<K,V>(map);
for (K key : keys) {
filtered.remove(key);
}
return unmodifiableMap(filtered);
}
// returns un unmodifiable view of a map. // returns un unmodifiable view of a map.
public static <K,V> Map<K,V> unmodifiableMap(Map<K,V> aMap) { public static <K,V> Map<K,V> unmodifiableMap(Map<K,V> aMap) {
if (aMap == null || aMap.isEmpty()) if (aMap == null || aMap.isEmpty())
......
...@@ -25,22 +25,15 @@ ...@@ -25,22 +25,15 @@
package com.sun.jmx.namespace; package com.sun.jmx.namespace;
import com.sun.jmx.defaults.JmxProperties; import com.sun.jmx.defaults.JmxProperties;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.management.Attribute; import javax.management.Attribute;
import javax.management.AttributeList; import javax.management.AttributeList;
import javax.management.MBeanServer; import javax.management.MBeanServer;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException; import javax.management.MalformedObjectNameException;
import javax.management.ObjectName; import javax.management.ObjectName;
import javax.management.QueryExp;
import javax.management.namespace.JMXNamespaces;
import javax.management.namespace.JMXNamespace; import javax.management.namespace.JMXNamespace;
import javax.management.namespace.JMXNamespacePermission; import javax.management.namespace.JMXNamespacePermission;
...@@ -54,12 +47,6 @@ import javax.management.namespace.JMXNamespacePermission; ...@@ -54,12 +47,6 @@ import javax.management.namespace.JMXNamespacePermission;
*/ */
public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> { public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> {
/**
* A logger for this class.
**/
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
private static final Logger PROBE_LOG = Logger.getLogger(
JmxProperties.NAMESPACE_LOGGER+".probe");
// The target name space in which the NamepsaceHandler is mounted. // The target name space in which the NamepsaceHandler is mounted.
private final String targetNs; private final String targetNs;
...@@ -68,21 +55,6 @@ public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> { ...@@ -68,21 +55,6 @@ public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> {
private final ObjectNameRouter proc; private final ObjectNameRouter proc;
/**
* Internal hack. The JMXRemoteNamespace can be closed and reconnected.
* Each time the JMXRemoteNamespace connects, a probe should be sent
* to detect cycle. The MBeanServer exposed by JMXRemoteNamespace thus
* implements the DynamicProbe interface, which makes it possible for
* this handler to know that it should send a new probe.
*
* XXX: TODO this probe thing is way too complex and fragile.
* This *must* go away or be replaced by something simpler.
* ideas are welcomed.
**/
public static interface DynamicProbe {
public boolean isProbeRequested();
}
/** /**
* Creates a new instance of NamespaceInterceptor * Creates a new instance of NamespaceInterceptor
*/ */
...@@ -104,164 +76,6 @@ public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> { ...@@ -104,164 +76,6 @@ public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> {
", namespace="+this.targetNs+")"; ", namespace="+this.targetNs+")";
} }
/*
* XXX: TODO this probe thing is way too complex and fragile.
* This *must* go away or be replaced by something simpler.
* ideas are welcomed.
*/
private volatile boolean probed = false;
private volatile ObjectName probe;
// Query Pattern that we will send through the source server in order
// to detect self-linking namespaces.
//
// XXX: TODO this probe thing is way too complex and fragile.
// This *must* go away or be replaced by something simpler.
// ideas are welcomed.
final ObjectName makeProbePattern(ObjectName probe)
throws MalformedObjectNameException {
// we could probably link the probe pattern with the probe - e.g.
// using the UUID as key in the pattern - but is it worth it? it
// also has some side effects on the context namespace - because
// such a probe may get rejected by the jmx.context// namespace.
//
// The trick here is to devise a pattern that is not likely to
// be blocked by intermediate levels. Querying for all namespace
// handlers in the source (or source namespace) is more likely to
// achieve this goal.
//
return ObjectName.getInstance("*" +
JMXNamespaces.NAMESPACE_SEPARATOR + ":" +
JMXNamespace.TYPE_ASSIGNMENT);
}
// tell whether the name pattern corresponds to what might have been
// sent as a probe.
// XXX: TODO this probe thing is way too complex and fragile.
// This *must* go away or be replaced by something simpler.
// ideas are welcomed.
final boolean isProbePattern(ObjectName name) {
final ObjectName p = probe;
if (p == null) return false;
try {
return String.valueOf(name).endsWith(targetNs+
JMXNamespaces.NAMESPACE_SEPARATOR + "*" +
JMXNamespaces.NAMESPACE_SEPARATOR + ":" +
JMXNamespace.TYPE_ASSIGNMENT);
} catch (RuntimeException x) {
// should not happen.
PROBE_LOG.finest("Ignoring unexpected exception in self link detection: "+
x);
return false;
}
}
// The first time a request reaches this NamespaceInterceptor, the
// interceptor will send a probe to detect whether the underlying
// JMXNamespace links to itslef.
//
// One way to create such self-linking namespace would be for instance
// to create a JMXNamespace whose getSourceServer() method would return:
// JMXNamespaces.narrowToNamespace(getMBeanServer(),
// getObjectName().getDomain())
//
// If such an MBeanServer is returned, then any call to that MBeanServer
// will trigger an infinite loop.
// There can be even trickier configurations if remote connections are
// involved.
//
// In order to prevent this from happening, the NamespaceInterceptor will
// send a probe, in an attempt to detect whether it will receive it at
// the other end. If the probe is received, an exception will be thrown
// in order to break the recursion. The probe is only sent once - when
// the first request to the namespace occurs. The DynamicProbe interface
// can also be used by a Sun JMXNamespace implementation to request the
// emission of a probe at any time (see JMXRemoteNamespace
// implementation).
//
// Probes work this way: the NamespaceInterceptor sets a flag and sends
// a queryNames() request. If a queryNames() request comes in when the flag
// is on, then it deduces that there is a self-linking loop - and instead
// of calling queryNames() on the source MBeanServer of the JMXNamespace
// handler (which would cause the loop to go on) it breaks the recursion
// by returning the probe ObjectName.
// If the NamespaceInterceptor receives the probe ObjectName as result of
// its original sendProbe() request it knows that it has been looping
// back on itslef and throws an IOException...
//
//
// XXX: TODO this probe thing is way too complex and fragile.
// This *must* go away or be replaced by something simpler.
// ideas are welcomed.
//
final void sendProbe(MBeanServerConnection msc)
throws IOException {
try {
PROBE_LOG.fine("Sending probe");
// This is just to prevent any other thread to modify
// the probe while the detection cycle is in progress.
//
final ObjectName probePattern;
// we don't want to synchronize on this - we use targetNs
// because it's non null and final.
synchronized (targetNs) {
probed = false;
if (probe != null) {
throw new IOException("concurent connection in progress");
}
final String uuid = UUID.randomUUID().toString();
final String endprobe =
JMXNamespaces.NAMESPACE_SEPARATOR + uuid +
":type=Probe,key="+uuid;
final ObjectName newprobe =
ObjectName.getInstance(endprobe);
probePattern = makeProbePattern(newprobe);
probe = newprobe;
}
try {
PROBE_LOG.finer("Probe query: "+probePattern+" expecting: "+probe);
final Set<ObjectName> res = msc.queryNames(probePattern, null);
final ObjectName expected = probe;
PROBE_LOG.finer("Probe res: "+res);
if (res.contains(expected)) {
throw new IOException("namespace " +
targetNs + " is linking to itself: " +
"cycle detected by probe");
}
} catch (SecurityException x) {
PROBE_LOG.finer("Can't check for cycles: " + x);
// can't do anything....
} catch (RuntimeException x) {
PROBE_LOG.finer("Exception raised by queryNames: " + x);
throw x;
} finally {
probe = null;
}
} catch (MalformedObjectNameException x) {
final IOException io =
new IOException("invalid name space: probe failed");
io.initCause(x);
throw io;
}
PROBE_LOG.fine("Probe returned - no cycles");
probed = true;
}
// allows a Sun implementation JMX Namespace, such as the
// JMXRemoteNamespace, to control when a probe should be sent.
//
// XXX: TODO this probe thing is way too complex and fragile.
// This *must* go away or be replaced by something simpler.
// ideas are welcomed.
private boolean isProbeRequested(Object o) {
if (o instanceof DynamicProbe)
return ((DynamicProbe)o).isProbeRequested();
return false;
}
/** /**
* This method will send a probe to detect self-linking name spaces. * This method will send a probe to detect self-linking name spaces.
* A self linking namespace is a namespace that links back directly * A self linking namespace is a namespace that links back directly
...@@ -281,29 +95,9 @@ public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> { ...@@ -281,29 +95,9 @@ public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> {
* (see JMXRemoteNamespace implementation). * (see JMXRemoteNamespace implementation).
*/ */
private MBeanServer connection() { private MBeanServer connection() {
try { final MBeanServer c = super.source();
final MBeanServer c = super.source(); if (c != null) return c;
if (probe != null) // should not happen // should not come here
throw new RuntimeException("connection is being probed");
if (probed == false || isProbeRequested(c)) {
try {
// Should not happen if class well behaved.
// Never probed. Force it.
//System.err.println("sending probe for " +
// "target="+targetNs+", source="+srcNs);
sendProbe(c);
} catch (IOException io) {
throw new RuntimeException(io.getMessage(), io);
}
}
if (c != null) {
return c;
}
} catch (RuntimeException x) {
throw x;
}
throw new NullPointerException("getMBeanServerConnection"); throw new NullPointerException("getMBeanServerConnection");
} }
...@@ -319,24 +113,6 @@ public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> { ...@@ -319,24 +113,6 @@ public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> {
return super.source(); return super.source();
} }
/**
* Calls {@link MBeanServerConnection#queryNames queryNames}
* on the underlying
* {@link #getMBeanServerConnection MBeanServerConnection}.
**/
@Override
public final Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
// XXX: TODO this probe thing is way too complex and fragile.
// This *must* go away or be replaced by something simpler.
// ideas are welcomed.
PROBE_LOG.finer("probe is: "+probe+" pattern is: "+name);
if (probe != null && isProbePattern(name)) {
PROBE_LOG.finer("Return probe: "+probe);
return Collections.singleton(probe);
}
return super.queryNames(name, query);
}
@Override @Override
protected ObjectName toSource(ObjectName targetName) protected ObjectName toSource(ObjectName targetName)
throws MalformedObjectNameException { throws MalformedObjectNameException {
......
...@@ -45,6 +45,9 @@ import javax.management.namespace.JMXNamespaces; ...@@ -45,6 +45,9 @@ import javax.management.namespace.JMXNamespaces;
* </b></p> * </b></p>
* @since 1.7 * @since 1.7
*/ */
// See class hierarchy and detailled explanations in RoutingProxy in this
// package.
//
public class RoutingConnectionProxy public class RoutingConnectionProxy
extends RoutingProxy<MBeanServerConnection> { extends RoutingProxy<MBeanServerConnection> {
...@@ -93,40 +96,28 @@ public class RoutingConnectionProxy ...@@ -93,40 +96,28 @@ public class RoutingConnectionProxy
targetNs+"\", "+forwardsContext+")"; targetNs+"\", "+forwardsContext+")";
} }
static final RoutingProxyFactory
<MBeanServerConnection,RoutingConnectionProxy>
FACTORY = new RoutingProxyFactory
<MBeanServerConnection,RoutingConnectionProxy>() {
public RoutingConnectionProxy newInstance(MBeanServerConnection source,
String sourcePath, String targetPath,
boolean forwardsContext) {
return new RoutingConnectionProxy(source,sourcePath,
targetPath,forwardsContext);
}
public RoutingConnectionProxy newInstance(
MBeanServerConnection source, String sourcePath) {
return new RoutingConnectionProxy(source,sourcePath);
}
};
public static MBeanServerConnection cd(MBeanServerConnection source, public static MBeanServerConnection cd(MBeanServerConnection source,
String sourcePath) { String sourcePath) {
if (source == null) throw new IllegalArgumentException("null"); return RoutingProxy.cd(RoutingConnectionProxy.class, FACTORY,
if (source.getClass().equals(RoutingConnectionProxy.class)) { source, sourcePath);
// cast is OK here, but findbugs complains unless we use class.cast
final RoutingConnectionProxy other =
RoutingConnectionProxy.class.cast(source);
final String target = other.getTargetNamespace();
// Avoid multiple layers of serialization.
//
// We construct a new proxy from the original source instead of
// stacking a new proxy on top of the old one.
// - that is we replace
// cd ( cd ( x, dir1), dir2);
// by
// cd (x, dir1//dir2);
//
// We can do this only when the source class is exactly
// NamespaceConnectionProxy.
//
if (target == null || target.equals("")) {
final String path =
JMXNamespaces.concat(other.getSourceNamespace(),
sourcePath);
return new RoutingConnectionProxy(other.source(),path,"",
other.forwardsContext);
}
// Note: we could do possibly something here - but it would involve
// removing part of targetDir, and possibly adding
// something to sourcePath.
// Too complex to bother! => simply default to stacking...
}
return new RoutingConnectionProxy(source,sourcePath);
} }
} }
...@@ -83,18 +83,32 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -83,18 +83,32 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
} }
/** /**
* Returns the wrapped source connection. * Returns the wrapped source connection. The {@code source} connection
* is a connection to the MBeanServer that contains the actual MBean.
* In the case of cascading, that would be a connection to the sub
* agent.
**/ **/
protected abstract T source() throws IOException; protected abstract T source() throws IOException;
/** /**
* Converts a target ObjectName to a source ObjectName. * Converts a target ObjectName to a source ObjectName.
* The target ObjectName is the name of the MBean in the mount point
* target. In the case of cascading, that would be the name of the
* MBean in the master agent. So if a subagent S containing an MBean
* named "X" is mounted in the target namespace "foo//" of a master agent M,
* the source is S, the target is "foo//" in M, the source name is "X", and
* the target name is "foo//X".
* In the case of cascading - such as in NamespaceInterceptor, this method
* will convert "foo//X" (the targetName) into "X", the source name.
**/ **/
protected abstract ObjectName toSource(ObjectName targetName) protected abstract ObjectName toSource(ObjectName targetName)
throws MalformedObjectNameException; throws MalformedObjectNameException;
/** /**
* Converts a source ObjectName to a target ObjectName. * Converts a source ObjectName to a target ObjectName.
* (see description of toSource above for explanations)
* In the case of cascading - such as in NamespaceInterceptor, this method
* will convert "X" (the sourceName) into "foo//X", the target name.
**/ **/
protected abstract ObjectName toTarget(ObjectName sourceName) protected abstract ObjectName toTarget(ObjectName sourceName)
throws MalformedObjectNameException; throws MalformedObjectNameException;
...@@ -142,90 +156,17 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -142,90 +156,17 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
return new RuntimeOperationsException(x2); return new RuntimeOperationsException(x2);
} }
/**
* This method is a hook to implement permission checking in subclasses.
* By default, this method does nothing and simply returns
* {@code attribute}.
*
* @param routingName The name of the MBean in the enclosing context.
* This is of the form {@code <namespace>//<ObjectName>}.
* @param attributes The list of attributes to check permission for.
* @param action one of "getAttribute" or "setAttribute"
* @return The list of attributes for which the callers has the
* appropriate {@link
* javax.management.namespace.JMXNamespacePermission}.
*/
String[] checkAttributes(ObjectName routingName,
String[] attributes, String action) {
check(routingName,null,action);
return attributes;
}
/**
* This method is a hook to implement permission checking in subclasses.
* By default, this method does nothing and simply returns
* {@code attribute}.
*
* @param routingName The name of the MBean in the enclosing context.
* This is of the form {@code <namespace>//<ObjectName>}.
* @param attributes The list of attributes to check permission for.
* @param action one of "getAttribute" or "setAttribute"
* @return The list of attributes for which the callers has the
* appropriate {@link
* javax.management.namespace.JMXNamespacePermission}.
*/
AttributeList checkAttributes(ObjectName routingName,
AttributeList attributes, String action) {
check(routingName,null,action);
return attributes;
}
// from MBeanServerConnection // from MBeanServerConnection
public AttributeList getAttributes(ObjectName name, String[] attributes) public AttributeList getAttributes(ObjectName name, String[] attributes)
throws InstanceNotFoundException, ReflectionException, IOException { throws InstanceNotFoundException, ReflectionException, IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
final String[] authorized = return source().getAttributes(sourceName, attributes);
checkAttributes(name,attributes,"getAttribute");
final AttributeList attrList =
source().getAttributes(sourceName,authorized);
return attrList;
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
throw makeCompliantRuntimeException(ex); throw makeCompliantRuntimeException(ex);
} }
} }
/**
* This method is a hook to implement permission checking in subclasses.
* By default, this method does nothing.
* A subclass may override this method and throw a {@link
* SecurityException} if the permission is denied.
*
* @param routingName The name of the MBean in the enclosing context.
* This is of the form {@code <namespace>//<ObjectName>}.
* @param member The {@link
* javax.management.namespace.JMXNamespacePermission#getMember member}
* name.
* @param action The {@link
* javax.management.namespace.JMXNamespacePermission#getActions action}
* name.
*/
void check(ObjectName routingName,
String member, String action) {
}
void checkPattern(ObjectName routingPattern,
String member, String action) {
// pattern is checked only at posteriori by checkQuery.
// checking it a priori usually doesn't work, because ObjectName.apply
// does not work between two patterns.
check(null,null,action);
}
void checkCreate(ObjectName routingName, String className,
String action) {
}
// from MBeanServerConnection // from MBeanServerConnection
public Object invoke(ObjectName name, String operationName, Object[] params, public Object invoke(ObjectName name, String operationName, Object[] params,
String[] signature) String[] signature)
...@@ -233,7 +174,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -233,7 +174,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
IOException { IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
check(name, operationName, "invoke");
final Object result = final Object result =
source().invoke(sourceName,operationName,params, source().invoke(sourceName,operationName,params,
signature); signature);
...@@ -249,7 +189,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -249,7 +189,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
IOException { IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
check(name, null, "unregisterMBean");
source().unregisterMBean(sourceName); source().unregisterMBean(sourceName);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
throw makeCompliantRuntimeException(ex); throw makeCompliantRuntimeException(ex);
...@@ -262,7 +201,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -262,7 +201,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
ReflectionException, IOException { ReflectionException, IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
check(name, null, "getMBeanInfo");
return source().getMBeanInfo(sourceName); return source().getMBeanInfo(sourceName);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
throw makeCompliantRuntimeException(ex); throw makeCompliantRuntimeException(ex);
...@@ -274,7 +212,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -274,7 +212,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
throws InstanceNotFoundException, IOException { throws InstanceNotFoundException, IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
check(name, null, "getObjectInstance");
return processOutputInstance( return processOutputInstance(
source().getObjectInstance(sourceName)); source().getObjectInstance(sourceName));
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
...@@ -301,9 +238,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -301,9 +238,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
ReflectionException, IOException { ReflectionException, IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
check(name,
(attribute==null?null:attribute.getName()),
"setAttribute");
source().setAttribute(sourceName,attribute); source().setAttribute(sourceName,attribute);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
throw makeCompliantRuntimeException(ex); throw makeCompliantRuntimeException(ex);
...@@ -321,8 +255,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -321,8 +255,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
// Loader Name is already a sourceLoaderName. // Loader Name is already a sourceLoaderName.
final ObjectName sourceLoaderName = loaderName; final ObjectName sourceLoaderName = loaderName;
try { try {
checkCreate(name, className, "instantiate");
checkCreate(name, className, "registerMBean");
final ObjectInstance instance = final ObjectInstance instance =
source().createMBean(className,sourceName, source().createMBean(className,sourceName,
sourceLoaderName, sourceLoaderName,
...@@ -341,8 +273,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -341,8 +273,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
NotCompliantMBeanException, IOException { NotCompliantMBeanException, IOException {
final ObjectName sourceName = newSourceMBeanName(name); final ObjectName sourceName = newSourceMBeanName(name);
try { try {
checkCreate(name, className, "instantiate");
checkCreate(name, className, "registerMBean");
return processOutputInstance(source().createMBean(className, return processOutputInstance(source().createMBean(className,
sourceName,params,signature)); sourceName,params,signature));
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
...@@ -360,8 +290,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -360,8 +290,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
// Loader Name is already a source Loader Name. // Loader Name is already a source Loader Name.
final ObjectName sourceLoaderName = loaderName; final ObjectName sourceLoaderName = loaderName;
try { try {
checkCreate(name, className, "instantiate");
checkCreate(name, className, "registerMBean");
return processOutputInstance(source().createMBean(className, return processOutputInstance(source().createMBean(className,
sourceName,sourceLoaderName)); sourceName,sourceLoaderName));
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
...@@ -376,8 +304,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -376,8 +304,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
NotCompliantMBeanException, IOException { NotCompliantMBeanException, IOException {
final ObjectName sourceName = newSourceMBeanName(name); final ObjectName sourceName = newSourceMBeanName(name);
try { try {
checkCreate(name, className, "instantiate");
checkCreate(name, className, "registerMBean");
return processOutputInstance(source(). return processOutputInstance(source().
createMBean(className,sourceName)); createMBean(className,sourceName));
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
...@@ -391,7 +317,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -391,7 +317,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
InstanceNotFoundException, ReflectionException, IOException { InstanceNotFoundException, ReflectionException, IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
check(name, attribute, "getAttribute");
return source().getAttribute(sourceName,attribute); return source().getAttribute(sourceName,attribute);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
throw makeCompliantRuntimeException(ex); throw makeCompliantRuntimeException(ex);
...@@ -403,7 +328,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -403,7 +328,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
throws InstanceNotFoundException, IOException { throws InstanceNotFoundException, IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
check(name, null, "isInstanceOf");
return source().isInstanceOf(sourceName,className); return source().isInstanceOf(sourceName,className);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
throw makeCompliantRuntimeException(ex); throw makeCompliantRuntimeException(ex);
...@@ -415,10 +339,8 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -415,10 +339,8 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
throws InstanceNotFoundException, ReflectionException, IOException { throws InstanceNotFoundException, ReflectionException, IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
final AttributeList authorized =
checkAttributes(name, attributes, "setAttribute");
return source(). return source().
setAttributes(sourceName,authorized); setAttributes(sourceName,attributes);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
throw makeCompliantRuntimeException(ex); throw makeCompliantRuntimeException(ex);
} }
...@@ -431,7 +353,7 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -431,7 +353,7 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
for (ObjectInstance i : sources) { for (ObjectInstance i : sources) {
try { try {
final ObjectInstance target = processOutputInstance(i); final ObjectInstance target = processOutputInstance(i);
if (!checkQuery(target.getObjectName(), "queryMBeans")) if (excludesFromResult(target.getObjectName(), "queryMBeans"))
continue; continue;
result.add(target); result.add(target);
} catch (Exception x) { } catch (Exception x) {
...@@ -446,24 +368,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -446,24 +368,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
return result; return result;
} }
/**
* This is a hook to implement permission checking in subclasses.
*
* Checks that the caller has sufficient permission for returning
* information about {@code sourceName} in {@code action}.
*
* By default always return true. Subclass may override this method
* and return false if the caller doesn't have sufficient permissions.
*
* @param routingName The name of the MBean to include or exclude from
* the query, expressed in the enclosing context.
* This is of the form {@code <namespace>//<ObjectName>}.
* @param action one of "queryNames" or "queryMBeans"
* @return true if {@code sourceName} can be returned.
*/
boolean checkQuery(ObjectName routingName, String action) {
return true;
}
// Return names in the target's context. // Return names in the target's context.
ObjectInstance processOutputInstance(ObjectInstance source) { ObjectInstance processOutputInstance(ObjectInstance source) {
...@@ -488,7 +392,7 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -488,7 +392,7 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
for (ObjectName n : sourceNames) { for (ObjectName n : sourceNames) {
try { try {
final ObjectName targetName = toTarget(n); final ObjectName targetName = toTarget(n);
if (!checkQuery(targetName, "queryNames")) continue; if (excludesFromResult(targetName, "queryNames")) continue;
names.add(targetName); names.add(targetName);
} catch (Exception x) { } catch (Exception x) {
if (LOG.isLoggable(Level.FINE)) { if (LOG.isLoggable(Level.FINE)) {
...@@ -508,7 +412,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -508,7 +412,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
if (name == null) name=ObjectName.WILDCARD; if (name == null) name=ObjectName.WILDCARD;
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
checkPattern(name,null,"queryMBeans");
return processOutputInstances( return processOutputInstances(
source().queryMBeans(sourceName,query)); source().queryMBeans(sourceName,query));
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
...@@ -523,7 +426,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -523,7 +426,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
if (name == null) name=ObjectName.WILDCARD; if (name == null) name=ObjectName.WILDCARD;
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
checkPattern(name,null,"queryNames");
final Set<ObjectName> tmp = source().queryNames(sourceName,query); final Set<ObjectName> tmp = source().queryNames(sourceName,query);
final Set<ObjectName> out = processOutputNames(tmp); final Set<ObjectName> out = processOutputNames(tmp);
//System.err.println("queryNames: out: "+out); //System.err.println("queryNames: out: "+out);
...@@ -540,7 +442,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -540,7 +442,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
ListenerNotFoundException, IOException { ListenerNotFoundException, IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
check(name,null,"removeNotificationListener");
source().removeNotificationListener(sourceName,listener); source().removeNotificationListener(sourceName,listener);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
throw makeCompliantRuntimeException(ex); throw makeCompliantRuntimeException(ex);
...@@ -554,7 +455,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -554,7 +455,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
// Listener name is already a source listener name. // Listener name is already a source listener name.
try { try {
check(name,null,"addNotificationListener");
source().addNotificationListener(sourceName,listener, source().addNotificationListener(sourceName,listener,
filter,handback); filter,handback);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
...@@ -568,7 +468,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -568,7 +468,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
Object handback) throws InstanceNotFoundException, IOException { Object handback) throws InstanceNotFoundException, IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
check(name,null,"addNotificationListener");
source().addNotificationListener(sourceName, listener, filter, source().addNotificationListener(sourceName, listener, filter,
handback); handback);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
...@@ -585,7 +484,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -585,7 +484,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
IOException { IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
check(name,null,"removeNotificationListener");
source().removeNotificationListener(sourceName,listener,filter, source().removeNotificationListener(sourceName,listener,filter,
handback); handback);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
...@@ -600,7 +498,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -600,7 +498,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
IOException { IOException {
final ObjectName sourceName = toSourceOrRuntime(name); final ObjectName sourceName = toSourceOrRuntime(name);
try { try {
check(name,null,"removeNotificationListener");
source().removeNotificationListener(sourceName,listener, source().removeNotificationListener(sourceName,listener,
filter,handback); filter,handback);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
...@@ -616,7 +513,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -616,7 +513,6 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
// listener name is already a source name... // listener name is already a source name...
final ObjectName sourceListener = listener; final ObjectName sourceListener = listener;
try { try {
check(name,null,"removeNotificationListener");
source().removeNotificationListener(sourceName,sourceListener); source().removeNotificationListener(sourceName,sourceListener);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
throw makeCompliantRuntimeException(ex); throw makeCompliantRuntimeException(ex);
...@@ -635,30 +531,12 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -635,30 +531,12 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
// from MBeanServerConnection // from MBeanServerConnection
public String[] getDomains() throws IOException { public String[] getDomains() throws IOException {
try { try {
check(null,null,"getDomains"); return source().getDomains();
final String[] domains = source().getDomains();
return checkDomains(domains,"getDomains");
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
throw makeCompliantRuntimeException(ex); throw makeCompliantRuntimeException(ex);
} }
} }
/**
* This method is a hook to implement permission checking in subclasses.
* Checks that the caller as the necessary permissions to view the
* given domain. If not remove the domains for which the caller doesn't
* have permission from the list.
* <p>
* By default, this method always returns {@code domains}
*
* @param domains The domains to return.
* @param action "getDomains"
* @return a filtered list of domains.
*/
String[] checkDomains(String[] domains, String action) {
return domains;
}
// from MBeanServerConnection // from MBeanServerConnection
public String getDefaultDomain() throws IOException { public String getDefaultDomain() throws IOException {
try { try {
...@@ -668,4 +546,22 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti ...@@ -668,4 +546,22 @@ public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnecti
} }
} }
/**
* Returns true if the given targetName must be excluded from the
* query result.
* In this base class, always return {@code false}.
* By default all object names returned by the sources are
* transmitted to the caller - there is no filtering.
*
* @param name A target object name expressed in the caller's
* context. In the case of cascading, where the source
* is a sub agent mounted on e.g. namespace "foo",
* that would be a name prefixed by "foo//"...
* @param queryMethod either "queryNames" or "queryMBeans".
* @return true if the name must be excluded.
*/
boolean excludesFromResult(ObjectName targetName, String queryMethod) {
return false;
}
} }
...@@ -30,31 +30,110 @@ import java.io.IOException; ...@@ -30,31 +30,110 @@ import java.io.IOException;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException; import javax.management.MBeanException;
import javax.management.MBeanRegistrationException; import javax.management.MBeanRegistrationException;
import javax.management.MBeanServerConnection; import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException; import javax.management.MalformedObjectNameException;
import javax.management.ObjectName; import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.namespace.JMXNamespaces; import javax.management.namespace.JMXNamespaces;
/** /**
* An RoutingProxy narrows on a given name space in a * A RoutingProxy narrows on a given name space in a
* source object implementing MBeanServerConnection. * source object implementing MBeanServerConnection.
* It is used to implement * It is used to implement
* {@code JMXNamespaces.narrowToNamespace(...)}. * {@code JMXNamespaces.narrowToNamespace(...)}.
* This abstract class has two concrete subclasses: * This abstract class has two concrete subclasses:
* <p>{@link RoutingConnectionProxy}: to cd in an MBeanServerConnection.</p> * <p>{@link RoutingConnectionProxy}: to narrow down into an
* <p>{@link RoutingServerProxy}: to cd in an MBeanServer.</p> * MBeanServerConnection.</p>
* <p>{@link RoutingServerProxy}: to narrow down into an MBeanServer.</p>
*
* <p>This class can also be used to "broaden" from a namespace. The same
* class is used for both purposes because in both cases all that happens
* is that ObjectNames are rewritten in one way on the way in (e.g. the
* parameter of getMBeanInfo) and another way on the way out (e.g. the
* return value of queryNames).</p>
*
* <p>Specifically, if you narrow into "a//" then you want to add the
* "a//" prefix to ObjectNames on the way in and subtract it on the way
* out. But ClientContext uses this class to subtract the
* "jmx.context//foo=bar//" prefix on the way in and add it back on the
* way out.</p>
*
* <p><b> * <p><b>
* This API is a Sun internal API and is subject to changes without notice. * This API is a Sun internal API and is subject to changes without notice.
* </b></p> * </b></p>
* @since 1.7 * @since 1.7
*/ */
//
// RoutingProxies are client side objects which are used to narrow down
// into a namespace. They are used to perform ObjectName translation,
// adding the namespace to the routing ObjectName before sending it over
// to the source connection, and removing that prefix from results of
// queries, createMBean, registerMBean, and getObjectInstance.
// This translation is the opposite to that which is performed by
// NamespaceInterceptors.
//
// There is however a special case where routing proxies are used on the
// 'server' side to remove a namespace - rather than to add it:
// This the case of ClientContext.
// When an ObjectName like "jmx.context//c1=v1,c2=v2//D:k=v" reaches the
// jmx.context namespace, a routing proxy is used to remove the prefix
// c1=v1,c2=v2// from the routing objectname.
//
// For a RoutingProxy used in a narrowDownToNamespace operation, we have:
// targetNs="" // targetNS is the namespace 'to remove'
// sourceNS=<namespace-we-narrow-down-to> // namespace 'to add'
//
// For a RoutingProxy used in a ClientContext operation, we have:
// targetNs=<encoded-context> // context must be removed from object name
// sourceNs="" // nothing to add...
//
// RoutingProxies can also be used on the client side to implement
// "withClientContext" operations. In that case, the boolean parameter
// 'forwards context' is set to true, targetNs is "", and sourceNS may
// also be "". When forwardsContext is true, the RoutingProxy dynamically
// creates an ObjectNameRouter for each operation - in order to dynamically add
// the context attached to the thread to the routing ObjectName. This is
// performed in the getObjectNameRouter() method.
//
// Finally, in order to avoid too many layers of wrapping,
// RoutingConnectionProxy and RoutingServerProxy can be created through a
// factory method that can concatenate namespace pathes in order to
// return a single RoutingProxy - rather than wrapping a RoutingProxy inside
// another RoutingProxy. See RoutingConnectionProxy.cd and
// RoutingServerProxy.cd
//
// The class hierarchy is as follows:
//
// RoutingMBeanServerConnection
// [abstract class for all routing interceptors,
// such as RoutingProxies and HandlerInterceptors]
// / \
// / \
// RoutingProxy HandlerInterceptor
// [base class for [base class for server side
// client-side objects used objects, created by
// in narrowDownTo] DispatchInterceptors]
// / \ | \
// RoutingConnectionProxy \ | NamespaceInterceptor
// [wraps MBeanServerConnection \ | [used to remove
// objects] \ | namespace prefix and
// RoutingServerProxy | wrap JMXNamespace]
// [wraps MBeanServer |
// Objects] |
// DomainInterceptor
// [used to wrap JMXDomain]
//
// RoutingProxies also differ from HandlerInterceptors in that they transform
// calls to MBeanServerConnection operations that do not have any parameters
// into a call to the underlying JMXNamespace MBean.
// So for instance a call to:
// JMXNamespaces.narrowDownToNamespace(conn,"foo").getDomains()
// is transformed into
// conn.getAttribute("foo//type=JMXNamespace","Domains");
//
public abstract class RoutingProxy<T extends MBeanServerConnection> public abstract class RoutingProxy<T extends MBeanServerConnection>
extends RoutingMBeanServerConnection<T> { extends RoutingMBeanServerConnection<T> {
...@@ -179,17 +258,11 @@ public abstract class RoutingProxy<T extends MBeanServerConnection> ...@@ -179,17 +258,11 @@ public abstract class RoutingProxy<T extends MBeanServerConnection>
throw x; throw x;
} catch (MBeanException ex) { } catch (MBeanException ex) {
throw new IOException("Failed to get "+attributeName+": "+ throw new IOException("Failed to get "+attributeName+": "+
ex.getMessage(), ex.getCause(),
ex.getTargetException()); ex.getCause());
} catch (AttributeNotFoundException ex) { } catch (Exception ex) {
throw new IOException("Failed to get "+attributeName+": "+
ex.getMessage(),ex);
} catch (InstanceNotFoundException ex) {
throw new IOException("Failed to get "+attributeName+": "+ throw new IOException("Failed to get "+attributeName+": "+
ex.getMessage(),ex); ex,ex);
} catch (ReflectionException ex) {
throw new IOException("Failed to get "+attributeName+": "+
ex.getMessage(),ex);
} }
} }
...@@ -279,4 +352,62 @@ public abstract class RoutingProxy<T extends MBeanServerConnection> ...@@ -279,4 +352,62 @@ public abstract class RoutingProxy<T extends MBeanServerConnection>
(" mounted on targetNs="+targetNs)); (" mounted on targetNs="+targetNs));
} }
// Creates an instance of a subclass 'R' of RoutingProxy<T>
// RoutingServerProxy and RoutingConnectionProxy have their own factory
// instance.
static interface RoutingProxyFactory<T extends MBeanServerConnection,
R extends RoutingProxy<T>> {
R newInstance(T source,
String sourcePath, String targetPath,
boolean forwardsContext);
R newInstance(T source,
String sourcePath);
}
// Performs a narrowDownToNamespace operation.
// This method will attempt to merge two RoutingProxies in a single
// one if they are of the same class.
//
// This method is never called directly - it should be called only by
// subclasses of RoutingProxy.
//
// As for now it is called by:
// RoutingServerProxy.cd and RoutingConnectionProxy.cd.
//
static <T extends MBeanServerConnection, R extends RoutingProxy<T>>
R cd(Class<R> routingProxyClass,
RoutingProxyFactory<T,R> factory,
T source, String sourcePath) {
if (source == null) throw new IllegalArgumentException("null");
if (source.getClass().equals(routingProxyClass)) {
// cast is OK here, but findbugs complains unless we use class.cast
final R other = routingProxyClass.cast(source);
final String target = other.getTargetNamespace();
// Avoid multiple layers of serialization.
//
// We construct a new proxy from the original source instead of
// stacking a new proxy on top of the old one.
// - that is we replace
// cd ( cd ( x, dir1), dir2);
// by
// cd (x, dir1//dir2);
//
// We can do this only when the source class is exactly
// RoutingServerProxy.
//
if (target == null || target.equals("")) {
final String path =
JMXNamespaces.concat(other.getSourceNamespace(),
sourcePath);
return factory.newInstance(other.source(),path,"",
other.forwardsContext);
}
// Note: we could do possibly something here - but it would involve
// removing part of targetDir, and possibly adding
// something to sourcePath.
// Too complex to bother! => simply default to stacking...
}
return factory.newInstance(source,sourcePath);
}
} }
...@@ -69,6 +69,9 @@ import javax.management.namespace.JMXNamespaces; ...@@ -69,6 +69,9 @@ import javax.management.namespace.JMXNamespaces;
* *
* @since 1.7 * @since 1.7
*/ */
// See class hierarchy and detailled explanations in RoutingProxy in this
// package.
//
public class RoutingServerProxy public class RoutingServerProxy
extends RoutingProxy<MBeanServer> extends RoutingProxy<MBeanServer>
implements MBeanServer { implements MBeanServer {
...@@ -564,39 +567,24 @@ public class RoutingServerProxy ...@@ -564,39 +567,24 @@ public class RoutingServerProxy
} }
} }
static final RoutingProxyFactory<MBeanServer,RoutingServerProxy>
FACTORY = new RoutingProxyFactory<MBeanServer,RoutingServerProxy>() {
public RoutingServerProxy newInstance(MBeanServer source,
String sourcePath, String targetPath,
boolean forwardsContext) {
return new RoutingServerProxy(source,sourcePath,
targetPath,forwardsContext);
}
public RoutingServerProxy newInstance(
MBeanServer source, String sourcePath) {
return new RoutingServerProxy(source,sourcePath);
}
};
public static MBeanServer cd(MBeanServer source, String sourcePath) { public static MBeanServer cd(MBeanServer source, String sourcePath) {
if (source == null) throw new IllegalArgumentException("null"); return RoutingProxy.cd(RoutingServerProxy.class, FACTORY,
if (source.getClass().equals(RoutingServerProxy.class)) { source, sourcePath);
// cast is OK here, but findbugs complains unless we use class.cast
final RoutingServerProxy other =
RoutingServerProxy.class.cast(source);
final String target = other.getTargetNamespace();
// Avoid multiple layers of serialization.
//
// We construct a new proxy from the original source instead of
// stacking a new proxy on top of the old one.
// - that is we replace
// cd ( cd ( x, dir1), dir2);
// by
// cd (x, dir1//dir2);
//
// We can do this only when the source class is exactly
// NamespaceServerProxy.
//
if (target == null || target.equals("")) {
final String path =
JMXNamespaces.concat(other.getSourceNamespace(),
sourcePath);
return new RoutingServerProxy(other.source(),path,"",
other.forwardsContext);
}
// Note: we could do possibly something here - but it would involve
// removing part of targetDir, and possibly adding
// something to sourcePath.
// Too complex to bother! => simply default to stacking...
}
return new RoutingServerProxy(source,sourcePath);
} }
} }
...@@ -32,13 +32,15 @@ import com.sun.jmx.remote.util.ClassLogger; ...@@ -32,13 +32,15 @@ import com.sun.jmx.remote.util.ClassLogger;
import com.sun.jmx.remote.util.EnvHelp; import com.sun.jmx.remote.util.EnvHelp;
public abstract class ClientCommunicatorAdmin { public abstract class ClientCommunicatorAdmin {
private static volatile long threadNo = 1;
public ClientCommunicatorAdmin(long period) { public ClientCommunicatorAdmin(long period) {
this.period = period; this.period = period;
if (period > 0) { if (period > 0) {
checker = new Checker(); checker = new Checker();
Thread t = new Thread(checker); Thread t = new Thread(checker, "JMX client heartbeat " + ++threadNo);
t.setDaemon(true); t.setDaemon(true);
t.start(); t.start();
} else } else
......
...@@ -290,28 +290,6 @@ public abstract class ClientNotifForwarder { ...@@ -290,28 +290,6 @@ public abstract class ClientNotifForwarder {
infoList.clear(); infoList.clear();
if (currentFetchThread == Thread.currentThread()) {
/* we do not need to stop the fetching thread, because this thread is
used to do restarting and it will not be used to do fetching during
the re-registering the listeners.*/
return tmp;
}
while (state == STARTING) {
try {
wait();
} catch (InterruptedException ire) {
IOException ioe = new IOException(ire.toString());
EnvHelp.initCause(ioe, ire);
throw ioe;
}
}
if (state == STARTED) {
setState(STOPPING);
}
return tmp; return tmp;
} }
...@@ -353,8 +331,9 @@ public abstract class ClientNotifForwarder { ...@@ -353,8 +331,9 @@ public abstract class ClientNotifForwarder {
beingReconnected = false; beingReconnected = false;
notifyAll(); notifyAll();
if (currentFetchThread == Thread.currentThread()) { if (currentFetchThread == Thread.currentThread() ||
// no need to init, simply get the id state == STARTING || state == STARTED) { // doing or waiting reconnection
// only update mbeanRemovedNotifID
try { try {
mbeanRemovedNotifID = addListenerForMBeanRemovedNotif(); mbeanRemovedNotifID = addListenerForMBeanRemovedNotif();
} catch (Exception e) { } catch (Exception e) {
...@@ -366,12 +345,23 @@ public abstract class ClientNotifForwarder { ...@@ -366,12 +345,23 @@ public abstract class ClientNotifForwarder {
logger.trace("init", msg, e); logger.trace("init", msg, e);
} }
} }
} else if (listenerInfos.length > 0) { // old listeners re-registered } else {
init(true); while (state == STOPPING) {
} else if (infoList.size() > 0) { try {
// but new listeners registered during reconnection wait();
init(false); } catch (InterruptedException ire) {
} IOException ioe = new IOException(ire.toString());
EnvHelp.initCause(ioe, ire);
throw ioe;
}
}
if (listenerInfos.length > 0) { // old listeners are re-added
init(true); // not update clientSequenceNumber
} else if (infoList.size() > 0) { // only new listeners added during reconnection
init(false); // need update clientSequenceNumber
}
}
} }
public synchronized void terminate() { public synchronized void terminate() {
...@@ -486,6 +476,15 @@ public abstract class ClientNotifForwarder { ...@@ -486,6 +476,15 @@ public abstract class ClientNotifForwarder {
if (nr == null || shouldStop()) { if (nr == null || shouldStop()) {
// tell that the thread is REALLY stopped // tell that the thread is REALLY stopped
setState(STOPPED); setState(STOPPED);
try {
removeListenerForMBeanRemovedNotif(mbeanRemovedNotifID);
} catch (Exception e) {
if (logger.traceOn()) {
logger.trace("NotifFetcher-run",
"removeListenerForMBeanRemovedNotif", e);
}
}
} else { } else {
executor.execute(this); executor.execute(this);
} }
......
...@@ -42,7 +42,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -42,7 +42,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
/** /**
* The value is used for character storage. * The value is used for character storage.
*/ */
char value[]; char[] value;
/** /**
* The count is the number of characters used. * The count is the number of characters used.
...@@ -333,8 +333,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -333,8 +333,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* <code>dst.length</code> * <code>dst.length</code>
* </ul> * </ul>
*/ */
public void getChars(int srcBegin, int srcEnd, char dst[], public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
int dstBegin)
{ {
if (srcBegin < 0) if (srcBegin < 0)
throw new StringIndexOutOfBoundsException(srcBegin); throw new StringIndexOutOfBoundsException(srcBegin);
...@@ -366,14 +365,14 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -366,14 +365,14 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
} }
/** /**
* Appends the string representation of the <code>Object</code> * Appends the string representation of the {@code Object} argument.
* argument.
* <p> * <p>
* The argument is converted to a string as if by the method * The overall effect is exactly as if the argument were converted
* <code>String.valueOf</code>, and the characters of that * to a string by the method {@link String#valueOf(Object)},
* string are then appended to this sequence. * and the characters of that string were then
* {@link #append(String) appended} to this character sequence.
* *
* @param obj an <code>Object</code>. * @param obj an {@code Object}.
* @return a reference to this object. * @return a reference to this object.
*/ */
public AbstractStringBuilder append(Object obj) { public AbstractStringBuilder append(Object obj) {
...@@ -383,17 +382,17 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -383,17 +382,17 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
/** /**
* Appends the specified string to this character sequence. * Appends the specified string to this character sequence.
* <p> * <p>
* The characters of the <code>String</code> argument are appended, in * The characters of the {@code String} argument are appended, in
* order, increasing the length of this sequence by the length of the * order, increasing the length of this sequence by the length of the
* argument. If <code>str</code> is <code>null</code>, then the four * argument. If {@code str} is {@code null}, then the four
* characters <code>"null"</code> are appended. * characters {@code "null"} are appended.
* <p> * <p>
* Let <i>n</i> be the length of this character sequence just prior to * Let <i>n</i> be the length of this character sequence just prior to
* execution of the <code>append</code> method. Then the character at * execution of the {@code append} method. Then the character at
* index <i>k</i> in the new character sequence is equal to the character * index <i>k</i> in the new character sequence is equal to the character
* at index <i>k</i> in the old character sequence, if <i>k</i> is less * at index <i>k</i> in the old character sequence, if <i>k</i> is less
* than <i>n</i>; otherwise, it is equal to the character at index * than <i>n</i>; otherwise, it is equal to the character at index
* <i>k-n</i> in the argument <code>str</code>. * <i>k-n</i> in the argument {@code str}.
* *
* @param str a string. * @param str a string.
* @return a reference to this object. * @return a reference to this object.
...@@ -435,33 +434,33 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -435,33 +434,33 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
} }
/** /**
* Appends a subsequence of the specified <code>CharSequence</code> to this * Appends a subsequence of the specified {@code CharSequence} to this
* sequence. * sequence.
* <p> * <p>
* Characters of the argument <code>s</code>, starting at * Characters of the argument {@code s}, starting at
* index <code>start</code>, are appended, in order, to the contents of * index {@code start}, are appended, in order, to the contents of
* this sequence up to the (exclusive) index <code>end</code>. The length * this sequence up to the (exclusive) index {@code end}. The length
* of this sequence is increased by the value of <code>end - start</code>. * of this sequence is increased by the value of {@code end - start}.
* <p> * <p>
* Let <i>n</i> be the length of this character sequence just prior to * Let <i>n</i> be the length of this character sequence just prior to
* execution of the <code>append</code> method. Then the character at * execution of the {@code append} method. Then the character at
* index <i>k</i> in this character sequence becomes equal to the * index <i>k</i> in this character sequence becomes equal to the
* character at index <i>k</i> in this sequence, if <i>k</i> is less than * character at index <i>k</i> in this sequence, if <i>k</i> is less than
* <i>n</i>; otherwise, it is equal to the character at index * <i>n</i>; otherwise, it is equal to the character at index
* <i>k+start-n</i> in the argument <code>s</code>. * <i>k+start-n</i> in the argument {@code s}.
* <p> * <p>
* If <code>s</code> is <code>null</code>, then this method appends * If {@code s} is {@code null}, then this method appends
* characters as if the s parameter was a sequence containing the four * characters as if the s parameter was a sequence containing the four
* characters <code>"null"</code>. * characters {@code "null"}.
* *
* @param s the sequence to append. * @param s the sequence to append.
* @param start the starting index of the subsequence to be appended. * @param start the starting index of the subsequence to be appended.
* @param end the end index of the subsequence to be appended. * @param end the end index of the subsequence to be appended.
* @return a reference to this object. * @return a reference to this object.
* @throws IndexOutOfBoundsException if * @throws IndexOutOfBoundsException if
* <code>start</code> or <code>end</code> are negative, or * {@code start} is negative, or
* <code>start</code> is greater than <code>end</code> or * {@code start} is greater than {@code end} or
* <code>end</code> is greater than <code>s.length()</code> * {@code end} is greater than {@code s.length()}
*/ */
public AbstractStringBuilder append(CharSequence s, int start, int end) { public AbstractStringBuilder append(CharSequence s, int start, int end) {
if (s == null) if (s == null)
...@@ -483,22 +482,22 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -483,22 +482,22 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
} }
/** /**
* Appends the string representation of the <code>char</code> array * Appends the string representation of the {@code char} array
* argument to this sequence. * argument to this sequence.
* <p> * <p>
* The characters of the array argument are appended, in order, to * The characters of the array argument are appended, in order, to
* the contents of this sequence. The length of this sequence * the contents of this sequence. The length of this sequence
* increases by the length of the argument. * increases by the length of the argument.
* <p> * <p>
* The overall effect is exactly as if the argument were converted to * The overall effect is exactly as if the argument were converted
* a string by the method {@link String#valueOf(char[])} and the * to a string by the method {@link String#valueOf(char[])},
* characters of that string were then {@link #append(String) appended} * and the characters of that string were then
* to this character sequence. * {@link #append(String) appended} to this character sequence.
* *
* @param str the characters to be appended. * @param str the characters to be appended.
* @return a reference to this object. * @return a reference to this object.
*/ */
public AbstractStringBuilder append(char str[]) { public AbstractStringBuilder append(char[] str) {
int newCount = count + str.length; int newCount = count + str.length;
if (newCount > value.length) if (newCount > value.length)
expandCapacity(newCount); expandCapacity(newCount);
...@@ -509,22 +508,25 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -509,22 +508,25 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
/** /**
* Appends the string representation of a subarray of the * Appends the string representation of a subarray of the
* <code>char</code> array argument to this sequence. * {@code char} array argument to this sequence.
* <p> * <p>
* Characters of the <code>char</code> array <code>str</code>, starting at * Characters of the {@code char} array {@code str}, starting at
* index <code>offset</code>, are appended, in order, to the contents * index {@code offset}, are appended, in order, to the contents
* of this sequence. The length of this sequence increases * of this sequence. The length of this sequence increases
* by the value of <code>len</code>. * by the value of {@code len}.
* <p> * <p>
* The overall effect is exactly as if the arguments were converted to * The overall effect is exactly as if the arguments were converted
* a string by the method {@link String#valueOf(char[],int,int)} and the * to a string by the method {@link String#valueOf(char[],int,int)},
* characters of that string were then {@link #append(String) appended} * and the characters of that string were then
* to this character sequence. * {@link #append(String) appended} to this character sequence.
* *
* @param str the characters to be appended. * @param str the characters to be appended.
* @param offset the index of the first <code>char</code> to append. * @param offset the index of the first {@code char} to append.
* @param len the number of <code>char</code>s to append. * @param len the number of {@code char}s to append.
* @return a reference to this object. * @return a reference to this object.
* @throws IndexOutOfBoundsException
* if {@code offset < 0} or {@code len < 0}
* or {@code offset+len > str.length}
*/ */
public AbstractStringBuilder append(char str[], int offset, int len) { public AbstractStringBuilder append(char str[], int offset, int len) {
int newCount = count + len; int newCount = count + len;
...@@ -536,14 +538,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -536,14 +538,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
} }
/** /**
* Appends the string representation of the <code>boolean</code> * Appends the string representation of the {@code boolean}
* argument to the sequence. * argument to the sequence.
* <p> * <p>
* The argument is converted to a string as if by the method * The overall effect is exactly as if the argument were converted
* <code>String.valueOf</code>, and the characters of that * to a string by the method {@link String#valueOf(boolean)},
* string are then appended to this sequence. * and the characters of that string were then
* {@link #append(String) appended} to this character sequence.
* *
* @param b a <code>boolean</code>. * @param b a {@code boolean}.
* @return a reference to this object. * @return a reference to this object.
*/ */
public AbstractStringBuilder append(boolean b) { public AbstractStringBuilder append(boolean b) {
...@@ -569,18 +572,18 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -569,18 +572,18 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
} }
/** /**
* Appends the string representation of the <code>char</code> * Appends the string representation of the {@code char}
* argument to this sequence. * argument to this sequence.
* <p> * <p>
* The argument is appended to the contents of this sequence. * The argument is appended to the contents of this sequence.
* The length of this sequence increases by <code>1</code>. * The length of this sequence increases by {@code 1}.
* <p> * <p>
* The overall effect is exactly as if the argument were converted to * The overall effect is exactly as if the argument were converted
* a string by the method {@link String#valueOf(char)} and the character * to a string by the method {@link String#valueOf(char)},
* in that string were then {@link #append(String) appended} to this * and the character in that string were then
* character sequence. * {@link #append(String) appended} to this character sequence.
* *
* @param c a <code>char</code>. * @param c a {@code char}.
* @return a reference to this object. * @return a reference to this object.
*/ */
public AbstractStringBuilder append(char c) { public AbstractStringBuilder append(char c) {
...@@ -592,14 +595,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -592,14 +595,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
} }
/** /**
* Appends the string representation of the <code>int</code> * Appends the string representation of the {@code int}
* argument to this sequence. * argument to this sequence.
* <p> * <p>
* The argument is converted to a string as if by the method * The overall effect is exactly as if the argument were converted
* <code>String.valueOf</code>, and the characters of that * to a string by the method {@link String#valueOf(int)},
* string are then appended to this sequence. * and the characters of that string were then
* {@link #append(String) appended} to this character sequence.
* *
* @param i an <code>int</code>. * @param i an {@code int}.
* @return a reference to this object. * @return a reference to this object.
*/ */
public AbstractStringBuilder append(int i) { public AbstractStringBuilder append(int i) {
...@@ -618,14 +622,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -618,14 +622,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
} }
/** /**
* Appends the string representation of the <code>long</code> * Appends the string representation of the {@code long}
* argument to this sequence. * argument to this sequence.
* <p> * <p>
* The argument is converted to a string as if by the method * The overall effect is exactly as if the argument were converted
* <code>String.valueOf</code>, and the characters of that * to a string by the method {@link String#valueOf(long)},
* string are then appended to this sequence. * and the characters of that string were then
* {@link #append(String) appended} to this character sequence.
* *
* @param l a <code>long</code>. * @param l a {@code long}.
* @return a reference to this object. * @return a reference to this object.
*/ */
public AbstractStringBuilder append(long l) { public AbstractStringBuilder append(long l) {
...@@ -644,14 +649,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -644,14 +649,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
} }
/** /**
* Appends the string representation of the <code>float</code> * Appends the string representation of the {@code float}
* argument to this sequence. * argument to this sequence.
* <p> * <p>
* The argument is converted to a string as if by the method * The overall effect is exactly as if the argument were converted
* <code>String.valueOf</code>, and the characters of that * to a string by the method {@link String#valueOf(float)},
* string are then appended to this string sequence. * and the characters of that string were then
* {@link #append(String) appended} to this character sequence.
* *
* @param f a <code>float</code>. * @param f a {@code float}.
* @return a reference to this object. * @return a reference to this object.
*/ */
public AbstractStringBuilder append(float f) { public AbstractStringBuilder append(float f) {
...@@ -660,14 +666,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -660,14 +666,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
} }
/** /**
* Appends the string representation of the <code>double</code> * Appends the string representation of the {@code double}
* argument to this sequence. * argument to this sequence.
* <p> * <p>
* The argument is converted to a string as if by the method * The overall effect is exactly as if the argument were converted
* <code>String.valueOf</code>, and the characters of that * to a string by the method {@link String#valueOf(double)},
* string are then appended to this sequence. * and the characters of that string were then
* {@link #append(String) appended} to this character sequence.
* *
* @param d a <code>double</code>. * @param d a {@code double}.
* @return a reference to this object. * @return a reference to this object.
*/ */
public AbstractStringBuilder append(double d) { public AbstractStringBuilder append(double d) {
...@@ -677,17 +684,17 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -677,17 +684,17 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
/** /**
* Removes the characters in a substring of this sequence. * Removes the characters in a substring of this sequence.
* The substring begins at the specified <code>start</code> and extends to * The substring begins at the specified {@code start} and extends to
* the character at index <code>end - 1</code> or to the end of the * the character at index {@code end - 1} or to the end of the
* sequence if no such character exists. If * sequence if no such character exists. If
* <code>start</code> is equal to <code>end</code>, no changes are made. * {@code start} is equal to {@code end}, no changes are made.
* *
* @param start The beginning index, inclusive. * @param start The beginning index, inclusive.
* @param end The ending index, exclusive. * @param end The ending index, exclusive.
* @return This object. * @return This object.
* @throws StringIndexOutOfBoundsException if <code>start</code> * @throws StringIndexOutOfBoundsException if {@code start}
* is negative, greater than <code>length()</code>, or * is negative, greater than {@code length()}, or
* greater than <code>end</code>. * greater than {@code end}.
*/ */
public AbstractStringBuilder delete(int start, int end) { public AbstractStringBuilder delete(int start, int end) {
if (start < 0) if (start < 0)
...@@ -705,7 +712,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -705,7 +712,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
} }
/** /**
* Appends the string representation of the <code>codePoint</code> * Appends the string representation of the {@code codePoint}
* argument to this sequence. * argument to this sequence.
* *
* <p> The argument is appended to the contents of this sequence. * <p> The argument is appended to the contents of this sequence.
...@@ -713,15 +720,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -713,15 +720,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* {@link Character#charCount(int) Character.charCount(codePoint)}. * {@link Character#charCount(int) Character.charCount(codePoint)}.
* *
* <p> The overall effect is exactly as if the argument were * <p> The overall effect is exactly as if the argument were
* converted to a <code>char</code> array by the method {@link * converted to a {@code char} array by the method
* Character#toChars(int)} and the character in that array were * {@link Character#toChars(int)} and the character in that array
* then {@link #append(char[]) appended} to this character * were then {@link #append(char[]) appended} to this character
* sequence. * sequence.
* *
* @param codePoint a Unicode code point * @param codePoint a Unicode code point
* @return a reference to this object. * @return a reference to this object.
* @exception IllegalArgumentException if the specified * @exception IllegalArgumentException if the specified
* <code>codePoint</code> isn't a valid Unicode code point * {@code codePoint} isn't a valid Unicode code point
*/ */
public AbstractStringBuilder appendCodePoint(int codePoint) { public AbstractStringBuilder appendCodePoint(int codePoint) {
if (!Character.isValidCodePoint(codePoint)) { if (!Character.isValidCodePoint(codePoint)) {
...@@ -879,27 +886,27 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -879,27 +886,27 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
} }
/** /**
* Inserts the string representation of a subarray of the <code>str</code> * Inserts the string representation of a subarray of the {@code str}
* array argument into this sequence. The subarray begins at the * array argument into this sequence. The subarray begins at the
* specified <code>offset</code> and extends <code>len</code> <code>char</code>s. * specified {@code offset} and extends {@code len} {@code char}s.
* The characters of the subarray are inserted into this sequence at * The characters of the subarray are inserted into this sequence at
* the position indicated by <code>index</code>. The length of this * the position indicated by {@code index}. The length of this
* sequence increases by <code>len</code> <code>char</code>s. * sequence increases by {@code len} {@code char}s.
* *
* @param index position at which to insert subarray. * @param index position at which to insert subarray.
* @param str A <code>char</code> array. * @param str A {@code char} array.
* @param offset the index of the first <code>char</code> in subarray to * @param offset the index of the first {@code char} in subarray to
* be inserted. * be inserted.
* @param len the number of <code>char</code>s in the subarray to * @param len the number of {@code char}s in the subarray to
* be inserted. * be inserted.
* @return This object * @return This object
* @throws StringIndexOutOfBoundsException if <code>index</code> * @throws StringIndexOutOfBoundsException if {@code index}
* is negative or greater than <code>length()</code>, or * is negative or greater than {@code length()}, or
* <code>offset</code> or <code>len</code> are negative, or * {@code offset} or {@code len} are negative, or
* <code>(offset+len)</code> is greater than * {@code (offset+len)} is greater than
* <code>str.length</code>. * {@code str.length}.
*/ */
public AbstractStringBuilder insert(int index, char str[], int offset, public AbstractStringBuilder insert(int index, char[] str, int offset,
int len) int len)
{ {
if ((index < 0) || (index > length())) if ((index < 0) || (index > length()))
...@@ -918,20 +925,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -918,20 +925,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
} }
/** /**
* Inserts the string representation of the <code>Object</code> * Inserts the string representation of the {@code Object}
* argument into this character sequence. * argument into this character sequence.
* <p> * <p>
* The second argument is converted to a string as if by the method * The overall effect is exactly as if the second argument were
* <code>String.valueOf</code>, and the characters of that * converted to a string by the method {@link String#valueOf(Object)},
* string are then inserted into this sequence at the indicated * and the characters of that string were then
* offset. * {@link #insert(int,String) inserted} into this character
* sequence at the indicated offset.
* <p> * <p>
* The offset argument must be greater than or equal to * The {@code offset} argument must be greater than or equal to
* <code>0</code>, and less than or equal to the length of this * {@code 0}, and less than or equal to the {@linkplain #length() length}
* sequence. * of this sequence.
* *
* @param offset the offset. * @param offset the offset.
* @param obj an <code>Object</code>. * @param obj an {@code Object}.
* @return a reference to this object. * @return a reference to this object.
* @throws StringIndexOutOfBoundsException if the offset is invalid. * @throws StringIndexOutOfBoundsException if the offset is invalid.
*/ */
...@@ -942,28 +950,28 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -942,28 +950,28 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
/** /**
* Inserts the string into this character sequence. * Inserts the string into this character sequence.
* <p> * <p>
* The characters of the <code>String</code> argument are inserted, in * The characters of the {@code String} argument are inserted, in
* order, into this sequence at the indicated offset, moving up any * order, into this sequence at the indicated offset, moving up any
* characters originally above that position and increasing the length * characters originally above that position and increasing the length
* of this sequence by the length of the argument. If * of this sequence by the length of the argument. If
* <code>str</code> is <code>null</code>, then the four characters * {@code str} is {@code null}, then the four characters
* <code>"null"</code> are inserted into this sequence. * {@code "null"} are inserted into this sequence.
* <p> * <p>
* The character at index <i>k</i> in the new character sequence is * The character at index <i>k</i> in the new character sequence is
* equal to: * equal to:
* <ul> * <ul>
* <li>the character at index <i>k</i> in the old character sequence, if * <li>the character at index <i>k</i> in the old character sequence, if
* <i>k</i> is less than <code>offset</code> * <i>k</i> is less than {@code offset}
* <li>the character at index <i>k</i><code>-offset</code> in the * <li>the character at index <i>k</i>{@code -offset} in the
* argument <code>str</code>, if <i>k</i> is not less than * argument {@code str}, if <i>k</i> is not less than
* <code>offset</code> but is less than <code>offset+str.length()</code> * {@code offset} but is less than {@code offset+str.length()}
* <li>the character at index <i>k</i><code>-str.length()</code> in the * <li>the character at index <i>k</i>{@code -str.length()} in the
* old character sequence, if <i>k</i> is not less than * old character sequence, if <i>k</i> is not less than
* <code>offset+str.length()</code> * {@code offset+str.length()}
* </ul><p> * </ul><p>
* The offset argument must be greater than or equal to * The {@code offset} argument must be greater than or equal to
* <code>0</code>, and less than or equal to the length of this * {@code 0}, and less than or equal to the {@linkplain #length() length}
* sequence. * of this sequence.
* *
* @param offset the offset. * @param offset the offset.
* @param str a string. * @param str a string.
...@@ -986,27 +994,30 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -986,27 +994,30 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
} }
/** /**
* Inserts the string representation of the <code>char</code> array * Inserts the string representation of the {@code char} array
* argument into this sequence. * argument into this sequence.
* <p> * <p>
* The characters of the array argument are inserted into the * The characters of the array argument are inserted into the
* contents of this sequence at the position indicated by * contents of this sequence at the position indicated by
* <code>offset</code>. The length of this sequence increases by * {@code offset}. The length of this sequence increases by
* the length of the argument. * the length of the argument.
* <p> * <p>
* The overall effect is exactly as if the argument were converted to * The overall effect is exactly as if the second argument were
* a string by the method {@link String#valueOf(char[])} and the * converted to a string by the method {@link String#valueOf(char[])},
* characters of that string were then * and the characters of that string were then
* {@link #insert(int,String) inserted} into this * {@link #insert(int,String) inserted} into this character
* character sequence at the position indicated by * sequence at the indicated offset.
* <code>offset</code>. * <p>
* The {@code offset} argument must be greater than or equal to
* {@code 0}, and less than or equal to the {@linkplain #length() length}
* of this sequence.
* *
* @param offset the offset. * @param offset the offset.
* @param str a character array. * @param str a character array.
* @return a reference to this object. * @return a reference to this object.
* @throws StringIndexOutOfBoundsException if the offset is invalid. * @throws StringIndexOutOfBoundsException if the offset is invalid.
*/ */
public AbstractStringBuilder insert(int offset, char str[]) { public AbstractStringBuilder insert(int offset, char[] str) {
if ((offset < 0) || (offset > length())) if ((offset < 0) || (offset > length()))
throw new StringIndexOutOfBoundsException(offset); throw new StringIndexOutOfBoundsException(offset);
int len = str.length; int len = str.length;
...@@ -1020,18 +1031,20 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -1020,18 +1031,20 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
} }
/** /**
* Inserts the specified <code>CharSequence</code> into this sequence. * Inserts the specified {@code CharSequence} into this sequence.
* <p> * <p>
* The characters of the <code>CharSequence</code> argument are inserted, * The characters of the {@code CharSequence} argument are inserted,
* in order, into this sequence at the indicated offset, moving up * in order, into this sequence at the indicated offset, moving up
* any characters originally above that position and increasing the length * any characters originally above that position and increasing the length
* of this sequence by the length of the argument s. * of this sequence by the length of the argument s.
* <p> * <p>
* The result of this method is exactly the same as if it were an * The result of this method is exactly the same as if it were an
* invocation of this object's insert(dstOffset, s, 0, s.length()) method. * invocation of this object's
* {@link #insert(int,CharSequence,int,int) insert}(dstOffset, s, 0, s.length())
* method.
* *
* <p>If <code>s</code> is <code>null</code>, then the four characters * <p>If {@code s} is {@code null}, then the four characters
* <code>"null"</code> are inserted into this sequence. * {@code "null"} are inserted into this sequence.
* *
* @param dstOffset the offset. * @param dstOffset the offset.
* @param s the sequence to be inserted * @param s the sequence to be inserted
...@@ -1047,51 +1060,51 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -1047,51 +1060,51 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
} }
/** /**
* Inserts a subsequence of the specified <code>CharSequence</code> into * Inserts a subsequence of the specified {@code CharSequence} into
* this sequence. * this sequence.
* <p> * <p>
* The subsequence of the argument <code>s</code> specified by * The subsequence of the argument {@code s} specified by
* <code>start</code> and <code>end</code> are inserted, * {@code start} and {@code end} are inserted,
* in order, into this sequence at the specified destination offset, moving * in order, into this sequence at the specified destination offset, moving
* up any characters originally above that position. The length of this * up any characters originally above that position. The length of this
* sequence is increased by <code>end - start</code>. * sequence is increased by {@code end - start}.
* <p> * <p>
* The character at index <i>k</i> in this sequence becomes equal to: * The character at index <i>k</i> in this sequence becomes equal to:
* <ul> * <ul>
* <li>the character at index <i>k</i> in this sequence, if * <li>the character at index <i>k</i> in this sequence, if
* <i>k</i> is less than <code>dstOffset</code> * <i>k</i> is less than {@code dstOffset}
* <li>the character at index <i>k</i><code>+start-dstOffset</code> in * <li>the character at index <i>k</i>{@code +start-dstOffset} in
* the argument <code>s</code>, if <i>k</i> is greater than or equal to * the argument {@code s}, if <i>k</i> is greater than or equal to
* <code>dstOffset</code> but is less than <code>dstOffset+end-start</code> * {@code dstOffset} but is less than {@code dstOffset+end-start}
* <li>the character at index <i>k</i><code>-(end-start)</code> in this * <li>the character at index <i>k</i>{@code -(end-start)} in this
* sequence, if <i>k</i> is greater than or equal to * sequence, if <i>k</i> is greater than or equal to
* <code>dstOffset+end-start</code> * {@code dstOffset+end-start}
* </ul><p> * </ul><p>
* The dstOffset argument must be greater than or equal to * The {@code dstOffset} argument must be greater than or equal to
* <code>0</code>, and less than or equal to the length of this * {@code 0}, and less than or equal to the {@linkplain #length() length}
* sequence. * of this sequence.
* <p>The start argument must be nonnegative, and not greater than * <p>The start argument must be nonnegative, and not greater than
* <code>end</code>. * {@code end}.
* <p>The end argument must be greater than or equal to * <p>The end argument must be greater than or equal to
* <code>start</code>, and less than or equal to the length of s. * {@code start}, and less than or equal to the length of s.
* *
* <p>If <code>s</code> is <code>null</code>, then this method inserts * <p>If {@code s} is {@code null}, then this method inserts
* characters as if the s parameter was a sequence containing the four * characters as if the s parameter was a sequence containing the four
* characters <code>"null"</code>. * characters {@code "null"}.
* *
* @param dstOffset the offset in this sequence. * @param dstOffset the offset in this sequence.
* @param s the sequence to be inserted. * @param s the sequence to be inserted.
* @param start the starting index of the subsequence to be inserted. * @param start the starting index of the subsequence to be inserted.
* @param end the end index of the subsequence to be inserted. * @param end the end index of the subsequence to be inserted.
* @return a reference to this object. * @return a reference to this object.
* @throws IndexOutOfBoundsException if <code>dstOffset</code> * @throws IndexOutOfBoundsException if {@code dstOffset}
* is negative or greater than <code>this.length()</code>, or * is negative or greater than {@code this.length()}, or
* <code>start</code> or <code>end</code> are negative, or * {@code start} or {@code end} are negative, or
* <code>start</code> is greater than <code>end</code> or * {@code start} is greater than {@code end} or
* <code>end</code> is greater than <code>s.length()</code> * {@code end} is greater than {@code s.length()}
*/ */
public AbstractStringBuilder insert(int dstOffset, CharSequence s, public AbstractStringBuilder insert(int dstOffset, CharSequence s,
int start, int end) { int start, int end) {
if (s == null) if (s == null)
s = "null"; s = "null";
if ((dstOffset < 0) || (dstOffset > this.length())) if ((dstOffset < 0) || (dstOffset > this.length()))
...@@ -1115,20 +1128,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -1115,20 +1128,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
} }
/** /**
* Inserts the string representation of the <code>boolean</code> * Inserts the string representation of the {@code boolean}
* argument into this sequence. * argument into this sequence.
* <p> * <p>
* The second argument is converted to a string as if by the method * The overall effect is exactly as if the second argument were
* <code>String.valueOf</code>, and the characters of that * converted to a string by the method {@link String#valueOf(boolean)},
* string are then inserted into this sequence at the indicated * and the characters of that string were then
* offset. * {@link #insert(int,String) inserted} into this character
* sequence at the indicated offset.
* <p> * <p>
* The offset argument must be greater than or equal to * The {@code offset} argument must be greater than or equal to
* <code>0</code>, and less than or equal to the length of this * {@code 0}, and less than or equal to the {@linkplain #length() length}
* sequence. * of this sequence.
* *
* @param offset the offset. * @param offset the offset.
* @param b a <code>boolean</code>. * @param b a {@code boolean}.
* @return a reference to this object. * @return a reference to this object.
* @throws StringIndexOutOfBoundsException if the offset is invalid. * @throws StringIndexOutOfBoundsException if the offset is invalid.
*/ */
...@@ -1137,25 +1151,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -1137,25 +1151,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
} }
/** /**
* Inserts the string representation of the <code>char</code> * Inserts the string representation of the {@code char}
* argument into this sequence. * argument into this sequence.
* <p> * <p>
* The second argument is inserted into the contents of this sequence * The overall effect is exactly as if the second argument were
* at the position indicated by <code>offset</code>. The length * converted to a string by the method {@link String#valueOf(char)},
* of this sequence increases by one. * and the character in that string were then
* <p> * {@link #insert(int,String) inserted} into this character
* The overall effect is exactly as if the argument were converted to * sequence at the indicated offset.
* a string by the method {@link String#valueOf(char)} and the character
* in that string were then {@link #insert(int, String) inserted} into
* this character sequence at the position indicated by
* <code>offset</code>.
* <p> * <p>
* The offset argument must be greater than or equal to * The {@code offset} argument must be greater than or equal to
* <code>0</code>, and less than or equal to the length of this * {@code 0}, and less than or equal to the {@linkplain #length() length}
* sequence. * of this sequence.
* *
* @param offset the offset. * @param offset the offset.
* @param c a <code>char</code>. * @param c a {@code char}.
* @return a reference to this object. * @return a reference to this object.
* @throws IndexOutOfBoundsException if the offset is invalid. * @throws IndexOutOfBoundsException if the offset is invalid.
*/ */
...@@ -1170,20 +1180,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -1170,20 +1180,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
} }
/** /**
* Inserts the string representation of the second <code>int</code> * Inserts the string representation of the second {@code int}
* argument into this sequence. * argument into this sequence.
* <p> * <p>
* The second argument is converted to a string as if by the method * The overall effect is exactly as if the second argument were
* <code>String.valueOf</code>, and the characters of that * converted to a string by the method {@link String#valueOf(int)},
* string are then inserted into this sequence at the indicated * and the characters of that string were then
* offset. * {@link #insert(int,String) inserted} into this character
* sequence at the indicated offset.
* <p> * <p>
* The offset argument must be greater than or equal to * The {@code offset} argument must be greater than or equal to
* <code>0</code>, and less than or equal to the length of this * {@code 0}, and less than or equal to the {@linkplain #length() length}
* sequence. * of this sequence.
* *
* @param offset the offset. * @param offset the offset.
* @param i an <code>int</code>. * @param i an {@code int}.
* @return a reference to this object. * @return a reference to this object.
* @throws StringIndexOutOfBoundsException if the offset is invalid. * @throws StringIndexOutOfBoundsException if the offset is invalid.
*/ */
...@@ -1192,20 +1203,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -1192,20 +1203,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
} }
/** /**
* Inserts the string representation of the <code>long</code> * Inserts the string representation of the {@code long}
* argument into this sequence. * argument into this sequence.
* <p> * <p>
* The second argument is converted to a string as if by the method * The overall effect is exactly as if the second argument were
* <code>String.valueOf</code>, and the characters of that * converted to a string by the method {@link String#valueOf(long)},
* string are then inserted into this sequence at the position * and the characters of that string were then
* indicated by <code>offset</code>. * {@link #insert(int,String) inserted} into this character
* sequence at the indicated offset.
* <p> * <p>
* The offset argument must be greater than or equal to * The {@code offset} argument must be greater than or equal to
* <code>0</code>, and less than or equal to the length of this * {@code 0}, and less than or equal to the {@linkplain #length() length}
* sequence. * of this sequence.
* *
* @param offset the offset. * @param offset the offset.
* @param l a <code>long</code>. * @param l a {@code long}.
* @return a reference to this object. * @return a reference to this object.
* @throws StringIndexOutOfBoundsException if the offset is invalid. * @throws StringIndexOutOfBoundsException if the offset is invalid.
*/ */
...@@ -1214,20 +1226,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -1214,20 +1226,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
} }
/** /**
* Inserts the string representation of the <code>float</code> * Inserts the string representation of the {@code float}
* argument into this sequence. * argument into this sequence.
* <p> * <p>
* The second argument is converted to a string as if by the method * The overall effect is exactly as if the second argument were
* <code>String.valueOf</code>, and the characters of that * converted to a string by the method {@link String#valueOf(float)},
* string are then inserted into this sequence at the indicated * and the characters of that string were then
* offset. * {@link #insert(int,String) inserted} into this character
* sequence at the indicated offset.
* <p> * <p>
* The offset argument must be greater than or equal to * The {@code offset} argument must be greater than or equal to
* <code>0</code>, and less than or equal to the length of this * {@code 0}, and less than or equal to the {@linkplain #length() length}
* sequence. * of this sequence.
* *
* @param offset the offset. * @param offset the offset.
* @param f a <code>float</code>. * @param f a {@code float}.
* @return a reference to this object. * @return a reference to this object.
* @throws StringIndexOutOfBoundsException if the offset is invalid. * @throws StringIndexOutOfBoundsException if the offset is invalid.
*/ */
...@@ -1236,20 +1249,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { ...@@ -1236,20 +1249,21 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
} }
/** /**
* Inserts the string representation of the <code>double</code> * Inserts the string representation of the {@code double}
* argument into this sequence. * argument into this sequence.
* <p> * <p>
* The second argument is converted to a string as if by the method * The overall effect is exactly as if the second argument were
* <code>String.valueOf</code>, and the characters of that * converted to a string by the method {@link String#valueOf(double)},
* string are then inserted into this sequence at the indicated * and the characters of that string were then
* offset. * {@link #insert(int,String) inserted} into this character
* sequence at the indicated offset.
* <p> * <p>
* The offset argument must be greater than or equal to * The {@code offset} argument must be greater than or equal to
* <code>0</code>, and less than or equal to the length of this * {@code 0}, and less than or equal to the {@linkplain #length() length}
* sequence. * of this sequence.
* *
* @param offset the offset. * @param offset the offset.
* @param d a <code>double</code>. * @param d a {@code double}.
* @return a reference to this object. * @return a reference to this object.
* @throws StringIndexOutOfBoundsException if the offset is invalid. * @throws StringIndexOutOfBoundsException if the offset is invalid.
*/ */
......
...@@ -212,7 +212,7 @@ package java.lang; ...@@ -212,7 +212,7 @@ package java.lang;
* @throws NullPointerException {@inheritDoc} * @throws NullPointerException {@inheritDoc}
* @throws IndexOutOfBoundsException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc}
*/ */
public synchronized void getChars(int srcBegin, int srcEnd, char dst[], public synchronized void getChars(int srcBegin, int srcEnd, char[] dst,
int dstBegin) int dstBegin)
{ {
super.getChars(srcBegin, srcEnd, dst, dstBegin); super.getChars(srcBegin, srcEnd, dst, dstBegin);
...@@ -228,10 +228,6 @@ package java.lang; ...@@ -228,10 +228,6 @@ package java.lang;
value[index] = ch; value[index] = ch;
} }
/**
* @see java.lang.String#valueOf(java.lang.Object)
* @see #append(java.lang.String)
*/
public synchronized StringBuffer append(Object obj) { public synchronized StringBuffer append(Object obj) {
super.append(String.valueOf(obj)); super.append(String.valueOf(obj));
return this; return this;
...@@ -314,20 +310,19 @@ package java.lang; ...@@ -314,20 +310,19 @@ package java.lang;
return this; return this;
} }
public synchronized StringBuffer append(char str[]) { public synchronized StringBuffer append(char[] str) {
super.append(str); super.append(str);
return this; return this;
} }
public synchronized StringBuffer append(char str[], int offset, int len) { /**
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public synchronized StringBuffer append(char[] str, int offset, int len) {
super.append(str, offset, len); super.append(str, offset, len);
return this; return this;
} }
/**
* @see java.lang.String#valueOf(boolean)
* @see #append(java.lang.String)
*/
public synchronized StringBuffer append(boolean b) { public synchronized StringBuffer append(boolean b) {
super.append(b); super.append(b);
return this; return this;
...@@ -338,10 +333,6 @@ package java.lang; ...@@ -338,10 +333,6 @@ package java.lang;
return this; return this;
} }
/**
* @see java.lang.String#valueOf(int)
* @see #append(java.lang.String)
*/
public synchronized StringBuffer append(int i) { public synchronized StringBuffer append(int i) {
super.append(i); super.append(i);
return this; return this;
...@@ -355,28 +346,16 @@ package java.lang; ...@@ -355,28 +346,16 @@ package java.lang;
return this; return this;
} }
/**
* @see java.lang.String#valueOf(long)
* @see #append(java.lang.String)
*/
public synchronized StringBuffer append(long lng) { public synchronized StringBuffer append(long lng) {
super.append(lng); super.append(lng);
return this; return this;
} }
/**
* @see java.lang.String#valueOf(float)
* @see #append(java.lang.String)
*/
public synchronized StringBuffer append(float f) { public synchronized StringBuffer append(float f) {
super.append(f); super.append(f);
return this; return this;
} }
/**
* @see java.lang.String#valueOf(double)
* @see #append(java.lang.String)
*/
public synchronized StringBuffer append(double d) { public synchronized StringBuffer append(double d) {
super.append(d); super.append(d);
return this; return this;
...@@ -437,7 +416,7 @@ package java.lang; ...@@ -437,7 +416,7 @@ package java.lang;
* @throws StringIndexOutOfBoundsException {@inheritDoc} * @throws StringIndexOutOfBoundsException {@inheritDoc}
* @since 1.2 * @since 1.2
*/ */
public synchronized StringBuffer insert(int index, char str[], int offset, public synchronized StringBuffer insert(int index, char[] str, int offset,
int len) int len)
{ {
super.insert(index, str, offset, len); super.insert(index, str, offset, len);
...@@ -446,9 +425,6 @@ package java.lang; ...@@ -446,9 +425,6 @@ package java.lang;
/** /**
* @throws StringIndexOutOfBoundsException {@inheritDoc} * @throws StringIndexOutOfBoundsException {@inheritDoc}
* @see java.lang.String#valueOf(java.lang.Object)
* @see #insert(int, java.lang.String)
* @see #length()
*/ */
public synchronized StringBuffer insert(int offset, Object obj) { public synchronized StringBuffer insert(int offset, Object obj) {
super.insert(offset, String.valueOf(obj)); super.insert(offset, String.valueOf(obj));
...@@ -457,7 +433,6 @@ package java.lang; ...@@ -457,7 +433,6 @@ package java.lang;
/** /**
* @throws StringIndexOutOfBoundsException {@inheritDoc} * @throws StringIndexOutOfBoundsException {@inheritDoc}
* @see #length()
*/ */
public synchronized StringBuffer insert(int offset, String str) { public synchronized StringBuffer insert(int offset, String str) {
super.insert(offset, str); super.insert(offset, str);
...@@ -467,7 +442,7 @@ package java.lang; ...@@ -467,7 +442,7 @@ package java.lang;
/** /**
* @throws StringIndexOutOfBoundsException {@inheritDoc} * @throws StringIndexOutOfBoundsException {@inheritDoc}
*/ */
public synchronized StringBuffer insert(int offset, char str[]) { public synchronized StringBuffer insert(int offset, char[] str) {
super.insert(offset, str); super.insert(offset, str);
return this; return this;
} }
...@@ -498,9 +473,6 @@ package java.lang; ...@@ -498,9 +473,6 @@ package java.lang;
/** /**
* @throws StringIndexOutOfBoundsException {@inheritDoc} * @throws StringIndexOutOfBoundsException {@inheritDoc}
* @see java.lang.String#valueOf(boolean)
* @see #insert(int, java.lang.String)
* @see #length()
*/ */
public StringBuffer insert(int offset, boolean b) { public StringBuffer insert(int offset, boolean b) {
return insert(offset, String.valueOf(b)); return insert(offset, String.valueOf(b));
...@@ -508,7 +480,6 @@ package java.lang; ...@@ -508,7 +480,6 @@ package java.lang;
/** /**
* @throws IndexOutOfBoundsException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc}
* @see #length()
*/ */
public synchronized StringBuffer insert(int offset, char c) { public synchronized StringBuffer insert(int offset, char c) {
super.insert(offset, c); super.insert(offset, c);
...@@ -517,9 +488,6 @@ package java.lang; ...@@ -517,9 +488,6 @@ package java.lang;
/** /**
* @throws StringIndexOutOfBoundsException {@inheritDoc} * @throws StringIndexOutOfBoundsException {@inheritDoc}
* @see java.lang.String#valueOf(int)
* @see #insert(int, java.lang.String)
* @see #length()
*/ */
public StringBuffer insert(int offset, int i) { public StringBuffer insert(int offset, int i) {
return insert(offset, String.valueOf(i)); return insert(offset, String.valueOf(i));
...@@ -527,9 +495,6 @@ package java.lang; ...@@ -527,9 +495,6 @@ package java.lang;
/** /**
* @throws StringIndexOutOfBoundsException {@inheritDoc} * @throws StringIndexOutOfBoundsException {@inheritDoc}
* @see java.lang.String#valueOf(long)
* @see #insert(int, java.lang.String)
* @see #length()
*/ */
public StringBuffer insert(int offset, long l) { public StringBuffer insert(int offset, long l) {
return insert(offset, String.valueOf(l)); return insert(offset, String.valueOf(l));
...@@ -537,9 +502,6 @@ package java.lang; ...@@ -537,9 +502,6 @@ package java.lang;
/** /**
* @throws StringIndexOutOfBoundsException {@inheritDoc} * @throws StringIndexOutOfBoundsException {@inheritDoc}
* @see java.lang.String#valueOf(float)
* @see #insert(int, java.lang.String)
* @see #length()
*/ */
public StringBuffer insert(int offset, float f) { public StringBuffer insert(int offset, float f) {
return insert(offset, String.valueOf(f)); return insert(offset, String.valueOf(f));
...@@ -547,9 +509,6 @@ package java.lang; ...@@ -547,9 +509,6 @@ package java.lang;
/** /**
* @throws StringIndexOutOfBoundsException {@inheritDoc} * @throws StringIndexOutOfBoundsException {@inheritDoc}
* @see java.lang.String#valueOf(double)
* @see #insert(int, java.lang.String)
* @see #length()
*/ */
public StringBuffer insert(int offset, double d) { public StringBuffer insert(int offset, double d) {
return insert(offset, String.valueOf(d)); return insert(offset, String.valueOf(d));
......
...@@ -124,10 +124,6 @@ public final class StringBuilder ...@@ -124,10 +124,6 @@ public final class StringBuilder
append(seq); append(seq);
} }
/**
* @see java.lang.String#valueOf(java.lang.Object)
* @see #append(java.lang.String)
*/
public StringBuilder append(Object obj) { public StringBuilder append(Object obj) {
return append(String.valueOf(obj)); return append(String.valueOf(obj));
} }
...@@ -175,7 +171,6 @@ public final class StringBuilder ...@@ -175,7 +171,6 @@ public final class StringBuilder
} }
/** /**
* @throws IndexOutOfBoundsException {@inheritDoc}
*/ */
public StringBuilder append(CharSequence s) { public StringBuilder append(CharSequence s) {
if (s == null) if (s == null)
...@@ -197,20 +192,19 @@ public final class StringBuilder ...@@ -197,20 +192,19 @@ public final class StringBuilder
return this; return this;
} }
public StringBuilder append(char str[]) { public StringBuilder append(char[] str) {
super.append(str); super.append(str);
return this; return this;
} }
public StringBuilder append(char str[], int offset, int len) { /**
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public StringBuilder append(char[] str, int offset, int len) {
super.append(str, offset, len); super.append(str, offset, len);
return this; return this;
} }
/**
* @see java.lang.String#valueOf(boolean)
* @see #append(java.lang.String)
*/
public StringBuilder append(boolean b) { public StringBuilder append(boolean b) {
super.append(b); super.append(b);
return this; return this;
...@@ -221,37 +215,21 @@ public final class StringBuilder ...@@ -221,37 +215,21 @@ public final class StringBuilder
return this; return this;
} }
/**
* @see java.lang.String#valueOf(int)
* @see #append(java.lang.String)
*/
public StringBuilder append(int i) { public StringBuilder append(int i) {
super.append(i); super.append(i);
return this; return this;
} }
/**
* @see java.lang.String#valueOf(long)
* @see #append(java.lang.String)
*/
public StringBuilder append(long lng) { public StringBuilder append(long lng) {
super.append(lng); super.append(lng);
return this; return this;
} }
/**
* @see java.lang.String#valueOf(float)
* @see #append(java.lang.String)
*/
public StringBuilder append(float f) { public StringBuilder append(float f) {
super.append(f); super.append(f);
return this; return this;
} }
/**
* @see java.lang.String#valueOf(double)
* @see #append(java.lang.String)
*/
public StringBuilder append(double d) { public StringBuilder append(double d) {
super.append(d); super.append(d);
return this; return this;
...@@ -292,7 +270,7 @@ public final class StringBuilder ...@@ -292,7 +270,7 @@ public final class StringBuilder
/** /**
* @throws StringIndexOutOfBoundsException {@inheritDoc} * @throws StringIndexOutOfBoundsException {@inheritDoc}
*/ */
public StringBuilder insert(int index, char str[], int offset, public StringBuilder insert(int index, char[] str, int offset,
int len) int len)
{ {
super.insert(index, str, offset, len); super.insert(index, str, offset, len);
...@@ -301,9 +279,6 @@ public final class StringBuilder ...@@ -301,9 +279,6 @@ public final class StringBuilder
/** /**
* @throws StringIndexOutOfBoundsException {@inheritDoc} * @throws StringIndexOutOfBoundsException {@inheritDoc}
* @see java.lang.String#valueOf(java.lang.Object)
* @see #insert(int, java.lang.String)
* @see #length()
*/ */
public StringBuilder insert(int offset, Object obj) { public StringBuilder insert(int offset, Object obj) {
return insert(offset, String.valueOf(obj)); return insert(offset, String.valueOf(obj));
...@@ -311,7 +286,6 @@ public final class StringBuilder ...@@ -311,7 +286,6 @@ public final class StringBuilder
/** /**
* @throws StringIndexOutOfBoundsException {@inheritDoc} * @throws StringIndexOutOfBoundsException {@inheritDoc}
* @see #length()
*/ */
public StringBuilder insert(int offset, String str) { public StringBuilder insert(int offset, String str) {
super.insert(offset, str); super.insert(offset, str);
...@@ -321,7 +295,7 @@ public final class StringBuilder ...@@ -321,7 +295,7 @@ public final class StringBuilder
/** /**
* @throws StringIndexOutOfBoundsException {@inheritDoc} * @throws StringIndexOutOfBoundsException {@inheritDoc}
*/ */
public StringBuilder insert(int offset, char str[]) { public StringBuilder insert(int offset, char[] str) {
super.insert(offset, str); super.insert(offset, str);
return this; return this;
} }
...@@ -349,9 +323,6 @@ public final class StringBuilder ...@@ -349,9 +323,6 @@ public final class StringBuilder
/** /**
* @throws StringIndexOutOfBoundsException {@inheritDoc} * @throws StringIndexOutOfBoundsException {@inheritDoc}
* @see java.lang.String#valueOf(boolean)
* @see #insert(int, java.lang.String)
* @see #length()
*/ */
public StringBuilder insert(int offset, boolean b) { public StringBuilder insert(int offset, boolean b) {
super.insert(offset, b); super.insert(offset, b);
...@@ -360,7 +331,6 @@ public final class StringBuilder ...@@ -360,7 +331,6 @@ public final class StringBuilder
/** /**
* @throws IndexOutOfBoundsException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc}
* @see #length()
*/ */
public StringBuilder insert(int offset, char c) { public StringBuilder insert(int offset, char c) {
super.insert(offset, c); super.insert(offset, c);
...@@ -369,9 +339,6 @@ public final class StringBuilder ...@@ -369,9 +339,6 @@ public final class StringBuilder
/** /**
* @throws StringIndexOutOfBoundsException {@inheritDoc} * @throws StringIndexOutOfBoundsException {@inheritDoc}
* @see java.lang.String#valueOf(int)
* @see #insert(int, java.lang.String)
* @see #length()
*/ */
public StringBuilder insert(int offset, int i) { public StringBuilder insert(int offset, int i) {
return insert(offset, String.valueOf(i)); return insert(offset, String.valueOf(i));
...@@ -379,9 +346,6 @@ public final class StringBuilder ...@@ -379,9 +346,6 @@ public final class StringBuilder
/** /**
* @throws StringIndexOutOfBoundsException {@inheritDoc} * @throws StringIndexOutOfBoundsException {@inheritDoc}
* @see java.lang.String#valueOf(long)
* @see #insert(int, java.lang.String)
* @see #length()
*/ */
public StringBuilder insert(int offset, long l) { public StringBuilder insert(int offset, long l) {
return insert(offset, String.valueOf(l)); return insert(offset, String.valueOf(l));
...@@ -389,9 +353,6 @@ public final class StringBuilder ...@@ -389,9 +353,6 @@ public final class StringBuilder
/** /**
* @throws StringIndexOutOfBoundsException {@inheritDoc} * @throws StringIndexOutOfBoundsException {@inheritDoc}
* @see java.lang.String#valueOf(float)
* @see #insert(int, java.lang.String)
* @see #length()
*/ */
public StringBuilder insert(int offset, float f) { public StringBuilder insert(int offset, float f) {
return insert(offset, String.valueOf(f)); return insert(offset, String.valueOf(f));
...@@ -399,9 +360,6 @@ public final class StringBuilder ...@@ -399,9 +360,6 @@ public final class StringBuilder
/** /**
* @throws StringIndexOutOfBoundsException {@inheritDoc} * @throws StringIndexOutOfBoundsException {@inheritDoc}
* @see java.lang.String#valueOf(double)
* @see #insert(int, java.lang.String)
* @see #length()
*/ */
public StringBuilder insert(int offset, double d) { public StringBuilder insert(int offset, double d) {
return insert(offset, String.valueOf(d)); return insert(offset, String.valueOf(d));
......
...@@ -388,7 +388,7 @@ enum PlatformComponent { ...@@ -388,7 +388,7 @@ enum PlatformComponent {
// if there are more than 1 key properties (i.e. other than "type") // if there are more than 1 key properties (i.e. other than "type")
domainAndType += ",*"; domainAndType += ",*";
} }
ObjectName on = com.sun.jmx.mbeanserver.Util.newObjectName(domainAndType); ObjectName on = ObjectName.valueOf(domainAndType);
Set<ObjectName> set = mbs.queryNames(on, null); Set<ObjectName> set = mbs.queryNames(on, null);
for (PlatformComponent pc : subComponents) { for (PlatformComponent pc : subComponents) {
set.addAll(pc.getObjectNames(mbs)); set.addAll(pc.getObjectNames(mbs));
......
...@@ -75,6 +75,7 @@ public final class HttpCookie implements Cloneable { ...@@ -75,6 +75,7 @@ public final class HttpCookie implements Cloneable {
private String path; // Path=VALUE ... URLs that see the cookie private String path; // Path=VALUE ... URLs that see the cookie
private String portlist; // Port[="portlist"] ... the port cookie may be returned to private String portlist; // Port[="portlist"] ... the port cookie may be returned to
private boolean secure; // Secure ... e.g. use SSL private boolean secure; // Secure ... e.g. use SSL
private boolean httpOnly; // HttpOnly ... i.e. not accessible to scripts
private int version = 1; // Version=1 ... RFC 2965 style private int version = 1; // Version=1 ... RFC 2965 style
// //
...@@ -656,6 +657,32 @@ public final class HttpCookie implements Cloneable { ...@@ -656,6 +657,32 @@ public final class HttpCookie implements Cloneable {
version = v; version = v;
} }
/**
* Returns {@code true} if this cookie contains the <i>HttpOnly</i>
* attribute. This means that the cookie should not be accessible to
* scripting engines, like javascript.
*
* @return {@code true} if this cookie should be considered http only.
* @see #setHttpOnly(boolean)
*/
public boolean isHttpOnly()
{
return httpOnly;
}
/**
* Indicates whether the cookie should be considered HTTP Only. If set to
* {@code true} it means the cookie should not be accessible to scripting
* engines like javascript.
*
* @param httpOnly if {@code true} make the cookie HTTP only, i.e.
* only visible as part of an HTTP request.
* @see #isHttpOnly()
*/
public void setHttpOnly(boolean httpOnly)
{
this.httpOnly = httpOnly;
}
/** /**
* The utility method to check whether a host name is in a domain * The utility method to check whether a host name is in a domain
...@@ -877,6 +904,7 @@ public final class HttpCookie implements Cloneable { ...@@ -877,6 +904,7 @@ public final class HttpCookie implements Cloneable {
|| name.equalsIgnoreCase("Port") // rfc2965 only || name.equalsIgnoreCase("Port") // rfc2965 only
|| name.equalsIgnoreCase("Secure") || name.equalsIgnoreCase("Secure")
|| name.equalsIgnoreCase("Version") || name.equalsIgnoreCase("Version")
|| name.equalsIgnoreCase("HttpOnly")
|| name.charAt(0) == '$') || name.charAt(0) == '$')
{ {
return true; return true;
...@@ -996,6 +1024,11 @@ public final class HttpCookie implements Cloneable { ...@@ -996,6 +1024,11 @@ public final class HttpCookie implements Cloneable {
cookie.setSecure(true); cookie.setSecure(true);
} }
}); });
assignors.put("httponly", new CookieAttributeAssignor(){
public void assign(HttpCookie cookie, String attrName, String attrValue) {
cookie.setHttpOnly(true);
}
});
assignors.put("version", new CookieAttributeAssignor(){ assignors.put("version", new CookieAttributeAssignor(){
public void assign(HttpCookie cookie, String attrName, String attrValue) { public void assign(HttpCookie cookie, String attrName, String attrValue) {
try { try {
......
...@@ -186,7 +186,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private ...@@ -186,7 +186,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
// --- Methods to support CharSequence --- // --- Methods to support CharSequence ---
public CharSequence subSequence(int start, int end) { public CharBuffer subSequence(int start, int end) {
int pos = position(); int pos = position();
int lim = limit(); int lim = limit();
assert (pos <= lim); assert (pos <= lim);
......
...@@ -402,7 +402,7 @@ class Direct$Type$Buffer$RW$$BO$ ...@@ -402,7 +402,7 @@ class Direct$Type$Buffer$RW$$BO$
// --- Methods to support CharSequence --- // --- Methods to support CharSequence ---
public CharSequence subSequence(int start, int end) { public CharBuffer subSequence(int start, int end) {
int pos = position(); int pos = position();
int lim = limit(); int lim = limit();
assert (pos <= lim); assert (pos <= lim);
......
...@@ -566,7 +566,7 @@ class Heap$Type$Buffer$RW$ ...@@ -566,7 +566,7 @@ class Heap$Type$Buffer$RW$
// --- Methods to support CharSequence --- // --- Methods to support CharSequence ---
public CharSequence subSequence(int start, int end) { public CharBuffer subSequence(int start, int end) {
if ((start < 0) if ((start < 0)
|| (end > length()) || (end > length())
|| (start > end)) || (start > end))
......
...@@ -99,7 +99,7 @@ class StringCharBuffer // package-private ...@@ -99,7 +99,7 @@ class StringCharBuffer // package-private
return str.toString().substring(start + offset, end + offset); return str.toString().substring(start + offset, end + offset);
} }
public final CharSequence subSequence(int start, int end) { public final CharBuffer subSequence(int start, int end) {
try { try {
int pos = position(); int pos = position();
return new StringCharBuffer(str, -1, return new StringCharBuffer(str, -1,
......
...@@ -1239,13 +1239,13 @@ public abstract class $Type$Buffer ...@@ -1239,13 +1239,13 @@ public abstract class $Type$Buffer
* smaller than <tt>start</tt> and no larger than * smaller than <tt>start</tt> and no larger than
* <tt>remaining()</tt> * <tt>remaining()</tt>
* *
* @return The new character sequence * @return The new character buffer
* *
* @throws IndexOutOfBoundsException * @throws IndexOutOfBoundsException
* If the preconditions on <tt>start</tt> and <tt>end</tt> * If the preconditions on <tt>start</tt> and <tt>end</tt>
* do not hold * do not hold
*/ */
public abstract CharSequence subSequence(int start, int end); public abstract CharBuffer subSequence(int start, int end);
// --- Methods to support Appendable --- // --- Methods to support Appendable ---
......
/* /*
* Copyright 2000-2005 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -25,6 +25,9 @@ ...@@ -25,6 +25,9 @@
package java.security.cert; package java.security.cert;
import java.io.InvalidObjectException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
/** /**
...@@ -36,10 +39,11 @@ import java.security.GeneralSecurityException; ...@@ -36,10 +39,11 @@ import java.security.GeneralSecurityException;
* if any, that caused this exception to be thrown. * if any, that caused this exception to be thrown.
* <p> * <p>
* A <code>CertPathValidatorException</code> may also include the * A <code>CertPathValidatorException</code> may also include the
* certification path that was being validated when the exception was thrown * certification path that was being validated when the exception was thrown,
* and the index of the certificate in the certification path that caused the * the index of the certificate in the certification path that caused the
* exception to be thrown. Use the {@link #getCertPath getCertPath} and * exception to be thrown, and the reason that caused the failure. Use the
* {@link #getIndex getIndex} methods to retrieve this information. * {@link #getCertPath getCertPath}, {@link #getIndex getIndex}, and
* {@link #getReason getReason} methods to retrieve this information.
* *
* <p> * <p>
* <b>Concurrent Access</b> * <b>Concurrent Access</b>
...@@ -71,12 +75,17 @@ public class CertPathValidatorException extends GeneralSecurityException { ...@@ -71,12 +75,17 @@ public class CertPathValidatorException extends GeneralSecurityException {
*/ */
private CertPath certPath; private CertPath certPath;
/**
* @serial the reason the validation failed
*/
private Reason reason = BasicReason.UNSPECIFIED;
/** /**
* Creates a <code>CertPathValidatorException</code> with * Creates a <code>CertPathValidatorException</code> with
* no detail message. * no detail message.
*/ */
public CertPathValidatorException() { public CertPathValidatorException() {
super(); this(null, null);
} }
/** /**
...@@ -87,7 +96,7 @@ public class CertPathValidatorException extends GeneralSecurityException { ...@@ -87,7 +96,7 @@ public class CertPathValidatorException extends GeneralSecurityException {
* @param msg the detail message * @param msg the detail message
*/ */
public CertPathValidatorException(String msg) { public CertPathValidatorException(String msg) {
super(msg); this(msg, null);
} }
/** /**
...@@ -104,7 +113,7 @@ public class CertPathValidatorException extends GeneralSecurityException { ...@@ -104,7 +113,7 @@ public class CertPathValidatorException extends GeneralSecurityException {
* permitted, and indicates that the cause is nonexistent or unknown.) * permitted, and indicates that the cause is nonexistent or unknown.)
*/ */
public CertPathValidatorException(Throwable cause) { public CertPathValidatorException(Throwable cause) {
super(cause); this(null, cause);
} }
/** /**
...@@ -117,7 +126,7 @@ public class CertPathValidatorException extends GeneralSecurityException { ...@@ -117,7 +126,7 @@ public class CertPathValidatorException extends GeneralSecurityException {
* permitted, and indicates that the cause is nonexistent or unknown.) * permitted, and indicates that the cause is nonexistent or unknown.)
*/ */
public CertPathValidatorException(String msg, Throwable cause) { public CertPathValidatorException(String msg, Throwable cause) {
super(msg, cause); this(msg, cause, null, -1);
} }
/** /**
...@@ -139,6 +148,32 @@ public class CertPathValidatorException extends GeneralSecurityException { ...@@ -139,6 +148,32 @@ public class CertPathValidatorException extends GeneralSecurityException {
*/ */
public CertPathValidatorException(String msg, Throwable cause, public CertPathValidatorException(String msg, Throwable cause,
CertPath certPath, int index) { CertPath certPath, int index) {
this(msg, cause, certPath, index, BasicReason.UNSPECIFIED);
}
/**
* Creates a <code>CertPathValidatorException</code> with the specified
* detail message, cause, certification path, index, and reason.
*
* @param msg the detail message (or <code>null</code> if none)
* @param cause the cause (or <code>null</code> if none)
* @param certPath the certification path that was in the process of
* being validated when the error was encountered
* @param index the index of the certificate in the certification path
* that caused the error (or -1 if not applicable). Note that
* the list of certificates in a <code>CertPath</code> is zero based.
* @param reason the reason the validation failed
* @throws IndexOutOfBoundsException if the index is out of range
* <code>(index < -1 || (certPath != null && index >=
* certPath.getCertificates().size())</code>
* @throws IllegalArgumentException if <code>certPath</code> is
* <code>null</code> and <code>index</code> is not -1
* @throws NullPointerException if <code>reason</code> is <code>null</code>
*
* @since 1.7
*/
public CertPathValidatorException(String msg, Throwable cause,
CertPath certPath, int index, Reason reason) {
super(msg, cause); super(msg, cause);
if (certPath == null && index != -1) { if (certPath == null && index != -1) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
...@@ -147,8 +182,12 @@ public class CertPathValidatorException extends GeneralSecurityException { ...@@ -147,8 +182,12 @@ public class CertPathValidatorException extends GeneralSecurityException {
(certPath != null && index >= certPath.getCertificates().size())) { (certPath != null && index >= certPath.getCertificates().size())) {
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
} }
if (reason == null) {
throw new NullPointerException("reason can't be null");
}
this.certPath = certPath; this.certPath = certPath;
this.index = index; this.index = index;
this.reason = reason;
} }
/** /**
...@@ -174,4 +213,79 @@ public class CertPathValidatorException extends GeneralSecurityException { ...@@ -174,4 +213,79 @@ public class CertPathValidatorException extends GeneralSecurityException {
return this.index; return this.index;
} }
/**
* Returns the reason that the validation failed. The reason is
* associated with the index of the certificate returned by
* {@link getIndex}.
*
* @return the reason that the validation failed, or
* <code>BasicReason.UNSPECIFIED</code> if a reason has not been
* specified
*
* @since 1.7
*/
public Reason getReason() {
return this.reason;
}
private void readObject(ObjectInputStream stream)
throws ClassNotFoundException, IOException {
stream.defaultReadObject();
if (reason == null) {
reason = BasicReason.UNSPECIFIED;
}
if (certPath == null && index != -1) {
throw new InvalidObjectException("certpath is null and index != -1");
}
if (index < -1 ||
(certPath != null && index >= certPath.getCertificates().size())) {
throw new InvalidObjectException("index out of range");
}
}
/**
* The reason the validation algorithm failed.
*
* @since 1.7
*/
public static interface Reason extends java.io.Serializable { }
/**
* The BasicReason enumerates the potential reasons that a certification
* path of any type may be invalid.
*
* @since 1.7
*/
public static enum BasicReason implements Reason {
/**
* Unspecified reason.
*/
UNSPECIFIED,
/**
* The certificate is expired.
*/
EXPIRED,
/**
* The certificate is not yet valid.
*/
NOT_YET_VALID,
/**
* The certificate is revoked.
*/
REVOKED,
/**
* The revocation status of the certificate could not be determined.
*/
UNDETERMINED_REVOCATION_STATUS,
/**
* The signature is invalid.
*/
INVALID_SIGNATURE
}
} }
/*
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package java.security.cert;
/**
* The <code>PKIXReason</code> enumerates the potential PKIX-specific reasons
* that an X.509 certification path may be invalid according to the PKIX
* (RFC 3280) standard. These reasons are in addition to those of the
* <code>CertPathValidatorException.BasicReason</code> enumeration.
*
* @since 1.7
*/
public enum PKIXReason implements CertPathValidatorException.Reason {
/**
* The certificate does not chain correctly.
*/
NAME_CHAINING,
/**
* The certificate's key usage is invalid.
*/
INVALID_KEY_USAGE,
/**
* The policy constraints have been violated.
*/
INVALID_POLICY,
/**
* No acceptable trust anchor found.
*/
NO_TRUST_ANCHOR,
/**
* The certificate contains one or more unrecognized critical
* extensions.
*/
UNRECOGNIZED_CRIT_EXT,
/**
* The certificate is not a CA certificate.
*/
NOT_CA_CERT,
/**
* The path length constraint has been violated.
*/
PATH_TOO_LONG,
/**
* The name constraints have been violated.
*/
INVALID_NAME
}
...@@ -118,6 +118,6 @@ class Logging implements LoggingMXBean { ...@@ -118,6 +118,6 @@ class Logging implements LoggingMXBean {
} }
public ObjectName getObjectName() { public ObjectName getObjectName() {
return com.sun.jmx.mbeanserver.Util.newObjectName(LogManager.LOGGING_MXBEAN_NAME); return ObjectName.valueOf(LogManager.LOGGING_MXBEAN_NAME);
} }
} }
/* /*
* Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved. * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -317,9 +317,6 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { ...@@ -317,9 +317,6 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
if (current != null) { if (current != null) {
closeEntry(); closeEntry();
} }
if (xentries.size() < 1) {
throw new ZipException("ZIP file must have at least one entry");
}
// write central directory // write central directory
long off = written; long off = written;
for (XEntry xentry : xentries) for (XEntry xentry : xentries)
......
...@@ -61,6 +61,6 @@ public class InstanceNotFoundException extends OperationsException { ...@@ -61,6 +61,6 @@ public class InstanceNotFoundException extends OperationsException {
* @since 1.7 * @since 1.7
*/ */
public InstanceNotFoundException(ObjectName name) { public InstanceNotFoundException(ObjectName name) {
this(name.toString()); this(String.valueOf(name));
} }
} }
...@@ -304,7 +304,7 @@ public class MBeanServerDelegate implements MBeanServerDelegateMBean, ...@@ -304,7 +304,7 @@ public class MBeanServerDelegate implements MBeanServerDelegateMBean,
* @since 1.6 * @since 1.6
*/ */
public static final ObjectName DELEGATE_NAME = public static final ObjectName DELEGATE_NAME =
Util.newObjectName("JMImplementation:type=MBeanServerDelegate"); ObjectName.valueOf("JMImplementation:type=MBeanServerDelegate");
/* Return a timestamp that is monotonically increasing even if /* Return a timestamp that is monotonically increasing even if
System.currentTimeMillis() isn't (for example, if you call this System.currentTimeMillis() isn't (for example, if you call this
......
...@@ -413,7 +413,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp { ...@@ -413,7 +413,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp {
} }
private void copyToOtherDomain(String domain, ObjectName aname) private void copyToOtherDomain(String domain, ObjectName aname)
throws MalformedObjectNameException, NullPointerException { throws MalformedObjectNameException {
// The domain cannot be null // The domain cannot be null
if (domain == null) if (domain == null)
...@@ -467,7 +467,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp { ...@@ -467,7 +467,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp {
* is null. * is null.
*/ */
private void construct(String name) private void construct(String name)
throws MalformedObjectNameException, NullPointerException { throws MalformedObjectNameException {
// The name cannot be null // The name cannot be null
if (name == null) if (name == null)
...@@ -729,7 +729,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp { ...@@ -729,7 +729,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp {
* @exception NullPointerException One of the parameters is null. * @exception NullPointerException One of the parameters is null.
*/ */
private void construct(String domain, Map<String,String> props) private void construct(String domain, Map<String,String> props)
throws MalformedObjectNameException, NullPointerException { throws MalformedObjectNameException {
// The domain cannot be null // The domain cannot be null
if (domain == null) if (domain == null)
...@@ -1071,7 +1071,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp { ...@@ -1071,7 +1071,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp {
* Check if the supplied key is a valid key. * Check if the supplied key is a valid key.
*/ */
private static void checkKey(String key) private static void checkKey(String key)
throws MalformedObjectNameException, NullPointerException { throws MalformedObjectNameException {
if (key == null) throw new if (key == null) throw new
NullPointerException("Invalid key (null)"); NullPointerException("Invalid key (null)");
...@@ -1359,9 +1359,10 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp { ...@@ -1359,9 +1359,10 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp {
* @exception NullPointerException The <code>name</code> parameter * @exception NullPointerException The <code>name</code> parameter
* is null. * is null.
* *
* @see #valueOf(String)
*/ */
public static ObjectName getInstance(String name) public static ObjectName getInstance(String name)
throws MalformedObjectNameException, NullPointerException { throws MalformedObjectNameException {
return new ObjectName(name); return new ObjectName(name);
} }
...@@ -1386,10 +1387,11 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp { ...@@ -1386,10 +1387,11 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp {
* follow the rules for quoting. * follow the rules for quoting.
* @exception NullPointerException One of the parameters is null. * @exception NullPointerException One of the parameters is null.
* *
* @see #valueOf(String, String, String)
*/ */
public static ObjectName getInstance(String domain, String key, public static ObjectName getInstance(String domain, String key,
String value) String value)
throws MalformedObjectNameException, NullPointerException { throws MalformedObjectNameException {
return new ObjectName(domain, key, value); return new ObjectName(domain, key, value);
} }
...@@ -1417,10 +1419,11 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp { ...@@ -1417,10 +1419,11 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp {
* quoting. * quoting.
* @exception NullPointerException One of the parameters is null. * @exception NullPointerException One of the parameters is null.
* *
* @see #valueOf(String, Hashtable)
*/ */
public static ObjectName getInstance(String domain, public static ObjectName getInstance(String domain,
Hashtable<String,String> table) Hashtable<String,String> table)
throws MalformedObjectNameException, NullPointerException { throws MalformedObjectNameException {
return new ObjectName(domain, table); return new ObjectName(domain, table);
} }
...@@ -1453,11 +1456,120 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp { ...@@ -1453,11 +1456,120 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp {
* @exception NullPointerException The <code>name</code> is null. * @exception NullPointerException The <code>name</code> is null.
* *
*/ */
public static ObjectName getInstance(ObjectName name) public static ObjectName getInstance(ObjectName name) {
throws NullPointerException {
if (name.getClass().equals(ObjectName.class)) if (name.getClass().equals(ObjectName.class))
return name; return name;
return Util.newObjectName(name.getSerializedNameString()); return valueOf(name.getSerializedNameString());
}
/**
* <p>Return an instance of ObjectName that can be used anywhere
* an object obtained with {@link #ObjectName(String) new
* ObjectName(name)} can be used. The returned object may be of
* a subclass of ObjectName. Calling this method twice with the
* same parameters may return the same object or two equal but
* not identical objects.</p>
*
* <p>This method is equivalent to {@link #getInstance(String)} except that
* it does not throw any checked exceptions.</p>
*
* @param name A string representation of the object name.
*
* @return an ObjectName corresponding to the given String.
*
* @exception IllegalArgumentException The string passed as a
* parameter does not have the right format. The {@linkplain
* Throwable#getCause() cause} of this exception will be a
* {@link MalformedObjectNameException}.
* @exception NullPointerException The <code>name</code> parameter
* is null.
*
* @since 1.7
*/
public static ObjectName valueOf(String name) {
try {
return getInstance(name);
} catch (MalformedObjectNameException e) {
throw new IllegalArgumentException(e.getMessage(), e);
// Just plain IllegalArgumentException(e) produces an exception
// message "javax.management.MalformedObjectNameException: ..."
// which is distracting.
}
}
/**
* <p>Return an instance of ObjectName that can be used anywhere
* an object obtained with {@link #ObjectName(String, String,
* String) new ObjectName(domain, key, value)} can be used. The
* returned object may be of a subclass of ObjectName. Calling
* this method twice with the same parameters may return the same
* object or two equal but not identical objects.</p>
*
* <p>This method is equivalent to {@link #getInstance(String, String,
* String)} except that it does not throw any checked exceptions.</p>
*
* @param domain The domain part of the object name.
* @param key The attribute in the key property of the object name.
* @param value The value in the key property of the object name.
*
* @return an ObjectName corresponding to the given domain,
* key, and value.
*
* @exception IllegalArgumentException The
* <code>domain</code>, <code>key</code>, or <code>value</code>
* contains an illegal character, or <code>value</code> does not
* follow the rules for quoting. The {@linkplain
* Throwable#getCause() cause} of this exception will be a
* {@link MalformedObjectNameException}.
* @exception NullPointerException One of the parameters is null.
*
* @since 1.7
*/
public static ObjectName valueOf(String domain, String key, String value) {
try {
return getInstance(domain, key, value);
} catch (MalformedObjectNameException e) {
throw new IllegalArgumentException(e.getMessage(), e);
}
}
/**
* <p>Return an instance of ObjectName that can be used anywhere
* an object obtained with {@link #ObjectName(String, Hashtable)
* new ObjectName(domain, table)} can be used. The returned
* object may be of a subclass of ObjectName. Calling this method
* twice with the same parameters may return the same object or
* two equal but not identical objects.</p>
*
* <p>This method is equivalent to {@link #getInstance(String, Hashtable)}
* except that it does not throw any checked exceptions.</p>
*
* @param domain The domain part of the object name.
* @param table A hash table containing one or more key
* properties. The key of each entry in the table is the key of a
* key property in the object name. The associated value in the
* table is the associated value in the object name.
*
* @return an ObjectName corresponding to the given domain and
* key mappings.
*
* @exception IllegalArgumentException The <code>domain</code>
* contains an illegal character, or one of the keys or values in
* <code>table</code> contains an illegal character, or one of the
* values in <code>table</code> does not follow the rules for
* quoting. The {@linkplain Throwable#getCause() cause} of this exception
* will be a {@link MalformedObjectNameException}.
* @exception NullPointerException One of the parameters is null.
*
* @since 1.7
*/
public static ObjectName valueOf(String domain,
Hashtable<String,String> table) {
try {
return new ObjectName(domain, table);
} catch (MalformedObjectNameException e) {
throw new IllegalArgumentException(e.getMessage(), e);
}
} }
/** /**
...@@ -1477,7 +1589,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp { ...@@ -1477,7 +1589,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp {
* @since 1.7 * @since 1.7
**/ **/
public final ObjectName withDomain(String newDomain) public final ObjectName withDomain(String newDomain)
throws NullPointerException, MalformedObjectNameException { throws MalformedObjectNameException {
return new ObjectName(newDomain, this); return new ObjectName(newDomain, this);
} }
...@@ -1490,9 +1602,11 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp { ...@@ -1490,9 +1602,11 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp {
* parameter does not have the right format. * parameter does not have the right format.
* @exception NullPointerException The <code>name</code> parameter * @exception NullPointerException The <code>name</code> parameter
* is null. * is null.
*
* @see #valueOf(String)
*/ */
public ObjectName(String name) public ObjectName(String name)
throws MalformedObjectNameException, NullPointerException { throws MalformedObjectNameException {
construct(name); construct(name);
} }
...@@ -1508,9 +1622,11 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp { ...@@ -1508,9 +1622,11 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp {
* contains an illegal character, or <code>value</code> does not * contains an illegal character, or <code>value</code> does not
* follow the rules for quoting. * follow the rules for quoting.
* @exception NullPointerException One of the parameters is null. * @exception NullPointerException One of the parameters is null.
*
* @see #valueOf(String, String, String)
*/ */
public ObjectName(String domain, String key, String value) public ObjectName(String domain, String key, String value)
throws MalformedObjectNameException, NullPointerException { throws MalformedObjectNameException {
// If key or value are null a NullPointerException // If key or value are null a NullPointerException
// will be thrown by the put method in Hashtable. // will be thrown by the put method in Hashtable.
// //
...@@ -1533,9 +1649,11 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp { ...@@ -1533,9 +1649,11 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp {
* values in <code>table</code> does not follow the rules for * values in <code>table</code> does not follow the rules for
* quoting. * quoting.
* @exception NullPointerException One of the parameters is null. * @exception NullPointerException One of the parameters is null.
*
* @see #valueOf(String, Hashtable)
*/ */
public ObjectName(String domain, Hashtable<String,String> table) public ObjectName(String domain, Hashtable<String,String> table)
throws MalformedObjectNameException, NullPointerException { throws MalformedObjectNameException {
construct(domain, table); construct(domain, table);
/* The exception for when a key or value in the table is not a /* The exception for when a key or value in the table is not a
String is now ClassCastException rather than String is now ClassCastException rather than
...@@ -1629,8 +1747,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp { ...@@ -1629,8 +1747,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp {
* *
* @since 1.6 * @since 1.6
*/ */
public boolean isPropertyValuePattern(String property) public boolean isPropertyValuePattern(String property) {
throws NullPointerException, IllegalArgumentException {
if (property == null) if (property == null)
throw new NullPointerException("key property can't be null"); throw new NullPointerException("key property can't be null");
for (int i = 0; i < _ca_array.length; i++) { for (int i = 0; i < _ca_array.length; i++) {
...@@ -1691,7 +1808,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp { ...@@ -1691,7 +1808,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp {
* *
* @exception NullPointerException If <code>property</code> is null. * @exception NullPointerException If <code>property</code> is null.
*/ */
public String getKeyProperty(String property) throws NullPointerException { public String getKeyProperty(String property) {
return _getKeyPropertyList().get(property); return _getKeyPropertyList().get(property);
} }
...@@ -1950,8 +2067,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp { ...@@ -1950,8 +2067,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp {
* @exception NullPointerException if <code>s</code> is null. * @exception NullPointerException if <code>s</code> is null.
* *
*/ */
public static String quote(String s) public static String quote(String s) {
throws NullPointerException {
final StringBuilder buf = new StringBuilder("\""); final StringBuilder buf = new StringBuilder("\"");
final int len = s.length(); final int len = s.length();
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
...@@ -1995,8 +2111,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp { ...@@ -1995,8 +2111,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp {
* @exception NullPointerException if <code>q</code> is null. * @exception NullPointerException if <code>q</code> is null.
* *
*/ */
public static String unquote(String q) public static String unquote(String q) {
throws IllegalArgumentException, NullPointerException {
final StringBuilder buf = new StringBuilder(); final StringBuilder buf = new StringBuilder();
final int len = q.length(); final int len = q.length();
if (len < 2 || q.charAt(0) != '"' || q.charAt(len - 1) != '"') if (len < 2 || q.charAt(0) != '"' || q.charAt(len - 1) != '"')
...@@ -2041,7 +2156,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp { ...@@ -2041,7 +2156,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp {
* *
* @since 1.6 * @since 1.6
*/ */
public static final ObjectName WILDCARD = Util.newObjectName("*:*"); public static final ObjectName WILDCARD = valueOf("*:*");
// Category : Utilities <=================================== // Category : Utilities <===================================
...@@ -2064,7 +2179,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp { ...@@ -2064,7 +2179,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp {
* @exception NullPointerException if <code>name</code> is null. * @exception NullPointerException if <code>name</code> is null.
* *
*/ */
public boolean apply(ObjectName name) throws NullPointerException { public boolean apply(ObjectName name) {
if (name == null) throw new NullPointerException(); if (name == null) throw new NullPointerException();
......
...@@ -170,7 +170,7 @@ public class QueryNotificationFilter implements NotificationFilter { ...@@ -170,7 +170,7 @@ public class QueryNotificationFilter implements NotificationFilter {
private static final long serialVersionUID = -8408613922660635231L; private static final long serialVersionUID = -8408613922660635231L;
private static final ObjectName DEFAULT_NAME = private static final ObjectName DEFAULT_NAME =
Util.newObjectName(":type=Notification"); ObjectName.valueOf(":type=Notification");
private static final QueryExp trueQuery; private static final QueryExp trueQuery;
static { static {
ValueExp zero = Query.value(0); ValueExp zero = Query.value(0);
......
...@@ -264,11 +264,12 @@ public class EventClient implements EventConsumer, NotificationManager { ...@@ -264,11 +264,12 @@ public class EventClient implements EventConsumer, NotificationManager {
new PerThreadGroupPool.Create<ScheduledThreadPoolExecutor>() { new PerThreadGroupPool.Create<ScheduledThreadPoolExecutor>() {
public ScheduledThreadPoolExecutor createThreadPool(ThreadGroup group) { public ScheduledThreadPoolExecutor createThreadPool(ThreadGroup group) {
ThreadFactory daemonThreadFactory = new DaemonThreadFactory( ThreadFactory daemonThreadFactory = new DaemonThreadFactory(
"EventClient lease renewer %d"); "JMX EventClient lease renewer %d");
ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor( ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(
20, daemonThreadFactory); 20, daemonThreadFactory);
exec.setKeepAliveTime(3, TimeUnit.SECONDS); exec.setKeepAliveTime(1, TimeUnit.SECONDS);
exec.allowCoreThreadTimeOut(true); exec.allowCoreThreadTimeOut(true);
exec.setRemoveOnCancelPolicy(true);
return exec; return exec;
} }
}; };
......
...@@ -96,7 +96,7 @@ public interface EventClientDelegateMBean { ...@@ -96,7 +96,7 @@ public interface EventClientDelegateMBean {
* <code>{@value #OBJECT_NAME_STRING}</code>. * <code>{@value #OBJECT_NAME_STRING}</code>.
*/ */
public final static ObjectName OBJECT_NAME = public final static ObjectName OBJECT_NAME =
Util.newObjectName(OBJECT_NAME_STRING); ObjectName.valueOf(OBJECT_NAME_STRING);
/** /**
* A unique listener identifier specified for an EventClient. * A unique listener identifier specified for an EventClient.
......
...@@ -149,10 +149,10 @@ public class EventSubscriber implements EventConsumer { ...@@ -149,10 +149,10 @@ public class EventSubscriber implements EventConsumer {
if (listener == null) if (listener == null)
throw new IllegalArgumentException("Null listener"); throw new IllegalArgumentException("Null listener");
final ListenerInfo li = new ListenerInfo(listener, filter, handback); final MyListenerInfo li = new MyListenerInfo(listener, filter, handback);
List<ListenerInfo> list; List<MyListenerInfo> list;
Map<ObjectName, List<ListenerInfo>> map; Map<ObjectName, List<MyListenerInfo>> map;
Set<ObjectName> names; Set<ObjectName> names;
if (name.isPattern()) { if (name.isPattern()) {
map = patternSubscriptionMap; map = patternSubscriptionMap;
...@@ -165,7 +165,7 @@ public class EventSubscriber implements EventConsumer { ...@@ -165,7 +165,7 @@ public class EventSubscriber implements EventConsumer {
synchronized (map) { synchronized (map) {
list = map.get(name); list = map.get(name);
if (list == null) { if (list == null) {
list = new ArrayList<ListenerInfo>(); list = new ArrayList<MyListenerInfo>();
map.put(name, list); map.put(name, list);
} }
list.add(li); list.add(li);
...@@ -186,7 +186,6 @@ public class EventSubscriber implements EventConsumer { ...@@ -186,7 +186,6 @@ public class EventSubscriber implements EventConsumer {
public void unsubscribe(ObjectName name, public void unsubscribe(ObjectName name,
NotificationListener listener) NotificationListener listener)
throws ListenerNotFoundException, IOException { throws ListenerNotFoundException, IOException {
if (logger.traceOn()) if (logger.traceOn())
logger.trace("unsubscribe", "" + name); logger.trace("unsubscribe", "" + name);
...@@ -196,7 +195,7 @@ public class EventSubscriber implements EventConsumer { ...@@ -196,7 +195,7 @@ public class EventSubscriber implements EventConsumer {
if (listener == null) if (listener == null)
throw new ListenerNotFoundException(); throw new ListenerNotFoundException();
Map<ObjectName, List<ListenerInfo>> map; Map<ObjectName, List<MyListenerInfo>> map;
Set<ObjectName> names; Set<ObjectName> names;
if (name.isPattern()) { if (name.isPattern()) {
...@@ -207,22 +206,39 @@ public class EventSubscriber implements EventConsumer { ...@@ -207,22 +206,39 @@ public class EventSubscriber implements EventConsumer {
names = Collections.singleton(name); names = Collections.singleton(name);
} }
final ListenerInfo li = new ListenerInfo(listener, null, null); List<MyListenerInfo> toRemove = new ArrayList<MyListenerInfo>();
List<ListenerInfo> list;
synchronized (map) { synchronized (map) {
list = map.get(name); List<MyListenerInfo> list = map.get(name);
if (list == null || !list.remove(li)) if (list == null) {
throw new ListenerNotFoundException();
}
for (MyListenerInfo info : list) {
if (info.listener == listener) {
toRemove.add(info);
}
}
if (toRemove.isEmpty()) {
throw new ListenerNotFoundException(); throw new ListenerNotFoundException();
}
for (MyListenerInfo info : toRemove) {
list.remove(info);
}
if (list.isEmpty()) if (list.isEmpty())
map.remove(name); map.remove(name);
} }
for (ObjectName mbeanName : names) { for (ObjectName mbeanName : names) {
try { for (MyListenerInfo i : toRemove) {
mbeanServer.removeNotificationListener(mbeanName, li.listener); try {
} catch (Exception e) { mbeanServer.removeNotificationListener(mbeanName,
logger.fine("unsubscribe", "removeNotificationListener", e); i.listener, i.filter, i.handback);
} catch (Exception e) {
logger.fine("unsubscribe", "removeNotificationListener", e);
}
} }
} }
} }
...@@ -256,12 +272,12 @@ public class EventSubscriber implements EventConsumer { ...@@ -256,12 +272,12 @@ public class EventSubscriber implements EventConsumer {
return; return;
} }
final List<ListenerInfo> listeners = new ArrayList<ListenerInfo>(); final List<MyListenerInfo> listeners = new ArrayList<MyListenerInfo>();
// If there are subscribers for the exact name that has just arrived // If there are subscribers for the exact name that has just arrived
// then add their listeners to the list. // then add their listeners to the list.
synchronized (exactSubscriptionMap) { synchronized (exactSubscriptionMap) {
List<ListenerInfo> exactListeners = exactSubscriptionMap.get(name); List<MyListenerInfo> exactListeners = exactSubscriptionMap.get(name);
if (exactListeners != null) if (exactListeners != null)
listeners.addAll(exactListeners); listeners.addAll(exactListeners);
} }
...@@ -277,7 +293,7 @@ public class EventSubscriber implements EventConsumer { ...@@ -277,7 +293,7 @@ public class EventSubscriber implements EventConsumer {
} }
// Add all the listeners just found to the new MBean. // Add all the listeners just found to the new MBean.
for (ListenerInfo li : listeners) { for (MyListenerInfo li : listeners) {
try { try {
mbeanServer.addNotificationListener( mbeanServer.addNotificationListener(
name, name,
...@@ -292,12 +308,12 @@ public class EventSubscriber implements EventConsumer { ...@@ -292,12 +308,12 @@ public class EventSubscriber implements EventConsumer {
} }
}; };
private static class ListenerInfo { private static class MyListenerInfo {
public final NotificationListener listener; public final NotificationListener listener;
public final NotificationFilter filter; public final NotificationFilter filter;
public final Object handback; public final Object handback;
public ListenerInfo(NotificationListener listener, public MyListenerInfo(NotificationListener listener,
NotificationFilter filter, NotificationFilter filter,
Object handback) { Object handback) {
...@@ -308,26 +324,6 @@ public class EventSubscriber implements EventConsumer { ...@@ -308,26 +324,6 @@ public class EventSubscriber implements EventConsumer {
this.filter = filter; this.filter = filter;
this.handback = handback; this.handback = handback;
} }
/* Two ListenerInfo instances are equal if they have the same
* NotificationListener. This means that we can use List.remove
* to implement the two-argument removeNotificationListener.
*/
@Override
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof ListenerInfo))
return false;
return listener.equals(((ListenerInfo)o).listener);
}
@Override
public int hashCode() {
return listener.hashCode();
}
} }
// --------------------------------- // ---------------------------------
...@@ -338,10 +334,10 @@ public class EventSubscriber implements EventConsumer { ...@@ -338,10 +334,10 @@ public class EventSubscriber implements EventConsumer {
// --------------------------------- // ---------------------------------
private final MBeanServer mbeanServer; private final MBeanServer mbeanServer;
private final Map<ObjectName, List<ListenerInfo>> exactSubscriptionMap = private final Map<ObjectName, List<MyListenerInfo>> exactSubscriptionMap =
new HashMap<ObjectName, List<ListenerInfo>>(); new HashMap<ObjectName, List<MyListenerInfo>>();
private final Map<ObjectName, List<ListenerInfo>> patternSubscriptionMap = private final Map<ObjectName, List<MyListenerInfo>> patternSubscriptionMap =
new HashMap<ObjectName, List<ListenerInfo>>(); new HashMap<ObjectName, List<MyListenerInfo>>();
......
...@@ -31,10 +31,8 @@ import com.sun.jmx.remote.util.ClassLogger; ...@@ -31,10 +31,8 @@ import com.sun.jmx.remote.util.ClassLogger;
import java.io.IOException; import java.io.IOException;
import java.io.NotSerializableException; import java.io.NotSerializableException;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.management.MBeanException; import javax.management.MBeanException;
...@@ -215,50 +213,47 @@ public class FetchingEventRelay implements EventRelay { ...@@ -215,50 +213,47 @@ public class FetchingEventRelay implements EventRelay {
this.maxNotifs = maxNotifs; this.maxNotifs = maxNotifs;
if (executor == null) { if (executor == null) {
executor = Executors.newSingleThreadScheduledExecutor( ScheduledThreadPoolExecutor stpe = new ScheduledThreadPoolExecutor(1,
daemonThreadFactory); daemonThreadFactory);
} stpe.setKeepAliveTime(1, TimeUnit.SECONDS);
stpe.allowCoreThreadTimeOut(true);
executor = stpe;
this.defaultExecutor = stpe;
} else
this.defaultExecutor = null;
this.executor = executor; this.executor = executor;
if (executor instanceof ScheduledExecutorService)
leaseScheduler = (ScheduledExecutorService) executor;
else {
leaseScheduler = Executors.newSingleThreadScheduledExecutor(
daemonThreadFactory);
}
startSequenceNumber = 0; startSequenceNumber = 0;
fetchingJob = new MyJob(); fetchingJob = new MyJob();
} }
public void setEventReceiver(EventReceiver eventReceiver) { public synchronized void setEventReceiver(EventReceiver eventReceiver) {
if (logger.traceOn()) { if (logger.traceOn()) {
logger.trace("setEventReceiver", ""+eventReceiver); logger.trace("setEventReceiver", ""+eventReceiver);
} }
EventReceiver old = this.eventReceiver; EventReceiver old = this.eventReceiver;
synchronized(fetchingJob) { this.eventReceiver = eventReceiver;
this.eventReceiver = eventReceiver; if (old == null && eventReceiver != null)
if (old == null && eventReceiver != null) fetchingJob.resume();
fetchingJob.resume();
}
} }
public String getClientId() { public String getClientId() {
return clientId; return clientId;
} }
public void stop() { public synchronized void stop() {
if (logger.traceOn()) { if (logger.traceOn()) {
logger.trace("stop", ""); logger.trace("stop", "");
} }
synchronized(fetchingJob) { if (stopped) {
if (stopped) { return;
return;
}
stopped = true;
clientId = null;
} }
stopped = true;
clientId = null;
if (defaultExecutor != null)
defaultExecutor.shutdown();
} }
private class MyJob extends RepeatedSingletonJob { private class MyJob extends RepeatedSingletonJob {
...@@ -372,10 +367,9 @@ public class FetchingEventRelay implements EventRelay { ...@@ -372,10 +367,9 @@ public class FetchingEventRelay implements EventRelay {
private final EventClientDelegateMBean delegate; private final EventClientDelegateMBean delegate;
private String clientId; private String clientId;
private boolean stopped = false; private boolean stopped = false;
private volatile ScheduledFuture<?> leaseRenewalFuture;
private final Executor executor; private final Executor executor;
private final ScheduledExecutorService leaseScheduler; private final ExecutorService defaultExecutor;
private final MyJob fetchingJob; private final MyJob fetchingJob;
private final long timeout; private final long timeout;
...@@ -385,5 +379,5 @@ public class FetchingEventRelay implements EventRelay { ...@@ -385,5 +379,5 @@ public class FetchingEventRelay implements EventRelay {
new ClassLogger("javax.management.event", new ClassLogger("javax.management.event",
"FetchingEventRelay"); "FetchingEventRelay");
private static final ThreadFactory daemonThreadFactory = private static final ThreadFactory daemonThreadFactory =
new DaemonThreadFactory("FetchingEventRelay-executor"); new DaemonThreadFactory("JMX FetchingEventRelay executor %d");
} }
...@@ -185,7 +185,7 @@ public class RMIPushEventForwarder implements EventForwarder { ...@@ -185,7 +185,7 @@ public class RMIPushEventForwarder implements EventForwarder {
private static final ExecutorService executor = private static final ExecutorService executor =
Executors.newCachedThreadPool( Executors.newCachedThreadPool(
new DaemonThreadFactory("RMIEventForwarder Executor")); new DaemonThreadFactory("JMX RMIEventForwarder Executor"));
private final SendingJob sendingJob = new SendingJob(); private final SendingJob sendingJob = new SendingJob();
private final BlockingQueue<TargetedNotification> buffer; private final BlockingQueue<TargetedNotification> buffer;
......
...@@ -308,17 +308,17 @@ public class JMXDomain extends JMXNamespace { ...@@ -308,17 +308,17 @@ public class JMXDomain extends JMXNamespace {
* It is however only available for subclasses in this package. * It is however only available for subclasses in this package.
**/ **/
@Override @Override
ObjectName validateHandlerName(ObjectName supliedName) { ObjectName validateHandlerName(ObjectName suppliedName) {
if (supliedName == null) if (suppliedName == null)
throw new IllegalArgumentException("Must supply a valid name"); throw new IllegalArgumentException("Must supply a valid name");
final String dirName = JMXNamespaces. final String dirName = JMXNamespaces.
normalizeNamespaceName(supliedName.getDomain()); normalizeNamespaceName(suppliedName.getDomain());
final ObjectName handlerName = getDomainObjectName(dirName); final ObjectName handlerName = getDomainObjectName(dirName);
if (!supliedName.equals(handlerName)) if (!suppliedName.equals(handlerName))
throw new IllegalArgumentException("invalid name space name: "+ throw new IllegalArgumentException("invalid name space name: "+
supliedName); suppliedName);
return supliedName; return suppliedName;
} }
/** /**
......
...@@ -482,8 +482,8 @@ public class JMXNamespace ...@@ -482,8 +482,8 @@ public class JMXNamespace
/** /**
* This method is part of the {@link MBeanRegistration} interface. * This method is part of the {@link MBeanRegistration} interface.
* The {@link JMXNamespace} class uses the {@link MBeanRegistration} * The {@link JMXNamespace} class uses the {@link MBeanRegistration}
* interface in order to get a handle to the MBean server in which it is * interface in order to get a reference to the MBean server in which it is
* registered. It also check the validity of its own ObjectName. * registered. It also checks the validity of its own ObjectName.
* <p> * <p>
* This method is called by the MBean server. * This method is called by the MBean server.
* Application classes should never call this method directly. * Application classes should never call this method directly.
...@@ -502,11 +502,14 @@ public class JMXNamespace ...@@ -502,11 +502,14 @@ public class JMXNamespace
*/ */
public ObjectName preRegister(MBeanServer server, ObjectName name) public ObjectName preRegister(MBeanServer server, ObjectName name)
throws Exception { throws Exception {
if (objectName != null && ! objectName.equals(name)) // need to synchronize to protect against multiple registration.
throw new IllegalStateException( synchronized(this) {
if (objectName != null && ! objectName.equals(name))
throw new IllegalStateException(
"Already registered under another name: " + objectName); "Already registered under another name: " + objectName);
objectName = validateHandlerName(name); objectName = validateHandlerName(name);
mbeanServer = server; mbeanServer = server;
}
return name; return name;
} }
...@@ -517,23 +520,23 @@ public class JMXNamespace ...@@ -517,23 +520,23 @@ public class JMXNamespace
* reuse JMXNamespace in order to implement sessions... * reuse JMXNamespace in order to implement sessions...
* It is however only available for subclasses in this package. * It is however only available for subclasses in this package.
**/ **/
ObjectName validateHandlerName(ObjectName supliedName) { ObjectName validateHandlerName(ObjectName suppliedName) {
if (supliedName == null) if (suppliedName == null)
throw new IllegalArgumentException("Must supply a valid name"); throw new IllegalArgumentException("Must supply a valid name");
final String dirName = JMXNamespaces. final String dirName = JMXNamespaces.
normalizeNamespaceName(supliedName.getDomain()); normalizeNamespaceName(suppliedName.getDomain());
final ObjectName handlerName = final ObjectName handlerName =
JMXNamespaces.getNamespaceObjectName(dirName); JMXNamespaces.getNamespaceObjectName(dirName);
if (!supliedName.equals(handlerName)) if (!suppliedName.equals(handlerName))
throw new IllegalArgumentException("invalid name space name: "+ throw new IllegalArgumentException("invalid name space name: "+
supliedName); suppliedName);
return supliedName; return suppliedName;
} }
/** /**
* This method is part of the {@link MBeanRegistration} interface. * This method is part of the {@link MBeanRegistration} interface.
* The {@link JMXNamespace} class uses the {@link MBeanRegistration} * The {@link JMXNamespace} class uses the {@link MBeanRegistration}
* interface in order to get a handle to the MBean server in which it is * interface in order to get a reference to the MBean server in which it is
* registered. * registered.
* <p> * <p>
* This method is called by the MBean server. Application classes should * This method is called by the MBean server. Application classes should
...@@ -549,7 +552,7 @@ public class JMXNamespace ...@@ -549,7 +552,7 @@ public class JMXNamespace
/** /**
* This method is part of the {@link MBeanRegistration} interface. * This method is part of the {@link MBeanRegistration} interface.
* The {@link JMXNamespace} class uses the {@link MBeanRegistration} * The {@link JMXNamespace} class uses the {@link MBeanRegistration}
* interface in order to get a handle to the MBean server in which it is * interface in order to get a reference to the MBean server in which it is
* registered. * registered.
* <p> * <p>
* This method is called by the MBean server. Application classes should * This method is called by the MBean server. Application classes should
...@@ -573,8 +576,11 @@ public class JMXNamespace ...@@ -573,8 +576,11 @@ public class JMXNamespace
* @see MBeanRegistration#postDeregister MBeanRegistration * @see MBeanRegistration#postDeregister MBeanRegistration
*/ */
public void postDeregister() { public void postDeregister() {
mbeanServer = null; // need to synchronize to protect against multiple registration.
objectName = null; synchronized(this) {
mbeanServer = null;
objectName = null;
}
} }
......
...@@ -266,11 +266,15 @@ public class JMXNamespaces { ...@@ -266,11 +266,15 @@ public class JMXNamespaces {
ObjectNameRouter.normalizeNamespacePath(namespace,false, ObjectNameRouter.normalizeNamespacePath(namespace,false,
true,false); true,false);
try { try {
// We could use Util.newObjectName here - but throwing an
// IllegalArgumentException that contains just the supplied
// namespace instead of the whole ObjectName seems preferable.
return ObjectName.getInstance(sourcePath+ return ObjectName.getInstance(sourcePath+
NAMESPACE_SEPARATOR+":"+ NAMESPACE_SEPARATOR+":"+
JMXNamespace.TYPE_ASSIGNMENT); JMXNamespace.TYPE_ASSIGNMENT);
} catch (MalformedObjectNameException x) { } catch (MalformedObjectNameException x) {
throw new IllegalArgumentException(namespace,x); throw new IllegalArgumentException("Invalid namespace: " +
namespace,x);
} }
} }
......
...@@ -28,13 +28,12 @@ package javax.management.namespace; ...@@ -28,13 +28,12 @@ package javax.management.namespace;
import com.sun.jmx.defaults.JmxProperties; import com.sun.jmx.defaults.JmxProperties;
import com.sun.jmx.mbeanserver.Util; import com.sun.jmx.mbeanserver.Util;
import com.sun.jmx.namespace.JMXNamespaceUtils; import com.sun.jmx.namespace.JMXNamespaceUtils;
import com.sun.jmx.namespace.NamespaceInterceptor.DynamicProbe;
import com.sun.jmx.remote.util.EnvHelp; import com.sun.jmx.remote.util.EnvHelp;
import java.io.IOException; import java.io.IOException;
import java.security.AccessControlException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
...@@ -43,9 +42,7 @@ import javax.management.AttributeChangeNotification; ...@@ -43,9 +42,7 @@ import javax.management.AttributeChangeNotification;
import javax.management.InstanceNotFoundException; import javax.management.InstanceNotFoundException;
import javax.management.ListenerNotFoundException; import javax.management.ListenerNotFoundException;
import javax.management.MBeanNotificationInfo; import javax.management.MBeanNotificationInfo;
import javax.management.MBeanPermission;
import javax.management.MBeanServerConnection; import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.Notification; import javax.management.Notification;
import javax.management.NotificationBroadcasterSupport; import javax.management.NotificationBroadcasterSupport;
import javax.management.NotificationEmitter; import javax.management.NotificationEmitter;
...@@ -117,18 +114,13 @@ public class JMXRemoteNamespace ...@@ -117,18 +114,13 @@ public class JMXRemoteNamespace
*/ */
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER; private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
private static final Logger PROBE_LOG = Logger.getLogger(
JmxProperties.NAMESPACE_LOGGER_NAME+".probe");
// This connection listener is used to listen for connection events from // This connection listener is used to listen for connection events from
// the underlying JMXConnector. It is used in particular to maintain the // the underlying JMXConnector. It is used in particular to maintain the
// "connected" state in this MBean. // "connected" state in this MBean.
// //
private static class ConnectionListener implements NotificationListener { private class ConnectionListener implements NotificationListener {
private final JMXRemoteNamespace handler; private ConnectionListener() {
private ConnectionListener(JMXRemoteNamespace handler) {
this.handler = handler;
} }
public void handleNotification(Notification notification, public void handleNotification(Notification notification,
Object handback) { Object handback) {
...@@ -136,7 +128,11 @@ public class JMXRemoteNamespace ...@@ -136,7 +128,11 @@ public class JMXRemoteNamespace
return; return;
final JMXConnectionNotification cn = final JMXConnectionNotification cn =
(JMXConnectionNotification)notification; (JMXConnectionNotification)notification;
handler.checkState(this,cn,(JMXConnector)handback); final String type = cn.getType();
if (JMXConnectionNotification.CLOSED.equals(type)
|| JMXConnectionNotification.FAILED.equals(type)) {
checkState(this,cn,(JMXConnector)handback);
}
} }
} }
...@@ -150,8 +146,7 @@ public class JMXRemoteNamespace ...@@ -150,8 +146,7 @@ public class JMXRemoteNamespace
// because the one that is actually used is the one supplied by the // because the one that is actually used is the one supplied by the
// override of getMBeanServerConnection(). // override of getMBeanServerConnection().
private static class JMXRemoteNamespaceDelegate private static class JMXRemoteNamespaceDelegate
extends MBeanServerConnectionWrapper extends MBeanServerConnectionWrapper {
implements DynamicProbe {
private volatile JMXRemoteNamespace parent=null; private volatile JMXRemoteNamespace parent=null;
JMXRemoteNamespaceDelegate() { JMXRemoteNamespaceDelegate() {
...@@ -177,9 +172,6 @@ public class JMXRemoteNamespace ...@@ -177,9 +172,6 @@ public class JMXRemoteNamespace
} }
public boolean isProbeRequested() {
return this.parent.isProbeRequested();
}
} }
private static final MBeanNotificationInfo connectNotification = private static final MBeanNotificationInfo connectNotification =
...@@ -188,7 +180,7 @@ public class JMXRemoteNamespace ...@@ -188,7 +180,7 @@ public class JMXRemoteNamespace
"Connected", "Connected",
"Emitted when the Connected state of this object changes"); "Emitted when the Connected state of this object changes");
private static long seqNumber=0; private static AtomicLong seqNumber = new AtomicLong(0);
private final NotificationBroadcasterSupport broadcaster; private final NotificationBroadcasterSupport broadcaster;
private final ConnectionListener listener; private final ConnectionListener listener;
...@@ -198,7 +190,6 @@ public class JMXRemoteNamespace ...@@ -198,7 +190,6 @@ public class JMXRemoteNamespace
private volatile MBeanServerConnection server = null; private volatile MBeanServerConnection server = null;
private volatile JMXConnector conn = null; private volatile JMXConnector conn = null;
private volatile ClassLoader defaultClassLoader = null; private volatile ClassLoader defaultClassLoader = null;
private volatile boolean probed;
/** /**
* Creates a new instance of {@code JMXRemoteNamespace}. * Creates a new instance of {@code JMXRemoteNamespace}.
...@@ -237,10 +228,7 @@ public class JMXRemoteNamespace ...@@ -237,10 +228,7 @@ public class JMXRemoteNamespace
this.optionsMap = JMXNamespaceUtils.unmodifiableMap(optionsMap); this.optionsMap = JMXNamespaceUtils.unmodifiableMap(optionsMap);
// handles (dis)connection events // handles (dis)connection events
this.listener = new ConnectionListener(this); this.listener = new ConnectionListener();
// XXX TODO: remove the probe, or simplify it.
this.probed = false;
} }
/** /**
...@@ -271,10 +259,6 @@ public class JMXRemoteNamespace ...@@ -271,10 +259,6 @@ public class JMXRemoteNamespace
return optionsMap; return optionsMap;
} }
boolean isProbeRequested() {
return probed==false;
}
public void addNotificationListener(NotificationListener listener, public void addNotificationListener(NotificationListener listener,
NotificationFilter filter, Object handback) { NotificationFilter filter, Object handback) {
broadcaster.addNotificationListener(listener, filter, handback); broadcaster.addNotificationListener(listener, filter, handback);
...@@ -313,8 +297,8 @@ public class JMXRemoteNamespace ...@@ -313,8 +297,8 @@ public class JMXRemoteNamespace
broadcaster.removeNotificationListener(listener, filter, handback); broadcaster.removeNotificationListener(listener, filter, handback);
} }
private static synchronized long getNextSeqNumber() { private static long getNextSeqNumber() {
return seqNumber++; return seqNumber.getAndIncrement();
} }
...@@ -362,14 +346,18 @@ public class JMXRemoteNamespace ...@@ -362,14 +346,18 @@ public class JMXRemoteNamespace
// lock while evaluating the true value of the connected state, // lock while evaluating the true value of the connected state,
// while anyone might also call close() or connect() from a // while anyone might also call close() or connect() from a
// different thread. // different thread.
//
// The method switchConnection() (called from here too) also has the // The method switchConnection() (called from here too) also has the
// same kind of complex logic. // same kind of complex logic:
// //
// We use the JMXConnector has a handback to the notification listener // We use the JMXConnector has a handback to the notification listener
// (emittingConnector) in order to be able to determine whether the // (emittingConnector) in order to be able to determine whether the
// notification concerns the current connector in use, or an older // notification concerns the current connector in use, or an older
// one. // one. The 'emittingConnector' is the connector from which the
// notification originated. This could be an 'old' connector - as
// closed() and connect() could already have been called before the
// notification arrived. So what we do is to compare the
// 'emittingConnector' with the current connector, to see if the
// notification actually comes from the curent connector.
// //
boolean remove = false; boolean remove = false;
...@@ -486,14 +474,12 @@ public class JMXRemoteNamespace ...@@ -486,14 +474,12 @@ public class JMXRemoteNamespace
} }
} }
private void closeall(JMXConnector... a) { private void close(JMXConnector c) {
for (JMXConnector c : a) { try {
try { if (c != null) c.close();
if (c != null) c.close(); } catch (Exception x) {
} catch (Exception x) { // OK: we're gonna throw the original exception later.
// OK: we're gonna throw the original exception later. LOG.finest("Ignoring exception when closing connector: "+x);
LOG.finest("Ignoring exception when closing connector: "+x);
}
} }
} }
...@@ -598,26 +584,7 @@ public class JMXRemoteNamespace ...@@ -598,26 +584,7 @@ public class JMXRemoteNamespace
} }
public void connect() throws IOException { public void connect() throws IOException {
if (conn != null) {
try {
// This is much too fragile. It must go away!
PROBE_LOG.finest("Probing again...");
triggerProbe(getMBeanServerConnection());
} catch(Exception x) {
close();
Throwable cause = x;
// if the cause is a security exception - rethrows it...
while (cause != null) {
if (cause instanceof SecurityException)
throw (SecurityException) cause;
cause = cause.getCause();
}
throw new IOException("connection failed: cycle?",x);
}
}
LOG.fine("connecting..."); LOG.fine("connecting...");
// TODO remove these traces
// System.err.println(getInitParameter()+" connecting");
final Map<String,Object> env = final Map<String,Object> env =
new HashMap<String,Object>(getEnvMap()); new HashMap<String,Object>(getEnvMap());
try { try {
...@@ -640,86 +607,16 @@ public class JMXRemoteNamespace ...@@ -640,86 +607,16 @@ public class JMXRemoteNamespace
msc = aconn.getMBeanServerConnection(); msc = aconn.getMBeanServerConnection();
aconn.addConnectionNotificationListener(listener,null,aconn); aconn.addConnectionNotificationListener(listener,null,aconn);
} catch (IOException io) { } catch (IOException io) {
closeall(aconn); close(aconn);
throw io; throw io;
} catch (RuntimeException x) { } catch (RuntimeException x) {
closeall(aconn); close(aconn);
throw x; throw x;
} }
// XXX Revisit here
// Note from the author: This business of switching connection is
// incredibly complex. Isn't there any means to simplify it?
//
switchConnection(conn,aconn,msc); switchConnection(conn,aconn,msc);
try {
triggerProbe(msc);
} catch(Exception x) {
close();
Throwable cause = x;
// if the cause is a security exception - rethrows it...
while (cause != null) {
if (cause instanceof SecurityException)
throw (SecurityException) cause;
cause = cause.getCause();
}
throw new IOException("connection failed: cycle?",x);
}
LOG.fine("connected.");
}
// If this is a self-linking namespace, this method should trigger LOG.fine("connected.");
// the emission of a probe in the wrapping NamespaceInterceptor.
// The first call to source() in the wrapping NamespaceInterceptor
// causes the emission of the probe.
//
// Note: the MBeanServer returned by getSourceServer
// (our private JMXRemoteNamespaceDelegate inner class)
// implements a sun private interface (DynamicProbe) which is
// used by the NamespaceInterceptor to determine whether it should
// send a probe or not.
// We needed this interface here because the NamespaceInterceptor
// has otherwise no means to knows that this object has just
// connected, and that a new probe should be sent.
//
// Probes work this way: the NamespaceInterceptor sets a flag and sends
// a queryNames() request. If a queryNames() request comes in when the flag
// is on, then it deduces that there is a self-linking loop - and instead
// of calling queryNames() on the JMXNamespace (which would cause the
// loop to go on) it breaks the recursion by returning the probe ObjectName.
// If the NamespaceInterceptor receives the probe ObjectName as result of
// its original queryNames() it knows that it has been looping back on
// itslef and throws an Exception - which will be raised through this
// method, thus preventing the connection to be established...
//
// More info in the com.sun.jmx.namespace.NamespaceInterceptor class
//
// XXX: TODO this probe thing is way too complex and fragile.
// This *must* go away or be replaced by something simpler.
// ideas are welcomed.
//
private void triggerProbe(final MBeanServerConnection msc)
throws MalformedObjectNameException, IOException {
// Query Pattern that we will send through the source server in order
// to detect self-linking namespaces.
//
//
final ObjectName pattern;
pattern = ObjectName.getInstance("*" +
JMXNamespaces.NAMESPACE_SEPARATOR + ":" +
JMXNamespace.TYPE_ASSIGNMENT);
probed = false;
try {
msc.queryNames(pattern, null);
probed = true;
} catch (AccessControlException x) {
// if we have an MBeanPermission missing then do nothing...
if (!(x.getPermission() instanceof MBeanPermission))
throw x;
PROBE_LOG.finer("Can't check for cycles: " + x);
probed = false; // no need to do it again...
}
} }
public void close() throws IOException { public void close() throws IOException {
......
...@@ -28,7 +28,6 @@ package javax.management.namespace; ...@@ -28,7 +28,6 @@ package javax.management.namespace;
import com.sun.jmx.mbeanserver.Util; import com.sun.jmx.mbeanserver.Util;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.security.AccessController;
import java.util.Set; import java.util.Set;
import javax.management.Attribute; import javax.management.Attribute;
......
...@@ -193,14 +193,6 @@ import javax.management.loading.ClassLoaderRepository; ...@@ -193,14 +193,6 @@ import javax.management.loading.ClassLoaderRepository;
* } * }
* *
* <a name="PropsMBS"></a>public class PropsMBS extends MBeanServerSupport { * <a name="PropsMBS"></a>public class PropsMBS extends MBeanServerSupport {
* private static ObjectName newObjectName(String name) {
* try {
* return new ObjectName(name);
* } catch (MalformedObjectNameException e) {
* throw new AssertionError(e);
* }
* }
*
* public static class PropertyImpl implements PropertyMBean { * public static class PropertyImpl implements PropertyMBean {
* private final String name; * private final String name;
* *
...@@ -219,7 +211,7 @@ import javax.management.loading.ClassLoaderRepository; ...@@ -219,7 +211,7 @@ import javax.management.loading.ClassLoaderRepository;
* throws InstanceNotFoundException { * throws InstanceNotFoundException {
* *
* // Check that the name is a legal one for a Property MBean * // Check that the name is a legal one for a Property MBean
* ObjectName namePattern = newObjectName( * ObjectName namePattern = ObjectName.valueOf(
* "com.example:type=Property,name=\"*\""); * "com.example:type=Property,name=\"*\"");
* if (!namePattern.apply(name)) * if (!namePattern.apply(name))
* throw new InstanceNotFoundException(name); * throw new InstanceNotFoundException(name);
...@@ -239,7 +231,7 @@ import javax.management.loading.ClassLoaderRepository; ...@@ -239,7 +231,7 @@ import javax.management.loading.ClassLoaderRepository;
* {@code Set<ObjectName> names = new TreeSet<ObjectName>();} * {@code Set<ObjectName> names = new TreeSet<ObjectName>();}
* Properties props = System.getProperties(); * Properties props = System.getProperties();
* for (String propName : props.stringPropertyNames()) { * for (String propName : props.stringPropertyNames()) {
* ObjectName objectName = newObjectName( * ObjectName objectName = ObjectName.valueOf(
* "com.example:type=Property,name=" + * "com.example:type=Property,name=" +
* ObjectName.quote(propName)); * ObjectName.quote(propName));
* names.add(objectName); * names.add(objectName);
...@@ -278,7 +270,7 @@ import javax.management.loading.ClassLoaderRepository; ...@@ -278,7 +270,7 @@ import javax.management.loading.ClassLoaderRepository;
* } * }
* *
* public void propertyChanged(String name, String newValue) { * public void propertyChanged(String name, String newValue) {
* ObjectName objectName = newObjectName( * ObjectName objectName = ObjectName.valueOf(
* "com.example:type=Property,name=" + ObjectName.quote(name)); * "com.example:type=Property,name=" + ObjectName.quote(name));
* Notification n = new Notification( * Notification n = new Notification(
* "com.example.property.changed", objectName, 0L, * "com.example.property.changed", objectName, 0L,
......
...@@ -420,7 +420,7 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable ...@@ -420,7 +420,7 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
new PerThreadGroupPool.Create<ThreadPoolExecutor>() { new PerThreadGroupPool.Create<ThreadPoolExecutor>() {
public ThreadPoolExecutor createThreadPool(ThreadGroup group) { public ThreadPoolExecutor createThreadPool(ThreadGroup group) {
ThreadFactory daemonThreadFactory = new DaemonThreadFactory( ThreadFactory daemonThreadFactory = new DaemonThreadFactory(
"RMIConnector listener dispatch %d"); "JMX RMIConnector listener dispatch %d");
ThreadPoolExecutor exec = new ThreadPoolExecutor( ThreadPoolExecutor exec = new ThreadPoolExecutor(
1, 10, 1, TimeUnit.SECONDS, 1, 10, 1, TimeUnit.SECONDS,
new LinkedBlockingDeque<Runnable>(), new LinkedBlockingDeque<Runnable>(),
......
...@@ -71,6 +71,6 @@ class ClassLoadingImpl implements ClassLoadingMXBean { ...@@ -71,6 +71,6 @@ class ClassLoadingImpl implements ClassLoadingMXBean {
native static void setVerboseClass(boolean value); native static void setVerboseClass(boolean value);
public ObjectName getObjectName() { public ObjectName getObjectName() {
return Util.newObjectName(ManagementFactory.CLASS_LOADING_MXBEAN_NAME); return ObjectName.valueOf(ManagementFactory.CLASS_LOADING_MXBEAN_NAME);
} }
} }
...@@ -70,7 +70,7 @@ class CompilationImpl implements CompilationMXBean { ...@@ -70,7 +70,7 @@ class CompilationImpl implements CompilationMXBean {
} }
public ObjectName getObjectName() { public ObjectName getObjectName() {
return Util.newObjectName(ManagementFactory.COMPILATION_MXBEAN_NAME); return ObjectName.valueOf(ManagementFactory.COMPILATION_MXBEAN_NAME);
} }
......
...@@ -117,6 +117,6 @@ public class HotSpotDiagnostic implements HotSpotDiagnosticMXBean { ...@@ -117,6 +117,6 @@ public class HotSpotDiagnostic implements HotSpotDiagnosticMXBean {
} }
public ObjectName getObjectName() { public ObjectName getObjectName() {
return Util.newObjectName("com.sun.management:type=HotSpotDiagnostic"); return ObjectName.valueOf("com.sun.management:type=HotSpotDiagnostic");
} }
} }
...@@ -41,7 +41,7 @@ public class HotspotInternal ...@@ -41,7 +41,7 @@ public class HotspotInternal
private final static String HOTSPOT_INTERNAL_MBEAN_NAME = private final static String HOTSPOT_INTERNAL_MBEAN_NAME =
"sun.management:type=HotspotInternal"; "sun.management:type=HotspotInternal";
private static ObjectName objName = Util.newObjectName(HOTSPOT_INTERNAL_MBEAN_NAME); private static ObjectName objName = ObjectName.valueOf(HOTSPOT_INTERNAL_MBEAN_NAME);
private MBeanServer server = null; private MBeanServer server = null;
/** /**
......
...@@ -220,7 +220,7 @@ public class ManagementFactoryHelper { ...@@ -220,7 +220,7 @@ public class ManagementFactoryHelper {
*/ */
private static void addMBean(MBeanServer mbs, Object mbean, String mbeanName) { private static void addMBean(MBeanServer mbs, Object mbean, String mbeanName) {
try { try {
final ObjectName objName = Util.newObjectName(mbeanName); final ObjectName objName = ObjectName.valueOf(mbeanName);
// inner class requires these fields to be final // inner class requires these fields to be final
final MBeanServer mbs0 = mbs; final MBeanServer mbs0 = mbs;
...@@ -280,7 +280,7 @@ public class ManagementFactoryHelper { ...@@ -280,7 +280,7 @@ public class ManagementFactoryHelper {
private static void unregisterMBean(MBeanServer mbs, String mbeanName) { private static void unregisterMBean(MBeanServer mbs, String mbeanName) {
try { try {
final ObjectName objName = Util.newObjectName(mbeanName); final ObjectName objName = ObjectName.valueOf(mbeanName);
// inner class requires these fields to be final // inner class requires these fields to be final
final MBeanServer mbs0 = mbs; final MBeanServer mbs0 = mbs;
......
...@@ -177,7 +177,7 @@ class MemoryImpl extends NotificationEmitterSupport ...@@ -177,7 +177,7 @@ class MemoryImpl extends NotificationEmitterSupport
} }
public ObjectName getObjectName() { public ObjectName getObjectName() {
return Util.newObjectName(ManagementFactory.MEMORY_MXBEAN_NAME); return ObjectName.valueOf(ManagementFactory.MEMORY_MXBEAN_NAME);
} }
} }
...@@ -74,7 +74,7 @@ public class OperatingSystemImpl implements OperatingSystemMXBean { ...@@ -74,7 +74,7 @@ public class OperatingSystemImpl implements OperatingSystemMXBean {
} }
} }
public ObjectName getObjectName() { public ObjectName getObjectName() {
return Util.newObjectName(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME); return ObjectName.valueOf(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME);
} }
} }
......
...@@ -149,7 +149,7 @@ class RuntimeImpl implements RuntimeMXBean { ...@@ -149,7 +149,7 @@ class RuntimeImpl implements RuntimeMXBean {
} }
public ObjectName getObjectName() { public ObjectName getObjectName() {
return Util.newObjectName(ManagementFactory.RUNTIME_MXBEAN_NAME); return ObjectName.valueOf(ManagementFactory.RUNTIME_MXBEAN_NAME);
} }
} }
...@@ -415,7 +415,7 @@ class ThreadImpl implements ThreadMXBean { ...@@ -415,7 +415,7 @@ class ThreadImpl implements ThreadMXBean {
private static native void resetContentionTimes0(long tid); private static native void resetContentionTimes0(long tid);
public ObjectName getObjectName() { public ObjectName getObjectName() {
return Util.newObjectName(ManagementFactory.THREAD_MXBEAN_NAME); return ObjectName.valueOf(ManagementFactory.THREAD_MXBEAN_NAME);
} }
} }
......
...@@ -43,12 +43,8 @@ class Util { ...@@ -43,12 +43,8 @@ class Util {
return (String[]) list.toArray(EMPTY_STRING_ARRAY); return (String[]) list.toArray(EMPTY_STRING_ARRAY);
} }
static ObjectName newObjectName(String name) {
return com.sun.jmx.mbeanserver.Util.newObjectName(name);
}
public static ObjectName newObjectName(String domainAndType, String name) { public static ObjectName newObjectName(String domainAndType, String name) {
return newObjectName(domainAndType + ",name=" + name); return ObjectName.valueOf(domainAndType + ",name=" + name);
} }
private static ManagementPermission monitorPermission = private static ManagementPermission monitorPermission =
......
...@@ -73,6 +73,7 @@ class ChunkedOutputStream extends FilterOutputStream ...@@ -73,6 +73,7 @@ class ChunkedOutputStream extends FilterOutputStream
if (count == CHUNK_SIZE) { if (count == CHUNK_SIZE) {
writeChunk(); writeChunk();
} }
assert count < CHUNK_SIZE;
} }
public void write (byte[]b, int off, int len) throws IOException { public void write (byte[]b, int off, int len) throws IOException {
...@@ -86,20 +87,22 @@ class ChunkedOutputStream extends FilterOutputStream ...@@ -86,20 +87,22 @@ class ChunkedOutputStream extends FilterOutputStream
writeChunk(); writeChunk();
len -= remain; len -= remain;
off += remain; off += remain;
while (len > CHUNK_SIZE) { while (len >= CHUNK_SIZE) {
System.arraycopy (b,off,buf,OFFSET,CHUNK_SIZE); System.arraycopy (b,off,buf,OFFSET,CHUNK_SIZE);
len -= CHUNK_SIZE; len -= CHUNK_SIZE;
off += CHUNK_SIZE; off += CHUNK_SIZE;
count = CHUNK_SIZE; count = CHUNK_SIZE;
writeChunk(); writeChunk();
} }
pos = OFFSET;
} }
if (len > 0) { if (len > 0) {
System.arraycopy (b,off,buf,pos,len); System.arraycopy (b,off,buf,pos,len);
count += len; count += len;
pos += len; pos += len;
} }
if (count == CHUNK_SIZE) {
writeChunk();
}
} }
/** /**
......
...@@ -803,7 +803,7 @@ public class Config { ...@@ -803,7 +803,7 @@ public class Config {
for (int j = 0; j < line.length(); j++) { for (int j = 0; j < line.length(); j++) {
if (line.charAt(j) == '=') { if (line.charAt(j) == '=') {
int index; int index;
key = line.substring(0, j - 1).trim(); key = line.substring(0, j).trim();
if (! exists(key, keyVector)) { if (! exists(key, keyVector)) {
keyVector.addElement(key); keyVector.addElement(key);
nameVector = new Vector<String> (); nameVector = new Vector<String> ();
......
/* /*
* Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -29,12 +29,18 @@ import java.math.BigInteger; ...@@ -29,12 +29,18 @@ import java.math.BigInteger;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.Set; import java.util.Set;
import java.security.GeneralSecurityException;
import java.security.KeyFactory; import java.security.KeyFactory;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.SignatureException;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertPathValidatorException.BasicReason;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.security.cert.PKIXCertPathChecker; import java.security.cert.PKIXCertPathChecker;
import java.security.cert.CertPathValidatorException; import java.security.cert.PKIXReason;
import java.security.cert.TrustAnchor; import java.security.cert.TrustAnchor;
import java.security.interfaces.DSAParams; import java.security.interfaces.DSAParams;
import java.security.interfaces.DSAPublicKey; import java.security.interfaces.DSAPublicKey;
...@@ -152,11 +158,11 @@ class BasicChecker extends PKIXCertPathChecker { ...@@ -152,11 +158,11 @@ class BasicChecker extends PKIXCertPathChecker {
try { try {
cert.verify(prevPubKey, sigProvider); cert.verify(prevPubKey, sigProvider);
} catch (Exception e) { } catch (SignatureException e) {
if (debug != null) { throw new CertPathValidatorException
debug.println(e.getMessage()); (msg + " check failed", e, null, -1,
e.printStackTrace(); BasicReason.INVALID_SIGNATURE);
} } catch (GeneralSecurityException e) {
throw new CertPathValidatorException(msg + " check failed", e); throw new CertPathValidatorException(msg + " check failed", e);
} }
...@@ -176,12 +182,12 @@ class BasicChecker extends PKIXCertPathChecker { ...@@ -176,12 +182,12 @@ class BasicChecker extends PKIXCertPathChecker {
try { try {
cert.checkValidity(date); cert.checkValidity(date);
} catch (Exception e) { } catch (CertificateExpiredException e) {
if (debug != null) { throw new CertPathValidatorException
debug.println(e.getMessage()); (msg + " check failed", e, null, -1, BasicReason.EXPIRED);
e.printStackTrace(); } catch (CertificateNotYetValidException e) {
} throw new CertPathValidatorException
throw new CertPathValidatorException(msg + " check failed", e); (msg + " check failed", e, null, -1, BasicReason.NOT_YET_VALID);
} }
if (debug != null) if (debug != null)
...@@ -204,12 +210,16 @@ class BasicChecker extends PKIXCertPathChecker { ...@@ -204,12 +210,16 @@ class BasicChecker extends PKIXCertPathChecker {
// reject null or empty issuer DNs // reject null or empty issuer DNs
if (X500Name.asX500Name(currIssuer).isEmpty()) { if (X500Name.asX500Name(currIssuer).isEmpty()) {
throw new CertPathValidatorException(msg + " check failed: " + throw new CertPathValidatorException
"empty/null issuer DN in certificate is invalid"); (msg + " check failed: " +
"empty/null issuer DN in certificate is invalid", null,
null, -1, PKIXReason.NAME_CHAINING);
} }
if (!(currIssuer.equals(prevSubject))) { if (!(currIssuer.equals(prevSubject))) {
throw new CertPathValidatorException(msg + " check failed"); throw new CertPathValidatorException
(msg + " check failed", null, null, -1,
PKIXReason.NAME_CHAINING);
} }
if (debug != null) if (debug != null)
...@@ -270,7 +280,7 @@ class BasicChecker extends PKIXCertPathChecker { ...@@ -270,7 +280,7 @@ class BasicChecker extends PKIXCertPathChecker {
params.getQ(), params.getQ(),
params.getG()); params.getG());
usableKey = kf.generatePublic(ks); usableKey = kf.generatePublic(ks);
} catch (Exception e) { } catch (GeneralSecurityException e) {
throw new CertPathValidatorException("Unable to generate key with" + throw new CertPathValidatorException("Unable to generate key with" +
" inherited parameters: " + " inherited parameters: " +
e.getMessage(), e); e.getMessage(), e);
......
/* /*
* Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -32,9 +32,10 @@ import java.util.HashSet; ...@@ -32,9 +32,10 @@ import java.util.HashSet;
import java.io.IOException; import java.io.IOException;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.CertPathValidatorException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.security.cert.PKIXCertPathChecker; import java.security.cert.PKIXCertPathChecker;
import java.security.cert.CertPathValidatorException; import java.security.cert.PKIXReason;
import sun.security.util.Debug; import sun.security.util.Debug;
import sun.security.x509.PKIXExtensions; import sun.security.x509.PKIXExtensions;
import sun.security.x509.NameConstraintsExtension; import sun.security.x509.NameConstraintsExtension;
...@@ -147,7 +148,8 @@ class ConstraintsChecker extends PKIXCertPathChecker { ...@@ -147,7 +148,8 @@ class ConstraintsChecker extends PKIXCertPathChecker {
try { try {
if (!prevNC.verify(currCert)) { if (!prevNC.verify(currCert)) {
throw new CertPathValidatorException(msg + " check failed"); throw new CertPathValidatorException(msg + " check failed",
null, null, -1, PKIXReason.INVALID_NAME);
} }
} catch (IOException ioe) { } catch (IOException ioe) {
throw new CertPathValidatorException(ioe); throw new CertPathValidatorException(ioe);
...@@ -228,8 +230,9 @@ class ConstraintsChecker extends PKIXCertPathChecker { ...@@ -228,8 +230,9 @@ class ConstraintsChecker extends PKIXCertPathChecker {
if (i < certPathLength) { if (i < certPathLength) {
int pathLenConstraint = currCert.getBasicConstraints(); int pathLenConstraint = currCert.getBasicConstraints();
if (pathLenConstraint == -1) { if (pathLenConstraint == -1) {
throw new CertPathValidatorException(msg + " check failed: " throw new CertPathValidatorException
+ "this is not a CA certificate"); (msg + " check failed: this is not a CA certificate", null,
null, -1, PKIXReason.NOT_CA_CERT);
} }
if (!X509CertImpl.isSelfIssued(currCert)) { if (!X509CertImpl.isSelfIssued(currCert)) {
...@@ -237,7 +240,8 @@ class ConstraintsChecker extends PKIXCertPathChecker { ...@@ -237,7 +240,8 @@ class ConstraintsChecker extends PKIXCertPathChecker {
throw new CertPathValidatorException throw new CertPathValidatorException
(msg + " check failed: pathLenConstraint violated - " (msg + " check failed: pathLenConstraint violated - "
+ "this cert must be the last cert in the " + "this cert must be the last cert in the "
+ "certification path"); + "certification path", null, null, -1,
PKIXReason.PATH_TOO_LONG);
} }
maxPathLength--; maxPathLength--;
} }
......
/* /*
* Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -39,6 +39,7 @@ import java.security.InvalidAlgorithmParameterException; ...@@ -39,6 +39,7 @@ import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.cert.*; import java.security.cert.*;
import java.security.cert.CertPathValidatorException.BasicReason;
import java.security.interfaces.DSAPublicKey; import java.security.interfaces.DSAPublicKey;
import javax.security.auth.x500.X500Principal; import javax.security.auth.x500.X500Principal;
import sun.security.util.Debug; import sun.security.util.Debug;
...@@ -268,7 +269,8 @@ class CrlRevocationChecker extends PKIXCertPathChecker { ...@@ -268,7 +269,8 @@ class CrlRevocationChecker extends PKIXCertPathChecker {
" circular dependency"); " circular dependency");
} }
throw new CertPathValidatorException throw new CertPathValidatorException
("Could not determine revocation status"); ("Could not determine revocation status", null, null, -1,
BasicReason.UNDETERMINED_REVOCATION_STATUS);
} }
// init the state for this run // init the state for this run
...@@ -324,7 +326,8 @@ class CrlRevocationChecker extends PKIXCertPathChecker { ...@@ -324,7 +326,8 @@ class CrlRevocationChecker extends PKIXCertPathChecker {
return; return;
} else { } else {
throw new CertPathValidatorException throw new CertPathValidatorException
("Could not determine revocation status"); ("Could not determine revocation status", null, null, -1,
BasicReason.UNDETERMINED_REVOCATION_STATUS);
} }
} }
...@@ -370,7 +373,8 @@ class CrlRevocationChecker extends PKIXCertPathChecker { ...@@ -370,7 +373,8 @@ class CrlRevocationChecker extends PKIXCertPathChecker {
+ unresCritExts); + unresCritExts);
} }
throw new CertPathValidatorException throw new CertPathValidatorException
("Could not determine revocation status"); ("Could not determine revocation status", null, null,
-1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
} }
} }
...@@ -378,10 +382,11 @@ class CrlRevocationChecker extends PKIXCertPathChecker { ...@@ -378,10 +382,11 @@ class CrlRevocationChecker extends PKIXCertPathChecker {
if (reasonCode == null) { if (reasonCode == null) {
reasonCode = CRLReason.UNSPECIFIED; reasonCode = CRLReason.UNSPECIFIED;
} }
throw new CertPathValidatorException( Throwable t = new CertificateRevokedException
new CertificateRevokedException (entry.getRevocationDate(), reasonCode,
(entry.getRevocationDate(), reasonCode, crl.getIssuerX500Principal(), entry.getExtensions());
crl.getIssuerX500Principal(), entry.getExtensions())); throw new CertPathValidatorException(t.getMessage(), t,
null, -1, BasicReason.REVOKED);
} }
} }
} }
...@@ -428,7 +433,8 @@ class CrlRevocationChecker extends PKIXCertPathChecker { ...@@ -428,7 +433,8 @@ class CrlRevocationChecker extends PKIXCertPathChecker {
" circular dependency"); " circular dependency");
} }
throw new CertPathValidatorException throw new CertPathValidatorException
("Could not determine revocation status"); ("Could not determine revocation status", null, null,
-1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
} }
// If prevKey wasn't trusted, maybe we just didn't have the right // If prevKey wasn't trusted, maybe we just didn't have the right
...@@ -617,7 +623,7 @@ class CrlRevocationChecker extends PKIXCertPathChecker { ...@@ -617,7 +623,7 @@ class CrlRevocationChecker extends PKIXCertPathChecker {
return; return;
} catch (CertPathValidatorException cpve) { } catch (CertPathValidatorException cpve) {
// If it is revoked, rethrow exception // If it is revoked, rethrow exception
if (cpve.getCause() instanceof CertificateRevokedException) { if (cpve.getReason() == BasicReason.REVOKED) {
throw cpve; throw cpve;
} }
// Otherwise, ignore the exception and // Otherwise, ignore the exception and
...@@ -628,7 +634,8 @@ class CrlRevocationChecker extends PKIXCertPathChecker { ...@@ -628,7 +634,8 @@ class CrlRevocationChecker extends PKIXCertPathChecker {
throw new CertPathValidatorException(iape); throw new CertPathValidatorException(iape);
} catch (CertPathBuilderException cpbe) { } catch (CertPathBuilderException cpbe) {
throw new CertPathValidatorException throw new CertPathValidatorException
("Could not determine revocation status", cpbe); ("Could not determine revocation status", null, null,
-1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
} }
} }
} }
......
...@@ -32,6 +32,7 @@ import java.security.GeneralSecurityException; ...@@ -32,6 +32,7 @@ import java.security.GeneralSecurityException;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.CertPathValidatorException; import java.security.cert.CertPathValidatorException;
import java.security.cert.PKIXReason;
import java.security.cert.CertStore; import java.security.cert.CertStore;
import java.security.cert.CertStoreException; import java.security.cert.CertStoreException;
import java.security.cert.PKIXBuilderParameters; import java.security.cert.PKIXBuilderParameters;
...@@ -732,8 +733,9 @@ class ForwardBuilder extends Builder { ...@@ -732,8 +733,9 @@ class ForwardBuilder extends Builder {
PKIXExtensions.ExtendedKeyUsage_Id.toString()); PKIXExtensions.ExtendedKeyUsage_Id.toString());
if (!unresCritExts.isEmpty()) if (!unresCritExts.isEmpty())
throw new CertificateException("Unrecognized critical " throw new CertPathValidatorException
+ "extension(s)"); ("Unrecognized critical extension(s)", null, null, -1,
PKIXReason.UNRECOGNIZED_CRIT_EXT);
} }
} }
......
/* /*
* Copyright 2000-2003 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -27,6 +27,7 @@ package sun.security.provider.certpath; ...@@ -27,6 +27,7 @@ package sun.security.provider.certpath;
import java.util.*; import java.util.*;
import java.security.cert.*; import java.security.cert.*;
import java.security.cert.PKIXReason;
import sun.security.util.Debug; import sun.security.util.Debug;
import sun.security.x509.PKIXExtensions; import sun.security.x509.PKIXExtensions;
...@@ -75,11 +76,12 @@ class KeyChecker extends PKIXCertPathChecker { ...@@ -75,11 +76,12 @@ class KeyChecker extends PKIXCertPathChecker {
if (!forward) { if (!forward) {
remainingCerts = certPathLen; remainingCerts = certPathLen;
} else { } else {
throw new CertPathValidatorException("forward checking not supported"); throw new CertPathValidatorException
("forward checking not supported");
} }
} }
public boolean isForwardCheckingSupported() { public final boolean isForwardCheckingSupported() {
return false; return false;
} }
...@@ -155,8 +157,9 @@ class KeyChecker extends PKIXCertPathChecker { ...@@ -155,8 +157,9 @@ class KeyChecker extends PKIXCertPathChecker {
// throw an exception if the keyCertSign bit is not set // throw an exception if the keyCertSign bit is not set
if (!keyUsageBits[keyCertSign]) { if (!keyUsageBits[keyCertSign]) {
throw new CertPathValidatorException(msg + " check failed: " throw new CertPathValidatorException
+ "keyCertSign bit is not set"); (msg + " check failed: keyCertSign bit is not set", null,
null, -1, PKIXReason.INVALID_KEY_USAGE);
} }
if (debug != null) { if (debug != null) {
......
...@@ -33,6 +33,7 @@ import java.security.Principal; ...@@ -33,6 +33,7 @@ import java.security.Principal;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.security.Security; import java.security.Security;
import java.security.cert.*; import java.security.cert.*;
import java.security.cert.CertPathValidatorException.BasicReason;
import java.net.*; import java.net.*;
import javax.security.auth.x500.X500Principal; import javax.security.auth.x500.X500Principal;
...@@ -381,17 +382,18 @@ class OCSPChecker extends PKIXCertPathChecker { ...@@ -381,17 +382,18 @@ class OCSPChecker extends PKIXCertPathChecker {
} }
if (certOCSPStatus == OCSPResponse.CERT_STATUS_REVOKED) { if (certOCSPStatus == OCSPResponse.CERT_STATUS_REVOKED) {
throw new CertPathValidatorException( Throwable t = new CertificateRevokedException(
new CertificateRevokedException(
ocspResponse.getRevocationTime(), ocspResponse.getRevocationTime(),
ocspResponse.getRevocationReason(), ocspResponse.getRevocationReason(),
responderCert.getSubjectX500Principal(), responderCert.getSubjectX500Principal(),
ocspResponse.getSingleExtensions())); ocspResponse.getSingleExtensions());
throw new CertPathValidatorException(t.getMessage(), t,
null, -1, BasicReason.REVOKED);
} else if (certOCSPStatus == OCSPResponse.CERT_STATUS_UNKNOWN) { } else if (certOCSPStatus == OCSPResponse.CERT_STATUS_UNKNOWN) {
throw new CertPathValidatorException( throw new CertPathValidatorException(
"Certificate's revocation status is unknown", null, cp, "Certificate's revocation status is unknown", null, cp,
remainingCerts); remainingCerts, BasicReason.UNDETERMINED_REVOCATION_STATUS);
} }
} catch (Exception e) { } catch (Exception e) {
throw new CertPathValidatorException(e); throw new CertPathValidatorException(e);
......
/* /*
* Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -38,6 +38,7 @@ import java.security.cert.CertPathValidatorResult; ...@@ -38,6 +38,7 @@ import java.security.cert.CertPathValidatorResult;
import java.security.cert.PKIXCertPathChecker; import java.security.cert.PKIXCertPathChecker;
import java.security.cert.PKIXCertPathValidatorResult; import java.security.cert.PKIXCertPathValidatorResult;
import java.security.cert.PKIXParameters; import java.security.cert.PKIXParameters;
import java.security.cert.PKIXReason;
import java.security.cert.PolicyNode; import java.security.cert.PolicyNode;
import java.security.cert.TrustAnchor; import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
...@@ -47,7 +48,6 @@ import java.util.List; ...@@ -47,7 +48,6 @@ import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.Set; import java.util.Set;
import java.util.HashSet;
import javax.security.auth.x500.X500Principal; import javax.security.auth.x500.X500Principal;
import sun.security.util.Debug; import sun.security.util.Debug;
...@@ -67,6 +67,7 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi { ...@@ -67,6 +67,7 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi {
private List<PKIXCertPathChecker> userCheckers; private List<PKIXCertPathChecker> userCheckers;
private String sigProvider; private String sigProvider;
private BasicChecker basicChecker; private BasicChecker basicChecker;
private String ocspProperty;
/** /**
* Default constructor. * Default constructor.
...@@ -126,7 +127,7 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi { ...@@ -126,7 +127,7 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi {
// Must copy elements of certList into a new modifiable List before // Must copy elements of certList into a new modifiable List before
// calling Collections.reverse(). // calling Collections.reverse().
List<X509Certificate> certList = new ArrayList<X509Certificate> ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>
((List<X509Certificate>)cp.getCertificates()); ((List<X509Certificate>)cp.getCertificates());
if (debug != null) { if (debug != null) {
if (certList.isEmpty()) { if (certList.isEmpty()) {
...@@ -201,7 +202,8 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi { ...@@ -201,7 +202,8 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi {
} }
// (b) otherwise, generate new exception // (b) otherwise, generate new exception
throw new CertPathValidatorException throw new CertPathValidatorException
("Path does not chain with any of the trust anchors"); ("Path does not chain with any of the trust anchors",
null, null, -1, PKIXReason.NO_TRUST_ANCHOR);
} }
/** /**
...@@ -210,7 +212,6 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi { ...@@ -210,7 +212,6 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi {
*/ */
private boolean isWorthTrying(X509Certificate trustedCert, private boolean isWorthTrying(X509Certificate trustedCert,
X509Certificate firstCert) X509Certificate firstCert)
throws CertPathValidatorException
{ {
if (debug != null) { if (debug != null) {
debug.println("PKIXCertPathValidator.isWorthTrying() checking " debug.println("PKIXCertPathValidator.isWorthTrying() checking "
...@@ -240,7 +241,6 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi { ...@@ -240,7 +241,6 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi {
* Internal method to setup the internal state * Internal method to setup the internal state
*/ */
private void populateVariables(PKIXParameters pkixParam) private void populateVariables(PKIXParameters pkixParam)
throws CertPathValidatorException
{ {
// default value for testDate is current time // default value for testDate is current time
testDate = pkixParam.getDate(); testDate = pkixParam.getDate();
...@@ -250,6 +250,17 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi { ...@@ -250,6 +250,17 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi {
userCheckers = pkixParam.getCertPathCheckers(); userCheckers = pkixParam.getCertPathCheckers();
sigProvider = pkixParam.getSigProvider(); sigProvider = pkixParam.getSigProvider();
if (pkixParam.isRevocationEnabled()) {
// Examine OCSP security property
ocspProperty = AccessController.doPrivileged(
new PrivilegedAction<String>() {
public String run() {
return
Security.getProperty(OCSPChecker.OCSP_ENABLE_PROP);
}
});
}
} }
/** /**
...@@ -259,12 +270,9 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi { ...@@ -259,12 +270,9 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi {
*/ */
private PolicyNode doValidate( private PolicyNode doValidate(
TrustAnchor anchor, CertPath cpOriginal, TrustAnchor anchor, CertPath cpOriginal,
List<X509Certificate> certList, PKIXParameters pkixParam, ArrayList<X509Certificate> certList, PKIXParameters pkixParam,
PolicyNodeImpl rootNode) throws CertPathValidatorException PolicyNodeImpl rootNode) throws CertPathValidatorException
{ {
List<PKIXCertPathChecker> certPathCheckers =
new ArrayList<PKIXCertPathChecker>();
int certPathLen = certList.size(); int certPathLen = certList.size();
basicChecker = new BasicChecker(anchor, testDate, sigProvider, false); basicChecker = new BasicChecker(anchor, testDate, sigProvider, false);
...@@ -281,6 +289,8 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi { ...@@ -281,6 +289,8 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi {
pkixParam.getPolicyQualifiersRejected(), pkixParam.getPolicyQualifiersRejected(),
rootNode); rootNode);
ArrayList<PKIXCertPathChecker> certPathCheckers =
new ArrayList<PKIXCertPathChecker>();
// add standard checkers that we will be using // add standard checkers that we will be using
certPathCheckers.add(keyChecker); certPathCheckers.add(keyChecker);
certPathCheckers.add(constraintsChecker); certPathCheckers.add(constraintsChecker);
...@@ -290,15 +300,6 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi { ...@@ -290,15 +300,6 @@ public class PKIXCertPathValidator extends CertPathValidatorSpi {
// only add a revocationChecker if revocation is enabled // only add a revocationChecker if revocation is enabled
if (pkixParam.isRevocationEnabled()) { if (pkixParam.isRevocationEnabled()) {
// Examine OCSP security property
String ocspProperty = AccessController.doPrivileged(
new PrivilegedAction<String>() {
public String run() {
return
Security.getProperty(OCSPChecker.OCSP_ENABLE_PROP);
}
});
// Use OCSP if it has been enabled // Use OCSP if it has been enabled
if ("true".equalsIgnoreCase(ocspProperty)) { if ("true".equalsIgnoreCase(ocspProperty)) {
OCSPChecker ocspChecker = OCSPChecker ocspChecker =
......
/* /*
* Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -30,11 +30,12 @@ import sun.security.util.Debug; ...@@ -30,11 +30,12 @@ import sun.security.util.Debug;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.Iterator; import java.security.cert.CertificateRevokedException;
import java.security.cert.CertPath; import java.security.cert.CertPath;
import java.security.cert.CertPathValidatorException; import java.security.cert.CertPathValidatorException;
import java.security.cert.CertificateRevokedException; import java.security.cert.CertPathValidatorException.BasicReason;
import java.security.cert.PKIXCertPathChecker; import java.security.cert.PKIXCertPathChecker;
import java.security.cert.PKIXReason;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
/** /**
...@@ -153,10 +154,11 @@ class PKIXMasterCertPathValidator { ...@@ -153,10 +154,11 @@ class PKIXMasterCertPathValidator {
*/ */
CertPathValidatorException currentCause = CertPathValidatorException currentCause =
new CertPathValidatorException(cpve.getMessage(), new CertPathValidatorException(cpve.getMessage(),
cpve.getCause(), cpOriginal, cpSize - (i + 1)); cpve.getCause(), cpOriginal, cpSize - (i + 1),
cpve.getReason());
// Check if OCSP has confirmed that the cert was revoked // Check if OCSP has confirmed that the cert was revoked
if (cpve.getCause() instanceof CertificateRevokedException) { if (cpve.getReason() == BasicReason.REVOKED) {
throw currentCause; throw currentCause;
} }
// Check if it is appropriate to failover // Check if it is appropriate to failover
...@@ -184,7 +186,8 @@ class PKIXMasterCertPathValidator { ...@@ -184,7 +186,8 @@ class PKIXMasterCertPathValidator {
debug.println("checking for unresolvedCritExts"); debug.println("checking for unresolvedCritExts");
if (!unresolvedCritExts.isEmpty()) { if (!unresolvedCritExts.isEmpty()) {
throw new CertPathValidatorException("unrecognized " + throw new CertPathValidatorException("unrecognized " +
"critical extension(s)", null, cpOriginal, cpSize-(i+1)); "critical extension(s)", null, cpOriginal, cpSize-(i+1),
PKIXReason.UNRECOGNIZED_CRIT_EXT);
} }
if (debug != null) if (debug != null)
......
/* /*
* Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -30,11 +30,12 @@ import java.io.IOException; ...@@ -30,11 +30,12 @@ import java.io.IOException;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.cert.PKIXCertPathChecker;
import java.security.cert.CertPathValidatorException; import java.security.cert.CertPathValidatorException;
import java.security.cert.PKIXCertPathChecker;
import java.security.cert.PKIXReason;
import java.security.cert.PolicyNode; import java.security.cert.PolicyNode;
import java.security.cert.PolicyQualifierInfo; import java.security.cert.PolicyQualifierInfo;
import java.security.cert.X509Certificate;
import sun.security.util.Debug; import sun.security.util.Debug;
import sun.security.x509.CertificatePoliciesExtension; import sun.security.x509.CertificatePoliciesExtension;
...@@ -482,8 +483,9 @@ class PolicyChecker extends PKIXCertPathChecker { ...@@ -482,8 +483,9 @@ class PolicyChecker extends PKIXCertPathChecker {
// the policyQualifiersRejected flag is set in the params // the policyQualifiersRejected flag is set in the params
if (!pQuals.isEmpty() && rejectPolicyQualifiers && if (!pQuals.isEmpty() && rejectPolicyQualifiers &&
policiesCritical) { policiesCritical) {
throw new CertPathValidatorException("critical " + throw new CertPathValidatorException(
"policy qualifiers present in certificate"); "critical policy qualifiers present in certificate",
null, null, -1, PKIXReason.INVALID_POLICY);
} }
// PKIX: Section 6.1.3: Step (d)(1)(i) // PKIX: Section 6.1.3: Step (d)(1)(i)
...@@ -567,7 +569,8 @@ class PolicyChecker extends PKIXCertPathChecker { ...@@ -567,7 +569,8 @@ class PolicyChecker extends PKIXCertPathChecker {
if ((explicitPolicy == 0) && (rootNode == null)) { if ((explicitPolicy == 0) && (rootNode == null)) {
throw new CertPathValidatorException throw new CertPathValidatorException
("non-null policy tree required and policy tree is null"); ("non-null policy tree required and policy tree is null",
null, null, -1, PKIXReason.INVALID_POLICY);
} }
return rootNode; return rootNode;
...@@ -776,12 +779,14 @@ class PolicyChecker extends PKIXCertPathChecker { ...@@ -776,12 +779,14 @@ class PolicyChecker extends PKIXCertPathChecker {
if (issuerDomain.equals(ANY_POLICY)) { if (issuerDomain.equals(ANY_POLICY)) {
throw new CertPathValidatorException throw new CertPathValidatorException
("encountered an issuerDomainPolicy of ANY_POLICY"); ("encountered an issuerDomainPolicy of ANY_POLICY",
null, null, -1, PKIXReason.INVALID_POLICY);
} }
if (subjectDomain.equals(ANY_POLICY)) { if (subjectDomain.equals(ANY_POLICY)) {
throw new CertPathValidatorException throw new CertPathValidatorException
("encountered a subjectDomainPolicy of ANY_POLICY"); ("encountered a subjectDomainPolicy of ANY_POLICY",
null, null, -1, PKIXReason.INVALID_POLICY);
} }
Set<PolicyNodeImpl> validNodes = Set<PolicyNodeImpl> validNodes =
......
/* /*
* Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -29,14 +29,15 @@ import java.io.IOException; ...@@ -29,14 +29,15 @@ import java.io.IOException;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.security.Principal; import java.security.Principal;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.cert.CertPathValidatorException; import java.security.cert.CertPathValidatorException;
import java.security.cert.CertStore; import java.security.cert.CertStore;
import java.security.cert.CertStoreException; import java.security.cert.CertStoreException;
import java.security.cert.PKIXBuilderParameters; import java.security.cert.PKIXBuilderParameters;
import java.security.cert.PKIXCertPathChecker; import java.security.cert.PKIXCertPathChecker;
import java.security.cert.PKIXParameters; import java.security.cert.PKIXParameters;
import java.security.cert.PKIXReason;
import java.security.cert.TrustAnchor; import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
import java.security.cert.X509CertSelector; import java.security.cert.X509CertSelector;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
...@@ -402,7 +403,8 @@ class ReverseBuilder extends Builder { ...@@ -402,7 +403,8 @@ class ReverseBuilder extends Builder {
*/ */
if ((currentState.remainingCACerts <= 0) && !X509CertImpl.isSelfIssued(cert)) { if ((currentState.remainingCACerts <= 0) && !X509CertImpl.isSelfIssued(cert)) {
throw new CertPathValidatorException throw new CertPathValidatorException
("pathLenConstraint violated, path too long"); ("pathLenConstraint violated, path too long", null,
null, -1, PKIXReason.PATH_TOO_LONG);
} }
/* /*
...@@ -438,7 +440,8 @@ class ReverseBuilder extends Builder { ...@@ -438,7 +440,8 @@ class ReverseBuilder extends Builder {
try { try {
if (!currentState.nc.verify(cert)){ if (!currentState.nc.verify(cert)){
throw new CertPathValidatorException throw new CertPathValidatorException
("name constraints check failed"); ("name constraints check failed", null, null, -1,
PKIXReason.INVALID_NAME);
} }
} catch (IOException ioe){ } catch (IOException ioe){
throw new CertPathValidatorException(ioe); throw new CertPathValidatorException(ioe);
...@@ -483,7 +486,9 @@ class ReverseBuilder extends Builder { ...@@ -483,7 +486,9 @@ class ReverseBuilder extends Builder {
unresolvedCritExts.remove(PKIXExtensions.ExtendedKeyUsage_Id.toString()); unresolvedCritExts.remove(PKIXExtensions.ExtendedKeyUsage_Id.toString());
if (!unresolvedCritExts.isEmpty()) if (!unresolvedCritExts.isEmpty())
throw new CertificateException("Unrecognized critical extension(s)"); throw new CertPathValidatorException
("Unrecognized critical extension(s)", null, null, -1,
PKIXReason.UNRECOGNIZED_CRIT_EXT);
} }
/* /*
......
/* /*
* Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -30,6 +30,9 @@ import java.security.GeneralSecurityException; ...@@ -30,6 +30,9 @@ import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException; import java.security.InvalidAlgorithmParameterException;
import java.security.Principal; import java.security.Principal;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.cert.*;
import java.security.cert.PKIXReason;
import java.security.interfaces.DSAPublicKey;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
...@@ -39,10 +42,6 @@ import java.util.Iterator; ...@@ -39,10 +42,6 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Set; import java.util.Set;
import java.security.cert.*;
import java.security.interfaces.DSAPublicKey;
import javax.security.auth.x500.X500Principal; import javax.security.auth.x500.X500Principal;
import sun.security.x509.X500Name; import sun.security.x509.X500Name;
...@@ -565,8 +564,9 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi { ...@@ -565,8 +564,9 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi {
(PKIXExtensions.ExtendedKeyUsage_Id.toString()); (PKIXExtensions.ExtendedKeyUsage_Id.toString());
if (!unresCritExts.isEmpty()) { if (!unresCritExts.isEmpty()) {
throw new CertPathValidatorException("unrecognized " throw new CertPathValidatorException
+ "critical extension(s)"); ("unrecognized critical extension(s)", null,
null, -1, PKIXReason.UNRECOGNIZED_CRIT_EXT);
} }
} }
} }
......
...@@ -30,18 +30,15 @@ import java.awt.event.*; ...@@ -30,18 +30,15 @@ import java.awt.event.*;
import java.beans.*; import java.beans.*;
import java.io.*; import java.io.*;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.text.*;
import java.util.*; import java.util.*;
import javax.accessibility.*; import javax.accessibility.*;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.*; import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.filechooser.*; import javax.swing.filechooser.*;
import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileFilter;
import com.sun.tools.jconsole.JConsoleContext; import com.sun.tools.jconsole.JConsoleContext;
import com.sun.tools.jconsole.JConsoleContext.ConnectionState;
import static com.sun.tools.jconsole.JConsoleContext.ConnectionState.*; import static com.sun.tools.jconsole.JConsoleContext.ConnectionState.*;
...@@ -130,6 +127,7 @@ public class Plotter extends JComponent ...@@ -130,6 +127,7 @@ public class Plotter extends JComponent
private int bottomMargin = 45; private int bottomMargin = 45;
private int leftMargin = 65; private int leftMargin = 65;
private int rightMargin = 70; private int rightMargin = 70;
private final boolean displayLegend;
public Plotter() { public Plotter() {
this(Unit.NONE, 0); this(Unit.NONE, 0);
...@@ -139,15 +137,21 @@ public class Plotter extends JComponent ...@@ -139,15 +137,21 @@ public class Plotter extends JComponent
this(unit, 0); this(unit, 0);
} }
public Plotter(Unit unit, int decimals) {
this(unit,decimals,true);
}
// Note: If decimals > 0 then values must be decimally shifted left // Note: If decimals > 0 then values must be decimally shifted left
// that many places, i.e. multiplied by Math.pow(10.0, decimals). // that many places, i.e. multiplied by Math.pow(10.0, decimals).
public Plotter(Unit unit, int decimals) { public Plotter(Unit unit, int decimals, boolean displayLegend) {
this.displayLegend = displayLegend;
setUnit(unit); setUnit(unit);
setDecimals(decimals); setDecimals(decimals);
enableEvents(AWTEvent.MOUSE_EVENT_MASK); enableEvents(AWTEvent.MOUSE_EVENT_MASK);
addMouseListener(new MouseAdapter() { addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) { public void mousePressed(MouseEvent e) {
if (getParent() instanceof PlotterPanel) { if (getParent() instanceof PlotterPanel) {
getParent().requestFocusInWindow(); getParent().requestFocusInWindow();
...@@ -240,6 +244,7 @@ public class Plotter extends JComponent ...@@ -240,6 +244,7 @@ public class Plotter extends JComponent
} }
} }
@Override
public JPopupMenu getComponentPopupMenu() { public JPopupMenu getComponentPopupMenu() {
if (popupMenu == null) { if (popupMenu == null) {
popupMenu = new JPopupMenu(Resources.getText("Chart:")); popupMenu = new JPopupMenu(Resources.getText("Chart:"));
...@@ -330,6 +335,7 @@ public class Plotter extends JComponent ...@@ -330,6 +335,7 @@ public class Plotter extends JComponent
} }
} }
@Override
public void paintComponent(Graphics g) { public void paintComponent(Graphics g) {
super.paintComponent(g); super.paintComponent(g);
...@@ -670,7 +676,7 @@ public class Plotter extends JComponent ...@@ -670,7 +676,7 @@ public class Plotter extends JComponent
curValue += "%"; curValue += "%";
} }
int valWidth = fm.stringWidth(curValue); int valWidth = fm.stringWidth(curValue);
String legend = seq.name; String legend = (displayLegend?seq.name:"");
int legendWidth = fm.stringWidth(legend); int legendWidth = fm.stringWidth(legend);
if (checkRightMargin(valWidth) || checkRightMargin(legendWidth)) { if (checkRightMargin(valWidth) || checkRightMargin(legendWidth)) {
// Wait for next repaint // Wait for next repaint
...@@ -986,10 +992,12 @@ public class Plotter extends JComponent ...@@ -986,10 +992,12 @@ public class Plotter extends JComponent
} }
private static class SaveDataFileChooser extends JFileChooser { private static class SaveDataFileChooser extends JFileChooser {
private static final long serialVersionUID = -5182890922369369669L;
SaveDataFileChooser() { SaveDataFileChooser() {
setFileFilter(new FileNameExtensionFilter("CSV file", "csv")); setFileFilter(new FileNameExtensionFilter("CSV file", "csv"));
} }
@Override
public void approveSelection() { public void approveSelection() {
File file = getSelectedFile(); File file = getSelectedFile();
if (file != null) { if (file != null) {
...@@ -1034,6 +1042,7 @@ public class Plotter extends JComponent ...@@ -1034,6 +1042,7 @@ public class Plotter extends JComponent
} }
} }
@Override
public AccessibleContext getAccessibleContext() { public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) { if (accessibleContext == null) {
accessibleContext = new AccessiblePlotter(); accessibleContext = new AccessiblePlotter();
...@@ -1042,10 +1051,12 @@ public class Plotter extends JComponent ...@@ -1042,10 +1051,12 @@ public class Plotter extends JComponent
} }
protected class AccessiblePlotter extends AccessibleJComponent { protected class AccessiblePlotter extends AccessibleJComponent {
private static final long serialVersionUID = -3847205410473510922L;
protected AccessiblePlotter() { protected AccessiblePlotter() {
setAccessibleName(getText("Plotter.accessibleName")); setAccessibleName(getText("Plotter.accessibleName"));
} }
@Override
public String getAccessibleName() { public String getAccessibleName() {
String name = super.getAccessibleName(); String name = super.getAccessibleName();
...@@ -1076,6 +1087,7 @@ public class Plotter extends JComponent ...@@ -1076,6 +1087,7 @@ public class Plotter extends JComponent
return name; return name;
} }
@Override
public AccessibleRole getAccessibleRole() { public AccessibleRole getAccessibleRole() {
return AccessibleRole.CANVAS; return AccessibleRole.CANVAS;
} }
......
...@@ -872,8 +872,8 @@ public class XMBeanAttributes extends XTable { ...@@ -872,8 +872,8 @@ public class XMBeanAttributes extends XTable {
MaximizedCellRenderer(Component comp) { MaximizedCellRenderer(Component comp) {
this.comp = comp; this.comp = comp;
Dimension d = comp.getPreferredSize(); Dimension d = comp.getPreferredSize();
if (d.getHeight() > 200) { if (d.getHeight() > 220) {
comp.setPreferredSize(new Dimension((int) d.getWidth(), 200)); comp.setPreferredSize(new Dimension((int) d.getWidth(), 220));
} }
} }
@Override @Override
......
...@@ -34,7 +34,7 @@ public class XPlotter extends Plotter { ...@@ -34,7 +34,7 @@ public class XPlotter extends Plotter {
JTable table; JTable table;
public XPlotter(JTable table, public XPlotter(JTable table,
Plotter.Unit unit) { Plotter.Unit unit) {
super(unit); super(unit,0,false);
this.table = table; this.table = table;
} }
@Override @Override
......
...@@ -27,14 +27,10 @@ package sun.tools.jconsole.inspector; ...@@ -27,14 +27,10 @@ package sun.tools.jconsole.inspector;
import java.awt.*; import java.awt.*;
import java.awt.event.*; import java.awt.event.*;
import java.io.*;
import java.util.*; import java.util.*;
import java.util.Timer; import java.util.Timer;
import javax.management.*;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import sun.tools.jconsole.*; import sun.tools.jconsole.*;
...@@ -127,6 +123,7 @@ public class XPlottingViewer extends PlotterPanel implements ActionListener { ...@@ -127,6 +123,7 @@ public class XPlottingViewer extends PlotterPanel implements ActionListener {
setBackground(g.getColor()); setBackground(g.getColor());
plotter.paintComponent(g); plotter.paintComponent(g);
}*/ }*/
@Override
public void actionPerformed(ActionEvent evt) { public void actionPerformed(ActionEvent evt) {
plotterCache.remove(key); plotterCache.remove(key);
Timer t = timerCache.remove(key); Timer t = timerCache.remove(key);
...@@ -141,9 +138,11 @@ public class XPlottingViewer extends PlotterPanel implements ActionListener { ...@@ -141,9 +138,11 @@ public class XPlottingViewer extends PlotterPanel implements ActionListener {
JTable table) { JTable table) {
final Plotter plotter = new XPlotter(table, Plotter.Unit.NONE) { final Plotter plotter = new XPlotter(table, Plotter.Unit.NONE) {
Dimension prefSize = new Dimension(400, 170); Dimension prefSize = new Dimension(400, 170);
@Override
public Dimension getPreferredSize() { public Dimension getPreferredSize() {
return prefSize; return prefSize;
} }
@Override
public Dimension getMinimumSize() { public Dimension getMinimumSize() {
return prefSize; return prefSize;
} }
...@@ -183,42 +182,40 @@ public class XPlottingViewer extends PlotterPanel implements ActionListener { ...@@ -183,42 +182,40 @@ public class XPlottingViewer extends PlotterPanel implements ActionListener {
return plotter; return plotter;
} }
//Create Plotter display
private void setupDisplay(Plotter plotter) { private void setupDisplay(Plotter plotter) {
//setLayout(new GridLayout(2,0)); final JPanel buttonPanel = new JPanel();
GridBagLayout gbl = new GridBagLayout(); final GridBagLayout gbl = new GridBagLayout();
setLayout(gbl); buttonPanel.setLayout(gbl);
setLayout(new BorderLayout());
plotButton = new JButton(Resources.getText("Discard chart")); plotButton = new JButton(Resources.getText("Discard chart"));
plotButton.addActionListener(this); plotButton.addActionListener(this);
plotButton.setEnabled(true); plotButton.setEnabled(true);
// Add the display to the top four cells
GridBagConstraints buttonConstraints = new GridBagConstraints(); GridBagConstraints buttonConstraints = new GridBagConstraints();
buttonConstraints.gridx = 0; buttonConstraints.gridx = 0;
buttonConstraints.gridy = 0; buttonConstraints.gridy = 0;
buttonConstraints.fill = GridBagConstraints.VERTICAL; buttonConstraints.fill = GridBagConstraints.VERTICAL;
buttonConstraints.anchor = GridBagConstraints.CENTER; buttonConstraints.anchor = GridBagConstraints.CENTER;
gbl.setConstraints(plotButton, buttonConstraints); gbl.setConstraints(plotButton, buttonConstraints);
add(plotButton); buttonPanel.add(plotButton);
GridBagConstraints plotterConstraints = new GridBagConstraints(); if (attributeName != null && attributeName.length()!=0) {
plotterConstraints.gridx = 0; final JPanel plotterLabelPanel = new JPanel();
plotterConstraints.gridy = 1; final JLabel label = new JLabel(attributeName);
plotterConstraints.weightx = 1; final GridBagLayout gbl2 = new GridBagLayout();
//plotterConstraints.gridwidth = (int) plotter.getPreferredSize().getWidth(); plotterLabelPanel.setLayout(gbl2);
//plotterConstraints.gridheight = (int) plotter.getPreferredSize().getHeight(); final GridBagConstraints labelConstraints = new GridBagConstraints();
plotterConstraints.fill = GridBagConstraints.VERTICAL; labelConstraints.gridx = 0;
gbl.setConstraints(plotter, plotterConstraints); labelConstraints.gridy = 0;
labelConstraints.fill = GridBagConstraints.VERTICAL;
labelConstraints.anchor = GridBagConstraints.CENTER;
//bordered = new JPanel(); labelConstraints.ipady = 10;
//bordered.setPreferredSize(new Dimension(400, 250)); gbl2.setConstraints(label, labelConstraints);
//bordered.add(plotButton); plotterLabelPanel.add(label);
//bordered.add(plotter); add(plotterLabelPanel, BorderLayout.NORTH);
}
//add(bordered);
setPlotter(plotter); setPlotter(plotter);
add(buttonPanel, BorderLayout.SOUTH);
repaint(); repaint();
} }
......
/* /*
* Copyright 1995-2006 Sun Microsystems, Inc. All Rights Reserved. * Copyright 1995-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -722,16 +722,22 @@ ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified) ...@@ -722,16 +722,22 @@ ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified)
} }
len = zip->len = ZFILE_Lseek(zfd, 0, SEEK_END); len = zip->len = ZFILE_Lseek(zfd, 0, SEEK_END);
if (len == -1) { if (len <= 0) {
if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0) if (len == 0) { /* zip file is empty */
*pmsg = errbuf; if (pmsg) {
*pmsg = "zip file is empty";
}
} else { /* error */
if (pmsg && JVM_GetLastErrorString(errbuf, sizeof(errbuf)) > 0)
*pmsg = errbuf;
}
ZFILE_Close(zfd); ZFILE_Close(zfd);
freeZip(zip); freeZip(zip);
return NULL; return NULL;
} }
zip->zfd = zfd; zip->zfd = zfd;
if (readCEN(zip, -1) <= 0) { if (readCEN(zip, -1) < 0) {
/* An error occurred while trying to read the zip file */ /* An error occurred while trying to read the zip file */
if (pmsg != 0) { if (pmsg != 0) {
/* Set the zip error message */ /* Set the zip error message */
...@@ -947,10 +953,15 @@ jzentry * ...@@ -947,10 +953,15 @@ jzentry *
ZIP_GetEntry(jzfile *zip, char *name, jint ulen) ZIP_GetEntry(jzfile *zip, char *name, jint ulen)
{ {
unsigned int hsh = hash(name); unsigned int hsh = hash(name);
jint idx = zip->table[hsh % zip->tablelen]; jint idx;
jzentry *ze; jzentry *ze = 0;
ZIP_Lock(zip); ZIP_Lock(zip);
if (zip->total == 0) {
goto Finally;
}
idx = zip->table[hsh % zip->tablelen];
/* /*
* This while loop is an optimization where a double lookup * This while loop is an optimization where a double lookup
...@@ -1025,6 +1036,7 @@ ZIP_GetEntry(jzfile *zip, char *name, jint ulen) ...@@ -1025,6 +1036,7 @@ ZIP_GetEntry(jzfile *zip, char *name, jint ulen)
ulen = 0; ulen = 0;
} }
Finally:
ZIP_Unlock(zip); ZIP_Unlock(zip);
return ze; return ze;
} }
......
...@@ -41,8 +41,7 @@ import java.util.*; ...@@ -41,8 +41,7 @@ import java.util.*;
/********** target program **********/ /********** target program **********/
class ClassesByName2Targ { class ClassesByName2Targ {
public static void ready() { static void bkpt() {
System.out.println("Ready!");
} }
public static void main(String[] args){ public static void main(String[] args){
...@@ -74,22 +73,24 @@ class ClassesByName2Targ { ...@@ -74,22 +73,24 @@ class ClassesByName2Targ {
} }
}; };
ready();
two.start(); two.start();
one.start(); one.start();
zero.start(); zero.start();
try { try {
zero.join(); zero.join();
System.out.println("zero joined");
one.join(); one.join();
System.out.println("one joined");
two.join(); two.join();
System.out.println("two joined");
} catch (InterruptedException iex) { } catch (InterruptedException iex) {
iex.printStackTrace(); iex.printStackTrace();
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
bkpt();
System.out.println("Goodbye from ClassesByName2Targ!"); System.out.println("Goodbye from ClassesByName2Targ!");
} }
} }
...@@ -97,29 +98,64 @@ class ClassesByName2Targ { ...@@ -97,29 +98,64 @@ class ClassesByName2Targ {
/********** test program **********/ /********** test program **********/
public class ClassesByName2Test extends TestScaffold { public class ClassesByName2Test extends TestScaffold {
volatile boolean stop = false;
ClassesByName2Test (String args[]) { ClassesByName2Test (String args[]) {
super(args); super(args);
} }
public void breakpointReached(BreakpointEvent event) {
System.out.println("Got BreakpointEvent: " + event);
stop = true;
}
public void eventSetComplete(EventSet set) {
// Don't resume.
}
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
new ClassesByName2Test(args).startTests(); new ClassesByName2Test(args).startTests();
} }
void breakpointAtMethod(ReferenceType ref, String methodName)
throws Exception {
List meths = ref.methodsByName(methodName);
if (meths.size() != 1) {
throw new Exception("test error: should be one " +
methodName);
}
Method meth = (Method)meths.get(0);
BreakpointRequest bkptReq = vm().eventRequestManager().
createBreakpointRequest(meth.location());
bkptReq.enable();
try {
addListener (this);
} catch (Exception ex){
ex.printStackTrace();
failure("failure: Could not add listener");
throw new Exception("ClassesByname2Test: failed");
}
}
protected void runTests() throws Exception { protected void runTests() throws Exception {
/* BreakpointEvent bpe = startToMain("ClassesByName2Targ");
* Get to the top of ready()
*/
startTo("ClassesByName2Targ", "ready", "()V");
/*
Bug 6263966 - Don't just resume because the debuggee can
complete and disconnect while the following loop is
accessing it.
*/
breakpointAtMethod(bpe.location().declaringType(), "bkpt");
vm().resume(); vm().resume();
int i = 0; /* The test of 'stop' is so that we stop when the debuggee hits
while (i < 8 && !vmDisconnected) { the bkpt. The 150 is so we stop if the debuggee
i++; is slow (eg, -Xcomp -server) - we don't want to
spend all day waiting for it to get to the bkpt.
*/
for (int i = 0; i < 150 && !stop; i++) {
List all = vm().allClasses(); List all = vm().allClasses();
System.out.println(""); System.out.println("\n++++ Lookup number: " + i + ". allClasses() returned " +
System.out.println("++++ Lookup number: " + i + ". allClasses() returned " +
all.size() + " classes."); all.size() + " classes.");
for (Iterator it = all.iterator(); it.hasNext(); ) { for (Iterator it = all.iterator(); it.hasNext(); ) {
ReferenceType cls = (ReferenceType)it.next(); ReferenceType cls = (ReferenceType)it.next();
...@@ -135,9 +171,8 @@ public class ClassesByName2Test extends TestScaffold { ...@@ -135,9 +171,8 @@ public class ClassesByName2Test extends TestScaffold {
} }
} }
// In case of a slow debuggee, we don't want to resume the debuggee and wait
// Doing vm().exit(0) instead of listenUntilVMDisconnect() // for it to complete.
// speeds up the test up by more than 50% in -server -Xcomp (solsparc32-fastdebug)
vm().exit(0); vm().exit(0);
/* /*
......
/*
* Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/**
* @test
* @bug B6744329
* @summary Exception in light weight Http server
*/
import com.sun.net.httpserver.*;
import java.util.*;
import java.util.concurrent.*;
import java.io.*;
import java.net.*;
import java.security.*;
import java.security.cert.*;
import javax.net.ssl.*;
public class B6744329 {
public static void main (String[] args) throws Exception {
Handler handler = new Handler();
InetSocketAddress addr = new InetSocketAddress (0);
HttpServer server = HttpServer.create (addr, 0);
HttpContext ctx = server.createContext ("/test", handler);
ExecutorService executor = Executors.newCachedThreadPool();
server.setExecutor (executor);
server.start ();
URL url = new URL ("http://localhost:"+server.getAddress().getPort()+"/test/foo.html");
HttpURLConnection urlc = (HttpURLConnection)url.openConnection ();
try {
InputStream is = urlc.getInputStream();
int c = 0;
while (is.read()!= -1) {
c ++;
}
System.out.println ("OK");
} catch (IOException e) {
System.out.println ("exception");
error = true;
}
server.stop(2);
executor.shutdown();
if (error) {
throw new RuntimeException ("Test failed");
}
}
public static boolean error = false;
/* this must be the same size as in ChunkedOutputStream.java
*/
final static int CHUNK_SIZE = 4096;
static class Handler implements HttpHandler {
int invocation = 1;
public void handle (HttpExchange t)
throws IOException
{
InputStream is = t.getRequestBody();
Headers map = t.getRequestHeaders();
Headers rmap = t.getResponseHeaders();
while (is.read () != -1) ;
is.close();
/* chunked response */
t.sendResponseHeaders (200, 0);
OutputStream os = t.getResponseBody();
byte[] first = new byte [CHUNK_SIZE * 2];
byte[] second = new byte [2];
os.write (first);
os.write ('x');
os.write ('x');
/* An index out of bounds exception will be thrown
* below, which is caught by server, and connection
* will be closed. resulting in IOException to client
* - if bug present
*/
os.write ('x');
os.write ('x');
os.write ('x');
t.close();
}
}
}
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
/** /**
* @test * @test
* @summary Unit test for java.net.HttpCookie * @summary Unit test for java.net.HttpCookie
* @bug 6244040 6277796 6277801 6277808 6294071 * @bug 6244040 6277796 6277801 6277808 6294071 6692802
* @author Edward Wang * @author Edward Wang
*/ */
...@@ -178,6 +178,19 @@ public class TestHttpCookie { ...@@ -178,6 +178,19 @@ public class TestHttpCookie {
} }
TestHttpCookie port(String p) { return port(0, p); } TestHttpCookie port(String p) { return port(0, p); }
// check http only
TestHttpCookie httpOnly(int index, boolean b) {
HttpCookie cookie = cookies.get(index);
if (cookie == null || b != cookie.isHttpOnly()) {
raiseError("HttpOnly", String.valueOf(cookie.isHttpOnly()), String.valueOf(b));
}
return this;
}
TestHttpCookie httpOnly(boolean b) {
return httpOnly(0, b);
}
// check equality // check equality
static void eq(HttpCookie ck1, HttpCookie ck2, boolean same) { static void eq(HttpCookie ck1, HttpCookie ck2, boolean same) {
testCount++; testCount++;
...@@ -362,6 +375,10 @@ public class TestHttpCookie { ...@@ -362,6 +375,10 @@ public class TestHttpCookie {
} catch (IllegalArgumentException ignored) { } catch (IllegalArgumentException ignored) {
// expected exception; no-op // expected exception; no-op
} }
// CR 6692802: HttpOnly flag
test("set-cookie: CUSTOMER=WILE_E_COYOTE;HttpOnly").httpOnly(true);
test("set-cookie: CUSTOMER=WILE_E_COYOTE").httpOnly(false);
} }
static void header(String prompt) { static void header(String prompt) {
......
/* /*
* Copyright 2002 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -34,6 +34,7 @@ import java.io.InputStream; ...@@ -34,6 +34,7 @@ import java.io.InputStream;
import java.io.IOException; import java.io.IOException;
import java.security.cert.*; import java.security.cert.*;
import java.security.cert.PKIXReason;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
...@@ -69,6 +70,9 @@ public final class ValidateCertPath { ...@@ -69,6 +70,9 @@ public final class ValidateCertPath {
validate(path, params); validate(path, params);
throw new Exception("Successfully validated invalid path."); throw new Exception("Successfully validated invalid path.");
} catch (CertPathValidatorException e) { } catch (CertPathValidatorException e) {
if (e.getReason() != PKIXReason.INVALID_NAME) {
throw new Exception("unexpected reason: " + e.getReason());
}
System.out.println("Path rejected as expected: " + e); System.out.println("Path rejected as expected: " + e);
} }
} }
...@@ -86,14 +90,14 @@ public final class ValidateCertPath { ...@@ -86,14 +90,14 @@ public final class ValidateCertPath {
args = new String[] {"jane2jane.cer", "jane2steve.cer", "steve2tom.cer"}; args = new String[] {"jane2jane.cer", "jane2steve.cer", "steve2tom.cer"};
TrustAnchor anchor = new TrustAnchor(getCertFromFile(args[0]), null); TrustAnchor anchor = new TrustAnchor(getCertFromFile(args[0]), null);
List list = new ArrayList(); List<X509Certificate> list = new ArrayList<X509Certificate>();
for (int i = 1; i < args.length; i++) { for (int i = 1; i < args.length; i++) {
list.add(0, getCertFromFile(args[i])); list.add(0, getCertFromFile(args[i]));
} }
CertificateFactory cf = CertificateFactory.getInstance("X509"); CertificateFactory cf = CertificateFactory.getInstance("X509");
path = cf.generateCertPath(list); path = cf.generateCertPath(list);
Set anchors = Collections.singleton(anchor); Set<TrustAnchor> anchors = Collections.singleton(anchor);
params = new PKIXParameters(anchors); params = new PKIXParameters(anchors);
params.setRevocationEnabled(false); params.setRevocationEnabled(false);
} }
......
/*
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/*
* @test
* @bug 6465942
* @summary unit test for CertPathValidatorException.Reason
*/
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertPathValidatorException.BasicReason;
public class ReasonTest {
private static volatile boolean failed = false;
public static void main(String[] args) throws Exception {
// check that getReason returns UNSPECIFIED if reason not specified
CertPathValidatorException cpve = new CertPathValidatorException("abc");
if (cpve.getReason() != BasicReason.UNSPECIFIED) {
failed = true;
System.err.println("FAILED: unexpected reason: " + cpve.getReason());
}
// check that getReason returns specified reason
cpve = new CertPathValidatorException
("abc", null, null, -1, BasicReason.REVOKED);
if (cpve.getReason() != BasicReason.REVOKED) {
failed = true;
System.err.println("FAILED: unexpected reason: " + cpve.getReason());
}
// check that ctor throws NPE when reason is null
try {
cpve = new CertPathValidatorException("abc", null, null, -1, null);
failed = true;
System.err.println("ctor did not throw NPE for null reason");
} catch (Exception e) {
if (!(e instanceof NullPointerException)) {
failed = true;
System.err.println("FAILED: unexpected exception: " + e);
}
}
if (failed) {
throw new Exception("Some tests FAILED");
}
}
}
/*
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/*
* @test
* @bug 6465942
* @summary Test deserialization of CertPathValidatorException
*/
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
//import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.CertPath;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertPathValidatorException.BasicReason;
import java.util.Collections;
/**
* This class tests to see if CertPathValidatorException can be serialized and
* deserialized properly.
*/
public class Serial {
private static volatile boolean failed = false;
public static void main(String[] args) throws Exception {
File f = new File(System.getProperty("test.src", "."), "cert_file");
FileInputStream fis = new FileInputStream(f);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate c = cf.generateCertificate(fis);
fis.close();
CertPath cp = cf.generateCertPath(Collections.singletonList(c));
CertPathValidatorException cpve1 =
new CertPathValidatorException
("Test", new Exception("Expired"), cp, 0, BasicReason.EXPIRED);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// FileOutputStream fos = new FileOutputStream("jdk7.serial");
ObjectOutputStream oos = new ObjectOutputStream(baos);
// ObjectOutputStream foos = new ObjectOutputStream(fos);
oos.writeObject(cpve1);
// foos.writeObject(cpve1);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
CertPathValidatorException cpve2 =
(CertPathValidatorException) ois.readObject();
check(!cpve1.getMessage().equals(cpve2.getMessage()),
"CertPathValidatorException messages not equal");
check(!cpve1.getCause().getMessage().equals(cpve2.getCause().getMessage()),
"CertPathValidatorException causes not equal");
check(!cpve1.getCertPath().equals(cpve2.getCertPath()),
"CertPathValidatorException certpaths not equal");
check(cpve1.getIndex() != cpve2.getIndex(),
"CertPathValidatorException indexes not equal");
check(cpve1.getReason() != cpve2.getReason(),
"CertPathValidatorException reasons not equal");
oos.close();
ois.close();
f = new File(System.getProperty("test.src", "."), "jdk6.serial");
fis = new FileInputStream(f);
ois = new ObjectInputStream(fis);
cpve2 = (CertPathValidatorException) ois.readObject();
check(!cpve1.getMessage().equals(cpve2.getMessage()),
"CertPathValidatorException messages not equal");
check(!cpve1.getCause().getMessage().equals(cpve2.getCause().getMessage()),
"CertPathValidatorException causes not equal");
check(!cpve1.getCertPath().equals(cpve2.getCertPath()),
"CertPathValidatorException certpaths not equal");
check(cpve1.getIndex() != cpve2.getIndex(),
"CertPathValidatorException indexes not equal");
// System.out.println(cpve2.getReason());
check(cpve2.getReason() != BasicReason.UNSPECIFIED,
"CertPathValidatorException reasons not equal");
oos.close();
ois.close();
if (failed) {
throw new Exception("Some tests FAILED");
}
}
private static void check(boolean expr, String message) {
if (expr) {
failed = true;
System.err.println("FAILED: " + message);
}
}
}
/* /*
* Copyright 2001 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -74,6 +74,10 @@ public class GetPolicyQualifiers { ...@@ -74,6 +74,10 @@ public class GetPolicyQualifiers {
throw new Exception("Validation of CertPath containing critical " + throw new Exception("Validation of CertPath containing critical " +
"qualifiers should have failed when policyQualifiersRejected " + "qualifiers should have failed when policyQualifiersRejected " +
"flag is true"); "flag is true");
} catch (CertPathValidatorException cpve) {} } catch (CertPathValidatorException cpve) {
if (cpve.getReason() != PKIXReason.INVALID_POLICY) {
throw new Exception("unexpected reason: " + cpve.getReason());
}
}
} }
} }
/*
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/* @test
* @bug 6334003 6440786
* @summary Test ability to write and read zip files that have no entries.
* @author Dave Bristor
*/
import java.io.*;
import java.util.*;
import java.util.zip.*;
public class TestEmptyZip {
public static void realMain(String[] args) throws Throwable {
String zipName = "foo.zip";
File f = new File(System.getProperty("test.scratch", "."), zipName);
if (f.exists() && !f.delete()) {
throw new Exception("failed to delete " + zipName);
}
// Verify 0-length file cannot be read
f.createNewFile();
ZipFile zf = null;
try {
zf = new ZipFile(f);
fail();
} catch (Exception ex) {
check(ex.getMessage().contains("zip file is empty"));
} finally {
if (zf != null) {
zf.close();
}
}
ZipInputStream zis = null;
try {
zis = new ZipInputStream(new FileInputStream(f));
ZipEntry ze = zis.getNextEntry();
check(ze == null);
} catch (Exception ex) {
unexpected(ex);
} finally {
if (zis != null) {
zis.close();
}
}
f.delete();
// Verify 0-entries file can be written
write(f);
// Verify 0-entries file can be read
readFile(f);
readStream(f);
f.delete();
}
static void write(File f) throws Exception {
ZipOutputStream zos = null;
try {
zos = new ZipOutputStream(new FileOutputStream(f));
zos.finish();
zos.close();
pass();
} catch (Exception ex) {
unexpected(ex);
} finally {
if (zos != null) {
zos.close();
}
}
}
static void readFile(File f) throws Exception {
ZipFile zf = null;
try {
zf = new ZipFile(f);
Enumeration e = zf.entries();
while (e.hasMoreElements()) {
ZipEntry entry = (ZipEntry) e.nextElement();
fail();
}
zf.close();
pass();
} catch (Exception ex) {
unexpected(ex);
} finally {
if (zf != null) {
zf.close();
}
}
}
static void readStream(File f) throws Exception {
ZipInputStream zis = null;
try {
zis = new ZipInputStream(new FileInputStream(f));
ZipEntry ze = zis.getNextEntry();
check(ze == null);
byte[] buf = new byte[1024];
check(zis.read(buf, 0, 1024) == -1);
} finally {
if (zis != null) {
zis.close();
}
}
}
//--------------------- Infrastructure ---------------------------
static volatile int passed = 0, failed = 0;
static boolean pass() {passed++; return true;}
static boolean fail() {failed++; Thread.dumpStack(); return false;}
static boolean fail(String msg) {System.out.println(msg); return fail();}
static void unexpected(Throwable t) {failed++; t.printStackTrace();}
static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
static boolean equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) return pass();
else return fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
try {realMain(args);} catch (Throwable t) {unexpected(t);}
System.out.println("\nPassed = " + passed + " failed = " + failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}
/*
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/*
* @test
* @bug 6669137
* @summary Test the constructors of InstanceNotFoundExceptionTest.
* @author Daniel Fuchs
* @compile InstanceNotFoundExceptionTest.java
* @run main InstanceNotFoundExceptionTest
*/
import javax.management.InstanceNotFoundException;
import javax.management.ObjectName;
public class InstanceNotFoundExceptionTest {
public static void main(String[] args) throws Exception {
final InstanceNotFoundException x =
new InstanceNotFoundException();
System.out.println("InstanceNotFoundException(): "+x.getMessage());
final String msg = "who is toto?";
final InstanceNotFoundException x2 =
new InstanceNotFoundException(msg);
if (!msg.equals(x2.getMessage()))
throw new Exception("Bad message: expected "+msg+
", got "+x2.getMessage());
System.out.println("InstanceNotFoundException(" +
msg+"): "+x2.getMessage());
final InstanceNotFoundException x3 =
new InstanceNotFoundException((String)null);
if (x3.getMessage() != null)
throw new Exception("Bad message: expected "+null+
", got "+x3.getMessage());
System.out.println("InstanceNotFoundException((String)null): "+
x3.getMessage());
final ObjectName n = new ObjectName("who is toto?:type=msg");
final InstanceNotFoundException x4 =
new InstanceNotFoundException(n);
if (!String.valueOf(n).equals(x4.getMessage()))
throw new Exception("Bad message: expected "+n+
", got "+x4.getMessage());
System.out.println("InstanceNotFoundException(" +
n+"): "+x4.getMessage());
final InstanceNotFoundException x5 =
new InstanceNotFoundException((ObjectName)null);
if (!String.valueOf((ObjectName)null).equals(x5.getMessage()))
throw new Exception("Bad message: expected " +
String.valueOf((ObjectName)null)+" got "+x5.getMessage());
System.out.println("InstanceNotFoundException((ObjectName)null): "+
x5.getMessage());
}
}
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
* @test * @test
* @summary Test named MBeanServers. * @summary Test named MBeanServers.
* @author Daniel Fuchs * @author Daniel Fuchs
* @bug 6299231
* @run clean NamedMBeanServerTest * @run clean NamedMBeanServerTest
* @run build NamedMBeanServerTest * @run build NamedMBeanServerTest
* @run main NamedMBeanServerTest * @run main NamedMBeanServerTest
......
/*
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/*
* @test
* @bug 6734813
* @summary Test the ObjectName.valueOf methods
* @author Eamonn McManus
*/
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Hashtable;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
public class ValueOfTest {
public static void main(String[] args) throws Exception {
// Calls that should work
testPositive("d:foo=bar,baz=buh");
testPositive("foo", "bar", "baz");
Hashtable<String, String> h = new Hashtable<String, String>();
h.put("foo", "bar");
h.put("baz", "buh");
testPositive("domain", h);
// Calls that should not work
testNegative("d");
testNegative("d:");
testNegative("d::foo=bar");
testNegative("d:", "foo", "bar");
testNegative("d", "foo=", "bar");
testNegative("d:", h);
testNegative("d", new Hashtable<String, String>());
}
private static void testPositive(Object... args) throws Exception {
Method valueOf = valueOfMethod(args);
Method getInstance = getInstanceMethod(args);
Constructor<?> constructor = constructor(args);
Object valueOfValue = valueOf.invoke(null, args);
Object getInstanceValue = getInstance.invoke(null, args);
Object constructorValue = constructor.newInstance(args);
String argString =
Arrays.toString(args).replace('[', '(').replace(']', ')');
if (!valueOfValue.equals(getInstanceValue)) {
throw new Exception(
"valueOf" + argString + " differs from getInstance" +
argString);
}
if (!valueOfValue.equals(constructorValue)) {
throw new Exception(
"valueOf" + argString + " differs from new ObjectName " +
argString);
}
System.out.println("OK: valueOf" + argString);
}
private static void testNegative(Object... args) throws Exception {
Method valueOf = valueOfMethod(args);
Method getInstance = getInstanceMethod(args);
String argString =
Arrays.toString(args).replace('[', '(').replace(']', ')');
final Throwable valueOfException;
try {
valueOf.invoke(null, args);
throw new Exception("valueOf" + argString + " did not fail but should");
} catch (InvocationTargetException e) {
valueOfException = e.getCause();
}
if (!(valueOfException instanceof IllegalArgumentException)) {
throw new Exception(
"valueOf" + argString + " threw " +
valueOfException.getClass().getName() + " instead of " +
"IllegalArgumentException", valueOfException);
}
final Throwable valueOfCause = valueOfException.getCause();
if (!(valueOfCause instanceof MalformedObjectNameException)) {
throw new Exception(
"valueOf" + argString + " threw exception with wrong " +
"type of cause", valueOfCause);
}
if (!valueOfException.getMessage().equals(valueOfCause.getMessage())) {
// The IllegalArgumentException should have the same message as
// the MalformedObjectNameException it wraps.
// This isn't specified but is desirable.
throw new Exception(
"valueOf" + argString + ": message in wrapping " +
"IllegalArgumentException (" + valueOfException.getMessage() +
") differs from message in wrapped " +
"MalformedObjectNameException (" + valueOfCause.getMessage() +
")");
}
final Throwable getInstanceException;
try {
getInstance.invoke(null, args);
throw new Exception("getInstance" + argString + " did not fail but should");
} catch (InvocationTargetException e) {
getInstanceException = e.getCause();
}
if (!(getInstanceException instanceof MalformedObjectNameException)) {
throw new Exception(
"getInstance" + argString + " threw wrong exception",
getInstanceException);
}
if (!valueOfException.getMessage().equals(getInstanceException.getMessage())) {
// Again this is not specified.
throw new Exception(
"Exception message from valueOf" + argString + " (" +
valueOfException.getMessage() + ") differs from message " +
"from getInstance" + argString + " (" +
getInstanceException.getMessage() + ")");
}
System.out.println("OK (correct exception): valueOf" + argString);
}
private static Method valueOfMethod(Object[] args) throws Exception {
return method("valueOf", args);
}
private static Method getInstanceMethod(Object[] args) throws Exception {
return method("getInstance", args);
}
private static Method method(String name, Object[] args) throws Exception {
Class<?>[] argTypes = argTypes(args);
return ObjectName.class.getMethod(name, argTypes);
}
private static Constructor<?> constructor(Object[] args) throws Exception {
Class<?>[] argTypes = argTypes(args);
return ObjectName.class.getConstructor(argTypes);
}
private static Class<?>[] argTypes(Object[] args) {
Class<?>[] argTypes = new Class<?>[args.length];
for (int i = 0; i < args.length; i++)
argTypes[i] = args[i].getClass();
return argTypes;
}
}
/*
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/*
* @test
* @bug 6747411
* @summary Check that EventClient instances don't leak threads.
* @author Eamonn McManus
*/
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.Set;
import java.util.TreeSet;
import javax.management.MBeanServer;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerDelegate;
import javax.management.MBeanServerNotification;
import javax.management.Notification;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.management.event.EventClient;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
public class EventClientThreadTest {
private static final int MAX_TIME_SECONDS = 20;
private static final BlockingQueue<Notification> queue =
new ArrayBlockingQueue(100);
private static final NotificationListener queueListener =
new NotificationListener() {
public void handleNotification(Notification notification,
Object handback) {
queue.add(notification);
}
};
private static final NotificationFilter dummyFilter =
new NotificationFilter() {
public boolean isNotificationEnabled(Notification notification) {
return true;
}
};
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
long deadline = start + MAX_TIME_SECONDS * 1000;
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://");
JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(
url, null, mbs);
cs.start();
JMXServiceURL addr = cs.getAddress();
JMXConnector cc = JMXConnectorFactory.connect(addr);
MBeanServerConnection mbsc = cc.getMBeanServerConnection();
ThreadMXBean threads = ManagementFactory.getThreadMXBean();
System.out.println("Opening and closing some EventClients...");
// If we create a connection, then create and destroy EventClients
// over it, then close it, there should be no "JMX *" threads left.
for (int i = 0; i < 5; i++)
test(mbsc);
cc.close();
showTime("opening and closing initial EventClients", start);
Set<String> jmxThreads = threadsMatching("JMX .*");
while (!jmxThreads.isEmpty() && System.currentTimeMillis() < deadline) {
Set<String> jmxThreadsNow = threadsMatching("JMX .*");
Set<String> gone = new TreeSet<String>(jmxThreads);
gone.removeAll(jmxThreadsNow);
for (String s : gone)
showTime("expiry of \"" + s + "\"", start);
jmxThreads = jmxThreadsNow;
Thread.sleep(10);
}
if (System.currentTimeMillis() >= deadline) {
showThreads(threads);
throw new Exception("Timed out waiting for JMX threads to expire");
}
showTime("waiting for JMX threads to expire", start);
System.out.println("TEST PASSED");
}
static void showThreads(ThreadMXBean threads) throws Exception {
long[] ids = threads.getAllThreadIds();
for (long id : ids) {
ThreadInfo ti = threads.getThreadInfo(id);
String name = (ti == null) ? "(defunct)" : ti.getThreadName();
System.out.printf("%4d %s\n", id, name);
}
}
static void showTime(String what, long start) {
long elapsed = System.currentTimeMillis() - start;
System.out.printf("Time after %s: %.3f s\n", what, elapsed / 1000.0);
}
static Set<String> threadsMatching(String pattern) {
Set<String> matching = new TreeSet<String>();
ThreadMXBean threads = ManagementFactory.getThreadMXBean();
long[] ids = threads.getAllThreadIds();
for (long id : ids) {
ThreadInfo ti = threads.getThreadInfo(id);
String name = (ti == null) ? "(defunct)" : ti.getThreadName();
if (name.matches(pattern))
matching.add(name);
}
return matching;
}
static void test(MBeanServerConnection mbsc) throws Exception {
final ObjectName delegateName = MBeanServerDelegate.DELEGATE_NAME;
final ObjectName testName = new ObjectName("test:type=Test");
EventClient ec = new EventClient(mbsc);
ec.addNotificationListener(delegateName, queueListener, null, null);
mbsc.createMBean(MBeanServerDelegate.class.getName(), testName);
mbsc.unregisterMBean(testName);
final String[] expectedTypes = {
MBeanServerNotification.REGISTRATION_NOTIFICATION,
MBeanServerNotification.UNREGISTRATION_NOTIFICATION,
};
for (String s : expectedTypes) {
Notification n = queue.poll(3, TimeUnit.SECONDS);
if (n == null)
throw new Exception("Timed out waiting for notif: " + s);
if (!(n instanceof MBeanServerNotification))
throw new Exception("Got notif of wrong class: " + n.getClass());
if (!n.getType().equals(s)) {
throw new Exception("Got notif of wrong type: " + n.getType() +
" (expecting " + s + ")");
}
}
ec.removeNotificationListener(delegateName, queueListener);
ec.addNotificationListener(delegateName, queueListener, dummyFilter, "foo");
ec.removeNotificationListener(delegateName, queueListener, dummyFilter, "foo");
ec.close();
}
}
\ No newline at end of file
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
* @summary Check that a lock is not held when a LeaseManager expires. * @summary Check that a lock is not held when a LeaseManager expires.
* @author Eamonn McManus * @author Eamonn McManus
* @compile -XDignore.symbol.file=true LeaseManagerDeadlockTest.java * @compile -XDignore.symbol.file=true LeaseManagerDeadlockTest.java
* @run main LeaseManagerDeadlockTest
*/ */
import com.sun.jmx.event.LeaseManager; import com.sun.jmx.event.LeaseManager;
......
/*/* /*
* Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
......
/*
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/*
* @test SubUnsubTest
* @bug 6736611
* @summary Test not to remove other listeners when calling unsubscribe
* @author Shanliang JIANG
* @run clean SubUnsubTest
* @run build SubUnsubTest
* @run main SubUnsubTest
*/
import java.lang.management.ManagementFactory;
import javax.management.MBeanServer;
import javax.management.Notification;
import javax.management.NotificationFilter;
import javax.management.NotificationBroadcasterSupport;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.management.event.EventSubscriber;
import javax.management.event.EventClient;
public class SubUnsubTest {
private static class CountListener implements NotificationListener {
volatile int count;
public void handleNotification(Notification n, Object h) {
count++;
}
}
public static interface SenderMBean {}
public static class Sender extends NotificationBroadcasterSupport
implements SenderMBean {
void send() {
Notification n = new Notification("type", this, 1L);
sendNotification(n);
}
}
public static void main(String[] args) throws Exception {
System.out.println("Testing EventSubscriber-unsubscribe method.");
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName name1 = new ObjectName("d:type=Sender,id=1");
ObjectName name2 = new ObjectName("d:type=Sender,id=2");
ObjectName pattern = new ObjectName("d:type=Sender,*");
Sender sender1 = new Sender();
Sender sender2 = new Sender();
mbs.registerMBean(sender1, name1);
mbs.registerMBean(sender2, name2);
EventSubscriber sub = EventSubscriber.getEventSubscriber(mbs);
System.out.println("Single subscribe covering both MBeans");
CountListener listener = new CountListener();
System.out.println("Subscribing and adding listeners ...");
sub.subscribe(pattern, listener, null, null);
sub.subscribe(name2, listener, null, null);
mbs.addNotificationListener(name2, listener, null, null);
sender1.send();
sender2.send();
if (listener.count != 4) {
throw new RuntimeException("Do not receive all notifications: "+
"Expect 4, got "+listener.count);
}
System.out.println("Unsubscribe the listener with the pattern.");
sub.unsubscribe(pattern, listener);
listener.count = 0;
sender1.send();
sender2.send();
if (listener.count != 2) {
throw new RuntimeException("The method unsubscribe removes wrong listeners.");
}
System.out.println("Unsubscribe the listener with the ObjectName.");
sub.unsubscribe(name2, listener);
listener.count = 0;
sender1.send();
sender2.send();
if (listener.count != 1) {
throw new RuntimeException("The method unsubscribe removes wrong listeners.");
}
System.out.println("Subscribe twice to same MBean with same listener " +
"but different handback.");
sub.subscribe(name1, listener, null, new Object());
sub.subscribe(name1, listener, null, new Object());
listener.count = 0;
sub.unsubscribe(name1, listener);
sender1.send();
if (listener.count > 0) {
throw new RuntimeException("EventSubscriber: the method unsubscribe" +
" does not remove a listener which was subscribed 2 times.");
}
System.out.println("Bye bye!");
return;
}
}
\ No newline at end of file
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
/* /*
* *
* @test DomainCreationTest.java * @test DomainCreationTest.java
* @bug 5072476
* @summary Test the creation and registration of JMXDomain instances. * @summary Test the creation and registration of JMXDomain instances.
* @author Daniel Fuchs * @author Daniel Fuchs
* @run clean DomainCreationTest Wombat WombatMBean * @run clean DomainCreationTest Wombat WombatMBean
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
* @summary Check -Djmx.remote.use.event.service=true and * @summary Check -Djmx.remote.use.event.service=true and
* -Djmx.remote.delegate.event.service * -Djmx.remote.delegate.event.service
* @author Daniel Fuchs * @author Daniel Fuchs
* @bug 5072476 5108776
* @run clean EventWithNamespaceTest EventWithNamespaceControlTest * @run clean EventWithNamespaceTest EventWithNamespaceControlTest
* Wombat WombatMBean JMXRemoteTargetNamespace * Wombat WombatMBean JMXRemoteTargetNamespace
* NamespaceController NamespaceControllerMBean * NamespaceController NamespaceControllerMBean
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
/* /*
* *
* @test EventWithNamespaceTest.java 1.8 * @test EventWithNamespaceTest.java 1.8
* @bug 6539857 * @bug 6539857 5072476 5108776
* @summary General Namespace & Notifications test. * @summary General Namespace & Notifications test.
* @author Daniel Fuchs * @author Daniel Fuchs
* @run clean EventWithNamespaceTest Wombat WombatMBean * @run clean EventWithNamespaceTest Wombat WombatMBean
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
* @summary Test that you can export a single namespace through a * @summary Test that you can export a single namespace through a
* JMXConnectorServer. * JMXConnectorServer.
* @author Daniel Fuchs * @author Daniel Fuchs
* @bug 5072476
* @run clean ExportNamespaceTest Wombat WombatMBean * @run clean ExportNamespaceTest Wombat WombatMBean
* @run build ExportNamespaceTest Wombat WombatMBean * @run build ExportNamespaceTest Wombat WombatMBean
* @run main ExportNamespaceTest * @run main ExportNamespaceTest
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
/* /*
* *
* @test JMXDomainTest.java * @test JMXDomainTest.java
* @bug 5072476
* @summary Basic test for JMXDomain. * @summary Basic test for JMXDomain.
* @author Daniel Fuchs * @author Daniel Fuchs
* @run clean JMXDomainTest Wombat WombatMBean * @run clean JMXDomainTest Wombat WombatMBean
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
* @test JMXNamespaceSecurityTest.java * @test JMXNamespaceSecurityTest.java
* @summary General JMXNamespaceSecurityTest test. * @summary General JMXNamespaceSecurityTest test.
* @author Daniel Fuchs * @author Daniel Fuchs
* @bug 5072476 6299231
* @run clean JMXNamespaceViewTest JMXNamespaceSecurityTest Wombat WombatMBean * @run clean JMXNamespaceViewTest JMXNamespaceSecurityTest Wombat WombatMBean
* LazyDomainTest * LazyDomainTest
* @run build JMXNamespaceSecurityTest JMXNamespaceViewTest Wombat WombatMBean * @run build JMXNamespaceSecurityTest JMXNamespaceViewTest Wombat WombatMBean
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
* *
* @test JMXNamespaceTest.java * @test JMXNamespaceTest.java
* @summary General JMXNamespace test. * @summary General JMXNamespace test.
* @bug 5072476
* @author Daniel Fuchs * @author Daniel Fuchs
* @run clean JMXNamespaceTest * @run clean JMXNamespaceTest
* Wombat WombatMBean JMXRemoteTargetNamespace * Wombat WombatMBean JMXRemoteTargetNamespace
...@@ -34,7 +35,6 @@ ...@@ -34,7 +35,6 @@
* NamespaceController.java NamespaceControllerMBean.java * NamespaceController.java NamespaceControllerMBean.java
* @run main/othervm JMXNamespaceTest * @run main/othervm JMXNamespaceTest
*/ */
import java.io.IOException;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean; import java.lang.management.MemoryMXBean;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
...@@ -51,10 +51,10 @@ import javax.management.InvalidAttributeValueException; ...@@ -51,10 +51,10 @@ import javax.management.InvalidAttributeValueException;
import javax.management.JMX; import javax.management.JMX;
import javax.management.MBeanServer; import javax.management.MBeanServer;
import javax.management.MBeanServerConnection; import javax.management.MBeanServerConnection;
import javax.management.MBeanServerFactory;
import javax.management.NotificationEmitter; import javax.management.NotificationEmitter;
import javax.management.ObjectInstance; import javax.management.ObjectInstance;
import javax.management.ObjectName; import javax.management.ObjectName;
import javax.management.RuntimeOperationsException;
import javax.management.StandardMBean; import javax.management.StandardMBean;
import javax.management.namespace.JMXNamespaces; import javax.management.namespace.JMXNamespaces;
import javax.management.namespace.JMXNamespace; import javax.management.namespace.JMXNamespace;
...@@ -154,7 +154,7 @@ public class JMXNamespaceTest { ...@@ -154,7 +154,7 @@ public class JMXNamespaceTest {
} }
} }
private static class SimpleTestConf { public static class SimpleTestConf {
public final Wombat wombat; public final Wombat wombat;
public final StandardMBean mbean; public final StandardMBean mbean;
public final String dirname; public final String dirname;
...@@ -456,259 +456,56 @@ public class JMXNamespaceTest { ...@@ -456,259 +456,56 @@ public class JMXNamespaceTest {
} }
} }
/** public static void verySimpleTest(String[] args) {
* Test cycle detection. System.err.println("verySimpleTest: starting");
* mkdir test ; cd test ; ln -s . kanga ; ln -s kanga/kanga/roo/kanga roo
* touch kanga/roo/wombat
**/
public static void probeKangaRooTest(String[] args) {
final SimpleTestConf conf;
try { try {
conf = new SimpleTestConf(args); final MBeanServer srv = MBeanServerFactory.createMBeanServer();
try { srv.registerMBean(new JMXNamespace(
final JMXServiceURL url = JMXNamespaces.narrowToNamespace(srv, "foo")),
new JMXServiceURL("rmi","localHost",0); JMXNamespaces.getNamespaceObjectName("foo"));
final Map<String,Object> empty = Collections.emptyMap(); throw new Exception("Excpected IllegalArgumentException not raised.");
final JMXConnectorServer server = } catch (IllegalArgumentException x) {
JMXConnectorServerFactory.newJMXConnectorServer(url, System.err.println("verySimpleTest: got expected exception: "+x);
empty,conf.server);
server.start();
final JMXServiceURL address = server.getAddress();
final JMXConnector client =
JMXConnectorFactory.connect(address,
empty);
final String[] signature = {
JMXServiceURL.class.getName(),
Map.class.getName(),
};
final Object[] params = {
address,
null,
};
final MBeanServerConnection c =
client.getMBeanServerConnection();
// ln -s . kanga
final ObjectName dirName1 =
new ObjectName("kanga//:type=JMXNamespace");
c.createMBean(JMXRemoteTargetNamespace.class.getName(),
dirName1, params,signature);
c.invoke(dirName1, "connect", null, null);
try {
// ln -s kanga//kanga//roo//kanga roo
final JMXNamespace local = new JMXNamespace(
new MBeanServerConnectionWrapper(null,
JMXNamespaceTest.class.getClassLoader()){
@Override
protected MBeanServerConnection getMBeanServerConnection() {
return JMXNamespaces.narrowToNamespace(c,
"kanga//kanga//roo//kanga"
);
}
});
final ObjectName dirName2 =
new ObjectName("roo//:type=JMXNamespace");
conf.server.registerMBean(local,dirName2);
System.out.println(dirName2 + " created!");
try {
// touch kanga/roo/wombat
final ObjectName wombatName1 =
new ObjectName("kanga//roo//"+conf.wombatName);
final WombatMBean wombat1 =
JMX.newMBeanProxy(c,wombatName1,WombatMBean.class);
final String newCaption="I am still the same old wombat";
Exception x = null;
try {
wombat1.setCaption(newCaption);
} catch (RuntimeOperationsException r) {
x=r.getTargetException();
System.out.println("Got expected exception: " + x);
// r.printStackTrace();
}
if (x == null)
throw new RuntimeException("cycle not detected!");
} finally {
c.unregisterMBean(dirName2);
}
} finally {
c.unregisterMBean(dirName1);
client.close();
server.stop();
}
} finally {
conf.close();
}
System.err.println("probeKangaRooTest PASSED");
} catch (Exception x) { } catch (Exception x) {
System.err.println("probeKangaRooTest FAILED: " +x); System.err.println("verySimpleTest FAILED: " +x);
x.printStackTrace(); x.printStackTrace();
throw new RuntimeException(x); throw new RuntimeException(x);
} }
System.err.println("verySimpleTest: PASSED");
} }
/**
* Test cycle detection 2.
* mkdir test ; cd test ; ln -s . roo ; ln -s roo/roo kanga
* touch kanga/roo/wombat ; rm roo ; ln -s kanga roo ;
* touch kanga/roo/wombat
*
**/
public static void probeKangaRooCycleTest(String[] args) {
final SimpleTestConf conf;
try {
conf = new SimpleTestConf(args);
Exception failed = null;
try {
final JMXServiceURL url =
new JMXServiceURL("rmi","localHost",0);
final Map<String,Object> empty = Collections.emptyMap();
final JMXConnectorServer server =
JMXConnectorServerFactory.newJMXConnectorServer(url,
empty,conf.server);
server.start();
final JMXServiceURL address = server.getAddress();
final JMXConnector client =
JMXConnectorFactory.connect(address,
empty);
final String[] signature = {
JMXServiceURL.class.getName(),
Map.class.getName(),
};
final String[] signature2 = {
JMXServiceURL.class.getName(),
Map.class.getName(),
String.class.getName()
};
final Object[] params = {
address,
Collections.emptyMap(),
};
final Object[] params2 = {
address,
null,
"kanga",
};
final MBeanServerConnection c =
client.getMBeanServerConnection();
// ln -s . roo public static void verySimpleTest2(String[] args) {
final ObjectName dirName1 = System.err.println("verySimpleTest2: starting");
new ObjectName("roo//:type=JMXNamespace"); try {
c.createMBean(JMXRemoteTargetNamespace.class.getName(), final MBeanServer srv = MBeanServerFactory.createMBeanServer();
dirName1, params,signature); final JMXConnectorServer cs = JMXConnectorServerFactory.
c.invoke(dirName1, "connect",null,null); newJMXConnectorServer(new JMXServiceURL("rmi",null,0),
try { null, srv);
final Map<String,Object> emptyMap = cs.start();
Collections.emptyMap(); final JMXConnector cc = JMXConnectorFactory.connect(cs.getAddress());
final JMXNamespace local = new JMXNamespace(
new MBeanServerConnectionWrapper( srv.registerMBean(new JMXNamespace(
JMXNamespaces.narrowToNamespace(c, new MBeanServerConnectionWrapper(
"roo//roo//"), JMXNamespaces.narrowToNamespace(
JMXNamespaceTest.class.getClassLoader())) { cc.getMBeanServerConnection(),
}; "foo"))),
// ln -s roo/roo kanga JMXNamespaces.getNamespaceObjectName("foo"));
final ObjectName dirName2 = throw new Exception("Excpected IllegalArgumentException not raised.");
new ObjectName("kanga//:type=JMXNamespace"); } catch (IllegalArgumentException x) {
conf.server.registerMBean(local,dirName2); System.err.println("verySimpleTest2: got expected exception: "+x);
System.out.println(dirName2 + " created!");
try {
// touch kanga/roo/wombat
final ObjectName wombatName1 =
new ObjectName("kanga//roo//"+conf.wombatName);
final WombatMBean wombat1 =
JMX.newMBeanProxy(c,wombatName1,WombatMBean.class);
final String newCaption="I am still the same old wombat";
wombat1.setCaption(newCaption);
// rm roo
c.unregisterMBean(dirName1);
// ln -s kanga roo
System.err.println("**** Creating " + dirName1 +
" ****");
c.createMBean(JMXRemoteTargetNamespace.class.getName(),
dirName1, params2,signature2);
System.err.println("**** Created " + dirName1 +
" ****");
Exception x = null;
try {
// touch kanga/roo/wombat
wombat1.setCaption(newCaption+" I hope");
} catch (RuntimeOperationsException r) {
x=(Exception)r.getCause();
System.out.println("Got expected exception: " + x);
//r.printStackTrace();
}
if (x == null)
throw new RuntimeException("should have failed!");
x = null;
try {
// ls kanga/roo/wombat
System.err.println("**** Connecting " + dirName1 +
" ****");
JMX.newMBeanProxy(c,dirName1,
JMXRemoteNamespaceMBean.class).connect();
System.err.println("**** Connected " + dirName1 +
" ****");
} catch (IOException r) {
x=r;
System.out.println("Got expected exception: " + x);
//r.printStackTrace();
}
System.err.println("**** Expected Exception Not Raised ****");
if (x == null) {
System.out.println(dirName1+" contains: "+
c.queryNames(new ObjectName(
dirName1.getDomain()+"*:*"),null));
throw new RuntimeException("cycle not detected!");
}
} catch (Exception t) {
if (failed == null) failed = t;
} finally {
c.unregisterMBean(dirName2);
}
} finally {
try {
c.unregisterMBean(dirName1);
} catch (Exception t) {
if (failed == null) failed = t;
System.err.println("Failed to unregister "+dirName1+
": "+t);
}
try {
client.close();
} catch (Exception t) {
if (failed == null) failed = t;
System.err.println("Failed to close client: "+t);
}
try {
server.stop();
} catch (Exception t) {
if (failed == null) failed = t;
System.err.println("Failed to stop server: "+t);
}
}
} finally {
try {
conf.close();
} catch (Exception t) {
if (failed == null) failed = t;
System.err.println("Failed to stop server: "+t);
}
}
if (failed != null) throw failed;
System.err.println("probeKangaRooCycleTest PASSED");
} catch (Exception x) { } catch (Exception x) {
System.err.println("probeKangaRooCycleTest FAILED: " +x); System.err.println("verySimpleTest2 FAILED: " +x);
x.printStackTrace(); x.printStackTrace();
throw new RuntimeException(x); throw new RuntimeException(x);
} }
System.err.println("verySimpleTest2: PASSED");
} }
public static void main(String[] args) { public static void main(String[] args) {
simpleTest(args); simpleTest(args);
recursiveTest(args); recursiveTest(args);
probeKangaRooTest(args); verySimpleTest(args);
probeKangaRooCycleTest(args); verySimpleTest2(args);
} }
} }
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
* *
* @test JMXNamespaceViewTest.java * @test JMXNamespaceViewTest.java
* @summary Test the JMXNamespaceView class. * @summary Test the JMXNamespaceView class.
* @bug 5072476
* @author Daniel Fuchs * @author Daniel Fuchs
* @run clean JMXNamespaceViewTest Wombat WombatMBean * @run clean JMXNamespaceViewTest Wombat WombatMBean
* @run build JMXNamespaceViewTest Wombat WombatMBean * @run build JMXNamespaceViewTest Wombat WombatMBean
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
* @test JMXNamespacesTest.java * @test JMXNamespacesTest.java
* @summary Test the static method that rewrite ObjectNames in JMXNamespacesTest * @summary Test the static method that rewrite ObjectNames in JMXNamespacesTest
* @author Daniel Fuchs * @author Daniel Fuchs
* @bug 5072476
* @run clean JMXNamespacesTest * @run clean JMXNamespacesTest
* @compile -XDignore.symbol.file=true JMXNamespacesTest.java * @compile -XDignore.symbol.file=true JMXNamespacesTest.java
* @run main JMXNamespacesTest * @run main JMXNamespacesTest
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
* @test JMXRemoteNamespaceTest.java * @test JMXRemoteNamespaceTest.java
* @summary Basic tests on a JMXRemoteNamespace. * @summary Basic tests on a JMXRemoteNamespace.
* @author Daniel Fuchs * @author Daniel Fuchs
* @bug 5072476
* @run clean JMXRemoteNamespaceTest Wombat WombatMBean * @run clean JMXRemoteNamespaceTest Wombat WombatMBean
* @run build JMXRemoteNamespaceTest Wombat WombatMBean * @run build JMXRemoteNamespaceTest Wombat WombatMBean
* @run main JMXRemoteNamespaceTest * @run main JMXRemoteNamespaceTest
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
/* /*
* *
* @test LazyDomainTest.java * @test LazyDomainTest.java
* @bug 5072476
* @summary Basic test for Lazy Domains. * @summary Basic test for Lazy Domains.
* @author Daniel Fuchs * @author Daniel Fuchs
* @run clean LazyDomainTest Wombat WombatMBean * @run clean LazyDomainTest Wombat WombatMBean
......
/*
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/*
* @test LeadingSeparatorsTest.java
* @summary Test that the semantics of a leading // in ObjectName is respected.
* @author Daniel Fuchs
* @bug 5072476
* @run clean LeadingSeparatorsTest Wombat WombatMBean
* @compile -XDignore.symbol.file=true LeadingSeparatorsTest.java
* @run build LeadingSeparatorsTest Wombat WombatMBean
* @run main LeadingSeparatorsTest
*/
import java.lang.management.ManagementFactory;
import java.util.Arrays;
import java.util.Set;
import java.util.HashSet;
import java.util.logging.Logger;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import javax.management.namespace.JMXNamespaces;
import javax.management.namespace.JMXRemoteNamespace;
import javax.management.namespace.JMXNamespace;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
/**
* Class LeadingSeparatorsTest
* @author Sun Microsystems, 2005 - All rights reserved.
*/
public class LeadingSeparatorsTest {
/**
* A logger for this class.
**/
private static final Logger LOG =
Logger.getLogger(LeadingSeparatorsTest.class.getName());
/** Creates a new instance of NullObjectNameTest */
public LeadingSeparatorsTest() {
}
public static interface MyWombatMBean extends WombatMBean {
public Set<ObjectName> untrue(ObjectName pat) throws Exception;
}
public static class MyWombat
extends Wombat implements MyWombatMBean {
public MyWombat() throws NotCompliantMBeanException {
super(MyWombatMBean.class);
}
public Set<ObjectName> untrue(ObjectName pat) throws Exception {
final Set<ObjectName> res=listMatching(pat.withDomain("*"));
final Set<ObjectName> untrue = new HashSet<ObjectName>();
for (ObjectName a:res) {
untrue.add(a.withDomain(pat.getDomain()+"//"+a.getDomain()));
}
return untrue;
}
}
static String failure=null;
public static void testRegister() throws Exception {
final MBeanServer top = ManagementFactory.getPlatformMBeanServer();
final MBeanServer sub = MBeanServerFactory.createMBeanServer();
final JMXServiceURL url = new JMXServiceURL("rmi",null,0);
final JMXConnectorServer srv =
JMXConnectorServerFactory.newJMXConnectorServer(url,null,sub);
srv.start();
try {
// Create a namespace rmi// that points to 'sub' and flows through
// a JMXRemoteNamespace connected to 'srv'
// The namespace rmi// will accept createMBean, but not registerMBean.
//
final JMXRemoteNamespace rmiHandler = JMXRemoteNamespace.
newJMXRemoteNamespace(srv.getAddress(),null);
top.registerMBean(rmiHandler,
JMXNamespaces.getNamespaceObjectName("rmi"));
top.invoke(JMXNamespaces.getNamespaceObjectName("rmi"),
"connect", null, null);
// Create a namespace direct// that points to 'sub' and flows
// through a direct reference to 'sub'.
// The namespace direct// will accept createMBean, and registerMBean.
//
final JMXNamespace directHandler = new JMXNamespace(sub);
top.registerMBean(directHandler,
JMXNamespaces.getNamespaceObjectName("direct"));
final ObjectName n1 = new ObjectName("//direct//w:type=Wombat");
final ObjectName n2 = new ObjectName("direct//w:type=Wombat");
final ObjectName n3 = new ObjectName("//rmi//w:type=Wombat");
final ObjectName n4 = new ObjectName("rmi//w:type=Wombat");
// register wombat using an object name with a leading //
final Object obj = new MyWombat();
// check that returned object name doesn't have the leading //
assertEquals(n2,top.registerMBean(obj, n1).getObjectName());
System.out.println(n1+" registered");
// check that the registered Wombat can be accessed with all its
// names.
System.out.println(n2+" mood is: "+top.getAttribute(n2, "Mood"));
System.out.println(n1+" mood is: "+top.getAttribute(n1, "Mood"));
System.out.println(n4+" mood is: "+top.getAttribute(n4, "Mood"));
System.out.println(n3+" mood is: "+top.getAttribute(n3, "Mood"));
// call listMatching. The result should not contain any prefix.
final Set<ObjectName> res = (Set<ObjectName>)
top.invoke(n3, "listMatching",
// remove rmi// from rmi//*:*
JMXNamespaces.deepReplaceHeadNamespace(
new Object[] {ObjectName.WILDCARD.withDomain("rmi//*")},
"rmi", ""), new String[] {ObjectName.class.getName()});
// add rmi// prefix to all names in res.
final Set<ObjectName> res1 =
JMXNamespaces.deepReplaceHeadNamespace(res, "", "rmi");
System.out.println("got: "+res1);
// compute expected result
final Set<ObjectName> res2 = sub.queryNames(null,null);
final Set<ObjectName> res3 = new HashSet<ObjectName>();
for (ObjectName o:res2) {
res3.add(o.withDomain("rmi//"+o.getDomain()));
}
System.out.println("expected: "+res3);
assertEquals(res1, res3);
// invoke "untrue(//niark//niark:*)"
// should return a set were all ObjectNames begin with
// //niark//niark//
//
final Set<ObjectName> res4 = (Set<ObjectName>)
top.invoke(n3, "untrue",
// remove niark//niark : should remove nothing since
// our ObjectName begins with a leading //
JMXNamespaces.deepReplaceHeadNamespace(
new Object[] {
ObjectName.WILDCARD.withDomain("//niark//niark")},
"niark//niark", ""),
new String[] {ObjectName.class.getName()});
System.out.println("got: "+res4);
// add rmi// should add nothing since the returned names have a
// leading //
//
final Set<ObjectName> res5 =
JMXNamespaces.deepReplaceHeadNamespace(res4, "", "rmi");
System.out.println("got#2: "+res5);
// compute expected result
final Set<ObjectName> res6 = new HashSet<ObjectName>();
for (ObjectName o:res2) {
res6.add(o.withDomain("//niark//niark//"+o.getDomain()));
}
System.out.println("expected: "+res6);
// both res4 and res5 should be equals to the expected result.
assertEquals(res4, res6);
assertEquals(res5, res6);
} finally {
srv.stop();
}
if (failure != null)
throw new Exception(failure);
}
private static void assertEquals(Object x, Object y) {
if (!equal(x, y))
failed("expected " + string(x) + "; got " + string(y));
}
private static boolean equal(Object x, Object y) {
if (x == y)
return true;
if (x == null || y == null)
return false;
if (x.getClass().isArray())
return Arrays.deepEquals(new Object[] {x}, new Object[] {y});
return x.equals(y);
}
private static String string(Object x) {
String s = Arrays.deepToString(new Object[] {x});
return s.substring(1, s.length() - 1);
}
private static void failed(String why) {
failure = why;
new Throwable("FAILED: " + why).printStackTrace(System.out);
}
public static void main(String[] args) throws Exception {
testRegister();
}
}
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
* @test NamespaceCreationTest.java * @test NamespaceCreationTest.java
* @summary General JMXNamespace test. * @summary General JMXNamespace test.
* @author Daniel Fuchs * @author Daniel Fuchs
* @bug 5072476
* @run clean NamespaceCreationTest Wombat WombatMBean * @run clean NamespaceCreationTest Wombat WombatMBean
* @run build NamespaceCreationTest Wombat WombatMBean * @run build NamespaceCreationTest Wombat WombatMBean
* @run main NamespaceCreationTest * @run main NamespaceCreationTest
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
* *
* @test NamespaceNotificationsTest.java 1.12 * @test NamespaceNotificationsTest.java 1.12
* @summary General Namespace & Notifications test. * @summary General Namespace & Notifications test.
* @bug 5072476
* @author Daniel Fuchs * @author Daniel Fuchs
* @run clean NamespaceNotificationsTest * @run clean NamespaceNotificationsTest
* Wombat WombatMBean JMXRemoteTargetNamespace * Wombat WombatMBean JMXRemoteTargetNamespace
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
* @test NullObjectNameTest.java * @test NullObjectNameTest.java
* @summary Test that null ObjectName are correctly handled in namespaces. * @summary Test that null ObjectName are correctly handled in namespaces.
* @author Daniel Fuchs * @author Daniel Fuchs
* @bug 5072476
* @run clean NullObjectNameTest Wombat WombatMBean * @run clean NullObjectNameTest Wombat WombatMBean
* @compile -XDignore.symbol.file=true NullObjectNameTest.java * @compile -XDignore.symbol.file=true NullObjectNameTest.java
* @run build NullObjectNameTest Wombat WombatMBean * @run build NullObjectNameTest Wombat WombatMBean
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
* @test QueryNamesTest.java 1.4 * @test QueryNamesTest.java 1.4
* @summary Test how queryNames works with Namespaces. * @summary Test how queryNames works with Namespaces.
* @author Daniel Fuchs * @author Daniel Fuchs
* @bug 5072476
* @run clean QueryNamesTest Wombat WombatMBean * @run clean QueryNamesTest Wombat WombatMBean
* @run build QueryNamesTest Wombat WombatMBean * @run build QueryNamesTest Wombat WombatMBean
* @run main QueryNamesTest * @run main QueryNamesTest
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
* @test RemoveNotificationListenerTest.java 1.8 * @test RemoveNotificationListenerTest.java 1.8
* @summary General RemoveNotificationListenerTest test. * @summary General RemoveNotificationListenerTest test.
* @author Daniel Fuchs * @author Daniel Fuchs
* @bug 5072476
* @run clean RemoveNotificationListenerTest JMXRemoteTargetNamespace * @run clean RemoveNotificationListenerTest JMXRemoteTargetNamespace
* @compile -XDignore.symbol.file=true JMXRemoteTargetNamespace.java * @compile -XDignore.symbol.file=true JMXRemoteTargetNamespace.java
* @run build RemoveNotificationListenerTest JMXRemoteTargetNamespace * @run build RemoveNotificationListenerTest JMXRemoteTargetNamespace
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
* @test RoutingServerProxyTest.java 1.6 * @test RoutingServerProxyTest.java 1.6
* @summary General RoutingServerProxyTest test. * @summary General RoutingServerProxyTest test.
* @author Daniel Fuchs * @author Daniel Fuchs
* @bug 5072476
* @run clean RoutingServerProxyTest Wombat WombatMBean * @run clean RoutingServerProxyTest Wombat WombatMBean
* @compile -XDignore.symbol.file=true RoutingServerProxyTest.java * @compile -XDignore.symbol.file=true RoutingServerProxyTest.java
* @run build RoutingServerProxyTest Wombat WombatMBean * @run build RoutingServerProxyTest Wombat WombatMBean
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
* @test SerialParamProcessorTest.java 1.8 * @test SerialParamProcessorTest.java 1.8
* @summary General SerialParamProcessorTest test. * @summary General SerialParamProcessorTest test.
* @author Daniel Fuchs * @author Daniel Fuchs
* @bug 5072476
* @run clean SerialParamProcessorTest Wombat WombatMBean * @run clean SerialParamProcessorTest Wombat WombatMBean
* @compile -XDignore.symbol.file=true SerialParamProcessorTest.java * @compile -XDignore.symbol.file=true SerialParamProcessorTest.java
* @run build SerialParamProcessorTest Wombat WombatMBean * @run build SerialParamProcessorTest Wombat WombatMBean
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
* *
* @test SourceNamespaceTest.java * @test SourceNamespaceTest.java
* @summary Test how queryNames works with Namespaces. * @summary Test how queryNames works with Namespaces.
* @bug 5072476
* @author Daniel Fuchs * @author Daniel Fuchs
* @run clean SourceNamespaceTest Wombat WombatMBean * @run clean SourceNamespaceTest Wombat WombatMBean
* @run build SourceNamespaceTest Wombat WombatMBean * @run build SourceNamespaceTest Wombat WombatMBean
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
* @test VirtualMBeanNotifTest.java * @test VirtualMBeanNotifTest.java
* @bug 5108776 * @bug 5108776
* @build VirtualMBeanNotifTest Wombat WombatMBean * @build VirtualMBeanNotifTest Wombat WombatMBean
* @run main VirtualMBeanNotifTest
* @summary Test that Virtual MBeans can be implemented and emit notifs. * @summary Test that Virtual MBeans can be implemented and emit notifs.
* @author Daniel Fuchs * @author Daniel Fuchs
*/ */
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
/* /*
* @test VirtualMBeanTest.java * @test VirtualMBeanTest.java
* @bug 5108776 * @bug 5108776 5072476
* @summary Test that Virtual MBeans can be implemented and emit notifs. * @summary Test that Virtual MBeans can be implemented and emit notifs.
* @author Eamonn McManus * @author Eamonn McManus
*/ */
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
* @test VirtualNamespaceQueryTest.java * @test VirtualNamespaceQueryTest.java
* @summary General VirtualNamespaceQueryTest test. * @summary General VirtualNamespaceQueryTest test.
* @author Daniel Fuchs * @author Daniel Fuchs
* @bug 5072476
* @run clean VirtualNamespaceQueryTest Wombat WombatMBean * @run clean VirtualNamespaceQueryTest Wombat WombatMBean
* NamespaceController NamespaceControllerMBean * NamespaceController NamespaceControllerMBean
* JMXRemoteTargetNamespace * JMXRemoteTargetNamespace
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
/* /*
* @test * @test
* @bug 5108776 * @bug 5108776 5072476
* @summary Test the properties use case for Virtual MBeans that is documented * @summary Test the properties use case for Virtual MBeans that is documented
* in MBeanServerSupport. * in MBeanServerSupport.
* @author Eamonn McManus * @author Eamonn McManus
......
...@@ -68,7 +68,12 @@ public class Wombat extends StandardMBean ...@@ -68,7 +68,12 @@ public class Wombat extends StandardMBean
} }
public Wombat() throws NotCompliantMBeanException { public Wombat() throws NotCompliantMBeanException {
super(WombatMBean.class); this(WombatMBean.class);
}
public Wombat(Class<? extends WombatMBean> clazz)
throws NotCompliantMBeanException {
super(clazz);
final Random r = new Random(); final Random r = new Random();
seed = ((r.nextLong() % MAX_SEED) + MAX_SEED)%MAX_SEED; seed = ((r.nextLong() % MAX_SEED) + MAX_SEED)%MAX_SEED;
period = 200 + (((r.nextLong()%80)+80)%80)*10; period = 200 + (((r.nextLong()%80)+80)%80)*10;
......
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
import java.io.IOException;
import java.io.Serializable;
import java.net.Socket;
import java.rmi.server.RMIClientSocketFactory;
import java.util.HashMap;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.Notification;
import javax.management.NotificationBroadcasterSupport;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.rmi.RMIConnectorServer;
/*
* @test
* @bug 6697180
* @summary test on a client notification deadlock.
* @author Shanliang JIANG
* @run clean MultiThreadDeadLockTest
* @run build MultiThreadDeadLockTest
* @run main MultiThreadDeadLockTest
*/
public class MultiThreadDeadLockTest {
private static long serverTimeout = 500L;
public static void main(String[] args) throws Exception {
print("Create the MBean server");
MBeanServer mbs = MBeanServerFactory.createMBeanServer();
print("Initialize environment map");
HashMap env = new HashMap();
print("Specify a client socket factory to control socket creation.");
env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE,
clientFactory);
print("Specify a server idle timeout to make a server close an idle connection.");
env.put("jmx.remote.x.server.connection.timeout", serverTimeout);
print("Disable client heartbeat.");
env.put("jmx.remote.x.client.connection.check.period", 0);
env.put("jmx.remote.x.notification.fetch.timeout", serverTimeout);
print("Create an RMI server");
JMXServiceURL url = new JMXServiceURL("rmi", null, 0);
JMXConnectorServer server =
JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
server.start();
url = server.getAddress();
print("Create jmx client on "+url);
StateMachine.setState(CREATE_SOCKET); // allow to create client socket
client = JMXConnectorFactory.connect(url, env);
Thread.sleep(100);
totoName = new ObjectName("default:name=toto");
mbs.registerMBean(toto, totoName);
print("Register the mbean: " + totoName);
print("Add listener to toto MBean");
client.getMBeanServerConnection().addNotificationListener(
totoName, myListener, null, null);
Thread.sleep(10);
print("send notif, listener will block the fetcher");
toto.sendNotif();
Thread.sleep(100);
StateMachine.setState(NO_OP);
print("Sleep 3 times of server idle timeout: "+serverTimeout+
", the sever should close the idle connection.");
Thread.sleep(serverTimeout*3);
print("start the user thread to call mbean method, it will get IOexception" +
" and start the reconnection, the socket factory will block the" +
" socket creation.");
UserThread ut = new UserThread();
ut.start();
Thread.sleep(10);
print("Free the listener, the fetcher will get IO and makes " +
"a deadlock if the bug is not fixed.");
StateMachine.setState(FREE_LISTENER);
Thread.sleep(100);
print("Allow to create new socket for the reconnection");
StateMachine.setState(CREATE_SOCKET);
print("Check whether the user thread gets free to call the mbean.");
if (!ut.waitDone(5000)) {
throw new RuntimeException("Possible deadlock!");
}
print("Remove the listener.");
client.getMBeanServerConnection().removeNotificationListener(
totoName, myListener, null, null);
Thread.sleep(serverTimeout*3);
print("\nWell passed, bye!");
client.close();
Thread.sleep(10);
server.stop();
}
private static ObjectName totoName = null;
private static JMXConnector client;
public static class UserThread extends Thread {
public UserThread() {
setDaemon(true);
}
public void run() {
try {
client.getMBeanServerConnection().invoke(
totoName, "allowReturn", null, null);
} catch (Exception e) {
throw new Error(e);
}
synchronized(UserThread.class) {
done = true;
UserThread.class.notify();
}
}
public boolean waitDone(long timeout) {
synchronized(UserThread.class) {
if(!done) {
try {
UserThread.class.wait(timeout);
} catch (Exception e) {
throw new Error(e);
}
}
}
return done;
}
private boolean done = false;
}
public static interface TotoMBean {
public void allowReturn();
}
public static class Toto extends NotificationBroadcasterSupport
implements TotoMBean {
public void allowReturn() {
enter("allowReturn");
leave("allowReturn");
}
public void sendNotif() {
enter("sendNotif");
sendNotification(new Notification("Toto", totoName, 0));
leave("sendNotif");
}
}
private static Toto toto = new Toto();
public static NotificationListener myListener = new NotificationListener() {
public void handleNotification(Notification notification, Object handback) {
enter("handleNotification");
StateMachine.waitState(FREE_LISTENER);
leave("handleNotification");
}
};
public static class RMIClientFactory
implements RMIClientSocketFactory, Serializable {
public Socket createSocket(String host, int port) throws IOException {
enter("createSocket");
//print("Calling createSocket(" + host + " " + port + ")");
StateMachine.waitState(CREATE_SOCKET);
Socket s = new Socket(host, port);
leave("createSocket");
return s;
}
}
private static RMIClientFactory clientFactory = new RMIClientFactory();
private static int CREATE_SOCKET = 1;
private static int FREE_LISTENER = 3;
private static int NO_OP = 0;
public static class StateMachine {
private static int state = NO_OP;
private static int[] lock = new int[0];
public static void waitState(int s) {
synchronized (lock) {
while (state != s) {
try {
lock.wait();
} catch (InterruptedException ire) {
// should not
throw new Error(ire);
}
}
}
}
public static int getState() {
synchronized (lock) {
return state;
}
}
public static void setState(int s) {
synchronized (lock) {
state = s;
lock.notifyAll();
}
}
}
private static void print(String m) {
System.out.println(m);
}
private static void enter(String m) {
System.out.println("\n---Enter the method " + m);
}
private static void leave(String m) {
System.out.println("===Leave the method: " + m);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册