diff --git a/jdk/src/share/classes/com/sun/jmx/interceptor/DispatchInterceptor.java b/jdk/src/share/classes/com/sun/jmx/interceptor/DispatchInterceptor.java index 4a79567fed1..f68e539d2fc 100644 --- a/jdk/src/share/classes/com/sun/jmx/interceptor/DispatchInterceptor.java +++ b/jdk/src/share/classes/com/sun/jmx/interceptor/DispatchInterceptor.java @@ -44,7 +44,6 @@ import javax.management.MBeanException; import javax.management.MBeanInfo; import javax.management.MBeanRegistrationException; import javax.management.MBeanServer; -import javax.management.MalformedObjectNameException; import javax.management.NotCompliantMBeanException; import javax.management.NotificationFilter; import javax.management.NotificationListener; @@ -205,8 +204,7 @@ public abstract class DispatchInterceptor // Returns the ObjectName of the JMXNamespace (or JMXDomain) for that // key (a namespace or a domain name). - abstract ObjectName getHandlerNameFor(String key) - throws MalformedObjectNameException; + abstract ObjectName getHandlerNameFor(String key); // Creates an interceptor for the given key, name, JMXNamespace (or // JMXDomain). Note: this will be either a NamespaceInterceptor @@ -263,14 +261,10 @@ public abstract class DispatchInterceptor void validateHandlerNameFor(String key, ObjectName name) { if (key == null || key.equals("")) throw new IllegalArgumentException("invalid key for "+name+": "+key); - try { - final ObjectName handlerName = getHandlerNameFor(key); - if (!name.equals(handlerName)) - throw new IllegalArgumentException("bad handler name: "+name+ - ". Should be: "+handlerName); - } catch (MalformedObjectNameException x) { - throw new IllegalArgumentException(name.toString(),x); - } + final ObjectName handlerName = getHandlerNameFor(key); + if (!name.equals(handlerName)) + throw new IllegalArgumentException("bad handler name: "+name+ + ". Should be: "+handlerName); } // Called by the DefaultMBeanServerInterceptor when an instance diff --git a/jdk/src/share/classes/com/sun/jmx/interceptor/DomainDispatchInterceptor.java b/jdk/src/share/classes/com/sun/jmx/interceptor/DomainDispatchInterceptor.java index 9b9b1d6b19c..388af6b21dd 100644 --- a/jdk/src/share/classes/com/sun/jmx/interceptor/DomainDispatchInterceptor.java +++ b/jdk/src/share/classes/com/sun/jmx/interceptor/DomainDispatchInterceptor.java @@ -38,7 +38,6 @@ import java.util.logging.Logger; import javax.management.MBeanServer; import javax.management.MBeanServerDelegate; -import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import javax.management.QueryExp; import javax.management.namespace.JMXDomain; @@ -248,21 +247,17 @@ class DomainDispatchInterceptor if (pattern == null) return true; if (pattern.isDomainPattern()) return true; - try { - // case b) above. - // - // 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 - // the local namespace in our search. - // - // Returning true will have this effect. see 2. above. - // - if (pattern.apply(ALL_DOMAINS.withDomain(pattern.getDomain()))) - return true; - } catch (MalformedObjectNameException x) { - // should not happen - throw new IllegalArgumentException(String.valueOf(pattern), x); - } + // case b) above. + // + // 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 + // the local namespace in our search. + // + // Returning true will have this effect. see 2. above. + // + if (pattern.apply(ALL_DOMAINS.withDomain(pattern.getDomain()))) + return true; + return false; } @@ -291,8 +286,7 @@ class DomainDispatchInterceptor } @Override - final ObjectName getHandlerNameFor(String key) - throws MalformedObjectNameException { + final ObjectName getHandlerNameFor(String key) { return JMXDomain.getDomainObjectName(key); } diff --git a/jdk/src/share/classes/com/sun/jmx/interceptor/NamespaceDispatchInterceptor.java b/jdk/src/share/classes/com/sun/jmx/interceptor/NamespaceDispatchInterceptor.java index d86c787b898..5ab61f8933a 100644 --- a/jdk/src/share/classes/com/sun/jmx/interceptor/NamespaceDispatchInterceptor.java +++ b/jdk/src/share/classes/com/sun/jmx/interceptor/NamespaceDispatchInterceptor.java @@ -37,8 +37,8 @@ import java.util.logging.Logger; import javax.management.MBeanServer; import javax.management.MBeanServerDelegate; -import javax.management.MalformedObjectNameException; import javax.management.ObjectName; +import javax.management.RuntimeOperationsException; import javax.management.namespace.JMXDomain; import javax.management.namespace.JMXNamespace; import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR; @@ -60,6 +60,7 @@ public class NamespaceDispatchInterceptor private static final int NAMESPACE_SEPARATOR_LENGTH = NAMESPACE_SEPARATOR.length(); + private static final ObjectName X3 = ObjectName.valueOf("x:x=x"); private final DomainDispatchInterceptor nextInterceptor; private final String serverName; @@ -89,27 +90,38 @@ public class NamespaceDispatchInterceptor serverName = Util.getMBeanServerSecurityName(delegate); } - // TODO: Should move that to JMXNamespace? or to ObjectName? /** * Get first name space in ObjectName path. Ignore leading namespace - * separators. + * separators. Includes the trailing //. + * + * Examples: + *
+ * For ObjectName: Returns: + * foo//bar//baz:x=x -> "foo//" + * foo//:type=JMXNamespace -> "foo//" + * foo//:x=x -> "foo//" + * foo////:x=x -> "foo//" + * //foo//bar//baz:x=x -> "//" + * ////foo//bar//baz:x=x -> "//" + * //:x=x -> "//" + * foo:x=x -> "" + * (null) -> "" + * :x=x -> "" + * + ***/ - static String getFirstNamespace(ObjectName name) { + static String getFirstNamespaceWithSlash(ObjectName name) { if (name == null) return ""; final String domain = name.getDomain(); if (domain.equals("")) return ""; - // skip leading separators - int first = 0; - while (domain.startsWith(NAMESPACE_SEPARATOR,first)) - first += NAMESPACE_SEPARATOR_LENGTH; - // go to next separator - final int end = domain.indexOf(NAMESPACE_SEPARATOR,first); + final int end = domain.indexOf(NAMESPACE_SEPARATOR); 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(0,end+NAMESPACE_SEPARATOR_LENGTH); return namespace; } @@ -130,27 +142,49 @@ public class NamespaceDispatchInterceptor resource.getClass().getName()); } - final boolean isLocalHandlerNameFor(String namespace, - ObjectName handlerName) { - return handlerName.getDomain().equals(namespace+NAMESPACE_SEPARATOR) && - JMXNamespace.TYPE_ASSIGNMENT.equals( - handlerName.getKeyPropertyListString()); + // Removes the trailing //. namespaceWithSlash should be either + // "" or a namespace path ending with //. + // + private final String getKeyFor(String namespaceWithSlash) { + final int end = namespaceWithSlash.length() - + NAMESPACE_SEPARATOR_LENGTH; + if (end <= 0) return ""; + final String key = namespaceWithSlash.substring(0,end); + return key; } @Override final MBeanServer getInterceptorOrNullFor(ObjectName name) { - final String namespace = getFirstNamespace(name); - if (namespace.equals("") || isLocalHandlerNameFor(namespace,name) || - name.getDomain().equals(namespace+NAMESPACE_SEPARATOR)) { + final String namespace = getFirstNamespaceWithSlash(name); + + // Leading separators should trigger instance not found exception. + // returning null here has this effect. + // + if (namespace.equals(NAMESPACE_SEPARATOR)) { + LOG.finer("ObjectName starts with: "+namespace); + return null; + } + + // namespace="" means that there was no namespace path in the + // ObjectName. => delegate to the next interceptor (local MBS) + // name.getDomain()=namespace means that we have an ObjectName of + // the form blah//:x=x. This is either a JMXNamespace or a non + // existent MBean. => delegate to the next interceptor (local MBS) + if (namespace.equals("") || name.getDomain().equals(namespace)) { LOG.finer("dispatching to local name space"); return nextInterceptor; } - final NamespaceInterceptor ns = getInterceptor(namespace); + + // There was a namespace path in the ObjectName. Returns the + // interceptor that handles it, or null if there is no such + // interceptor. + final String key = getKeyFor(namespace); + final NamespaceInterceptor ns = getInterceptor(key); if (LOG.isLoggable(Level.FINER)) { if (ns != null) { - LOG.finer("dispatching to name space: " + namespace); + LOG.finer("dispatching to name space: " + key); } else { - LOG.finer("no handler for: " + namespace); + LOG.finer("no handler for: " + key); } } return ns; @@ -158,18 +192,44 @@ public class NamespaceDispatchInterceptor @Override final QueryInterceptor getInterceptorForQuery(ObjectName pattern) { - final String namespace = getFirstNamespace(pattern); - if (namespace.equals("") || isLocalHandlerNameFor(namespace,pattern) || - pattern.getDomain().equals(namespace+NAMESPACE_SEPARATOR)) { + final String namespace = getFirstNamespaceWithSlash(pattern); + + // Leading separators should trigger instance not found exception. + // returning null here has this effect. + // + if (namespace.equals(NAMESPACE_SEPARATOR)) { + LOG.finer("ObjectName starts with: "+namespace); + return null; + } + + // namespace="" means that there was no namespace path in the + // ObjectName. => delegate to the next interceptor (local MBS) + // name.getDomain()=namespace means that we have an ObjectName of + // the form blah//:x=x. This is either a JMXNamespace or a non + // existent MBean. => delegate to the next interceptor (local MBS) + if (namespace.equals("") || pattern.getDomain().equals(namespace)) { LOG.finer("dispatching to local name space"); return new QueryInterceptor(nextInterceptor); } - final NamespaceInterceptor ns = getInterceptor(namespace); + + // This is a 'hack' to check whether the first namespace is a pattern. + // We wan to throw RTOE wrapping IAE in that case + if (X3.withDomain(namespace).isDomainPattern()) { + throw new RuntimeOperationsException( + new IllegalArgumentException("Pattern not allowed in namespace path")); + } + + // There was a namespace path in the ObjectName. Returns the + // interceptor that handles it, or null if there is no such + // interceptor. + // + final String key = getKeyFor(namespace); + final NamespaceInterceptor ns = getInterceptor(key); if (LOG.isLoggable(Level.FINER)) { if (ns != null) { - LOG.finer("dispatching to name space: " + namespace); + LOG.finer("dispatching to name space: " + key); } else { - LOG.finer("no handler for: " + namespace); + LOG.finer("no handler for: " + key); } } if (ns == null) return null; @@ -177,15 +237,16 @@ public class NamespaceDispatchInterceptor } @Override - final ObjectName getHandlerNameFor(String key) - throws MalformedObjectNameException { - return ObjectName.getInstance(key+NAMESPACE_SEPARATOR, + final ObjectName getHandlerNameFor(String key) { + return ObjectName.valueOf(key+NAMESPACE_SEPARATOR, "type", JMXNamespace.TYPE); } @Override final public String getHandlerKey(ObjectName name) { - return getFirstNamespace(name); + final String namespace = getFirstNamespaceWithSlash(name); + // namespace is either "" or a namespace ending with // + return getKeyFor(namespace); } @Override diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanLookup.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanLookup.java index 227c1eec990..605c67f16b4 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanLookup.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanLookup.java @@ -37,7 +37,6 @@ import javax.management.InstanceAlreadyExistsException; import javax.management.JMX; import javax.management.MBeanServerConnection; import javax.management.MBeanServerInvocationHandler; -import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import javax.management.openmbean.OpenDataException; @@ -225,7 +224,7 @@ public abstract class MXBeanLookup { String domain = prefix + name.getDomain(); try { name = name.withDomain(domain); - } catch (MalformedObjectNameException e) { + } catch (IllegalArgumentException e) { throw EnvHelp.initCause( new InvalidObjectException(e.getMessage()), e); } @@ -239,12 +238,14 @@ public abstract class MXBeanLookup { String domain = name.getDomain(); if (!domain.startsWith(prefix)) { throw new OpenDataException( - "Proxy's name does not start with " + prefix + ": " + name); + "Proxy's name does not start with " + + prefix + ": " + name); } try { name = name.withDomain(domain.substring(prefix.length())); - } catch (MalformedObjectNameException e) { - throw EnvHelp.initCause(new OpenDataException(e.getMessage()), e); + } catch (IllegalArgumentException e) { + throw EnvHelp.initCause( + new OpenDataException(e.getMessage()), e); } return name; } diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java index 5fe4d1542cc..1e575e419d2 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Util.java @@ -48,7 +48,6 @@ import java.util.logging.Level; import javax.management.MBeanServer; import javax.management.MBeanServerDelegate; import javax.management.MBeanServerFactory; -import javax.management.MalformedObjectNameException; import javax.management.ObjectInstance; import javax.management.ObjectName; import javax.management.loading.ClassLoaderRepository; diff --git a/jdk/src/share/classes/com/sun/jmx/namespace/DomainInterceptor.java b/jdk/src/share/classes/com/sun/jmx/namespace/DomainInterceptor.java index 7b88087a81c..6e56c8385e8 100644 --- a/jdk/src/share/classes/com/sun/jmx/namespace/DomainInterceptor.java +++ b/jdk/src/share/classes/com/sun/jmx/namespace/DomainInterceptor.java @@ -42,7 +42,6 @@ import javax.management.ListenerNotFoundException; import javax.management.MBeanPermission; import javax.management.MBeanServerDelegate; import javax.management.MBeanServerNotification; -import javax.management.MalformedObjectNameException; import javax.management.Notification; import javax.management.NotificationFilter; import javax.management.NotificationListener; @@ -268,13 +267,9 @@ public class DomainInterceptor extends HandlerInterceptor
ObjectInstance
* objects for the selected MBeans. If no MBean satisfies the
@@ -444,6 +454,11 @@ public interface MBeanServerConnection extends NotificationManager {
*
* @exception IOException A communication problem occurred when
* talking to the MBean server.
+ * @exception RuntimeOperationsException Wraps a
+ * java.lang.IllegalArgumentException
: The name
+ * parameter contains an invalid pattern. See the
+ * namespaces documentation for more details.
*/
public Setjava.lang.IllegalArgumentException
: The name
+ * parameter contains an invalid pattern. See the
+ * namespaces documentation for more details.
*/
public SetThe domain is a string of characters not including
- * the character colon (:
). It is recommended that the domain
- * should not contain the string "{@code //}", which is reserved for future use.
+ * the character colon (:
).
Starting with the version 2.0 of the JMX specification, the
+ * domain can also start with a {@linkplain
+ * javax.management.namespace#NamespacePrefix namespace prefix} identifying
+ * the {@linkplain javax.management.namespace namespace} in which the
+ * MBean is registered. A namespace prefix is a path string where
+ * elements are separated by a double slash (//
).
+ * It identifies the {@linkplain javax.management.namespace namespace} in
+ * which the MBean so named is registered.
For instance the ObjectName bar//baz:k=v identifiies an MBean + * named baz:k=v in the namespace bar. Similarly the + * ObjectName foo//bar//baz:k=v identifiies an MBean named + * baz:k=v in the namespace foo//bar. See the {@linkplain + * javax.management.namespace namespace} documentation for more details.
* *If the domain includes at least one occurrence of the wildcard
* characters asterisk (*
) or question mark
* (?
), then the object name is a pattern. The asterisk
* matches any sequence of zero or more characters, while the question
- * mark matches any single character.
//
does not match wildcard
+ * characters unless it is at the very end of the domain string.
+ * So foo*bar*:* does not match foo//bar:k=v but it
+ * does match fooxbar//:k=v.
+ *
+ *
+ * When included in a namespace path the special path element
+ * **
matches any number of sub namespaces
+ * recursively, but only if used as a complete namespace path element,
+ * as in **//b//c//D:k=v
or a//**//c//D:k=v
+ * - see below.
*
*
If the domain is empty, it will be replaced in certain contexts * by the default domain of the MBean server in which the @@ -171,6 +195,51 @@ import java.util.Map; * with {@code \}. * * + *
Pattern and namespaces:
+ *In an object name pattern, a path element
+ * of exactly **
corresponds to a meta
+ * wildcard that will match any number of sub namespaces.
Hence:
pattern | matches | doesn't match | + * + *
---|---|---|
|
+ * a//D:k=v + * a//b//D:k=v + * a//b//c//D:k=v |
+ * D:k=v |
|
+ * a//b//D:k=v + * a//b//c//D:k=v |
+ * b//b//c//D:k=v + * a//D:k=v + * D:k=v |
|
+ * a//b//e//D:k=v + * a//b//c//e//D:k=v |
+ * a//b//c//c//D:k=v + * b//b//c//e//D:k=v + * a//e//D:k=v + * e//D:k=v |
|
+ * a//b//e//D:k=v |
+ * a//b//c//e//D:k=v + * because in that case b** + * is not a meta-wildcard - and b** + * is thus equivalent to b* . |
+ * Note: Although ObjectName patterns where the characters
+ * *
and ?
appear in the namespace path are legal,
+ * they are not valid in the {@code name} parameter of the MBean Server's
+ * {@link MBeanServer#queryNames queryNames} and {@link MBeanServer#queryMBeans
+ * queryMBeans} methods. See the
+ * namespaces documentation for more details.
+ *
An ObjectName can be written as a String with the following * elements in order:
* @@ -439,11 +508,6 @@ public class ObjectName implements Comparable**
matches any number of sub namespaces
* recursively, but only if used as a complete namespace path element,
* as in **//b//c//D:k=v
or a//**//c//D:k=v
- * - see below.
+ * - see ObjectName documentation
+ * for more details.
*
*
*
@@ -270,38 +271,9 @@ import java.security.Permission;
*
* Note on wildcards: In an object name pattern, a path element
* of exactly **
corresponds to a meta
- * wildcard that will match any number of sub namespaces. Hence:
pattern | matches | doesn't match | - * - *
---|---|---|
**//D:k=v |
- * a//D:k=v - * a//b//D:k=v - * a//b//c//D:k=v |
- * D:k=v |
a//**//D:k=v |
- * a//b//D:k=v - * a//b//c//D:k=v |
- * b//b//c//D:k=v - * a//D:k=v - * D:k=v |
a//**//e//D:k=v |
- * a//b//e//D:k=v - * a//b//c//e//D:k=v |
- * a//b//c//c//D:k=v - * b//b//c//e//D:k=v - * a//e//D:k=v - * e//D:k=v |
a//b**//e//D:k=v |
- * a//b//e//D:k=v |
- * a//b//c//e//D:k=v - * because in that case b** - * is not a meta-wildcard - and b** - * is thus equivalent to b* . |
If {@code member
or object name
may be omitted.
diff --git a/jdk/src/share/classes/javax/management/namespace/JMXNamespaces.java b/jdk/src/share/classes/javax/management/namespace/JMXNamespaces.java
index f19dfa570e4..ca7244abd28 100644
--- a/jdk/src/share/classes/javax/management/namespace/JMXNamespaces.java
+++ b/jdk/src/share/classes/javax/management/namespace/JMXNamespaces.java
@@ -292,17 +292,13 @@ public class JMXNamespaces {
if (path == null || to == null)
throw new IllegalArgumentException("Null argument");
checkTrailingSlashes(path);
- try {
- String prefix = path;
- if (!prefix.equals("")) prefix =
- ObjectNameRouter.normalizeNamespacePath(
+ String prefix = path;
+ if (!prefix.equals(""))
+ prefix = ObjectNameRouter.normalizeNamespacePath(
prefix + NAMESPACE_SEPARATOR,false,false,false);
- return to.withDomain(
+ return to.withDomain(
ObjectNameRouter.normalizeDomain(
prefix+to.getDomain(),false));
- } catch (MalformedObjectNameException x) {
- throw new IllegalArgumentException(path+": "+x,x);
- }
}
/**
diff --git a/jdk/src/share/classes/javax/management/namespace/package-info.java b/jdk/src/share/classes/javax/management/namespace/package-info.java
index df8354bab63..5c014286d4d 100644
--- a/jdk/src/share/classes/javax/management/namespace/package-info.java
+++ b/jdk/src/share/classes/javax/management/namespace/package-info.java
@@ -204,7 +204,38 @@
*
* An easier way to access MBeans contained in a name space is to
* cd inside the name space, as shown in the following paragraph.
- *
+ * Although ObjectName patterns where the characters
+ * *
and ?
appear in the namespace path are
+ * legal, they are not valid in the {@code name} parameter of the
+ * MBean Server {@link
+ * javax.management.MBeanServer#queryNames queryNames} and {@link
+ * javax.management.MBeanServer#queryMBeans queryMBeans} methods.
+ * When invoking queryNames
or queryMBeans
,
+ * only ObjectNames of the form:
+ * [namespace-without-pattern//]*[pattern-without-namespace]:key-properties-with-or-without-pattern
+ * are valid.
+ * In other words: in the case of {@link
+ * javax.management.MBeanServer#queryNames queryNames} and {@link
+ * javax.management.MBeanServer#queryMBeans queryMBeans}, if a
+ * namespace path is present, it must not contain any pattern.
+ *
+ * There is no such restriction for the {@code query} parameter of these
+ * methods. However, it must be noted that the {@code query} parameter
+ * will be evaluated in the context of the namespace where the MBeans
+ * selected by the pattern specified in {@code name} are located.
+ * This means that if {@code query} parameter is an ObjectName pattern that
+ * contains a namespace path, no MBean name will match and the result of
+ * the query will be empty.
+ * In other words:
@@ -228,7 +259,8 @@
* to name space {@code "foo"} behaves just like a regular MBean server.
* However, it may sometimes throw an {@link
* java.lang.UnsupportedOperationException UnsupportedOperationException}
- * wrapped in a JMX exception if you try to call an operation which is not
+ * wrapped in a {@link javax.management.RuntimeOperationsException
+ * RuntimeOperationsException} if you try to call an operation which is not
* supported by the underlying name space handler.
*
For instance, {@link javax.management.MBeanServer#registerMBean
* registerMBean} is not supported for name spaces mounted from remote
diff --git a/jdk/test/javax/management/namespace/LeadingSeparatorsTest.java b/jdk/test/javax/management/namespace/LeadingSeparatorsTest.java
index 5660b275317..6f931ffd46d 100644
--- a/jdk/test/javax/management/namespace/LeadingSeparatorsTest.java
+++ b/jdk/test/javax/management/namespace/LeadingSeparatorsTest.java
@@ -24,7 +24,7 @@
* @test LeadingSeparatorsTest.java
* @summary Test that the semantics of a leading // in ObjectName is respected.
* @author Daniel Fuchs
- * @bug 5072476
+ * @bug 5072476 6768935
* @run clean LeadingSeparatorsTest Wombat WombatMBean
* @compile -XDignore.symbol.file=true LeadingSeparatorsTest.java
* @run build LeadingSeparatorsTest Wombat WombatMBean
@@ -36,6 +36,7 @@ import java.util.Arrays;
import java.util.Set;
import java.util.HashSet;
import java.util.logging.Logger;
+import javax.management.InstanceNotFoundException;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.NotCompliantMBeanException;
@@ -121,19 +122,29 @@ public class LeadingSeparatorsTest {
// 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());
+ assertEquals(n2,top.registerMBean(obj, n2).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"));
+ try {
+ System.out.println(n1+" mood is: "+top.getAttribute(n1, "Mood"));
+ throw new Exception("Excepected exception not thrown for "+n1);
+ } catch (InstanceNotFoundException x) {
+ System.out.println("OK: "+x);
+ }
System.out.println(n4+" mood is: "+top.getAttribute(n4, "Mood"));
- System.out.println(n3+" mood is: "+top.getAttribute(n3, "Mood"));
+ try {
+ System.out.println(n3+" mood is: "+top.getAttribute(n3, "Mood"));
+ throw new Exception("Excepected exception not thrown for "+n3);
+ } catch (InstanceNotFoundException x) {
+ System.out.println("OK: "+x);
+ }
// call listMatching. The result should not contain any prefix.
final Set