mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-16 16:39:48 +00:00
Merge
This commit is contained in:
commit
c3d3d4780a
@ -160,10 +160,8 @@ CORE_PKGS = \
|
||||
javax.lang.model.type \
|
||||
javax.lang.model.util \
|
||||
javax.management \
|
||||
javax.management.event \
|
||||
javax.management.loading \
|
||||
javax.management.monitor \
|
||||
javax.management.namespace \
|
||||
javax.management.relation \
|
||||
javax.management.openmbean \
|
||||
javax.management.timer \
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1999-2007 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
|
||||
@ -176,18 +176,6 @@ public class JmxProperties {
|
||||
public static final String RELATION_LOGGER_NAME =
|
||||
"javax.management.relation";
|
||||
|
||||
/**
|
||||
* Logger name for Namespaces.
|
||||
*/
|
||||
public static final String NAMESPACE_LOGGER_NAME =
|
||||
"javax.management.namespace";
|
||||
|
||||
/**
|
||||
* Logger name for Namespaces.
|
||||
*/
|
||||
public static final Logger NAMESPACE_LOGGER =
|
||||
Logger.getLogger(NAMESPACE_LOGGER_NAME);
|
||||
|
||||
/**
|
||||
* Logger for Relation Service.
|
||||
*/
|
||||
|
||||
@ -69,9 +69,9 @@ public class ServiceName {
|
||||
/**
|
||||
* The version of the JMX specification implemented by this product.
|
||||
* <BR>
|
||||
* The value is <CODE>2.0</CODE>.
|
||||
* The value is <CODE>1.4</CODE>.
|
||||
*/
|
||||
public static final String JMX_SPEC_VERSION = "2.0";
|
||||
public static final String JMX_SPEC_VERSION = "1.4";
|
||||
|
||||
/**
|
||||
* The vendor of the JMX specification implemented by this product.
|
||||
|
||||
@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-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 com.sun.jmx.event;
|
||||
|
||||
import com.sun.jmx.remote.util.ClassLogger;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class DaemonThreadFactory implements ThreadFactory {
|
||||
public DaemonThreadFactory(String nameTemplate) {
|
||||
this(nameTemplate, null);
|
||||
}
|
||||
|
||||
// nameTemplate should be a format with %d in it, which will be replaced
|
||||
// by a sequence number of threads created by this factory.
|
||||
public DaemonThreadFactory(String nameTemplate, ThreadGroup threadGroup) {
|
||||
if (logger.debugOn()) {
|
||||
logger.debug("DaemonThreadFactory",
|
||||
"Construct a new daemon factory: "+nameTemplate);
|
||||
}
|
||||
|
||||
if (threadGroup == null) {
|
||||
SecurityManager s = System.getSecurityManager();
|
||||
threadGroup = (s != null) ? s.getThreadGroup() :
|
||||
Thread.currentThread().getThreadGroup();
|
||||
}
|
||||
|
||||
this.nameTemplate = nameTemplate;
|
||||
this.threadGroup = threadGroup;
|
||||
}
|
||||
|
||||
public Thread newThread(Runnable r) {
|
||||
final String name =
|
||||
String.format(nameTemplate, threadNumber.getAndIncrement());
|
||||
Thread t = new Thread(threadGroup, r, name, 0);
|
||||
t.setDaemon(true);
|
||||
if (t.getPriority() != Thread.NORM_PRIORITY)
|
||||
t.setPriority(Thread.NORM_PRIORITY);
|
||||
|
||||
if (logger.debugOn()) {
|
||||
logger.debug("newThread",
|
||||
"Create a new daemon thread with the name "+t.getName());
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
private final String nameTemplate;
|
||||
private final ThreadGroup threadGroup;
|
||||
private final AtomicInteger threadNumber = new AtomicInteger(1);
|
||||
|
||||
private static final ClassLogger logger =
|
||||
new ClassLogger("com.sun.jmx.event", "DaemonThreadFactory");
|
||||
}
|
||||
@ -1,252 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-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 com.sun.jmx.event;
|
||||
|
||||
import com.sun.jmx.remote.util.ClassLogger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.management.remote.NotificationResult;
|
||||
import javax.management.remote.TargetedNotification;
|
||||
|
||||
public class EventBuffer {
|
||||
|
||||
public EventBuffer() {
|
||||
this(Integer.MAX_VALUE, null);
|
||||
}
|
||||
|
||||
public EventBuffer(int capacity) {
|
||||
this(capacity, new ArrayList<TargetedNotification>());
|
||||
}
|
||||
|
||||
public EventBuffer(int capacity, final List<TargetedNotification> list) {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("EventBuffer", "New buffer with the capacity: "
|
||||
+capacity);
|
||||
}
|
||||
if (capacity < 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"The capacity must be bigger than 0");
|
||||
}
|
||||
|
||||
if (list == null) {
|
||||
throw new NullPointerException("Null list.");
|
||||
}
|
||||
|
||||
this.capacity = capacity;
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
public void add(TargetedNotification tn) {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("add", "Add one notif.");
|
||||
}
|
||||
|
||||
synchronized(lock) {
|
||||
if (list.size() == capacity) { // have to throw one
|
||||
passed++;
|
||||
list.remove(0);
|
||||
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("add", "Over, remove the oldest one.");
|
||||
}
|
||||
}
|
||||
|
||||
list.add(tn);
|
||||
lock.notify();
|
||||
}
|
||||
}
|
||||
|
||||
public void add(TargetedNotification[] tns) {
|
||||
if (tns == null || tns.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("add", "Add notifs: "+tns.length);
|
||||
}
|
||||
|
||||
synchronized(lock) {
|
||||
final int d = list.size() - capacity + tns.length;
|
||||
if (d > 0) { // have to throw
|
||||
passed += d;
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("add",
|
||||
"Over, remove the oldest: "+d);
|
||||
}
|
||||
if (tns.length <= capacity){
|
||||
list.subList(0, d).clear();
|
||||
} else {
|
||||
list.clear();
|
||||
TargetedNotification[] tmp =
|
||||
new TargetedNotification[capacity];
|
||||
System.arraycopy(tns, tns.length-capacity, tmp, 0, capacity);
|
||||
tns = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
Collections.addAll(list,tns);
|
||||
lock.notify();
|
||||
}
|
||||
}
|
||||
|
||||
public NotificationResult fetchNotifications(long startSequenceNumber,
|
||||
long timeout,
|
||||
int maxNotifications) {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("fetchNotifications",
|
||||
"Being called: "
|
||||
+startSequenceNumber+" "
|
||||
+timeout+" "+maxNotifications);
|
||||
}
|
||||
if (startSequenceNumber < 0 ||
|
||||
timeout < 0 ||
|
||||
maxNotifications < 0) {
|
||||
throw new IllegalArgumentException("Negative value.");
|
||||
}
|
||||
|
||||
TargetedNotification[] tns = new TargetedNotification[0];
|
||||
long earliest = startSequenceNumber < passed ?
|
||||
passed : startSequenceNumber;
|
||||
long next = earliest;
|
||||
|
||||
final long startTime = System.currentTimeMillis();
|
||||
long toWait = timeout;
|
||||
synchronized(lock) {
|
||||
int toSkip = (int)(startSequenceNumber - passed);
|
||||
|
||||
// skip those before startSequenceNumber.
|
||||
while (!closed && toSkip > 0) {
|
||||
toWait = timeout - (System.currentTimeMillis() - startTime);
|
||||
if (list.size() == 0) {
|
||||
if (toWait <= 0) {
|
||||
// the notification of startSequenceNumber
|
||||
// does not arrive yet.
|
||||
return new NotificationResult(startSequenceNumber,
|
||||
startSequenceNumber,
|
||||
new TargetedNotification[0]);
|
||||
}
|
||||
|
||||
waiting(toWait);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (toSkip <= list.size()) {
|
||||
list.subList(0, toSkip).clear();
|
||||
passed += toSkip;
|
||||
|
||||
break;
|
||||
} else {
|
||||
passed += list.size();
|
||||
toSkip -= list.size();
|
||||
|
||||
list.clear();
|
||||
}
|
||||
}
|
||||
|
||||
earliest = passed;
|
||||
|
||||
if (list.size() == 0) {
|
||||
toWait = timeout - (System.currentTimeMillis() - startTime);
|
||||
|
||||
waiting(toWait);
|
||||
}
|
||||
|
||||
if (list.size() == 0) {
|
||||
tns = new TargetedNotification[0];
|
||||
} else if (list.size() <= maxNotifications) {
|
||||
tns = list.toArray(new TargetedNotification[0]);
|
||||
} else {
|
||||
tns = new TargetedNotification[maxNotifications];
|
||||
for (int i=0; i<maxNotifications; i++) {
|
||||
tns[i] = list.get(i);
|
||||
}
|
||||
}
|
||||
|
||||
next = earliest + tns.length;
|
||||
}
|
||||
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("fetchNotifications",
|
||||
"Return: "+earliest+" "+next+" "+tns.length);
|
||||
}
|
||||
|
||||
return new NotificationResult(earliest, next, tns);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
public void addLost(long nb) {
|
||||
synchronized(lock) {
|
||||
passed += nb;
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("clear", "done");
|
||||
}
|
||||
|
||||
synchronized(lock) {
|
||||
list.clear();
|
||||
closed = true;
|
||||
lock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------
|
||||
// private classes
|
||||
// -------------------------------------------
|
||||
private void waiting(long timeout) {
|
||||
final long startTime = System.currentTimeMillis();
|
||||
long toWait = timeout;
|
||||
synchronized(lock) {
|
||||
while (!closed && list.size() == 0 && toWait > 0) {
|
||||
try {
|
||||
lock.wait(toWait);
|
||||
|
||||
toWait = timeout - (System.currentTimeMillis() - startTime);
|
||||
} catch (InterruptedException ire) {
|
||||
logger.trace("waiting", ire);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final int capacity;
|
||||
private final List<TargetedNotification> list;
|
||||
private boolean closed;
|
||||
|
||||
private long passed = 0;
|
||||
private final int[] lock = new int[0];
|
||||
|
||||
private static final ClassLogger logger =
|
||||
new ClassLogger("javax.management.event", "EventBuffer");
|
||||
}
|
||||
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-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 com.sun.jmx.event;
|
||||
|
||||
import javax.management.event.*;
|
||||
|
||||
/**
|
||||
* Implemented by objects which are using an {@link EventClient} to
|
||||
* subscribe for Notifications.
|
||||
*
|
||||
*/
|
||||
public interface EventClientFactory {
|
||||
/**
|
||||
* Returns the {@code EventClient} that the object implementing this
|
||||
* interface uses to subscribe for Notifications. This method returns
|
||||
* {@code null} if no {@code EventClient} can be used - e.g. because
|
||||
* the underlying server does not have any {@link EventDelegate}.
|
||||
*
|
||||
* @return an {@code EventClient} or {@code null}.
|
||||
**/
|
||||
public EventClient getEventClient();
|
||||
|
||||
}
|
||||
@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-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 com.sun.jmx.event;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.event.EventClient;
|
||||
import javax.management.event.EventClientDelegate;
|
||||
import javax.management.event.EventConsumer;
|
||||
import javax.management.event.NotificationManager;
|
||||
|
||||
/**
|
||||
* Override the methods related to the notification to use the
|
||||
* Event service.
|
||||
*/
|
||||
public interface EventConnection extends MBeanServerConnection, EventConsumer {
|
||||
public EventClient getEventClient();
|
||||
|
||||
public static class Factory {
|
||||
public static EventConnection make(
|
||||
final MBeanServerConnection mbsc,
|
||||
final EventClient eventClient)
|
||||
throws IOException {
|
||||
if (!mbsc.isRegistered(EventClientDelegate.OBJECT_NAME)) {
|
||||
throw new IOException(
|
||||
"The server does not support the event service.");
|
||||
}
|
||||
InvocationHandler ih = new InvocationHandler() {
|
||||
public Object invoke(Object proxy, Method method, Object[] args)
|
||||
throws Throwable {
|
||||
Class<?> intf = method.getDeclaringClass();
|
||||
try {
|
||||
if (intf.isInstance(eventClient))
|
||||
return method.invoke(eventClient, args);
|
||||
else
|
||||
return method.invoke(mbsc, args);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw e.getCause();
|
||||
}
|
||||
}
|
||||
};
|
||||
// It is important to declare NotificationManager.class first
|
||||
// in the array below, so that the relevant addNL and removeNL
|
||||
// methods will show up with method.getDeclaringClass() as
|
||||
// being from that interface and not MBeanServerConnection.
|
||||
return (EventConnection) Proxy.newProxyInstance(
|
||||
NotificationManager.class.getClassLoader(),
|
||||
new Class<?>[] {
|
||||
NotificationManager.class, EventConnection.class,
|
||||
},
|
||||
ih);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-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 com.sun.jmx.event;
|
||||
|
||||
import com.sun.jmx.mbeanserver.GetPropertyAction;
|
||||
import com.sun.jmx.remote.util.ClassLogger;
|
||||
import java.security.AccessController;
|
||||
import javax.management.event.EventClient;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author sjiang
|
||||
*/
|
||||
public class EventParams {
|
||||
public static final String DEFAULT_LEASE_TIMEOUT =
|
||||
"com.sun.event.lease.time";
|
||||
|
||||
|
||||
@SuppressWarnings("cast") // cast for jdk 1.5
|
||||
public static long getLeaseTimeout() {
|
||||
long timeout = EventClient.DEFAULT_REQUESTED_LEASE_TIME;
|
||||
try {
|
||||
final GetPropertyAction act =
|
||||
new GetPropertyAction(DEFAULT_LEASE_TIMEOUT);
|
||||
final String s = (String)AccessController.doPrivileged(act);
|
||||
if (s != null) {
|
||||
timeout = Long.parseLong(s);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
logger.fine("getLeaseTimeout", "exception getting property", e);
|
||||
}
|
||||
|
||||
return timeout;
|
||||
}
|
||||
|
||||
/** Creates a new instance of EventParams */
|
||||
private EventParams() {
|
||||
}
|
||||
|
||||
private static final ClassLogger logger =
|
||||
new ClassLogger("javax.management.event", "EventParams");
|
||||
}
|
||||
@ -1,155 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-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 com.sun.jmx.event;
|
||||
|
||||
import com.sun.jmx.remote.util.ClassLogger;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* <p>Manage a renewable lease. The lease can be renewed indefinitely
|
||||
* but if the lease runs to its current expiry date without being renewed
|
||||
* then the expiry callback is invoked. If the lease has already expired
|
||||
* when renewal is attempted then the lease method returns zero.</p>
|
||||
* @author sjiang
|
||||
* @author emcmanus
|
||||
*/
|
||||
// The synchronization logic of this class is tricky to deal correctly with the
|
||||
// case where the lease expires at the same time as the |lease| or |stop| method
|
||||
// is called. If the lease is active then the field |scheduled| represents
|
||||
// the expiry task; otherwise |scheduled| is null. Renewing or stopping the
|
||||
// lease involves canceling this task and setting |scheduled| either to a new
|
||||
// task (to renew) or to null (to stop).
|
||||
//
|
||||
// Suppose the expiry task runs at the same time as the |lease| method is called.
|
||||
// If the task enters its synchronized block before the method starts, then
|
||||
// it will set |scheduled| to null and the method will return 0. If the method
|
||||
// starts before the task enters its synchronized block, then the method will
|
||||
// cancel the task which will see that when it later enters the block.
|
||||
// Similar reasoning applies to the |stop| method. It is not expected that
|
||||
// different threads will call |lease| or |stop| simultaneously, although the
|
||||
// logic should be correct then too.
|
||||
public class LeaseManager {
|
||||
public LeaseManager(Runnable callback) {
|
||||
this(callback, EventParams.getLeaseTimeout());
|
||||
}
|
||||
|
||||
public LeaseManager(Runnable callback, long timeout) {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("LeaseManager", "new manager with lease: "+timeout);
|
||||
}
|
||||
if (callback == null) {
|
||||
throw new NullPointerException("Null callback.");
|
||||
}
|
||||
if (timeout <= 0)
|
||||
throw new IllegalArgumentException("Timeout must be positive: " + timeout);
|
||||
|
||||
this.callback = callback;
|
||||
schedule(timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Renew the lease for the given time. The new time can be shorter
|
||||
* than the previous one, in which case the lease will expire earlier
|
||||
* than it would have.</p>
|
||||
*
|
||||
* <p>Calling this method after the lease has expired will return zero
|
||||
* immediately and have no other effect.</p>
|
||||
*
|
||||
* @param timeout the new lifetime. If zero, the lease
|
||||
* will expire immediately.
|
||||
*/
|
||||
public synchronized long lease(long timeout) {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("lease", "new lease to: "+timeout);
|
||||
}
|
||||
|
||||
if (timeout < 0)
|
||||
throw new IllegalArgumentException("Negative lease: " + timeout);
|
||||
|
||||
if (scheduled == null)
|
||||
return 0L;
|
||||
|
||||
scheduled.cancel(false);
|
||||
|
||||
if (logger.traceOn())
|
||||
logger.trace("lease", "start lease: "+timeout);
|
||||
schedule(timeout);
|
||||
|
||||
return timeout;
|
||||
}
|
||||
|
||||
private class Expire implements Runnable {
|
||||
ScheduledFuture<?> task;
|
||||
|
||||
public void run() {
|
||||
synchronized (LeaseManager.this) {
|
||||
if (task.isCancelled())
|
||||
return;
|
||||
scheduled = null;
|
||||
}
|
||||
callback.run();
|
||||
executor.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void schedule(long timeout) {
|
||||
Expire expire = new Expire();
|
||||
scheduled = executor.schedule(expire, timeout, TimeUnit.MILLISECONDS);
|
||||
expire.task = scheduled;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Cancel the lease without calling the expiry callback.</p>
|
||||
*/
|
||||
public synchronized void stop() {
|
||||
logger.trace("stop", "canceling lease");
|
||||
scheduled.cancel(false);
|
||||
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 ScheduledFuture<?> scheduled; // If null, the lease has expired.
|
||||
|
||||
private static final ThreadFactory threadFactory =
|
||||
new DaemonThreadFactory("JMX LeaseManager %d");
|
||||
private final ScheduledExecutorService executor
|
||||
= Executors.newScheduledThreadPool(1, threadFactory);
|
||||
|
||||
private static final ClassLogger logger =
|
||||
new ClassLogger("javax.management.event", "LeaseManager");
|
||||
|
||||
}
|
||||
@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-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 com.sun.jmx.event;
|
||||
|
||||
import com.sun.jmx.remote.util.ClassLogger;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author sjiang
|
||||
*/
|
||||
public class LeaseRenewer {
|
||||
public LeaseRenewer(ScheduledExecutorService scheduler, Callable<Long> doRenew) {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("LeaseRenewer", "New LeaseRenewer.");
|
||||
}
|
||||
|
||||
if (doRenew == null) {
|
||||
throw new NullPointerException("Null job to call server.");
|
||||
}
|
||||
|
||||
this.doRenew = doRenew;
|
||||
nextRenewTime = System.currentTimeMillis();
|
||||
|
||||
this.scheduler = scheduler;
|
||||
future = this.scheduler.schedule(myRenew, 0, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("close", "Close the lease.");
|
||||
}
|
||||
|
||||
synchronized(lock) {
|
||||
if (closed) {
|
||||
return;
|
||||
} else {
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
future.cancel(false); // not interrupt if running
|
||||
} catch (Exception e) {
|
||||
// OK
|
||||
if (logger.debugOn()) {
|
||||
logger.debug("close", "Failed to cancel the leasing job.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean closed() {
|
||||
synchronized(lock) {
|
||||
return closed;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
// private
|
||||
// ------------------------------
|
||||
private final Runnable myRenew = new Runnable() {
|
||||
public void run() {
|
||||
synchronized(lock) {
|
||||
if (closed()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
long next = nextRenewTime - System.currentTimeMillis();
|
||||
if (next < MIN_MILLIS) {
|
||||
try {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("myRenew-run", "");
|
||||
}
|
||||
next = doRenew.call().longValue();
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.fine("myRenew-run", "Failed to renew lease", e);
|
||||
close();
|
||||
}
|
||||
|
||||
if (next > 0 && next < Long.MAX_VALUE) {
|
||||
next = next/2;
|
||||
next = (next < MIN_MILLIS) ? MIN_MILLIS : next;
|
||||
} else {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
nextRenewTime = System.currentTimeMillis() + next;
|
||||
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("myRenew-run", "Next leasing: "+next);
|
||||
}
|
||||
|
||||
synchronized(lock) {
|
||||
if (!closed) {
|
||||
future = scheduler.schedule(this, next, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final Callable<Long> doRenew;
|
||||
private ScheduledFuture<?> future;
|
||||
private boolean closed = false;
|
||||
private long nextRenewTime;
|
||||
|
||||
private final int[] lock = new int[0];
|
||||
|
||||
private final ScheduledExecutorService scheduler;
|
||||
|
||||
private static final long MIN_MILLIS = 50;
|
||||
|
||||
private static final ClassLogger logger =
|
||||
new ClassLogger("javax.management.event", "LeaseRenewer");
|
||||
}
|
||||
@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-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 com.sun.jmx.event;
|
||||
|
||||
import com.sun.jmx.remote.util.ClassLogger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.management.remote.NotificationResult;
|
||||
import javax.management.remote.TargetedNotification;
|
||||
|
||||
|
||||
public class ReceiverBuffer {
|
||||
public void addNotifs(NotificationResult nr) {
|
||||
if (nr == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
TargetedNotification[] tns = nr.getTargetedNotifications();
|
||||
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("addNotifs", "" + tns.length);
|
||||
}
|
||||
|
||||
long impliedStart = nr.getEarliestSequenceNumber();
|
||||
final long missed = impliedStart - start;
|
||||
start = nr.getNextSequenceNumber();
|
||||
|
||||
if (missed > 0) {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("addNotifs",
|
||||
"lost: "+missed);
|
||||
}
|
||||
|
||||
lost += missed;
|
||||
}
|
||||
|
||||
Collections.addAll(notifList, nr.getTargetedNotifications());
|
||||
}
|
||||
|
||||
public TargetedNotification[] removeNotifs() {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("removeNotifs", String.valueOf(notifList.size()));
|
||||
}
|
||||
|
||||
if (notifList.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TargetedNotification[] ret = notifList.toArray(
|
||||
new TargetedNotification[]{});
|
||||
notifList.clear();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return notifList.size();
|
||||
}
|
||||
|
||||
public int removeLost() {
|
||||
int ret = lost;
|
||||
lost = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
private List<TargetedNotification> notifList
|
||||
= new ArrayList<TargetedNotification>();
|
||||
private long start = 0;
|
||||
private int lost = 0;
|
||||
|
||||
private static final ClassLogger logger =
|
||||
new ClassLogger("javax.management.event", "ReceiverBuffer");
|
||||
}
|
||||
@ -1,119 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-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 com.sun.jmx.event;
|
||||
|
||||
import com.sun.jmx.remote.util.ClassLogger;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
/**
|
||||
* <p>A task that is repeatedly run by an Executor. The task will be
|
||||
* repeated as long as the {@link #isSuspended()} method returns true. Once
|
||||
* that method returns false, the task is no longer executed until someone
|
||||
* calls {@link #resume()}.</p>
|
||||
* @author sjiang
|
||||
*/
|
||||
public abstract class RepeatedSingletonJob implements Runnable {
|
||||
public RepeatedSingletonJob(Executor executor) {
|
||||
if (executor == null) {
|
||||
throw new NullPointerException("Null executor!");
|
||||
}
|
||||
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
public boolean isWorking() {
|
||||
return working;
|
||||
}
|
||||
|
||||
public void resume() {
|
||||
|
||||
synchronized(this) {
|
||||
if (!working) {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("resume", "");
|
||||
}
|
||||
working = true;
|
||||
execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void task();
|
||||
public abstract boolean isSuspended();
|
||||
|
||||
public void run() {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("run", "execute the task");
|
||||
}
|
||||
try {
|
||||
task();
|
||||
} catch (Exception e) {
|
||||
// A correct task() implementation should not throw exceptions.
|
||||
// It may cause isSuspended() to start returning true, though.
|
||||
logger.trace("run", "failed to execute the task", e);
|
||||
}
|
||||
|
||||
synchronized(this) {
|
||||
if (!isSuspended()) {
|
||||
execute();
|
||||
} else {
|
||||
if (logger.traceOn()) {
|
||||
logger.trace("run", "suspend the task");
|
||||
}
|
||||
working = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void execute() {
|
||||
try {
|
||||
executor.execute(this);
|
||||
} catch (RejectedExecutionException e) {
|
||||
logger.warning(
|
||||
"execute",
|
||||
"Executor threw exception (" + this.getClass().getName() + ")",
|
||||
e);
|
||||
throw new RejectedExecutionException(
|
||||
"Executor.execute threw exception -" +
|
||||
"should not be possible", e);
|
||||
// User-supplied Executor should not be configured in a way that
|
||||
// might cause this exception, for example if it is shared between
|
||||
// several client objects and doesn't have capacity for one job
|
||||
// from each one. CR 6732037 will add text to the spec explaining
|
||||
// the problem. The rethrown exception will propagate either out
|
||||
// of resume() to user code, or out of run() to the Executor
|
||||
// (which will probably ignore it).
|
||||
}
|
||||
}
|
||||
|
||||
private boolean working = false;
|
||||
private final Executor executor;
|
||||
|
||||
private static final ClassLogger logger =
|
||||
new ClassLogger("javax.management.event", "RepeatedSingletonJob");
|
||||
}
|
||||
@ -30,16 +30,15 @@ package com.sun.jmx.interceptor;
|
||||
import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
|
||||
import com.sun.jmx.mbeanserver.DynamicMBean2;
|
||||
import com.sun.jmx.mbeanserver.Introspector;
|
||||
import com.sun.jmx.mbeanserver.MBeanInjector;
|
||||
import com.sun.jmx.mbeanserver.MBeanInstantiator;
|
||||
import com.sun.jmx.mbeanserver.ModifiableClassLoaderRepository;
|
||||
import com.sun.jmx.mbeanserver.NamedObject;
|
||||
import com.sun.jmx.mbeanserver.NotifySupport;
|
||||
import com.sun.jmx.mbeanserver.Repository;
|
||||
import com.sun.jmx.mbeanserver.Repository.RegistrationContext;
|
||||
import com.sun.jmx.mbeanserver.Util;
|
||||
import com.sun.jmx.remote.util.EnvHelp;
|
||||
|
||||
import java.io.ObjectInputStream;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
@ -48,10 +47,7 @@ import java.security.PrivilegedAction;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.logging.Level;
|
||||
@ -61,7 +57,6 @@ import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.DynamicMBean;
|
||||
import javax.management.DynamicWrapperMBean;
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.IntrospectionException;
|
||||
@ -70,7 +65,6 @@ import javax.management.JMRuntimeException;
|
||||
import javax.management.ListenerNotFoundException;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanNotificationInfo;
|
||||
import javax.management.MBeanPermission;
|
||||
import javax.management.MBeanRegistration;
|
||||
import javax.management.MBeanRegistrationException;
|
||||
@ -81,19 +75,19 @@ import javax.management.MBeanTrustPermission;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.Notification;
|
||||
import javax.management.NotificationBroadcaster;
|
||||
import javax.management.NotificationBroadcasterSupport;
|
||||
import javax.management.NotificationEmitter;
|
||||
import javax.management.NotificationFilter;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.OperationsException;
|
||||
import javax.management.QueryEval;
|
||||
import javax.management.QueryExp;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.RuntimeErrorException;
|
||||
import javax.management.RuntimeMBeanException;
|
||||
import javax.management.RuntimeOperationsException;
|
||||
import javax.management.namespace.JMXNamespace;
|
||||
import javax.management.loading.ClassLoaderRepository;
|
||||
|
||||
/**
|
||||
* This is the default class for MBean manipulation on the agent side. It
|
||||
@ -116,8 +110,7 @@ import javax.management.namespace.JMXNamespace;
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
public class DefaultMBeanServerInterceptor
|
||||
extends MBeanServerInterceptorSupport {
|
||||
public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
|
||||
|
||||
/** The MBeanInstantiator object used by the
|
||||
* DefaultMBeanServerInterceptor */
|
||||
@ -142,14 +135,9 @@ public class DefaultMBeanServerInterceptor
|
||||
new WeakHashMap<ListenerWrapper,
|
||||
WeakReference<ListenerWrapper>>();
|
||||
|
||||
private final NamespaceDispatchInterceptor dispatcher;
|
||||
|
||||
/** The default domain of the object names */
|
||||
private final String domain;
|
||||
|
||||
/** The mbeanServerName */
|
||||
private final String mbeanServerName;
|
||||
|
||||
/** The sequence number identifying the notifications sent */
|
||||
// Now sequence number is handled by MBeanServerDelegate.
|
||||
// private int sequenceNumber=0;
|
||||
@ -168,13 +156,11 @@ public class DefaultMBeanServerInterceptor
|
||||
* @param instantiator The MBeanInstantiator that will be used to
|
||||
* instantiate MBeans and take care of class loading issues.
|
||||
* @param repository The repository to use for this MBeanServer.
|
||||
* @param dispatcher The dispatcher used by this MBeanServer
|
||||
*/
|
||||
public DefaultMBeanServerInterceptor(MBeanServer outer,
|
||||
MBeanServerDelegate delegate,
|
||||
MBeanInstantiator instantiator,
|
||||
Repository repository,
|
||||
NamespaceDispatchInterceptor dispatcher) {
|
||||
Repository repository) {
|
||||
if (outer == null) throw new
|
||||
IllegalArgumentException("outer MBeanServer cannot be null");
|
||||
if (delegate == null) throw new
|
||||
@ -189,8 +175,6 @@ public class DefaultMBeanServerInterceptor
|
||||
this.instantiator = instantiator;
|
||||
this.repository = repository;
|
||||
this.domain = repository.getDefaultDomain();
|
||||
this.dispatcher = dispatcher;
|
||||
this.mbeanServerName = Util.getMBeanServerSecurityName(delegate);
|
||||
}
|
||||
|
||||
public ObjectInstance createMBean(String className, ObjectName name)
|
||||
@ -269,8 +253,8 @@ public class DefaultMBeanServerInterceptor
|
||||
name = nonDefaultDomain(name);
|
||||
}
|
||||
|
||||
checkMBeanPermission(mbeanServerName,className, null, null, "instantiate");
|
||||
checkMBeanPermission(mbeanServerName,className, null, name, "registerMBean");
|
||||
checkMBeanPermission(className, null, null, "instantiate");
|
||||
checkMBeanPermission(className, null, name, "registerMBean");
|
||||
|
||||
/* Load the appropriate class. */
|
||||
if (withDefaultLoaderRepository) {
|
||||
@ -334,7 +318,7 @@ public class DefaultMBeanServerInterceptor
|
||||
|
||||
final String infoClassName = getNewMBeanClassName(object);
|
||||
|
||||
checkMBeanPermission(mbeanServerName,infoClassName, null, name, "registerMBean");
|
||||
checkMBeanPermission(infoClassName, null, name, "registerMBean");
|
||||
checkMBeanTrustPermission(theClass);
|
||||
|
||||
return registerObject(infoClassName, object, name);
|
||||
@ -443,8 +427,7 @@ public class DefaultMBeanServerInterceptor
|
||||
DynamicMBean instance = getMBean(name);
|
||||
// may throw InstanceNotFoundException
|
||||
|
||||
checkMBeanPermission(mbeanServerName, instance, null, name,
|
||||
"unregisterMBean");
|
||||
checkMBeanPermission(instance, null, name, "unregisterMBean");
|
||||
|
||||
if (instance instanceof MBeanRegistration)
|
||||
preDeregisterInvoke((MBeanRegistration) instance);
|
||||
@ -478,8 +461,7 @@ public class DefaultMBeanServerInterceptor
|
||||
name = nonDefaultDomain(name);
|
||||
DynamicMBean instance = getMBean(name);
|
||||
|
||||
checkMBeanPermission(mbeanServerName,
|
||||
instance, null, name, "getObjectInstance");
|
||||
checkMBeanPermission(instance, null, name, "getObjectInstance");
|
||||
|
||||
final String className = getClassName(instance);
|
||||
|
||||
@ -491,7 +473,7 @@ public class DefaultMBeanServerInterceptor
|
||||
if (sm != null) {
|
||||
// Check if the caller has the right to invoke 'queryMBeans'
|
||||
//
|
||||
checkMBeanPermission(mbeanServerName,(String) null, null, null, "queryMBeans");
|
||||
checkMBeanPermission((String) null, null, null, "queryMBeans");
|
||||
|
||||
// Perform query without "query".
|
||||
//
|
||||
@ -504,7 +486,7 @@ public class DefaultMBeanServerInterceptor
|
||||
new HashSet<ObjectInstance>(list.size());
|
||||
for (ObjectInstance oi : list) {
|
||||
try {
|
||||
checkMBeanPermission(mbeanServerName,oi.getClassName(), null,
|
||||
checkMBeanPermission(oi.getClassName(), null,
|
||||
oi.getObjectName(), "queryMBeans");
|
||||
allowedList.add(oi);
|
||||
} catch (SecurityException e) {
|
||||
@ -537,7 +519,7 @@ public class DefaultMBeanServerInterceptor
|
||||
if (sm != null) {
|
||||
// Check if the caller has the right to invoke 'queryNames'
|
||||
//
|
||||
checkMBeanPermission(mbeanServerName,(String) null, null, null, "queryNames");
|
||||
checkMBeanPermission((String) null, null, null, "queryNames");
|
||||
|
||||
// Perform query without "query".
|
||||
//
|
||||
@ -550,7 +532,7 @@ public class DefaultMBeanServerInterceptor
|
||||
new HashSet<ObjectInstance>(list.size());
|
||||
for (ObjectInstance oi : list) {
|
||||
try {
|
||||
checkMBeanPermission(mbeanServerName, oi.getClassName(), null,
|
||||
checkMBeanPermission(oi.getClassName(), null,
|
||||
oi.getObjectName(), "queryNames");
|
||||
allowedList.add(oi);
|
||||
} catch (SecurityException e) {
|
||||
@ -602,7 +584,7 @@ public class DefaultMBeanServerInterceptor
|
||||
if (sm != null) {
|
||||
// Check if the caller has the right to invoke 'getDomains'
|
||||
//
|
||||
checkMBeanPermission(mbeanServerName, (String) null, null, null, "getDomains");
|
||||
checkMBeanPermission((String) null, null, null, "getDomains");
|
||||
|
||||
// Return domains
|
||||
//
|
||||
@ -614,8 +596,8 @@ public class DefaultMBeanServerInterceptor
|
||||
List<String> result = new ArrayList<String>(domains.length);
|
||||
for (int i = 0; i < domains.length; i++) {
|
||||
try {
|
||||
ObjectName dom = ObjectName.valueOf(domains[i] + ":x=x");
|
||||
checkMBeanPermission(mbeanServerName, (String) null, null, dom, "getDomains");
|
||||
ObjectName dom = Util.newObjectName(domains[i] + ":x=x");
|
||||
checkMBeanPermission((String) null, null, dom, "getDomains");
|
||||
result.add(domains[i]);
|
||||
} catch (SecurityException e) {
|
||||
// OK: Do not add this domain to the list
|
||||
@ -659,8 +641,7 @@ public class DefaultMBeanServerInterceptor
|
||||
}
|
||||
|
||||
final DynamicMBean instance = getMBean(name);
|
||||
checkMBeanPermission(mbeanServerName, instance, attribute,
|
||||
name, "getAttribute");
|
||||
checkMBeanPermission(instance, attribute, name, "getAttribute");
|
||||
|
||||
try {
|
||||
return instance.getAttribute(attribute);
|
||||
@ -705,7 +686,7 @@ public class DefaultMBeanServerInterceptor
|
||||
|
||||
// Check if the caller has the right to invoke 'getAttribute'
|
||||
//
|
||||
checkMBeanPermission(mbeanServerName, classname, null, name, "getAttribute");
|
||||
checkMBeanPermission(classname, null, name, "getAttribute");
|
||||
|
||||
// Check if the caller has the right to invoke 'getAttribute'
|
||||
// on each specific attribute
|
||||
@ -714,8 +695,7 @@ public class DefaultMBeanServerInterceptor
|
||||
new ArrayList<String>(attributes.length);
|
||||
for (String attr : attributes) {
|
||||
try {
|
||||
checkMBeanPermission(mbeanServerName, classname, attr,
|
||||
name, "getAttribute");
|
||||
checkMBeanPermission(classname, attr, name, "getAttribute");
|
||||
allowedList.add(attr);
|
||||
} catch (SecurityException e) {
|
||||
// OK: Do not add this attribute to the list
|
||||
@ -760,8 +740,7 @@ public class DefaultMBeanServerInterceptor
|
||||
}
|
||||
|
||||
DynamicMBean instance = getMBean(name);
|
||||
checkMBeanPermission(mbeanServerName, instance, attribute.getName(),
|
||||
name, "setAttribute");
|
||||
checkMBeanPermission(instance, attribute.getName(), name, "setAttribute");
|
||||
|
||||
try {
|
||||
instance.setAttribute(attribute);
|
||||
@ -803,7 +782,7 @@ public class DefaultMBeanServerInterceptor
|
||||
|
||||
// Check if the caller has the right to invoke 'setAttribute'
|
||||
//
|
||||
checkMBeanPermission(mbeanServerName, classname, null, name, "setAttribute");
|
||||
checkMBeanPermission(classname, null, name, "setAttribute");
|
||||
|
||||
// Check if the caller has the right to invoke 'setAttribute'
|
||||
// on each specific attribute
|
||||
@ -811,7 +790,7 @@ public class DefaultMBeanServerInterceptor
|
||||
allowedAttributes = new AttributeList(attributes.size());
|
||||
for (Attribute attribute : attributes.asList()) {
|
||||
try {
|
||||
checkMBeanPermission(mbeanServerName, classname, attribute.getName(),
|
||||
checkMBeanPermission(classname, attribute.getName(),
|
||||
name, "setAttribute");
|
||||
allowedAttributes.add(attribute);
|
||||
} catch (SecurityException e) {
|
||||
@ -835,8 +814,7 @@ public class DefaultMBeanServerInterceptor
|
||||
name = nonDefaultDomain(name);
|
||||
|
||||
DynamicMBean instance = getMBean(name);
|
||||
checkMBeanPermission(mbeanServerName, instance, operationName,
|
||||
name, "invoke");
|
||||
checkMBeanPermission(instance, operationName, name, "invoke");
|
||||
try {
|
||||
return instance.invoke(operationName, params, signature);
|
||||
} catch (Throwable t) {
|
||||
@ -919,12 +897,6 @@ public class DefaultMBeanServerInterceptor
|
||||
|
||||
DynamicMBean mbean = Introspector.makeDynamicMBean(object);
|
||||
|
||||
//Access the ObjectName template value only if the provided name is null
|
||||
if(name == null) {
|
||||
name = Introspector.templateToObjectName(mbean.getMBeanInfo().
|
||||
getDescriptor(), mbean);
|
||||
}
|
||||
|
||||
return registerDynamicMBean(classname, mbean, name);
|
||||
}
|
||||
|
||||
@ -953,8 +925,6 @@ public class DefaultMBeanServerInterceptor
|
||||
ResourceContext context = null;
|
||||
|
||||
try {
|
||||
mbean = injectResources(mbean, server, logicalName);
|
||||
|
||||
if (mbean instanceof DynamicMBean2) {
|
||||
try {
|
||||
((DynamicMBean2) mbean).preRegister2(server, logicalName);
|
||||
@ -973,8 +943,7 @@ public class DefaultMBeanServerInterceptor
|
||||
ObjectName.getInstance(nonDefaultDomain(logicalName));
|
||||
}
|
||||
|
||||
checkMBeanPermission(mbeanServerName, classname, null, logicalName,
|
||||
"registerMBean");
|
||||
checkMBeanPermission(classname, null, logicalName, "registerMBean");
|
||||
|
||||
if (logicalName == null) {
|
||||
final RuntimeException wrapped =
|
||||
@ -988,10 +957,9 @@ public class DefaultMBeanServerInterceptor
|
||||
// Register the MBean with the repository.
|
||||
// Returns the resource context that was used.
|
||||
// The returned context does nothing for regular MBeans.
|
||||
// For ClassLoader MBeans and JMXNamespace (and JMXDomain)
|
||||
// MBeans - the context makes it possible to register these
|
||||
// For ClassLoader MBeans the context makes it possible to register these
|
||||
// objects with the appropriate framework artifacts, such as
|
||||
// the CLR or the dispatcher, from within the repository lock.
|
||||
// the CLR, from within the repository lock.
|
||||
// In case of success, we also need to call context.done() at the
|
||||
// end of this method.
|
||||
//
|
||||
@ -1045,27 +1013,6 @@ public class DefaultMBeanServerInterceptor
|
||||
else return name;
|
||||
}
|
||||
|
||||
private static DynamicMBean injectResources(
|
||||
DynamicMBean mbean, MBeanServer mbs, ObjectName name)
|
||||
throws MBeanRegistrationException {
|
||||
try {
|
||||
Object resource = getResource(mbean);
|
||||
MBeanInjector.inject(resource, mbs, name);
|
||||
if (MBeanInjector.injectsSendNotification(resource)) {
|
||||
MBeanNotificationInfo[] mbnis =
|
||||
mbean.getMBeanInfo().getNotifications();
|
||||
NotificationBroadcasterSupport nbs =
|
||||
new NotificationBroadcasterSupport(mbnis);
|
||||
MBeanInjector.injectSendNotification(resource, nbs);
|
||||
mbean = NotifySupport.wrap(mbean, nbs);
|
||||
}
|
||||
return mbean;
|
||||
} catch (Throwable t) {
|
||||
throwMBeanRegistrationException(t, "injecting @Resources");
|
||||
return null; // not reached
|
||||
}
|
||||
}
|
||||
|
||||
private static void postRegister(
|
||||
ObjectName logicalName, DynamicMBean mbean,
|
||||
boolean registrationDone, boolean registerFailed) {
|
||||
@ -1151,19 +1098,12 @@ public class DefaultMBeanServerInterceptor
|
||||
}
|
||||
|
||||
private static Object getResource(DynamicMBean mbean) {
|
||||
if (mbean instanceof DynamicWrapperMBean)
|
||||
return ((DynamicWrapperMBean) mbean).getWrappedObject();
|
||||
if (mbean instanceof DynamicMBean2)
|
||||
return ((DynamicMBean2) mbean).getResource();
|
||||
else
|
||||
return mbean;
|
||||
}
|
||||
|
||||
private static ClassLoader getResourceLoader(DynamicMBean mbean) {
|
||||
if (mbean instanceof DynamicWrapperMBean)
|
||||
return ((DynamicWrapperMBean) mbean).getWrappedClassLoader();
|
||||
else
|
||||
return mbean.getClass().getClassLoader();
|
||||
}
|
||||
|
||||
private ObjectName nonDefaultDomain(ObjectName name) {
|
||||
if (name == null || name.getDomain().length() > 0)
|
||||
return name;
|
||||
@ -1177,7 +1117,7 @@ public class DefaultMBeanServerInterceptor
|
||||
if one is supplied where it shouldn't be). */
|
||||
final String completeName = domain + name;
|
||||
|
||||
return ObjectName.valueOf(completeName);
|
||||
return Util.newObjectName(completeName);
|
||||
}
|
||||
|
||||
public String getDefaultDomain() {
|
||||
@ -1243,8 +1183,7 @@ public class DefaultMBeanServerInterceptor
|
||||
}
|
||||
|
||||
DynamicMBean instance = getMBean(name);
|
||||
checkMBeanPermission(mbeanServerName, instance, null,
|
||||
name, "addNotificationListener");
|
||||
checkMBeanPermission(instance, null, name, "addNotificationListener");
|
||||
|
||||
NotificationBroadcaster broadcaster =
|
||||
getNotificationBroadcaster(name, instance,
|
||||
@ -1381,8 +1320,7 @@ public class DefaultMBeanServerInterceptor
|
||||
}
|
||||
|
||||
DynamicMBean instance = getMBean(name);
|
||||
checkMBeanPermission(mbeanServerName, instance, null, name,
|
||||
"removeNotificationListener");
|
||||
checkMBeanPermission(instance, null, name, "removeNotificationListener");
|
||||
|
||||
/* We could simplify the code by assigning broadcaster after
|
||||
assigning listenerWrapper, but that would change the error
|
||||
@ -1415,8 +1353,8 @@ public class DefaultMBeanServerInterceptor
|
||||
Class<T> reqClass) {
|
||||
if (reqClass.isInstance(instance))
|
||||
return reqClass.cast(instance);
|
||||
if (instance instanceof DynamicWrapperMBean)
|
||||
instance = ((DynamicWrapperMBean) instance).getWrappedObject();
|
||||
if (instance instanceof DynamicMBean2)
|
||||
instance = ((DynamicMBean2) instance).getResource();
|
||||
if (reqClass.isInstance(instance))
|
||||
return reqClass.cast(instance);
|
||||
final RuntimeException exc =
|
||||
@ -1452,7 +1390,7 @@ public class DefaultMBeanServerInterceptor
|
||||
throw new JMRuntimeException("MBean " + name +
|
||||
"has no MBeanInfo");
|
||||
|
||||
checkMBeanPermission(mbeanServerName, mbi.getClassName(), null, name, "getMBeanInfo");
|
||||
checkMBeanPermission(mbi.getClassName(), null, name, "getMBeanInfo");
|
||||
|
||||
return mbi;
|
||||
}
|
||||
@ -1461,8 +1399,7 @@ public class DefaultMBeanServerInterceptor
|
||||
throws InstanceNotFoundException {
|
||||
|
||||
final DynamicMBean instance = getMBean(name);
|
||||
checkMBeanPermission(mbeanServerName,
|
||||
instance, null, name, "isInstanceOf");
|
||||
checkMBeanPermission(instance, null, name, "isInstanceOf");
|
||||
|
||||
try {
|
||||
Object resource = getResource(instance);
|
||||
@ -1474,20 +1411,12 @@ public class DefaultMBeanServerInterceptor
|
||||
|
||||
if (resourceClassName.equals(className))
|
||||
return true;
|
||||
final ClassLoader cl = getResourceLoader(instance);
|
||||
final ClassLoader cl = resource.getClass().getClassLoader();
|
||||
|
||||
final Class<?> classNameClass = Class.forName(className, false, cl);
|
||||
if (classNameClass.isInstance(resource))
|
||||
return true;
|
||||
|
||||
// Ensure that isInstanceOf(NotificationEmitter) is true when
|
||||
// the MBean is a NotificationEmitter by virtue of a @Resource
|
||||
// annotation specifying a SendNotification resource.
|
||||
// This is a hack.
|
||||
if (instance instanceof NotificationBroadcaster &&
|
||||
classNameClass.isAssignableFrom(NotificationEmitter.class))
|
||||
return true;
|
||||
|
||||
final Class<?> resourceClass = Class.forName(resourceClassName, false, cl);
|
||||
return classNameClass.isAssignableFrom(resourceClass);
|
||||
} catch (Exception x) {
|
||||
@ -1513,9 +1442,8 @@ public class DefaultMBeanServerInterceptor
|
||||
throws InstanceNotFoundException {
|
||||
|
||||
DynamicMBean instance = getMBean(mbeanName);
|
||||
checkMBeanPermission(mbeanServerName, instance, null, mbeanName,
|
||||
"getClassLoaderFor");
|
||||
return getResourceLoader(instance);
|
||||
checkMBeanPermission(instance, null, mbeanName, "getClassLoaderFor");
|
||||
return getResource(instance).getClass().getClassLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1529,13 +1457,12 @@ public class DefaultMBeanServerInterceptor
|
||||
throws InstanceNotFoundException {
|
||||
|
||||
if (loaderName == null) {
|
||||
checkMBeanPermission(mbeanServerName, (String) null, null, null, "getClassLoader");
|
||||
checkMBeanPermission((String) null, null, null, "getClassLoader");
|
||||
return server.getClass().getClassLoader();
|
||||
}
|
||||
|
||||
DynamicMBean instance = getMBean(loaderName);
|
||||
checkMBeanPermission(mbeanServerName, instance, null, loaderName,
|
||||
"getClassLoader");
|
||||
checkMBeanPermission(instance, null, loaderName, "getClassLoader");
|
||||
|
||||
Object resource = getResource(instance);
|
||||
|
||||
@ -1757,6 +1684,49 @@ public class DefaultMBeanServerInterceptor
|
||||
}
|
||||
}
|
||||
|
||||
public Object instantiate(String className) throws ReflectionException,
|
||||
MBeanException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
public Object instantiate(String className, ObjectName loaderName) throws ReflectionException,
|
||||
MBeanException,
|
||||
InstanceNotFoundException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
public Object instantiate(String className, Object[] params,
|
||||
String[] signature) throws ReflectionException, MBeanException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
public Object instantiate(String className, ObjectName loaderName,
|
||||
Object[] params, String[] signature) throws ReflectionException,
|
||||
MBeanException,
|
||||
InstanceNotFoundException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
public ObjectInputStream deserialize(ObjectName name, byte[] data) throws InstanceNotFoundException,
|
||||
OperationsException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
public ObjectInputStream deserialize(String className, byte[] data) throws OperationsException,
|
||||
ReflectionException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
public ObjectInputStream deserialize(String className, ObjectName loaderName,
|
||||
byte[] data) throws InstanceNotFoundException, OperationsException,
|
||||
ReflectionException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
public ClassLoaderRepository getClassLoaderRepository() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
private static class ListenerWrapper implements NotificationListener {
|
||||
ListenerWrapper(NotificationListener l, ObjectName name,
|
||||
Object mbean) {
|
||||
@ -1834,30 +1804,26 @@ public class DefaultMBeanServerInterceptor
|
||||
return mbean.getMBeanInfo().getClassName();
|
||||
}
|
||||
|
||||
private static void checkMBeanPermission(String mbeanServerName,
|
||||
DynamicMBean mbean,
|
||||
private static void checkMBeanPermission(DynamicMBean mbean,
|
||||
String member,
|
||||
ObjectName objectName,
|
||||
String actions) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
checkMBeanPermission(mbeanServerName,
|
||||
safeGetClassName(mbean),
|
||||
checkMBeanPermission(safeGetClassName(mbean),
|
||||
member,
|
||||
objectName,
|
||||
actions);
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkMBeanPermission(String mbeanServerName,
|
||||
String classname,
|
||||
private static void checkMBeanPermission(String classname,
|
||||
String member,
|
||||
ObjectName objectName,
|
||||
String actions) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
Permission perm = new MBeanPermission(mbeanServerName,
|
||||
classname,
|
||||
Permission perm = new MBeanPermission(classname,
|
||||
member,
|
||||
objectName,
|
||||
actions);
|
||||
@ -1923,12 +1889,6 @@ public class DefaultMBeanServerInterceptor
|
||||
throws InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException {
|
||||
|
||||
// this will throw an exception if the pair (resource, logicalName)
|
||||
// violates namespace conventions - for instance, if logicalName
|
||||
// ends with // but resource is not a JMXNamespace.
|
||||
//
|
||||
checkResourceObjectNameConstraints(resource, logicalName);
|
||||
|
||||
// Creates a registration context, if needed.
|
||||
//
|
||||
final ResourceContext context =
|
||||
@ -1995,56 +1955,6 @@ public class DefaultMBeanServerInterceptor
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks that the ObjectName is legal with regards to the
|
||||
* type of the MBean resource.
|
||||
* If the MBean name is domain:type=JMXDomain, the
|
||||
* MBean must be a JMXDomain.
|
||||
* If the MBean name is namespace//:type=JMXNamespace, the
|
||||
* MBean must be a JMXNamespace.
|
||||
* If the MBean is a JMXDomain, its name
|
||||
* must be domain:type=JMXDomain.
|
||||
* If the MBean is a JMXNamespace, its name
|
||||
* must be namespace//:type=JMXNamespace.
|
||||
*/
|
||||
private void checkResourceObjectNameConstraints(Object resource,
|
||||
ObjectName logicalName)
|
||||
throws MBeanRegistrationException {
|
||||
try {
|
||||
dispatcher.checkLocallyRegistrable(resource, logicalName);
|
||||
} catch (Throwable x) {
|
||||
DefaultMBeanServerInterceptor.throwMBeanRegistrationException(x, "validating ObjectName");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a JMXNamespace with the dispatcher.
|
||||
* This method is called by the ResourceContext from within the
|
||||
* repository lock.
|
||||
* @param namespace The JMXNamespace
|
||||
* @param logicalName The JMXNamespaceMBean ObjectName
|
||||
* @param postQueue A queue that will be processed after postRegister.
|
||||
*/
|
||||
private void addJMXNamespace(JMXNamespace namespace,
|
||||
final ObjectName logicalName,
|
||||
final Queue<Runnable> postQueue) {
|
||||
dispatcher.addInterceptorFor(logicalName, namespace, postQueue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a JMXNamespace from the dispatcher.
|
||||
* This method is called by the ResourceContext from within the
|
||||
* repository lock.
|
||||
* @param namespace The JMXNamespace
|
||||
* @param logicalName The JMXNamespaceMBean ObjectName
|
||||
* @param postQueue A queue that will be processed after postDeregister.
|
||||
*/
|
||||
private void removeJMXNamespace(JMXNamespace namespace,
|
||||
final ObjectName logicalName,
|
||||
final Queue<Runnable> postQueue) {
|
||||
dispatcher.removeInterceptorFor(logicalName, namespace, postQueue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a ClassLoader with the CLR.
|
||||
* This method is called by the ResourceContext from within the
|
||||
@ -2099,51 +2009,6 @@ public class DefaultMBeanServerInterceptor
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a ResourceContext for a JMXNamespace MBean.
|
||||
* The resource context makes it possible to add the JMXNamespace to
|
||||
* (ResourceContext.registering) or resp. remove the JMXNamespace from
|
||||
* (ResourceContext.unregistered) the NamespaceDispatchInterceptor
|
||||
* when the associated MBean is added to or resp. removed from the
|
||||
* repository.
|
||||
* Note: JMXDomains are special sub classes of JMXNamespaces and
|
||||
* are also handled by this object.
|
||||
*
|
||||
* @param namespace The JMXNamespace MBean being registered or
|
||||
* unregistered.
|
||||
* @param logicalName The name of the JMXNamespace MBean.
|
||||
* @return a ResourceContext that takes in charge the addition or removal
|
||||
* of the namespace to or from the NamespaceDispatchInterceptor.
|
||||
*/
|
||||
private ResourceContext createJMXNamespaceContext(
|
||||
final JMXNamespace namespace,
|
||||
final ObjectName logicalName) {
|
||||
final Queue<Runnable> doneTaskQueue = new LinkedList<Runnable>();
|
||||
return new ResourceContext() {
|
||||
|
||||
public void registering() {
|
||||
addJMXNamespace(namespace, logicalName, doneTaskQueue);
|
||||
}
|
||||
|
||||
public void unregistered() {
|
||||
removeJMXNamespace(namespace, logicalName,
|
||||
doneTaskQueue);
|
||||
}
|
||||
|
||||
public void done() {
|
||||
for (Runnable r : doneTaskQueue) {
|
||||
try {
|
||||
r.run();
|
||||
} catch (RuntimeException x) {
|
||||
MBEANSERVER_LOGGER.log(Level.FINE,
|
||||
"Failed to process post queue for "+
|
||||
logicalName, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ResourceContext for a ClassLoader MBean.
|
||||
* The resource context makes it possible to add the ClassLoader to
|
||||
@ -2180,8 +2045,7 @@ public class DefaultMBeanServerInterceptor
|
||||
* Creates a ResourceContext for the given resource.
|
||||
* If the resource does not need a ResourceContext, returns
|
||||
* ResourceContext.NONE.
|
||||
* At this time, only JMXNamespaces and ClassLoaders need a
|
||||
* ResourceContext.
|
||||
* At this time, only ClassLoaders need a ResourceContext.
|
||||
*
|
||||
* @param resource The resource being registered or unregistered.
|
||||
* @param logicalName The name of the associated MBean.
|
||||
@ -2189,10 +2053,6 @@ public class DefaultMBeanServerInterceptor
|
||||
*/
|
||||
private ResourceContext makeResourceContextFor(Object resource,
|
||||
ObjectName logicalName) {
|
||||
if (resource instanceof JMXNamespace) {
|
||||
return createJMXNamespaceContext((JMXNamespace) resource,
|
||||
logicalName);
|
||||
}
|
||||
if (resource instanceof ClassLoader) {
|
||||
return createClassLoaderContext((ClassLoader) resource,
|
||||
logicalName);
|
||||
|
||||
@ -1,551 +0,0 @@
|
||||
/*
|
||||
* 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 com.sun.jmx.interceptor;
|
||||
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.IntrospectionException;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.ListenerNotFoundException;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanRegistrationException;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.NotificationFilter;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.QueryExp;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.namespace.JMXNamespace;
|
||||
|
||||
/**
|
||||
* A dispatcher that dispatches to MBeanServers.
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
//
|
||||
// This is the base class for implementing dispatchers. We have two concrete
|
||||
// dispatcher implementations:
|
||||
//
|
||||
// * A NamespaceDispatchInterceptor, which dispatch calls to existing
|
||||
// namespace interceptors
|
||||
// * A DomainDispatchInterceptor, which dispatch calls to existing domain
|
||||
// interceptors.
|
||||
//
|
||||
// With the JMX Namespaces feature, the JMX MBeanServer is now structured
|
||||
// as follows:
|
||||
//
|
||||
// The JMX MBeanServer delegates to a NamespaceDispatchInterceptor,
|
||||
// which either dispatches to a namespace, or delegates to the
|
||||
// DomainDispatchInterceptor (if the object name contained no namespace).
|
||||
// The DomainDispatchInterceptor in turn either dispatches to a domain (if
|
||||
// there is a JMXDomain for that domain) or delegates to the
|
||||
// DefaultMBeanServerInterceptor (if there is no JMXDomain for that
|
||||
// domain). This makes the following picture:
|
||||
//
|
||||
// JMX MBeanServer (outer shell)
|
||||
// |
|
||||
// |
|
||||
// NamespaceDispatchInterceptor
|
||||
// / \
|
||||
// no namespace in object name? \
|
||||
// / \
|
||||
// / dispatch to namespace
|
||||
// DomainDispatchInterceptor
|
||||
// / \
|
||||
// no JMXDomain for domain? \
|
||||
// / \
|
||||
// / dispatch to domain
|
||||
// DefaultMBeanServerInterceptor
|
||||
// /
|
||||
// invoke locally registered MBean
|
||||
//
|
||||
// The logic for maintaining a map of interceptors
|
||||
// and dispatching to impacted interceptor, is implemented in this
|
||||
// base class, which both NamespaceDispatchInterceptor and
|
||||
// DomainDispatchInterceptor extend.
|
||||
//
|
||||
public abstract class DispatchInterceptor
|
||||
<T extends MBeanServer, N extends JMXNamespace>
|
||||
extends MBeanServerInterceptorSupport {
|
||||
|
||||
/**
|
||||
* This is an abstraction which allows us to handle queryNames
|
||||
* and queryMBeans with the same algorithm. There are some subclasses
|
||||
* where we need to override both queryNames & queryMBeans to apply
|
||||
* the same transformation (usually aggregation of results when
|
||||
* several namespaces/domains are impacted) to both algorithms.
|
||||
* Usually the only thing that varies between the algorithm of
|
||||
* queryNames & the algorithm of queryMBean is the type of objects
|
||||
* in the returned Set. By using a QueryInvoker we can implement the
|
||||
* transformation only once and apply it to both queryNames &
|
||||
* queryMBeans.
|
||||
* @see QueryInterceptor below, and its subclass in
|
||||
* {@link DomainDispatcher}.
|
||||
**/
|
||||
static abstract class QueryInvoker<T> {
|
||||
abstract Set<T> query(MBeanServer mbs,
|
||||
ObjectName pattern, QueryExp query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to perform queryNames. A QueryInvoker that invokes
|
||||
* queryNames on an MBeanServer.
|
||||
**/
|
||||
final static QueryInvoker<ObjectName> queryNamesInvoker =
|
||||
new QueryInvoker<ObjectName>() {
|
||||
Set<ObjectName> query(MBeanServer mbs,
|
||||
ObjectName pattern, QueryExp query) {
|
||||
return mbs.queryNames(pattern,query);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to perform queryMBeans. A QueryInvoker that invokes
|
||||
* queryMBeans on an MBeanServer.
|
||||
**/
|
||||
final static QueryInvoker<ObjectInstance> queryMBeansInvoker =
|
||||
new QueryInvoker<ObjectInstance>() {
|
||||
Set<ObjectInstance> query(MBeanServer mbs,
|
||||
ObjectName pattern, QueryExp query) {
|
||||
return mbs.queryMBeans(pattern,query);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* We use this class to intercept queries.
|
||||
* There's a special case for JMXNamespace MBeans, because
|
||||
* "namespace//*:*" matches both "namespace//domain:k=v" and
|
||||
* "namespace//:type=JMXNamespace".
|
||||
* Therefore, queries may need to be forwarded to more than
|
||||
* on interceptor and the results aggregated...
|
||||
*/
|
||||
static class QueryInterceptor {
|
||||
final MBeanServer wrapped;
|
||||
QueryInterceptor(MBeanServer mbs) {
|
||||
wrapped = mbs;
|
||||
}
|
||||
<X> Set<X> query(ObjectName pattern, QueryExp query,
|
||||
QueryInvoker<X> invoker, MBeanServer server) {
|
||||
return invoker.query(server, pattern, query);
|
||||
}
|
||||
|
||||
public Set<ObjectName> queryNames(ObjectName pattern, QueryExp query) {
|
||||
return query(pattern,query,queryNamesInvoker,wrapped);
|
||||
}
|
||||
|
||||
public Set<ObjectInstance> queryMBeans(ObjectName pattern,
|
||||
QueryExp query) {
|
||||
return query(pattern,query,queryMBeansInvoker,wrapped);
|
||||
}
|
||||
}
|
||||
|
||||
// We don't need a ConcurrentHashMap here because getkeys() returns
|
||||
// an array of keys. Therefore there's no risk to have a
|
||||
// ConcurrentModificationException. We must however take into
|
||||
// account the fact that there can be no interceptor for
|
||||
// some of the returned keys if the map is being modified by
|
||||
// another thread, or by a callback within the same thread...
|
||||
// See getKeys() in this class and query() in DomainDispatcher.
|
||||
//
|
||||
private final Map<String,T> handlerMap =
|
||||
Collections.synchronizedMap(
|
||||
new HashMap<String,T>());
|
||||
|
||||
// The key at which an interceptor for accessing the named MBean can be
|
||||
// found in the handlerMap. Note: there doesn't need to be an interceptor
|
||||
// for that key in the Map.
|
||||
//
|
||||
abstract String getHandlerKey(ObjectName name);
|
||||
|
||||
// Returns an interceptor for that name, or null if there's no interceptor
|
||||
// for that name.
|
||||
abstract MBeanServer getInterceptorOrNullFor(ObjectName name);
|
||||
|
||||
// Returns a QueryInterceptor for that pattern.
|
||||
abstract QueryInterceptor getInterceptorForQuery(ObjectName pattern);
|
||||
|
||||
// Returns the ObjectName of the JMXNamespace (or JMXDomain) for that
|
||||
// key (a namespace or a domain name).
|
||||
abstract ObjectName getHandlerNameFor(String key);
|
||||
|
||||
// Creates an interceptor for the given key, name, JMXNamespace (or
|
||||
// JMXDomain). Note: this will be either a NamespaceInterceptor
|
||||
// wrapping a JMXNamespace, if this object is an instance of
|
||||
// NamespaceDispatchInterceptor, or a DomainInterceptor wrapping a
|
||||
// JMXDomain, if this object is an instance of DomainDispatchInterceptor.
|
||||
abstract T createInterceptorFor(String key, ObjectName name,
|
||||
N jmxNamespace, Queue<Runnable> postRegisterQueue);
|
||||
//
|
||||
// The next interceptor in the chain.
|
||||
//
|
||||
// For the NamespaceDispatchInterceptor, this the DomainDispatchInterceptor.
|
||||
// For the DomainDispatchInterceptor, this is the
|
||||
// DefaultMBeanServerInterceptor.
|
||||
//
|
||||
// The logic of when to invoke the next interceptor in the chain depends
|
||||
// on the logic of the concrete dispatcher class.
|
||||
//
|
||||
// For instance, the NamespaceDispatchInterceptor invokes the next
|
||||
// interceptor when the object name doesn't contain any namespace.
|
||||
//
|
||||
// On the other hand, the DomainDispatchInterceptor invokes the
|
||||
// next interceptor when there's no interceptor for the accessed domain.
|
||||
//
|
||||
abstract MBeanServer getNextInterceptor();
|
||||
|
||||
// hook for cleanup in subclasses.
|
||||
void interceptorReleased(T interceptor,
|
||||
Queue<Runnable> postDeregisterQueue) {
|
||||
// hook
|
||||
}
|
||||
|
||||
// Hook for subclasses.
|
||||
MBeanServer getInterceptorForCreate(ObjectName name)
|
||||
throws MBeanRegistrationException {
|
||||
final MBeanServer ns = getInterceptorOrNullFor(name);
|
||||
if (ns == null) // name cannot be null here.
|
||||
throw new MBeanRegistrationException(
|
||||
new IllegalArgumentException("No such MBean handler: " +
|
||||
getHandlerKey(name) + " for " +name));
|
||||
return ns;
|
||||
}
|
||||
|
||||
// Hook for subclasses.
|
||||
MBeanServer getInterceptorForInstance(ObjectName name)
|
||||
throws InstanceNotFoundException {
|
||||
final MBeanServer ns = getInterceptorOrNullFor(name);
|
||||
if (ns == null) // name cannot be null here.
|
||||
throw new InstanceNotFoundException(String.valueOf(name));
|
||||
return ns;
|
||||
}
|
||||
|
||||
// sanity checks
|
||||
void validateHandlerNameFor(String key, ObjectName name) {
|
||||
if (key == null || key.equals(""))
|
||||
throw new IllegalArgumentException("invalid key for "+name+": "+key);
|
||||
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
|
||||
// of JMXNamespace (or a subclass of it) is registered as an MBean.
|
||||
// This method is usually invoked from within the repository lock,
|
||||
// hence the necessity of the postRegisterQueue.
|
||||
public void addInterceptorFor(ObjectName name, N jmxNamespace,
|
||||
Queue<Runnable> postRegisterQueue) {
|
||||
final String key = getHandlerKey(name);
|
||||
validateHandlerNameFor(key,name);
|
||||
synchronized (handlerMap) {
|
||||
final T exists =
|
||||
handlerMap.get(key);
|
||||
if (exists != null)
|
||||
throw new IllegalArgumentException(key+
|
||||
": handler already exists");
|
||||
|
||||
final T ns = createInterceptorFor(key,name,jmxNamespace,
|
||||
postRegisterQueue);
|
||||
handlerMap.put(key,ns);
|
||||
}
|
||||
}
|
||||
|
||||
// Called by the DefaultMBeanServerInterceptor when an instance
|
||||
// of JMXNamespace (or a subclass of it) is deregistered.
|
||||
// This method is usually invoked from within the repository lock,
|
||||
// hence the necessity of the postDeregisterQueue.
|
||||
public void removeInterceptorFor(ObjectName name, N jmxNamespace,
|
||||
Queue<Runnable> postDeregisterQueue) {
|
||||
final String key = getHandlerKey(name);
|
||||
final T ns;
|
||||
synchronized(handlerMap) {
|
||||
ns = handlerMap.remove(key);
|
||||
}
|
||||
interceptorReleased(ns,postDeregisterQueue);
|
||||
}
|
||||
|
||||
// Get the interceptor for that key.
|
||||
T getInterceptor(String key) {
|
||||
synchronized (handlerMap) {
|
||||
return handlerMap.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
// We return an array of keys, which makes it possible to make
|
||||
// concurrent modifications of the handlerMap, provided that
|
||||
// the code which loops over the keys is prepared to handle null
|
||||
// interceptors.
|
||||
// See declaration of handlerMap above, and see also query() in
|
||||
// DomainDispatcher
|
||||
//
|
||||
public String[] getKeys() {
|
||||
synchronized (handlerMap) {
|
||||
final int size = handlerMap.size();
|
||||
return handlerMap.keySet().toArray(new String[size]);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final ObjectInstance createMBean(String className, ObjectName name)
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException {
|
||||
return getInterceptorForCreate(name).createMBean(className,name);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final ObjectInstance createMBean(String className, ObjectName name,
|
||||
ObjectName loaderName)
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException, InstanceNotFoundException{
|
||||
return getInterceptorForCreate(name).createMBean(className,name,loaderName);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final ObjectInstance createMBean(String className, ObjectName name,
|
||||
Object params[], String signature[])
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException{
|
||||
return getInterceptorForCreate(name).
|
||||
createMBean(className,name,params,signature);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final ObjectInstance createMBean(String className, ObjectName name,
|
||||
ObjectName loaderName, Object params[],
|
||||
String signature[])
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException, InstanceNotFoundException{
|
||||
return getInterceptorForCreate(name).createMBean(className,name,loaderName,
|
||||
params,signature);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final ObjectInstance registerMBean(Object object, ObjectName name)
|
||||
throws InstanceAlreadyExistsException, MBeanRegistrationException,
|
||||
NotCompliantMBeanException {
|
||||
return getInterceptorForCreate(name).registerMBean(object,name);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final void unregisterMBean(ObjectName name)
|
||||
throws InstanceNotFoundException, MBeanRegistrationException {
|
||||
getInterceptorForInstance(name).unregisterMBean(name);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final ObjectInstance getObjectInstance(ObjectName name)
|
||||
throws InstanceNotFoundException {
|
||||
return getInterceptorForInstance(name).getObjectInstance(name);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final Set<ObjectInstance> queryMBeans(ObjectName name,
|
||||
QueryExp query) {
|
||||
final QueryInterceptor queryInvoker =
|
||||
getInterceptorForQuery(name);
|
||||
if (queryInvoker == null) return Collections.emptySet();
|
||||
else return queryInvoker.queryMBeans(name,query);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
|
||||
final QueryInterceptor queryInvoker =
|
||||
getInterceptorForQuery(name);
|
||||
if (queryInvoker == null) return Collections.emptySet();
|
||||
else return queryInvoker.queryNames(name,query);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final boolean isRegistered(ObjectName name) {
|
||||
final MBeanServer mbs = getInterceptorOrNullFor(name);
|
||||
if (mbs == null) return false;
|
||||
else return mbs.isRegistered(name);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public Integer getMBeanCount() {
|
||||
return getNextInterceptor().getMBeanCount();
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final Object getAttribute(ObjectName name, String attribute)
|
||||
throws MBeanException, AttributeNotFoundException,
|
||||
InstanceNotFoundException, ReflectionException {
|
||||
return getInterceptorForInstance(name).getAttribute(name,attribute);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final AttributeList getAttributes(ObjectName name,
|
||||
String[] attributes)
|
||||
throws InstanceNotFoundException, ReflectionException {
|
||||
return getInterceptorForInstance(name).getAttributes(name,attributes);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final void setAttribute(ObjectName name, Attribute attribute)
|
||||
throws InstanceNotFoundException, AttributeNotFoundException,
|
||||
InvalidAttributeValueException, MBeanException,
|
||||
ReflectionException {
|
||||
getInterceptorForInstance(name).setAttribute(name,attribute);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final AttributeList setAttributes(ObjectName name,
|
||||
AttributeList attributes)
|
||||
throws InstanceNotFoundException, ReflectionException {
|
||||
return getInterceptorForInstance(name).setAttributes(name,attributes);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final Object invoke(ObjectName name, String operationName,
|
||||
Object params[], String signature[])
|
||||
throws InstanceNotFoundException, MBeanException,
|
||||
ReflectionException {
|
||||
return getInterceptorForInstance(name).invoke(name,operationName,params,
|
||||
signature);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public String getDefaultDomain() {
|
||||
return getNextInterceptor().getDefaultDomain();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of domains in which any MBean is currently
|
||||
* registered.
|
||||
*/
|
||||
public abstract String[] getDomains();
|
||||
|
||||
// From MBeanServer
|
||||
public final void addNotificationListener(ObjectName name,
|
||||
NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException {
|
||||
getInterceptorForInstance(name).
|
||||
addNotificationListener(name,listener,filter,
|
||||
handback);
|
||||
}
|
||||
|
||||
|
||||
// From MBeanServer
|
||||
public final void addNotificationListener(ObjectName name,
|
||||
ObjectName listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException {
|
||||
getInterceptorForInstance(name).
|
||||
addNotificationListener(name,listener,filter,
|
||||
handback);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final void removeNotificationListener(ObjectName name,
|
||||
ObjectName listener)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
getInterceptorForInstance(name).
|
||||
removeNotificationListener(name,listener);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final void removeNotificationListener(ObjectName name,
|
||||
ObjectName listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
getInterceptorForInstance(name).
|
||||
removeNotificationListener(name,listener,filter,
|
||||
handback);
|
||||
}
|
||||
|
||||
|
||||
// From MBeanServer
|
||||
public final void removeNotificationListener(ObjectName name,
|
||||
NotificationListener listener)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
getInterceptorForInstance(name).
|
||||
removeNotificationListener(name,listener);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final void removeNotificationListener(ObjectName name,
|
||||
NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
getInterceptorForInstance(name).
|
||||
removeNotificationListener(name,listener,filter,
|
||||
handback);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final MBeanInfo getMBeanInfo(ObjectName name)
|
||||
throws InstanceNotFoundException, IntrospectionException,
|
||||
ReflectionException {
|
||||
return getInterceptorForInstance(name).getMBeanInfo(name);
|
||||
}
|
||||
|
||||
|
||||
// From MBeanServer
|
||||
public final boolean isInstanceOf(ObjectName name, String className)
|
||||
throws InstanceNotFoundException {
|
||||
return getInterceptorForInstance(name).isInstanceOf(name,className);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final ClassLoader getClassLoaderFor(ObjectName mbeanName)
|
||||
throws InstanceNotFoundException {
|
||||
return getInterceptorForInstance(mbeanName).
|
||||
getClassLoaderFor(mbeanName);
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public final ClassLoader getClassLoader(ObjectName loaderName)
|
||||
throws InstanceNotFoundException {
|
||||
return getInterceptorForInstance(loaderName).
|
||||
getClassLoader(loaderName);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,350 +0,0 @@
|
||||
/*
|
||||
* 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 com.sun.jmx.interceptor;
|
||||
|
||||
import com.sun.jmx.defaults.JmxProperties;
|
||||
import com.sun.jmx.mbeanserver.MBeanInstantiator;
|
||||
import com.sun.jmx.mbeanserver.Repository;
|
||||
import com.sun.jmx.mbeanserver.Util;
|
||||
import com.sun.jmx.namespace.DomainInterceptor;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MBeanServerDelegate;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.QueryExp;
|
||||
import javax.management.namespace.JMXDomain;
|
||||
import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR;
|
||||
|
||||
/**
|
||||
* A dispatcher that dispatch incoming MBeanServer requests to
|
||||
* DomainInterceptors.
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
//
|
||||
// See comments in DispatchInterceptor.
|
||||
//
|
||||
class DomainDispatchInterceptor
|
||||
extends DispatchInterceptor<DomainInterceptor, JMXDomain> {
|
||||
|
||||
/**
|
||||
* A logger for this class.
|
||||
**/
|
||||
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
|
||||
|
||||
private static final ObjectName ALL_DOMAINS =
|
||||
JMXDomain.getDomainObjectName("*");
|
||||
|
||||
|
||||
/**
|
||||
* A QueryInterceptor that perform & aggregates queries spanning several
|
||||
* domains.
|
||||
*/
|
||||
final static class AggregatingQueryInterceptor extends QueryInterceptor {
|
||||
|
||||
private final DomainDispatchInterceptor parent;
|
||||
AggregatingQueryInterceptor(DomainDispatchInterceptor dispatcher) {
|
||||
super(dispatcher.nextInterceptor);
|
||||
parent = dispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform queryNames or queryMBeans, depending on which QueryInvoker
|
||||
* is passed as argument. This is closures without closures.
|
||||
**/
|
||||
@Override
|
||||
<T> Set<T> query(ObjectName pattern, QueryExp query,
|
||||
QueryInvoker<T> invoker, MBeanServer localNamespace) {
|
||||
final Set<T> local = invoker.query(localNamespace, pattern, query);
|
||||
|
||||
// Add all matching MBeans from local namespace.
|
||||
final Set<T> res = Util.cloneSet(local);
|
||||
|
||||
if (pattern == null) pattern = ObjectName.WILDCARD;
|
||||
final boolean all = pattern.getDomain().equals("*");
|
||||
|
||||
final String domain = pattern.getDomain();
|
||||
|
||||
// If there's no domain pattern, just include the pattern's domain.
|
||||
// Otherwiae, loop over all virtual domains (parent.getKeys()).
|
||||
final String[] keys =
|
||||
(pattern.isDomainPattern() ?
|
||||
parent.getKeys() : new String[]{domain});
|
||||
|
||||
// Add all matching MBeans from each virtual domain
|
||||
//
|
||||
for (String key : keys) {
|
||||
// Only invoke those virtual domain which are selected
|
||||
// by the domain pattern
|
||||
//
|
||||
if (!all && !Util.isDomainSelected(key, domain))
|
||||
continue;
|
||||
|
||||
try {
|
||||
final MBeanServer mbs = parent.getInterceptor(key);
|
||||
|
||||
// mbs can be null if the interceptor was removed
|
||||
// concurrently...
|
||||
// See handlerMap and getKeys() in DispatchInterceptor
|
||||
//
|
||||
if (mbs == null) continue;
|
||||
|
||||
// If the domain is selected, we can replace the pattern
|
||||
// by the actual domain. This is safer if we want to avoid
|
||||
// a domain (which could be backed up by an MBeanServer) to
|
||||
// return names from outside the domain.
|
||||
// So instead of asking the domain handler for "foo" to
|
||||
// return all names which match "?o*:type=Bla,*" we're
|
||||
// going to ask it to return all names which match
|
||||
// "foo:type=Bla,*"
|
||||
//
|
||||
final ObjectName subPattern = pattern.withDomain(key);
|
||||
res.addAll(invoker.query(mbs, subPattern, query));
|
||||
} catch (Exception x) {
|
||||
LOG.finest("Ignoring exception " +
|
||||
"when attempting to query namespace "+key+": "+x);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
private final DefaultMBeanServerInterceptor nextInterceptor;
|
||||
private final String mbeanServerName;
|
||||
private final MBeanServerDelegate delegate;
|
||||
|
||||
/**
|
||||
* Creates a DomainDispatchInterceptor with the specified
|
||||
* repository instance.
|
||||
*
|
||||
* @param outer A pointer to the MBeanServer object that must be
|
||||
* passed to the MBeans when invoking their
|
||||
* {@link javax.management.MBeanRegistration} interface.
|
||||
* @param delegate A pointer to the MBeanServerDelegate associated
|
||||
* with the new MBeanServer. The new MBeanServer must register
|
||||
* this MBean in its MBean repository.
|
||||
* @param instantiator The MBeanInstantiator that will be used to
|
||||
* instantiate MBeans and take care of class loading issues.
|
||||
* @param repository The repository to use for this MBeanServer
|
||||
*/
|
||||
public DomainDispatchInterceptor(MBeanServer outer,
|
||||
MBeanServerDelegate delegate,
|
||||
MBeanInstantiator instantiator,
|
||||
Repository repository,
|
||||
NamespaceDispatchInterceptor namespaces) {
|
||||
nextInterceptor = new DefaultMBeanServerInterceptor(outer,
|
||||
delegate, instantiator,repository,namespaces);
|
||||
mbeanServerName = Util.getMBeanServerSecurityName(delegate);
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
final boolean isLocalHandlerNameFor(String domain,
|
||||
ObjectName handlerName) {
|
||||
if (domain == null) return true;
|
||||
return handlerName.getDomain().equals(domain) &&
|
||||
JMXDomain.TYPE_ASSIGNMENT.equals(
|
||||
handlerName.getKeyPropertyListString());
|
||||
}
|
||||
|
||||
@Override
|
||||
void validateHandlerNameFor(String key, ObjectName name) {
|
||||
super.validateHandlerNameFor(key,name);
|
||||
final String[] domains = nextInterceptor.getDomains();
|
||||
for (int i=0;i<domains.length;i++) {
|
||||
if (domains[i].equals(key))
|
||||
throw new IllegalArgumentException("domain "+key+
|
||||
" is not empty");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
final MBeanServer getInterceptorOrNullFor(ObjectName name) {
|
||||
|
||||
if (name == null) return nextInterceptor;
|
||||
|
||||
final String domain = name.getDomain();
|
||||
if (domain.endsWith(NAMESPACE_SEPARATOR))
|
||||
return nextInterceptor; // This can be a namespace handler.
|
||||
if (domain.contains(NAMESPACE_SEPARATOR))
|
||||
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");
|
||||
return nextInterceptor;
|
||||
}
|
||||
|
||||
final DomainInterceptor ns = getInterceptor(domain);
|
||||
if (ns == null) {
|
||||
// no JMXDomain found for that domain - return nextInterceptor.
|
||||
if (LOG.isLoggable(Level.FINER)) {
|
||||
LOG.finer("dispatching to local namespace: " + domain);
|
||||
}
|
||||
return getNextInterceptor();
|
||||
}
|
||||
|
||||
if (LOG.isLoggable(Level.FINER)) {
|
||||
LOG.finer("dispatching to domain: " + domain);
|
||||
}
|
||||
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) {
|
||||
// case a) above
|
||||
if (pattern == null) return true;
|
||||
if (pattern.isDomainPattern()) return true;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
final QueryInterceptor getInterceptorForQuery(ObjectName pattern) {
|
||||
|
||||
// Check if we need to aggregate.
|
||||
if (multipleQuery(pattern))
|
||||
return new AggregatingQueryInterceptor(this);
|
||||
|
||||
// We don't need to aggregate: do the "simple" thing...
|
||||
final String domain = pattern.getDomain();
|
||||
|
||||
// Do we have a virtual domain?
|
||||
final DomainInterceptor ns = getInterceptor(domain);
|
||||
if (ns != null) {
|
||||
if (LOG.isLoggable(Level.FINER))
|
||||
LOG.finer("dispatching to domain: " + domain);
|
||||
return new QueryInterceptor(ns);
|
||||
}
|
||||
|
||||
// We don't have a virtual domain. Send to local domains.
|
||||
if (LOG.isLoggable(Level.FINER))
|
||||
LOG.finer("dispatching to local namespace: " + domain);
|
||||
return new QueryInterceptor(nextInterceptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
final ObjectName getHandlerNameFor(String key) {
|
||||
return JMXDomain.getDomainObjectName(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
final public String getHandlerKey(ObjectName name) {
|
||||
return name.getDomain();
|
||||
}
|
||||
|
||||
@Override
|
||||
final DomainInterceptor createInterceptorFor(String key,
|
||||
ObjectName name, JMXDomain handler,
|
||||
Queue<Runnable> postRegisterQueue) {
|
||||
final DomainInterceptor ns =
|
||||
new DomainInterceptor(mbeanServerName,handler,key);
|
||||
ns.addPostRegisterTask(postRegisterQueue, delegate);
|
||||
if (LOG.isLoggable(Level.FINER)) {
|
||||
LOG.finer("DomainInterceptor created: "+ns);
|
||||
}
|
||||
return ns;
|
||||
}
|
||||
|
||||
@Override
|
||||
final void interceptorReleased(DomainInterceptor interceptor,
|
||||
Queue<Runnable> postDeregisterQueue) {
|
||||
interceptor.addPostDeregisterTask(postDeregisterQueue, delegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
final DefaultMBeanServerInterceptor getNextInterceptor() {
|
||||
return nextInterceptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of domains in which any MBean is currently
|
||||
* registered.
|
||||
*/
|
||||
@Override
|
||||
public String[] getDomains() {
|
||||
// A JMXDomain is registered in its own domain.
|
||||
// Therefore, nextInterceptor.getDomains() contains all domains.
|
||||
// In addition, nextInterceptor will perform the necessary
|
||||
// MBeanPermission checks for getDomains().
|
||||
//
|
||||
return nextInterceptor.getDomains();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of MBeans registered in the MBean server.
|
||||
*/
|
||||
@Override
|
||||
public Integer getMBeanCount() {
|
||||
int count = getNextInterceptor().getMBeanCount();
|
||||
final String[] keys = getKeys();
|
||||
for (String key:keys) {
|
||||
final MBeanServer mbs = getInterceptor(key);
|
||||
if (mbs == null) continue;
|
||||
count += mbs.getMBeanCount();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
@ -1,127 +0,0 @@
|
||||
/*
|
||||
* 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 com.sun.jmx.interceptor;
|
||||
|
||||
import java.io.ObjectInputStream;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.OperationsException;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.loading.ClassLoaderRepository;
|
||||
|
||||
/**
|
||||
* An abstract class for MBeanServerInterceptorSupport.
|
||||
* Some methods in MBeanServerInterceptor should never be called.
|
||||
* This base class provides an implementation of these methods that simply
|
||||
* throw an {@link UnsupportedOperationException}.
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
public abstract class MBeanServerInterceptorSupport
|
||||
implements MBeanServerInterceptor {
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
public Object instantiate(String className)
|
||||
throws ReflectionException, MBeanException {
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
public Object instantiate(String className, ObjectName loaderName)
|
||||
throws ReflectionException, MBeanException,
|
||||
InstanceNotFoundException {
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
public Object instantiate(String className, Object[] params,
|
||||
String[] signature) throws ReflectionException, MBeanException {
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
public Object instantiate(String className, ObjectName loaderName,
|
||||
Object[] params, String[] signature)
|
||||
throws ReflectionException, MBeanException,
|
||||
InstanceNotFoundException {
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
@Deprecated
|
||||
public ObjectInputStream deserialize(ObjectName name, byte[] data)
|
||||
throws InstanceNotFoundException, OperationsException {
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
@Deprecated
|
||||
public ObjectInputStream deserialize(String className, byte[] data)
|
||||
throws OperationsException, ReflectionException {
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
@Deprecated
|
||||
public ObjectInputStream deserialize(String className,
|
||||
ObjectName loaderName, byte[] data)
|
||||
throws InstanceNotFoundException, OperationsException,
|
||||
ReflectionException {
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
public ClassLoaderRepository getClassLoaderRepository() {
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,297 +0,0 @@
|
||||
/*
|
||||
* 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 com.sun.jmx.interceptor;
|
||||
|
||||
import com.sun.jmx.defaults.JmxProperties;
|
||||
import com.sun.jmx.mbeanserver.MBeanInstantiator;
|
||||
import com.sun.jmx.mbeanserver.Repository;
|
||||
import com.sun.jmx.mbeanserver.Util;
|
||||
import com.sun.jmx.namespace.NamespaceInterceptor;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MBeanServerDelegate;
|
||||
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;
|
||||
|
||||
/**
|
||||
* A dispatcher that dispatches to NamespaceInterceptors.
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
public class NamespaceDispatchInterceptor
|
||||
extends DispatchInterceptor<NamespaceInterceptor, JMXNamespace> {
|
||||
|
||||
/**
|
||||
* A logger for this class.
|
||||
**/
|
||||
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Creates a NamespaceDispatchInterceptor with the specified
|
||||
* repository instance.
|
||||
* <p>Do not forget to call <code>initialize(outer,delegate)</code>
|
||||
* before using this object.
|
||||
*
|
||||
* @param outer A pointer to the MBeanServer object that must be
|
||||
* passed to the MBeans when invoking their
|
||||
* {@link javax.management.MBeanRegistration} interface.
|
||||
* @param delegate A pointer to the MBeanServerDelegate associated
|
||||
* with the new MBeanServer. The new MBeanServer must register
|
||||
* this MBean in its MBean repository.
|
||||
* @param instantiator The MBeanInstantiator that will be used to
|
||||
* instantiate MBeans and take care of class loading issues.
|
||||
* @param repository The repository to use for this MBeanServer
|
||||
*/
|
||||
public NamespaceDispatchInterceptor(MBeanServer outer,
|
||||
MBeanServerDelegate delegate,
|
||||
MBeanInstantiator instantiator,
|
||||
Repository repository) {
|
||||
nextInterceptor = new DomainDispatchInterceptor(outer,delegate,
|
||||
instantiator,repository,this);
|
||||
serverName = Util.getMBeanServerSecurityName(delegate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get first name space in ObjectName path. Ignore leading namespace
|
||||
* separators. Includes the trailing //.
|
||||
*
|
||||
* Examples:
|
||||
* <pre>
|
||||
* 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 -> ""
|
||||
*
|
||||
* </pre>
|
||||
**/
|
||||
static String getFirstNamespaceWithSlash(ObjectName name) {
|
||||
if (name == null) return "";
|
||||
final String domain = name.getDomain();
|
||||
if (domain.equals("")) return "";
|
||||
|
||||
// go to next separator
|
||||
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(0,end+NAMESPACE_SEPARATOR_LENGTH);
|
||||
|
||||
return namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the DefaultMBeanServerInterceptor, just before adding an
|
||||
* MBean to the repository.
|
||||
*
|
||||
* @param resource the MBean to be registered.
|
||||
* @param logicalName the name of the MBean to be registered.
|
||||
*/
|
||||
final void checkLocallyRegistrable(Object resource,
|
||||
ObjectName logicalName) {
|
||||
if (!(resource instanceof JMXNamespace) &&
|
||||
logicalName.getDomain().contains(NAMESPACE_SEPARATOR))
|
||||
throw new IllegalArgumentException(String.valueOf(logicalName)+
|
||||
": Invalid ObjectName for an instance of " +
|
||||
resource.getClass().getName());
|
||||
}
|
||||
|
||||
// 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 = 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;
|
||||
}
|
||||
|
||||
// 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: " + key);
|
||||
} else {
|
||||
LOG.finer("no handler for: " + key);
|
||||
}
|
||||
}
|
||||
return ns;
|
||||
}
|
||||
|
||||
@Override
|
||||
final QueryInterceptor getInterceptorForQuery(ObjectName pattern) {
|
||||
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);
|
||||
}
|
||||
|
||||
// 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: " + key);
|
||||
} else {
|
||||
LOG.finer("no handler for: " + key);
|
||||
}
|
||||
}
|
||||
if (ns == null) return null;
|
||||
return new QueryInterceptor(ns);
|
||||
}
|
||||
|
||||
@Override
|
||||
final ObjectName getHandlerNameFor(String key) {
|
||||
return ObjectName.valueOf(key+NAMESPACE_SEPARATOR,
|
||||
"type", JMXNamespace.TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
final public String getHandlerKey(ObjectName name) {
|
||||
final String namespace = getFirstNamespaceWithSlash(name);
|
||||
// namespace is either "" or a namespace ending with //
|
||||
return getKeyFor(namespace);
|
||||
}
|
||||
|
||||
@Override
|
||||
final NamespaceInterceptor createInterceptorFor(String key,
|
||||
ObjectName name, JMXNamespace handler,
|
||||
Queue<Runnable> postRegisterQueue) {
|
||||
final NamespaceInterceptor ns =
|
||||
new NamespaceInterceptor(serverName,handler,key);
|
||||
if (LOG.isLoggable(Level.FINER)) {
|
||||
LOG.finer("NamespaceInterceptor created: "+ns);
|
||||
}
|
||||
return ns;
|
||||
}
|
||||
|
||||
@Override
|
||||
final DomainDispatchInterceptor getNextInterceptor() {
|
||||
return nextInterceptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of domains in which any MBean is currently
|
||||
* registered.
|
||||
*/
|
||||
@Override
|
||||
public String[] getDomains() {
|
||||
return nextInterceptor.getDomains();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInterceptorFor(ObjectName name, JMXNamespace handler,
|
||||
Queue<Runnable> postRegisterQueue) {
|
||||
if (handler instanceof JMXDomain)
|
||||
nextInterceptor.addInterceptorFor(name,
|
||||
(JMXDomain)handler,postRegisterQueue);
|
||||
else super.addInterceptorFor(name,handler,postRegisterQueue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeInterceptorFor(ObjectName name, JMXNamespace handler,
|
||||
Queue<Runnable> postDeregisterQueue) {
|
||||
if (handler instanceof JMXDomain)
|
||||
nextInterceptor.removeInterceptorFor(name,(JMXDomain)handler,
|
||||
postDeregisterQueue);
|
||||
else super.removeInterceptorFor(name,handler,postDeregisterQueue);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -1,442 +0,0 @@
|
||||
/*
|
||||
* 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 com.sun.jmx.interceptor;
|
||||
|
||||
import com.sun.jmx.mbeanserver.Util;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.DynamicMBean;
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.IntrospectionException;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.ListenerNotFoundException;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanRegistrationException;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.NotificationEmitter;
|
||||
import javax.management.NotificationFilter;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.QueryExp;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.namespace.JMXNamespaces;
|
||||
import javax.management.namespace.MBeanServerSupport;
|
||||
import javax.management.remote.IdentityMBeanServerForwarder;
|
||||
|
||||
/**
|
||||
* <p>An {@link MBeanServerForwarder} that simulates the existence of a
|
||||
* given MBean. Requests for that MBean, call it X, are intercepted by the
|
||||
* forwarder, and requests for any other MBean are forwarded to the next
|
||||
* forwarder in the chain. Requests such as queryNames which can span both the
|
||||
* X and other MBeans are handled by merging the results for X with the results
|
||||
* from the next forwarder, unless the "visible" parameter is false, in which
|
||||
* case X is invisible to such requests.</p>
|
||||
*/
|
||||
public class SingleMBeanForwarder extends IdentityMBeanServerForwarder {
|
||||
|
||||
private final ObjectName mbeanName;
|
||||
private final boolean visible;
|
||||
private DynamicMBean mbean;
|
||||
|
||||
private MBeanServer mbeanMBS = new MBeanServerSupport() {
|
||||
|
||||
@Override
|
||||
public DynamicMBean getDynamicMBeanFor(ObjectName name)
|
||||
throws InstanceNotFoundException {
|
||||
if (mbeanName.equals(name)) {
|
||||
return mbean;
|
||||
} else {
|
||||
throw new InstanceNotFoundException(name.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<ObjectName> getNames() {
|
||||
return Collections.singleton(mbeanName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NotificationEmitter getNotificationEmitterFor(
|
||||
ObjectName name) {
|
||||
if (mbean instanceof NotificationEmitter)
|
||||
return (NotificationEmitter) mbean;
|
||||
return null;
|
||||
}
|
||||
|
||||
// This will only be called if mbeanName has an empty domain.
|
||||
// In that case a getAttribute (e.g.) of that name will have the
|
||||
// domain replaced by MBeanServerSupport with the default domain,
|
||||
// so we must be sure that the default domain is empty too.
|
||||
@Override
|
||||
public String getDefaultDomain() {
|
||||
return mbeanName.getDomain();
|
||||
}
|
||||
};
|
||||
|
||||
public SingleMBeanForwarder(
|
||||
ObjectName mbeanName, DynamicMBean mbean, boolean visible) {
|
||||
this.mbeanName = mbeanName;
|
||||
this.visible = visible;
|
||||
setSingleMBean(mbean);
|
||||
}
|
||||
|
||||
protected void setSingleMBean(DynamicMBean mbean) {
|
||||
this.mbean = mbean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNotificationListener(ObjectName name, ObjectName listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException {
|
||||
if (mbeanName.equals(name))
|
||||
mbeanMBS.addNotificationListener(name, listener, filter, handback);
|
||||
else
|
||||
super.addNotificationListener(name, listener, filter, handback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNotificationListener(ObjectName name,
|
||||
NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException {
|
||||
if (mbeanName.equals(name))
|
||||
mbeanMBS.addNotificationListener(name, listener, filter, handback);
|
||||
else
|
||||
super.addNotificationListener(name, listener, filter, handback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInstance createMBean(String className, ObjectName name,
|
||||
ObjectName loaderName, Object[] params,
|
||||
String[] signature)
|
||||
throws ReflectionException,
|
||||
InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException,
|
||||
MBeanException,
|
||||
NotCompliantMBeanException,
|
||||
InstanceNotFoundException {
|
||||
if (mbeanName.equals(name))
|
||||
throw new InstanceAlreadyExistsException(mbeanName.toString());
|
||||
else
|
||||
return super.createMBean(className, name, loaderName, params, signature);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInstance createMBean(String className, ObjectName name,
|
||||
Object[] params, String[] signature)
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException {
|
||||
if (mbeanName.equals(name))
|
||||
throw new InstanceAlreadyExistsException(mbeanName.toString());
|
||||
return super.createMBean(className, name, params, signature);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInstance createMBean(String className, ObjectName name,
|
||||
ObjectName loaderName)
|
||||
throws ReflectionException,
|
||||
InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException,
|
||||
MBeanException,
|
||||
NotCompliantMBeanException,
|
||||
InstanceNotFoundException {
|
||||
if (mbeanName.equals(name))
|
||||
throw new InstanceAlreadyExistsException(mbeanName.toString());
|
||||
return super.createMBean(className, name, loaderName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInstance createMBean(String className, ObjectName name)
|
||||
throws ReflectionException,
|
||||
InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException,
|
||||
MBeanException,
|
||||
NotCompliantMBeanException {
|
||||
if (mbeanName.equals(name))
|
||||
throw new InstanceAlreadyExistsException(mbeanName.toString());
|
||||
return super.createMBean(className, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(ObjectName name, String attribute)
|
||||
throws MBeanException,
|
||||
AttributeNotFoundException,
|
||||
InstanceNotFoundException,
|
||||
ReflectionException {
|
||||
if (mbeanName.equals(name))
|
||||
return mbeanMBS.getAttribute(name, attribute);
|
||||
else
|
||||
return super.getAttribute(name, attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeList getAttributes(ObjectName name, String[] attributes)
|
||||
throws InstanceNotFoundException, ReflectionException {
|
||||
if (mbeanName.equals(name))
|
||||
return mbeanMBS.getAttributes(name, attributes);
|
||||
else
|
||||
return super.getAttributes(name, attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader getClassLoader(ObjectName loaderName)
|
||||
throws InstanceNotFoundException {
|
||||
if (mbeanName.equals(loaderName))
|
||||
return mbeanMBS.getClassLoader(loaderName);
|
||||
else
|
||||
return super.getClassLoader(loaderName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader getClassLoaderFor(ObjectName name)
|
||||
throws InstanceNotFoundException {
|
||||
if (mbeanName.equals(name))
|
||||
return mbeanMBS.getClassLoaderFor(name);
|
||||
else
|
||||
return super.getClassLoaderFor(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getDomains() {
|
||||
String[] domains = super.getDomains();
|
||||
if (!visible)
|
||||
return domains;
|
||||
TreeSet<String> domainSet = new TreeSet<String>(Arrays.asList(domains));
|
||||
domainSet.add(mbeanName.getDomain());
|
||||
return domainSet.toArray(new String[domainSet.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMBeanCount() {
|
||||
Integer count = super.getMBeanCount();
|
||||
if (visible && !super.isRegistered(mbeanName))
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MBeanInfo getMBeanInfo(ObjectName name)
|
||||
throws InstanceNotFoundException,
|
||||
IntrospectionException,
|
||||
ReflectionException {
|
||||
if (mbeanName.equals(name))
|
||||
return mbeanMBS.getMBeanInfo(name);
|
||||
else
|
||||
return super.getMBeanInfo(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInstance getObjectInstance(ObjectName name)
|
||||
throws InstanceNotFoundException {
|
||||
if (mbeanName.equals(name))
|
||||
return mbeanMBS.getObjectInstance(name);
|
||||
else
|
||||
return super.getObjectInstance(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(ObjectName name, String operationName, Object[] params,
|
||||
String[] signature)
|
||||
throws InstanceNotFoundException,
|
||||
MBeanException,
|
||||
ReflectionException {
|
||||
if (mbeanName.equals(name))
|
||||
return mbeanMBS.invoke(name, operationName, params, signature);
|
||||
else
|
||||
return super.invoke(name, operationName, params, signature);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInstanceOf(ObjectName name, String className)
|
||||
throws InstanceNotFoundException {
|
||||
if (mbeanName.equals(name))
|
||||
return mbeanMBS.isInstanceOf(name, className);
|
||||
else
|
||||
return super.isInstanceOf(name, className);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegistered(ObjectName name) {
|
||||
if (mbeanName.equals(name))
|
||||
return true;
|
||||
else
|
||||
return super.isRegistered(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a ugly hack. Although jmx.context//*:* matches jmx.context//:*
|
||||
* queryNames(jmx.context//*:*,null) must not return jmx.context//:*
|
||||
* @param pattern the pattern to match against. must not be null.
|
||||
* @return true if mbeanName can be included, false if it must not.
|
||||
*/
|
||||
private boolean applies(ObjectName pattern) {
|
||||
// we know pattern is not null.
|
||||
if (!visible || !pattern.apply(mbeanName))
|
||||
return false;
|
||||
|
||||
final String dompat = pattern.getDomain();
|
||||
if (!dompat.contains(JMXNamespaces.NAMESPACE_SEPARATOR))
|
||||
return true; // We already checked that patterns apply.
|
||||
|
||||
if (mbeanName.getDomain().endsWith(JMXNamespaces.NAMESPACE_SEPARATOR)) {
|
||||
// only matches if pattern ends with //
|
||||
return dompat.endsWith(JMXNamespaces.NAMESPACE_SEPARATOR);
|
||||
}
|
||||
|
||||
// should not come here, unless mbeanName contains a // in the
|
||||
// middle of its domain, which would be weird.
|
||||
// let query on mbeanMBS proceed and take care of that.
|
||||
//
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
|
||||
Set<ObjectInstance> names = super.queryMBeans(name, query);
|
||||
if (visible) {
|
||||
if (name == null || applies(name) ) {
|
||||
// Don't assume mbs.queryNames returns a writable set.
|
||||
names = Util.cloneSet(names);
|
||||
names.addAll(mbeanMBS.queryMBeans(name, query));
|
||||
}
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
|
||||
Set<ObjectName> names = super.queryNames(name, query);
|
||||
if (visible) {
|
||||
if (name == null || applies(name)) {
|
||||
// Don't assume mbs.queryNames returns a writable set.
|
||||
names = Util.cloneSet(names);
|
||||
names.addAll(mbeanMBS.queryNames(name, query));
|
||||
}
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ObjectInstance registerMBean(Object object, ObjectName name)
|
||||
throws InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException,
|
||||
NotCompliantMBeanException {
|
||||
if (mbeanName.equals(name))
|
||||
throw new InstanceAlreadyExistsException(mbeanName.toString());
|
||||
else
|
||||
return super.registerMBean(object, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotificationListener(ObjectName name,
|
||||
NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException,
|
||||
ListenerNotFoundException {
|
||||
if (mbeanName.equals(name))
|
||||
mbeanMBS.removeNotificationListener(name, listener, filter, handback);
|
||||
else
|
||||
super.removeNotificationListener(name, listener, filter, handback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotificationListener(ObjectName name,
|
||||
NotificationListener listener)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
if (mbeanName.equals(name))
|
||||
mbeanMBS.removeNotificationListener(name, listener);
|
||||
else
|
||||
super.removeNotificationListener(name, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotificationListener(ObjectName name, ObjectName listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException,
|
||||
ListenerNotFoundException {
|
||||
if (mbeanName.equals(name))
|
||||
mbeanMBS.removeNotificationListener(name, listener, filter, handback);
|
||||
else
|
||||
super.removeNotificationListener(name, listener, filter, handback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotificationListener(ObjectName name, ObjectName listener)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
if (mbeanName.equals(name))
|
||||
mbeanMBS.removeNotificationListener(name, listener);
|
||||
else
|
||||
super.removeNotificationListener(name, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(ObjectName name, Attribute attribute)
|
||||
throws InstanceNotFoundException,
|
||||
AttributeNotFoundException,
|
||||
InvalidAttributeValueException,
|
||||
MBeanException,
|
||||
ReflectionException {
|
||||
if (mbeanName.equals(name))
|
||||
mbeanMBS.setAttribute(name, attribute);
|
||||
else
|
||||
super.setAttribute(name, attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeList setAttributes(ObjectName name,
|
||||
AttributeList attributes)
|
||||
throws InstanceNotFoundException, ReflectionException {
|
||||
if (mbeanName.equals(name))
|
||||
return mbeanMBS.setAttributes(name, attributes);
|
||||
else
|
||||
return super.setAttributes(name, attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterMBean(ObjectName name)
|
||||
throws InstanceNotFoundException,
|
||||
MBeanRegistrationException {
|
||||
if (mbeanName.equals(name))
|
||||
mbeanMBS.unregisterMBean(name);
|
||||
else
|
||||
super.unregisterMBean(name);
|
||||
}
|
||||
}
|
||||
@ -31,15 +31,13 @@ import java.lang.reflect.Type;
|
||||
|
||||
import javax.management.Descriptor;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.openmbean.MXBeanMapping;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
import javax.management.openmbean.OpenDataException;
|
||||
import javax.management.openmbean.OpenType;
|
||||
|
||||
final class ConvertingMethod {
|
||||
static ConvertingMethod from(Method m, MXBeanMappingFactory mappingFactory) {
|
||||
static ConvertingMethod from(Method m) {
|
||||
try {
|
||||
return new ConvertingMethod(m, mappingFactory);
|
||||
return new ConvertingMethod(m);
|
||||
} catch (OpenDataException ode) {
|
||||
final String msg = "Method " + m.getDeclaringClass().getName() +
|
||||
"." + m.getName() + " has parameter or return type that " +
|
||||
@ -53,7 +51,7 @@ final class ConvertingMethod {
|
||||
}
|
||||
|
||||
Descriptor getDescriptor() {
|
||||
return Introspector.descriptorForElement(method, false);
|
||||
return Introspector.descriptorForElement(method);
|
||||
}
|
||||
|
||||
Type getGenericReturnType() {
|
||||
@ -206,9 +204,9 @@ final class ConvertingMethod {
|
||||
return method.getDeclaringClass() + "." + method.getName();
|
||||
}
|
||||
|
||||
private ConvertingMethod(Method m, MXBeanMappingFactory mappingFactory)
|
||||
throws OpenDataException {
|
||||
private ConvertingMethod(Method m) throws OpenDataException {
|
||||
this.method = m;
|
||||
MXBeanMappingFactory mappingFactory = MXBeanMappingFactory.DEFAULT;
|
||||
returnMapping =
|
||||
mappingFactory.mappingForType(m.getGenericReturnType(), mappingFactory);
|
||||
Type[] params = m.getGenericParameterTypes();
|
||||
|
||||
@ -28,8 +28,6 @@ package com.sun.jmx.mbeanserver;
|
||||
import static com.sun.jmx.mbeanserver.Util.*;
|
||||
import static com.sun.jmx.mbeanserver.MXBeanIntrospector.typeName;
|
||||
|
||||
import javax.management.openmbean.MXBeanMappingClass;
|
||||
|
||||
import static javax.management.openmbean.SimpleType.*;
|
||||
|
||||
import com.sun.jmx.remote.util.EnvHelp;
|
||||
@ -69,8 +67,6 @@ import javax.management.openmbean.CompositeDataInvocationHandler;
|
||||
import javax.management.openmbean.CompositeDataSupport;
|
||||
import javax.management.openmbean.CompositeDataView;
|
||||
import javax.management.openmbean.CompositeType;
|
||||
import javax.management.openmbean.MXBeanMapping;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
import javax.management.openmbean.OpenDataException;
|
||||
import javax.management.openmbean.OpenType;
|
||||
import javax.management.openmbean.SimpleType;
|
||||
@ -165,34 +161,29 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
|
||||
private static final class Mappings
|
||||
extends WeakHashMap<Type, WeakReference<MXBeanMapping>> {}
|
||||
|
||||
private static final Map<MXBeanMappingFactory, Mappings> factoryMappings =
|
||||
new WeakHashMap<MXBeanMappingFactory, Mappings>();
|
||||
private static final Mappings mappings = new Mappings();
|
||||
|
||||
private static final Map<Type, MXBeanMapping> permanentMappings = newMap();
|
||||
/** Following List simply serves to keep a reference to predefined
|
||||
MXBeanMappings so they don't get garbage collected. */
|
||||
private static final List<MXBeanMapping> permanentMappings = newList();
|
||||
|
||||
private static synchronized MXBeanMapping getMapping(
|
||||
Type type, MXBeanMappingFactory factory) {
|
||||
Mappings mappings = factoryMappings.get(factory);
|
||||
if (mappings == null) {
|
||||
mappings = new Mappings();
|
||||
factoryMappings.put(factory, mappings);
|
||||
}
|
||||
private static synchronized MXBeanMapping getMapping(Type type) {
|
||||
WeakReference<MXBeanMapping> wr = mappings.get(type);
|
||||
return (wr == null) ? null : wr.get();
|
||||
}
|
||||
|
||||
private static synchronized void putMapping(
|
||||
Type type, MXBeanMapping mapping, MXBeanMappingFactory factory) {
|
||||
Mappings mappings = factoryMappings.get(factory);
|
||||
if (mappings == null) {
|
||||
mappings = new Mappings();
|
||||
factoryMappings.put(factory, mappings);
|
||||
}
|
||||
private static synchronized void putMapping(Type type, MXBeanMapping mapping) {
|
||||
WeakReference<MXBeanMapping> wr =
|
||||
new WeakReference<MXBeanMapping>(mapping);
|
||||
mappings.put(type, wr);
|
||||
}
|
||||
|
||||
private static synchronized void putPermanentMapping(
|
||||
Type type, MXBeanMapping mapping) {
|
||||
putMapping(type, mapping);
|
||||
permanentMappings.add(mapping);
|
||||
}
|
||||
|
||||
static {
|
||||
/* Set up the mappings for Java types that map to SimpleType. */
|
||||
|
||||
@ -213,7 +204,7 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
|
||||
throw new Error(e);
|
||||
}
|
||||
final MXBeanMapping mapping = new IdentityMapping(c, t);
|
||||
permanentMappings.put(c, mapping);
|
||||
putPermanentMapping(c, mapping);
|
||||
|
||||
if (c.getName().startsWith("java.lang.")) {
|
||||
try {
|
||||
@ -221,7 +212,7 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
|
||||
final Class<?> primitiveType = (Class<?>) typeField.get(null);
|
||||
final MXBeanMapping primitiveMapping =
|
||||
new IdentityMapping(primitiveType, t);
|
||||
permanentMappings.put(primitiveType, primitiveMapping);
|
||||
putPermanentMapping(primitiveType, primitiveMapping);
|
||||
if (primitiveType != void.class) {
|
||||
final Class<?> primitiveArrayType =
|
||||
Array.newInstance(primitiveType, 0).getClass();
|
||||
@ -230,8 +221,8 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
|
||||
final MXBeanMapping primitiveArrayMapping =
|
||||
new IdentityMapping(primitiveArrayType,
|
||||
primitiveArrayOpenType);
|
||||
permanentMappings.put(primitiveArrayType,
|
||||
primitiveArrayMapping);
|
||||
putPermanentMapping(primitiveArrayType,
|
||||
primitiveArrayMapping);
|
||||
}
|
||||
} catch (NoSuchFieldException e) {
|
||||
// OK: must not be a primitive wrapper
|
||||
@ -255,7 +246,7 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
|
||||
|
||||
MXBeanMapping mapping;
|
||||
|
||||
mapping = getMapping(objType, null);
|
||||
mapping = getMapping(objType);
|
||||
if (mapping != null)
|
||||
return mapping;
|
||||
|
||||
@ -268,7 +259,7 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
|
||||
inProgress.remove(objType);
|
||||
}
|
||||
|
||||
putMapping(objType, mapping, factory);
|
||||
putMapping(objType, mapping);
|
||||
return mapping;
|
||||
}
|
||||
|
||||
@ -278,14 +269,6 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
|
||||
/* It's not yet worth formalizing these tests by having for example
|
||||
an array of factory classes, each of which says whether it
|
||||
recognizes the Type (Chain of Responsibility pattern). */
|
||||
MXBeanMapping mapping = permanentMappings.get(objType);
|
||||
if (mapping != null)
|
||||
return mapping;
|
||||
Class<?> erasure = erasure(objType);
|
||||
MXBeanMappingClass mappingClass =
|
||||
erasure.getAnnotation(MXBeanMappingClass.class);
|
||||
if (mappingClass != null)
|
||||
return makeAnnotationMapping(mappingClass, objType, factory);
|
||||
if (objType instanceof GenericArrayType) {
|
||||
Type componentType =
|
||||
((GenericArrayType) objType).getGenericComponentType();
|
||||
@ -313,51 +296,6 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
|
||||
throw new OpenDataException("Cannot map type: " + objType);
|
||||
}
|
||||
|
||||
private static MXBeanMapping
|
||||
makeAnnotationMapping(MXBeanMappingClass mappingClass,
|
||||
Type objType,
|
||||
MXBeanMappingFactory factory)
|
||||
throws OpenDataException {
|
||||
Class<? extends MXBeanMapping> c = mappingClass.value();
|
||||
Constructor<? extends MXBeanMapping> cons;
|
||||
try {
|
||||
cons = c.getConstructor(Type.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
final String msg =
|
||||
"Annotation @" + MXBeanMappingClass.class.getName() +
|
||||
" must name a class with a public constructor that has a " +
|
||||
"single " + Type.class.getName() + " argument";
|
||||
OpenDataException ode = new OpenDataException(msg);
|
||||
ode.initCause(e);
|
||||
throw ode;
|
||||
}
|
||||
try {
|
||||
return cons.newInstance(objType);
|
||||
} catch (Exception e) {
|
||||
final String msg =
|
||||
"Could not construct a " + c.getName() + " for @" +
|
||||
MXBeanMappingClass.class.getName();
|
||||
OpenDataException ode = new OpenDataException(msg);
|
||||
ode.initCause(e);
|
||||
throw ode;
|
||||
}
|
||||
}
|
||||
|
||||
private static Class<?> erasure(Type t) {
|
||||
if (t instanceof Class<?>)
|
||||
return (Class<?>) t;
|
||||
if (t instanceof ParameterizedType)
|
||||
return erasure(((ParameterizedType) t).getRawType());
|
||||
/* Other cases: GenericArrayType, TypeVariable, WildcardType.
|
||||
* Returning the erasure of GenericArrayType is not necessary because
|
||||
* anyway we will be recursing on the element type, and we'll erase
|
||||
* then. Returning the erasure of the other two would mean returning
|
||||
* the type bound (e.g. Foo in <T extends Foo> or <? extends Foo>)
|
||||
* and since we don't treat this as Foo elsewhere we shouldn't here.
|
||||
*/
|
||||
return Object.class;
|
||||
}
|
||||
|
||||
private static <T extends Enum<T>> MXBeanMapping
|
||||
makeEnumMapping(Class<?> enumClass, Class<T> fake) {
|
||||
return new EnumMapping<T>(Util.<Class<T>>cast(enumClass));
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2005 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
|
||||
@ -25,7 +25,7 @@
|
||||
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import javax.management.DynamicWrapperMBean;
|
||||
import javax.management.DynamicMBean;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
@ -35,7 +35,17 @@ import javax.management.ObjectName;
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface DynamicMBean2 extends DynamicWrapperMBean {
|
||||
public interface DynamicMBean2 extends DynamicMBean {
|
||||
/**
|
||||
* The resource corresponding to this MBean. This is the object whose
|
||||
* class name should be reflected by the MBean's
|
||||
* getMBeanInfo().getClassName() for example. For a "plain"
|
||||
* DynamicMBean it will be "this". For an MBean that wraps another
|
||||
* object, like javax.management.StandardMBean, it will be the wrapped
|
||||
* object.
|
||||
*/
|
||||
public Object getResource();
|
||||
|
||||
/**
|
||||
* The name of this MBean's class, as used by permission checks.
|
||||
* This is typically equal to getResource().getClass().getName().
|
||||
|
||||
@ -25,14 +25,9 @@
|
||||
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import com.sun.jmx.remote.util.EnvHelp;
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Proxy;
|
||||
@ -40,39 +35,21 @@ import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.Description;
|
||||
|
||||
import javax.management.Descriptor;
|
||||
import javax.management.DescriptorFields;
|
||||
import javax.management.DescriptorKey;
|
||||
import javax.management.DynamicMBean;
|
||||
import javax.management.ImmutableDescriptor;
|
||||
import javax.management.MBean;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MXBean;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.openmbean.CompositeData;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
|
||||
import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
|
||||
import com.sun.jmx.mbeanserver.Util;
|
||||
import com.sun.jmx.remote.util.EnvHelp;
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.JMX;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.ObjectNameTemplate;
|
||||
import javax.management.openmbean.CompositeData;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
|
||||
/**
|
||||
* This class contains the methods for performing all the tests needed to verify
|
||||
@ -82,13 +59,7 @@ import javax.management.openmbean.MXBeanMappingFactory;
|
||||
*/
|
||||
public class Introspector {
|
||||
|
||||
/**
|
||||
* Pattern used to extract Attribute Names from ObjectNameTemplate Annotation
|
||||
* For example, in the following example, the Name attribute value is
|
||||
* retrieved : ":type=MyType, name={Name}"
|
||||
*/
|
||||
private static Pattern OBJECT_NAME_PATTERN_TEMPLATE =
|
||||
Pattern.compile("(\\{[^\\}]+\\})|(=\"\\{[^\\}]+\\}\")");
|
||||
|
||||
/*
|
||||
* ------------------------------------------
|
||||
* PRIVATE CONSTRUCTORS
|
||||
@ -164,10 +135,6 @@ public class Introspector {
|
||||
|
||||
public static void checkCompliance(Class<?> mbeanClass)
|
||||
throws NotCompliantMBeanException {
|
||||
|
||||
// Check that @Resource is used correctly (if it used).
|
||||
MBeanInjector.validate(mbeanClass);
|
||||
|
||||
// Is DynamicMBean?
|
||||
//
|
||||
if (DynamicMBean.class.isAssignableFrom(mbeanClass))
|
||||
@ -190,36 +157,16 @@ public class Introspector {
|
||||
} catch (NotCompliantMBeanException e) {
|
||||
mxbeanException = e;
|
||||
}
|
||||
// Is @MBean or @MXBean class?
|
||||
// In fact we find @MBean or @MXBean as a hacky variant of
|
||||
// getStandardMBeanInterface or getMXBeanInterface. If we get here
|
||||
// then nothing worked.
|
||||
final String msg =
|
||||
"MBean class " + mbeanClass.getName() + " does not implement " +
|
||||
"DynamicMBean; does not follow the Standard MBean conventions (" +
|
||||
mbeanException.toString() + "); does not follow the MXBean conventions (" +
|
||||
mxbeanException.toString() + "); and does not have or inherit the @" +
|
||||
MBean.class.getSimpleName() + " or @" + MXBean.class.getSimpleName() +
|
||||
" annotation";
|
||||
"DynamicMBean, and neither follows the Standard MBean conventions (" +
|
||||
mbeanException.toString() + ") nor the MXBean conventions (" +
|
||||
mxbeanException.toString() + ")";
|
||||
throw new NotCompliantMBeanException(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Make a DynamicMBean out of the existing MBean object. The object
|
||||
* may already be a DynamicMBean, or it may be a Standard MBean or
|
||||
* MXBean, possibly defined using {@code @MBean} or {@code @MXBean}.</p>
|
||||
* @param mbean the object to convert to a DynamicMBean.
|
||||
* @param <T> a type parameter defined for implementation convenience
|
||||
* (which would have to be removed if this method were part of the public
|
||||
* API).
|
||||
* @return the converted DynamicMBean.
|
||||
* @throws NotCompliantMBeanException if {@code mbean} is not a compliant
|
||||
* MBean object, including the case where it is null.
|
||||
*/
|
||||
public static <T> DynamicMBean makeDynamicMBean(T mbean)
|
||||
throws NotCompliantMBeanException {
|
||||
if (mbean == null)
|
||||
throw new NotCompliantMBeanException("Null MBean object");
|
||||
throws NotCompliantMBeanException {
|
||||
if (mbean instanceof DynamicMBean)
|
||||
return (DynamicMBean) mbean;
|
||||
final Class<?> mbeanClass = mbean.getClass();
|
||||
@ -240,18 +187,8 @@ public class Introspector {
|
||||
// to be an MBean or an MXBean. We will call checkCompliance()
|
||||
// to generate the appropriate exception.
|
||||
}
|
||||
if (c != null) {
|
||||
MXBeanMappingFactory factory;
|
||||
try {
|
||||
factory = MXBeanMappingFactory.forInterface(c);
|
||||
} catch (IllegalArgumentException e) {
|
||||
NotCompliantMBeanException ncmbe =
|
||||
new NotCompliantMBeanException(e.getMessage());
|
||||
ncmbe.initCause(e);
|
||||
throw ncmbe;
|
||||
}
|
||||
return new MXBeanSupport(mbean, c, factory);
|
||||
}
|
||||
if (c != null)
|
||||
return new MXBeanSupport(mbean, c);
|
||||
checkCompliance(mbeanClass);
|
||||
throw new NotCompliantMBeanException("Not compliant"); // not reached
|
||||
}
|
||||
@ -280,10 +217,9 @@ public class Introspector {
|
||||
return testCompliance(baseClass, null);
|
||||
}
|
||||
|
||||
public static void testComplianceMXBeanInterface(Class<?> interfaceClass,
|
||||
MXBeanMappingFactory factory)
|
||||
public static void testComplianceMXBeanInterface(Class<?> interfaceClass)
|
||||
throws NotCompliantMBeanException {
|
||||
MXBeanIntrospector.getInstance(factory).getAnalyzer(interfaceClass);
|
||||
MXBeanIntrospector.getInstance().getAnalyzer(interfaceClass);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -352,8 +288,6 @@ public class Introspector {
|
||||
*/
|
||||
public static <T> Class<? super T> getStandardMBeanInterface(Class<T> baseClass)
|
||||
throws NotCompliantMBeanException {
|
||||
if (baseClass.isAnnotationPresent(MBean.class))
|
||||
return baseClass;
|
||||
Class<? super T> current = baseClass;
|
||||
Class<? super T> mbeanInterface = null;
|
||||
while (current != null) {
|
||||
@ -384,8 +318,6 @@ public class Introspector {
|
||||
*/
|
||||
public static <T> Class<? super T> getMXBeanInterface(Class<T> baseClass)
|
||||
throws NotCompliantMBeanException {
|
||||
if (hasMXBeanAnnotation(baseClass))
|
||||
return baseClass;
|
||||
try {
|
||||
return MXBeanSupport.findMXBeanInterface(baseClass);
|
||||
} catch (Exception e) {
|
||||
@ -393,61 +325,12 @@ public class Introspector {
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> Class<? super T> getStandardOrMXBeanInterface(
|
||||
Class<T> baseClass, boolean mxbean)
|
||||
throws NotCompliantMBeanException {
|
||||
if (mxbean)
|
||||
return getMXBeanInterface(baseClass);
|
||||
else
|
||||
return getStandardMBeanInterface(baseClass);
|
||||
}
|
||||
|
||||
public static ObjectName templateToObjectName(Descriptor descriptor,
|
||||
DynamicMBean mbean)
|
||||
throws NotCompliantMBeanException {
|
||||
String template = (String)
|
||||
descriptor.getFieldValue(JMX.OBJECT_NAME_TEMPLATE);
|
||||
if(template == null) return null;
|
||||
try {
|
||||
Matcher m = OBJECT_NAME_PATTERN_TEMPLATE.matcher(template);
|
||||
while (m.find()){
|
||||
String grp = m.group();
|
||||
System.out.println("GROUP " + grp);
|
||||
String attributeName = null;
|
||||
boolean quote = false;
|
||||
if(grp.startsWith("=\"{")) {
|
||||
attributeName = grp.substring(3, grp.length() - 2);
|
||||
quote = true;
|
||||
} else
|
||||
attributeName = grp.substring(1, grp.length() - 1);
|
||||
|
||||
Object attributeValue = mbean.getAttribute(attributeName);
|
||||
String validValue = quote ?
|
||||
"=" + ObjectName.quote(attributeValue.toString()) :
|
||||
attributeValue.toString();
|
||||
template = template.replace(grp, validValue);
|
||||
}
|
||||
return new ObjectName(template);
|
||||
}catch(Exception ex) {
|
||||
NotCompliantMBeanException ncex = new
|
||||
NotCompliantMBeanException(ObjectNameTemplate.class.
|
||||
getSimpleName() + " annotation value [" + template + "] " +
|
||||
"is invalid. " + ex);
|
||||
ncex.initCause(ex);
|
||||
throw ncex;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ------------------------------------------
|
||||
* PRIVATE METHODS
|
||||
* ------------------------------------------
|
||||
*/
|
||||
|
||||
static boolean hasMXBeanAnnotation(Class<?> c) {
|
||||
MXBean m = c.getAnnotation(MXBean.class);
|
||||
return (m != null && m.value());
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to find the MBean interface corresponding to the class aName
|
||||
@ -469,77 +352,11 @@ public class Introspector {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String descriptionForElement(AnnotatedElement elmt) {
|
||||
if (elmt == null)
|
||||
return null;
|
||||
Description d = elmt.getAnnotation(Description.class);
|
||||
if (d == null)
|
||||
return null;
|
||||
return d.value();
|
||||
}
|
||||
|
||||
public static String descriptionForParameter(
|
||||
Annotation[] parameterAnnotations) {
|
||||
for (Annotation a : parameterAnnotations) {
|
||||
if (a instanceof Description)
|
||||
return ((Description) a).value();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String nameForParameter(
|
||||
Annotation[] parameterAnnotations) {
|
||||
for (Annotation a : parameterAnnotations) {
|
||||
Class<? extends Annotation> ac = a.annotationType();
|
||||
// You'd really have to go out of your way to have more than
|
||||
// one @Name annotation, so we don't check for that.
|
||||
if (ac.getSimpleName().equals("Name")) {
|
||||
try {
|
||||
Method value = ac.getMethod("value");
|
||||
if (value.getReturnType() == String.class &&
|
||||
value.getParameterTypes().length == 0) {
|
||||
return (String) value.invoke(a);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
MBEANSERVER_LOGGER.log(
|
||||
Level.WARNING,
|
||||
"Unexpected exception getting @" + ac.getName(),
|
||||
e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Descriptor descriptorForElement(final AnnotatedElement elmt,
|
||||
boolean isSetter) {
|
||||
public static Descriptor descriptorForElement(final AnnotatedElement elmt) {
|
||||
if (elmt == null)
|
||||
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
|
||||
final Annotation[] annots = elmt.getAnnotations();
|
||||
Descriptor descr = descriptorForAnnotations(annots);
|
||||
String[] exceptions = {};
|
||||
if(elmt instanceof Method)
|
||||
exceptions = getAllExceptions(((Method) elmt).getExceptionTypes());
|
||||
else
|
||||
if(elmt instanceof Constructor<?>)
|
||||
exceptions = getAllExceptions(((Constructor<?>) elmt).
|
||||
getExceptionTypes());
|
||||
|
||||
if(exceptions.length > 0 ) {
|
||||
String fieldName = isSetter ? JMX.SET_EXCEPTIONS_FIELD :
|
||||
JMX.EXCEPTIONS_FIELD;
|
||||
|
||||
String[] fieldNames = {fieldName};
|
||||
Object[] fieldValues = {exceptions};
|
||||
descr = ImmutableDescriptor.union(descr,
|
||||
new ImmutableDescriptor(fieldNames, fieldValues));
|
||||
}
|
||||
|
||||
return descr;
|
||||
}
|
||||
|
||||
public static Descriptor descriptorForAnnotation(Annotation annot) {
|
||||
return descriptorForAnnotations(new Annotation[] {annot});
|
||||
return descriptorForAnnotations(annots);
|
||||
}
|
||||
|
||||
public static Descriptor descriptorForAnnotations(Annotation[] annots) {
|
||||
@ -547,9 +364,36 @@ public class Introspector {
|
||||
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
|
||||
Map<String, Object> descriptorMap = new HashMap<String, Object>();
|
||||
for (Annotation a : annots) {
|
||||
if (a instanceof DescriptorFields)
|
||||
addDescriptorFieldsToMap(descriptorMap, (DescriptorFields) a);
|
||||
addAnnotationFieldsToMap(descriptorMap, a);
|
||||
Class<? extends Annotation> c = a.annotationType();
|
||||
Method[] elements = c.getMethods();
|
||||
for (Method element : elements) {
|
||||
DescriptorKey key = element.getAnnotation(DescriptorKey.class);
|
||||
if (key != null) {
|
||||
String name = key.value();
|
||||
Object value;
|
||||
try {
|
||||
value = element.invoke(a);
|
||||
} catch (RuntimeException e) {
|
||||
// we don't expect this - except for possibly
|
||||
// security exceptions?
|
||||
// RuntimeExceptions shouldn't be "UndeclaredThrowable".
|
||||
// anyway...
|
||||
//
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
// we don't expect this
|
||||
throw new UndeclaredThrowableException(e);
|
||||
}
|
||||
value = annotationToField(value);
|
||||
Object oldValue = descriptorMap.put(name, value);
|
||||
if (oldValue != null && !equals(oldValue, value)) {
|
||||
final String msg =
|
||||
"Inconsistent values for descriptor field " + name +
|
||||
" from annotations: " + value + " :: " + oldValue;
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (descriptorMap.isEmpty())
|
||||
@ -558,76 +402,6 @@ public class Introspector {
|
||||
return new ImmutableDescriptor(descriptorMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Array of thrown excepions.
|
||||
* @param exceptions can be null;
|
||||
* @return An Array of Exception class names. Size is 0 if method is null.
|
||||
*/
|
||||
private static String[] getAllExceptions(Class<?>[] exceptions) {
|
||||
Set<String> set = new LinkedHashSet<String>();
|
||||
for(Class<?>ex : exceptions)
|
||||
set.add(ex.getName());
|
||||
|
||||
String[] arr = new String[set.size()];
|
||||
return set.toArray(arr);
|
||||
}
|
||||
|
||||
private static void addDescriptorFieldsToMap(
|
||||
Map<String, Object> descriptorMap, DescriptorFields df) {
|
||||
for (String field : df.value()) {
|
||||
int eq = field.indexOf('=');
|
||||
if (eq < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"@DescriptorFields string must contain '=': " +
|
||||
field);
|
||||
}
|
||||
String name = field.substring(0, eq);
|
||||
String value = field.substring(eq + 1);
|
||||
addToMap(descriptorMap, name, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addAnnotationFieldsToMap(
|
||||
Map<String, Object> descriptorMap, Annotation a) {
|
||||
Class<? extends Annotation> c = a.annotationType();
|
||||
Method[] elements = c.getMethods();
|
||||
for (Method element : elements) {
|
||||
DescriptorKey key = element.getAnnotation(DescriptorKey.class);
|
||||
if (key != null) {
|
||||
String name = key.value();
|
||||
Object value;
|
||||
try {
|
||||
value = element.invoke(a);
|
||||
} catch (RuntimeException e) {
|
||||
// we don't expect this - except for possibly
|
||||
// security exceptions?
|
||||
// RuntimeExceptions shouldn't be "UndeclaredThrowable".
|
||||
// anyway...
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
// we don't expect this
|
||||
throw new UndeclaredThrowableException(e);
|
||||
}
|
||||
if (!key.omitIfDefault() ||
|
||||
!equals(value, element.getDefaultValue())) {
|
||||
value = annotationToField(value);
|
||||
addToMap(descriptorMap, name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void addToMap(
|
||||
Map<String, Object> descriptorMap, String name, Object value) {
|
||||
Object oldValue = descriptorMap.put(name, value);
|
||||
if (oldValue != null && !equals(oldValue, value)) {
|
||||
final String msg =
|
||||
"Inconsistent values for descriptor field " + name +
|
||||
" from annotations: " + value + " :: " + oldValue;
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws a NotCompliantMBeanException or a SecurityException.
|
||||
* @param notCompliant the class which was under examination
|
||||
|
||||
@ -25,14 +25,14 @@
|
||||
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import com.sun.jmx.interceptor.DefaultMBeanServerInterceptor;
|
||||
import com.sun.jmx.interceptor.MBeanServerInterceptor;
|
||||
import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
|
||||
import com.sun.jmx.interceptor.NamespaceDispatchInterceptor;
|
||||
|
||||
import java.io.ObjectInputStream;
|
||||
import java.security.AccessController;
|
||||
import java.security.Permission;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
@ -108,8 +108,6 @@ public final class JmxMBeanServer
|
||||
/** The MBeanServerDelegate object representing the MBean Server */
|
||||
private final MBeanServerDelegate mBeanServerDelegateObject;
|
||||
|
||||
private final String mbeanServerName;
|
||||
|
||||
/**
|
||||
* <b>Package:</b> Creates an MBeanServer with the
|
||||
* specified default domain name, outer interface, and delegate.
|
||||
@ -241,10 +239,9 @@ public final class JmxMBeanServer
|
||||
|
||||
final Repository repository = new Repository(domain);
|
||||
this.mbsInterceptor =
|
||||
new NamespaceDispatchInterceptor(outer, delegate, instantiator,
|
||||
new DefaultMBeanServerInterceptor(outer, delegate, instantiator,
|
||||
repository);
|
||||
this.interceptorsEnabled = interceptors;
|
||||
this.mbeanServerName = Util.getMBeanServerSecurityName(delegate);
|
||||
initialize();
|
||||
}
|
||||
|
||||
@ -940,8 +937,7 @@ public final class JmxMBeanServer
|
||||
throws ReflectionException, MBeanException {
|
||||
|
||||
/* Permission check */
|
||||
checkMBeanPermission(mbeanServerName, className, null, null,
|
||||
"instantiate");
|
||||
checkMBeanPermission(className, null, null, "instantiate");
|
||||
|
||||
return instantiator.instantiate(className);
|
||||
}
|
||||
@ -978,8 +974,7 @@ public final class JmxMBeanServer
|
||||
InstanceNotFoundException {
|
||||
|
||||
/* Permission check */
|
||||
checkMBeanPermission(mbeanServerName, className, null,
|
||||
null, "instantiate");
|
||||
checkMBeanPermission(className, null, null, "instantiate");
|
||||
|
||||
ClassLoader myLoader = outerShell.getClass().getClassLoader();
|
||||
return instantiator.instantiate(className, loaderName, myLoader);
|
||||
@ -1017,8 +1012,7 @@ public final class JmxMBeanServer
|
||||
throws ReflectionException, MBeanException {
|
||||
|
||||
/* Permission check */
|
||||
checkMBeanPermission(mbeanServerName, className, null, null,
|
||||
"instantiate");
|
||||
checkMBeanPermission(className, null, null, "instantiate");
|
||||
|
||||
ClassLoader myLoader = outerShell.getClass().getClassLoader();
|
||||
return instantiator.instantiate(className, params, signature,
|
||||
@ -1061,8 +1055,7 @@ public final class JmxMBeanServer
|
||||
InstanceNotFoundException {
|
||||
|
||||
/* Permission check */
|
||||
checkMBeanPermission(mbeanServerName, className, null,
|
||||
null, "instantiate");
|
||||
checkMBeanPermission(className, null, null, "instantiate");
|
||||
|
||||
ClassLoader myLoader = outerShell.getClass().getClassLoader();
|
||||
return instantiator.instantiate(className,loaderName,params,signature,
|
||||
@ -1333,8 +1326,7 @@ public final class JmxMBeanServer
|
||||
**/
|
||||
public ClassLoaderRepository getClassLoaderRepository() {
|
||||
/* Permission check */
|
||||
checkMBeanPermission(mbeanServerName, null, null,
|
||||
null, "getClassLoaderRepository");
|
||||
checkMBeanPermission(null, null, null, "getClassLoaderRepository");
|
||||
return secureClr;
|
||||
}
|
||||
|
||||
@ -1487,16 +1479,14 @@ public final class JmxMBeanServer
|
||||
// SECURITY CHECKS
|
||||
//----------------
|
||||
|
||||
private static void checkMBeanPermission(String serverName,
|
||||
String classname,
|
||||
private static void checkMBeanPermission(String classname,
|
||||
String member,
|
||||
ObjectName objectName,
|
||||
String actions)
|
||||
throws SecurityException {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
Permission perm = new MBeanPermission(serverName,
|
||||
classname,
|
||||
Permission perm = new MBeanPermission(classname,
|
||||
member,
|
||||
objectName,
|
||||
actions);
|
||||
|
||||
@ -33,10 +33,6 @@ import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.management.MBean;
|
||||
import javax.management.MXBean;
|
||||
import javax.management.ManagedAttribute;
|
||||
import javax.management.ManagedOperation;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
|
||||
/**
|
||||
@ -55,15 +51,15 @@ import javax.management.NotCompliantMBeanException;
|
||||
*/
|
||||
class MBeanAnalyzer<M> {
|
||||
|
||||
static interface MBeanVisitor<M, X extends Exception> {
|
||||
static interface MBeanVisitor<M> {
|
||||
public void visitAttribute(String attributeName,
|
||||
M getter,
|
||||
M setter) throws X;
|
||||
M setter);
|
||||
public void visitOperation(String operationName,
|
||||
M operation) throws X;
|
||||
M operation);
|
||||
}
|
||||
|
||||
<X extends Exception> void visit(MBeanVisitor<M, X> visitor) throws X {
|
||||
void visit(MBeanVisitor<M> visitor) {
|
||||
// visit attributes
|
||||
for (Map.Entry<String, AttrMethods<M>> entry : attrMap.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
@ -108,7 +104,10 @@ class MBeanAnalyzer<M> {
|
||||
private MBeanAnalyzer(Class<?> mbeanType,
|
||||
MBeanIntrospector<M> introspector)
|
||||
throws NotCompliantMBeanException {
|
||||
introspector.checkCompliance(mbeanType);
|
||||
if (!mbeanType.isInterface()) {
|
||||
throw new NotCompliantMBeanException("Not an interface: " +
|
||||
mbeanType.getName());
|
||||
}
|
||||
|
||||
try {
|
||||
initMaps(mbeanType, introspector);
|
||||
@ -129,26 +128,18 @@ class MBeanAnalyzer<M> {
|
||||
for (Method m : methods) {
|
||||
final String name = m.getName();
|
||||
final int nParams = m.getParameterTypes().length;
|
||||
final boolean managedOp = m.isAnnotationPresent(ManagedOperation.class);
|
||||
final boolean managedAttr = m.isAnnotationPresent(ManagedAttribute.class);
|
||||
if (managedOp && managedAttr) {
|
||||
throw new NotCompliantMBeanException("Method " + name +
|
||||
" has both @ManagedOperation and @ManagedAttribute");
|
||||
}
|
||||
|
||||
final M cm = introspector.mFrom(m);
|
||||
|
||||
String attrName = "";
|
||||
if (!managedOp) {
|
||||
if (name.startsWith("get"))
|
||||
attrName = name.substring(3);
|
||||
else if (name.startsWith("is")
|
||||
&& m.getReturnType() == boolean.class)
|
||||
attrName = name.substring(2);
|
||||
}
|
||||
if (name.startsWith("get"))
|
||||
attrName = name.substring(3);
|
||||
else if (name.startsWith("is")
|
||||
&& m.getReturnType() == boolean.class)
|
||||
attrName = name.substring(2);
|
||||
|
||||
if (attrName.length() != 0 && nParams == 0
|
||||
&& m.getReturnType() != void.class && !managedOp) {
|
||||
&& m.getReturnType() != void.class) {
|
||||
// It's a getter
|
||||
// Check we don't have both isX and getX
|
||||
AttrMethods<M> am = attrMap.get(attrName);
|
||||
@ -165,7 +156,7 @@ class MBeanAnalyzer<M> {
|
||||
attrMap.put(attrName, am);
|
||||
} else if (name.startsWith("set") && name.length() > 3
|
||||
&& nParams == 1 &&
|
||||
m.getReturnType() == void.class && !managedOp) {
|
||||
m.getReturnType() == void.class) {
|
||||
// It's a setter
|
||||
attrName = name.substring(3);
|
||||
AttrMethods<M> am = attrMap.get(attrName);
|
||||
@ -178,9 +169,6 @@ class MBeanAnalyzer<M> {
|
||||
}
|
||||
am.setter = cm;
|
||||
attrMap.put(attrName, am);
|
||||
} else if (managedAttr) {
|
||||
throw new NotCompliantMBeanException("Method " + name +
|
||||
" has @ManagedAttribute but is not a valid getter or setter");
|
||||
} else {
|
||||
// It's an operation
|
||||
List<M> cms = opMap.get(name);
|
||||
|
||||
@ -1,295 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-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 com.sun.jmx.mbeanserver;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import javax.annotation.Resource;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import static com.sun.jmx.mbeanserver.Util.newMap;
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.security.AccessController;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.management.SendNotification;
|
||||
|
||||
public class MBeanInjector {
|
||||
// There are no instances of this class
|
||||
private MBeanInjector() {
|
||||
}
|
||||
|
||||
private static Class<?>[] injectedClasses = {
|
||||
MBeanServer.class, ObjectName.class, SendNotification.class,
|
||||
};
|
||||
|
||||
public static void inject(Object mbean, MBeanServer mbs, ObjectName name)
|
||||
throws Exception {
|
||||
ClassInjector injector = injectorForClass(mbean.getClass());
|
||||
injector.inject(mbean, MBeanServer.class, mbs);
|
||||
injector.inject(mbean, ObjectName.class, name);
|
||||
}
|
||||
|
||||
public static boolean injectsSendNotification(Object mbean)
|
||||
throws NotCompliantMBeanException {
|
||||
ClassInjector injector = injectorForClass(mbean.getClass());
|
||||
return injector.injects(SendNotification.class);
|
||||
}
|
||||
|
||||
public static void injectSendNotification(Object mbean, SendNotification sn)
|
||||
throws Exception {
|
||||
ClassInjector injector = injectorForClass(mbean.getClass());
|
||||
injector.inject(mbean, SendNotification.class, sn);
|
||||
}
|
||||
|
||||
public static void validate(Class<?> c) throws NotCompliantMBeanException {
|
||||
injectorForClass(c);
|
||||
}
|
||||
|
||||
private static class ClassInjector {
|
||||
private Map<Class<?>, List<Field>> fields;
|
||||
private Map<Class<?>, List<Method>> methods;
|
||||
|
||||
ClassInjector(Class<?> c) throws NotCompliantMBeanException {
|
||||
fields = newMap();
|
||||
methods = newMap();
|
||||
|
||||
Class<?> sup = c.getSuperclass();
|
||||
ClassInjector supInjector;
|
||||
if (sup == null) {
|
||||
supInjector = null;
|
||||
} else {
|
||||
supInjector = injectorForClass(sup);
|
||||
fields.putAll(supInjector.fields);
|
||||
methods.putAll(supInjector.methods);
|
||||
}
|
||||
|
||||
addMembers(c);
|
||||
eliminateOverriddenMethods();
|
||||
|
||||
// If we haven't added any new fields or methods to what we
|
||||
// inherited, then we can share the parent's maps.
|
||||
if (supInjector != null) {
|
||||
if (fields.equals(supInjector.fields))
|
||||
fields = supInjector.fields;
|
||||
if (methods.equals(supInjector.methods))
|
||||
methods = supInjector.methods;
|
||||
}
|
||||
}
|
||||
|
||||
boolean injects(Class<?> c) {
|
||||
return (fields.get(c) != null || methods.get(c) != null);
|
||||
}
|
||||
|
||||
<T> void inject(Object instance, Class<T> type, T resource)
|
||||
throws Exception {
|
||||
List<Field> fs = fields.get(type);
|
||||
if (fs != null) {
|
||||
for (Field f : fs)
|
||||
f.set(instance, resource);
|
||||
}
|
||||
List<Method> ms = methods.get(type);
|
||||
if (ms != null) {
|
||||
for (Method m : ms) {
|
||||
try {
|
||||
m.invoke(instance, resource);
|
||||
} catch (InvocationTargetException e) {
|
||||
Throwable cause = e.getCause();
|
||||
if (cause instanceof Error)
|
||||
throw (Error) cause;
|
||||
else
|
||||
throw (Exception) cause;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void eliminateOverriddenMethods() {
|
||||
/* Covariant overriding is unlikely, but it is possible that the
|
||||
* parent has a @Resource method that we override with another
|
||||
* @Resource method. We don't want to invoke both methods,
|
||||
* because polymorphism means we would actually invoke the same
|
||||
* method twice.
|
||||
*/
|
||||
for (Map.Entry<Class<?>, List<Method>> entry : methods.entrySet()) {
|
||||
List<Method> list = entry.getValue();
|
||||
list = MBeanAnalyzer.eliminateCovariantMethods(list);
|
||||
entry.setValue(list);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Find Fields or Methods within the given Class that we can inject
|
||||
* resource references into. Suppose we want to know if a Field can get
|
||||
* a reference to an ObjectName. We'll accept fields like this:
|
||||
*
|
||||
* @Resource
|
||||
* private transient ObjectName name;
|
||||
*
|
||||
* or like this:
|
||||
*
|
||||
* @Resource(type = ObjectName.class)
|
||||
* private transient Object name;
|
||||
*
|
||||
* but not like this:
|
||||
*
|
||||
* @Resource
|
||||
* private transient Object name;
|
||||
*
|
||||
* (Plain @Resource is equivalent to @Resource(type = Object.class).)
|
||||
*
|
||||
* We don't want to inject into everything that might possibly accept
|
||||
* an ObjectName reference, because examples like the last one above
|
||||
* could also accept an MBeanServer reference or any other sort of
|
||||
* reference.
|
||||
*
|
||||
* So we accept a Field if it has a @Resource annotation and either
|
||||
* (a) its type is exactly ObjectName and its @Resource type is
|
||||
* compatible with ObjectName (e.g. it is Object); or
|
||||
* (b) its type is compatible with ObjectName and its @Resource type
|
||||
* is exactly ObjectName. Fields that meet these criteria will not
|
||||
* meet the same criteria with respect to other types such as MBeanServer.
|
||||
*
|
||||
* The same logic applies mutatis mutandis to Methods such as this:
|
||||
*
|
||||
* @Resource
|
||||
* private void setObjectName1(ObjectName name)
|
||||
* @Resource(type = Object.class)
|
||||
* private void setObjectName2(Object name)
|
||||
*/
|
||||
private void addMembers(final Class<?> c)
|
||||
throws NotCompliantMBeanException {
|
||||
AccessibleObject[][] memberArrays =
|
||||
AccessController.doPrivileged(
|
||||
new PrivilegedAction<AccessibleObject[][]>() {
|
||||
public AccessibleObject[][] run() {
|
||||
return new AccessibleObject[][] {
|
||||
c.getDeclaredFields(), c.getDeclaredMethods()
|
||||
};
|
||||
}
|
||||
});
|
||||
for (AccessibleObject[] members : memberArrays) {
|
||||
for (final AccessibleObject member : members) {
|
||||
Resource res = member.getAnnotation(Resource.class);
|
||||
if (res == null)
|
||||
continue;
|
||||
|
||||
final Field field;
|
||||
final Method method;
|
||||
final Class<?> memberType;
|
||||
final int modifiers;
|
||||
if (member instanceof Field) {
|
||||
field = (Field) member;
|
||||
memberType = field.getType();
|
||||
modifiers = field.getModifiers();
|
||||
method = null;
|
||||
} else {
|
||||
field = null;
|
||||
method = (Method) member;
|
||||
Class<?>[] paramTypes = method.getParameterTypes();
|
||||
if (paramTypes.length != 1) {
|
||||
throw new NotCompliantMBeanException(
|
||||
"@Resource method must have exactly 1 " +
|
||||
"parameter: " + method);
|
||||
}
|
||||
if (method.getReturnType() != void.class) {
|
||||
throw new NotCompliantMBeanException(
|
||||
"@Resource method must return void: " +
|
||||
method);
|
||||
}
|
||||
memberType = paramTypes[0];
|
||||
modifiers = method.getModifiers();
|
||||
}
|
||||
|
||||
if (Modifier.isStatic(modifiers)) {
|
||||
throw new NotCompliantMBeanException(
|
||||
"@Resource method or field cannot be static: " +
|
||||
member);
|
||||
}
|
||||
|
||||
for (Class<?> injectedClass : injectedClasses) {
|
||||
Class<?>[] types = {memberType, res.type()};
|
||||
boolean accept = false;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (types[i] == injectedClass &&
|
||||
types[1 - i].isAssignableFrom(injectedClass)) {
|
||||
accept = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (accept) {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
member.setAccessible(true);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
addToMap(fields, injectedClass, field);
|
||||
addToMap(methods, injectedClass, method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static <K, V> void addToMap(Map<K, List<V>> map, K key, V value) {
|
||||
if (value == null)
|
||||
return;
|
||||
List<V> list = map.get(key);
|
||||
if (list == null)
|
||||
list = Collections.singletonList(value);
|
||||
else {
|
||||
if (list.size() == 1)
|
||||
list = new ArrayList<V>(list);
|
||||
list.add(value);
|
||||
}
|
||||
map.put(key, list);
|
||||
}
|
||||
}
|
||||
|
||||
private static synchronized ClassInjector injectorForClass(Class<?> c)
|
||||
throws NotCompliantMBeanException {
|
||||
WeakReference<ClassInjector> wr = injectorMap.get(c);
|
||||
ClassInjector ci = (wr == null) ? null : wr.get();
|
||||
if (ci == null) {
|
||||
ci = new ClassInjector(c);
|
||||
injectorMap.put(c, new WeakReference<ClassInjector>(ci));
|
||||
}
|
||||
return ci;
|
||||
}
|
||||
|
||||
private static Map<Class<?>, WeakReference<ClassInjector>> injectorMap =
|
||||
new WeakHashMap<Class<?>, WeakReference<ClassInjector>>();
|
||||
}
|
||||
@ -613,15 +613,6 @@ public class MBeanInstantiator {
|
||||
return clr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class of a primitive type.
|
||||
* @param name The type for which we the associated class.
|
||||
* @return the class, or null if name is not primitive.
|
||||
*/
|
||||
public static Class<?> primitiveType(String name) {
|
||||
return primitiveClasses.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a class with the specified loader, or with this object
|
||||
* class loader if the specified loader is null.
|
||||
|
||||
@ -36,28 +36,20 @@ import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import javax.management.Description;
|
||||
|
||||
import javax.management.Descriptor;
|
||||
import javax.management.ImmutableDescriptor;
|
||||
import javax.management.IntrospectionException;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.MBean;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanConstructorInfo;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanNotificationInfo;
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.MXBean;
|
||||
import javax.management.ManagedAttribute;
|
||||
import javax.management.ManagedOperation;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.NotificationBroadcaster;
|
||||
import javax.management.NotificationInfo;
|
||||
import javax.management.NotificationInfos;
|
||||
import javax.management.ReflectionException;
|
||||
|
||||
/**
|
||||
@ -79,7 +71,7 @@ import javax.management.ReflectionException;
|
||||
* ancestor with ConvertingMethod. But that would mean an extra object
|
||||
* for every Method in every Standard MBean interface.
|
||||
*/
|
||||
public abstract class MBeanIntrospector<M> {
|
||||
abstract class MBeanIntrospector<M> {
|
||||
static final class PerInterfaceMap<M>
|
||||
extends WeakHashMap<Class<?>, WeakReference<PerInterface<M>>> {}
|
||||
|
||||
@ -159,27 +151,7 @@ public abstract class MBeanIntrospector<M> {
|
||||
* may be null.
|
||||
*/
|
||||
abstract MBeanAttributeInfo getMBeanAttributeInfo(String attributeName,
|
||||
M getter, M setter) throws IntrospectionException;
|
||||
|
||||
final String getAttributeDescription(
|
||||
String attributeName, String defaultDescription,
|
||||
Method getter, Method setter) throws IntrospectionException {
|
||||
String g = Introspector.descriptionForElement(getter);
|
||||
String s = Introspector.descriptionForElement(setter);
|
||||
if (g == null) {
|
||||
if (s == null)
|
||||
return defaultDescription;
|
||||
else
|
||||
return s;
|
||||
} else if (s == null || g.equals(s)) {
|
||||
return g;
|
||||
} else {
|
||||
throw new IntrospectionException(
|
||||
"Inconsistent @Description on getter and setter for " +
|
||||
"attribute " + attributeName);
|
||||
}
|
||||
}
|
||||
|
||||
M getter, M setter);
|
||||
/**
|
||||
* Construct an MBeanOperationInfo for the given operation based on
|
||||
* the M it was derived from.
|
||||
@ -200,37 +172,11 @@ public abstract class MBeanIntrospector<M> {
|
||||
*/
|
||||
abstract Descriptor getMBeanDescriptor(Class<?> resourceClass);
|
||||
|
||||
/**
|
||||
* Get any additional Descriptor entries for this introspector instance.
|
||||
* If there is a non-default MXBeanMappingFactory, it will appear in
|
||||
* this Descriptor.
|
||||
* @return Additional Descriptor entries, or an empty Descriptor if none.
|
||||
*/
|
||||
Descriptor getSpecificMBeanDescriptor() {
|
||||
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
|
||||
}
|
||||
|
||||
void checkCompliance(Class<?> mbeanType) throws NotCompliantMBeanException {
|
||||
if (!mbeanType.isInterface() &&
|
||||
!mbeanType.isAnnotationPresent(MBean.class) &&
|
||||
!Introspector.hasMXBeanAnnotation(mbeanType)) {
|
||||
throw new NotCompliantMBeanException("Not an interface and " +
|
||||
"does not have @" + MBean.class.getSimpleName() +
|
||||
" or @" + MXBean.class.getSimpleName() + " annotation: " +
|
||||
mbeanType.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the methods to be analyzed to build the MBean interface.
|
||||
*/
|
||||
List<Method> getMethods(final Class<?> mbeanType) throws Exception {
|
||||
if (mbeanType.isInterface())
|
||||
return Arrays.asList(mbeanType.getMethods());
|
||||
|
||||
final List<Method> methods = newList();
|
||||
getAnnotatedMethods(mbeanType, methods);
|
||||
return methods;
|
||||
return Arrays.asList(mbeanType.getMethods());
|
||||
}
|
||||
|
||||
final PerInterface<M> getPerInterface(Class<?> mbeanInterface)
|
||||
@ -265,14 +211,11 @@ public abstract class MBeanIntrospector<M> {
|
||||
* the MBeanInfo's Descriptor.
|
||||
*/
|
||||
private MBeanInfo makeInterfaceMBeanInfo(Class<?> mbeanInterface,
|
||||
MBeanAnalyzer<M> analyzer) throws IntrospectionException {
|
||||
MBeanAnalyzer<M> analyzer) {
|
||||
final MBeanInfoMaker maker = new MBeanInfoMaker();
|
||||
analyzer.visit(maker);
|
||||
final String defaultDescription =
|
||||
final String description =
|
||||
"Information on the management interface of the MBean";
|
||||
String description = Introspector.descriptionForElement(mbeanInterface);
|
||||
if (description == null)
|
||||
description = defaultDescription;
|
||||
return maker.makeMBeanInfo(mbeanInterface, description);
|
||||
}
|
||||
|
||||
@ -370,11 +313,11 @@ public abstract class MBeanIntrospector<M> {
|
||||
|
||||
/** A visitor that constructs the per-interface MBeanInfo. */
|
||||
private class MBeanInfoMaker
|
||||
implements MBeanAnalyzer.MBeanVisitor<M, IntrospectionException> {
|
||||
implements MBeanAnalyzer.MBeanVisitor<M> {
|
||||
|
||||
public void visitAttribute(String attributeName,
|
||||
M getter,
|
||||
M setter) throws IntrospectionException {
|
||||
M setter) {
|
||||
MBeanAttributeInfo mbai =
|
||||
getMBeanAttributeInfo(attributeName, getter, setter);
|
||||
|
||||
@ -403,7 +346,7 @@ public abstract class MBeanIntrospector<M> {
|
||||
new ImmutableDescriptor(interfaceClassName);
|
||||
final Descriptor mbeanDescriptor = getBasicMBeanDescriptor();
|
||||
final Descriptor annotatedDescriptor =
|
||||
Introspector.descriptorForElement(mbeanInterface, false);
|
||||
Introspector.descriptorForElement(mbeanInterface);
|
||||
final Descriptor descriptor =
|
||||
DescriptorCache.getInstance().union(
|
||||
classNameDescriptor,
|
||||
@ -442,32 +385,20 @@ public abstract class MBeanIntrospector<M> {
|
||||
* Return the MBeanInfo for the given resource, based on the given
|
||||
* per-interface data.
|
||||
*/
|
||||
final MBeanInfo getMBeanInfo(Object resource, PerInterface<M> perInterface)
|
||||
throws NotCompliantMBeanException {
|
||||
final MBeanInfo getMBeanInfo(Object resource, PerInterface<M> perInterface) {
|
||||
MBeanInfo mbi =
|
||||
getClassMBeanInfo(resource.getClass(), perInterface);
|
||||
MBeanNotificationInfo[] notifs;
|
||||
try {
|
||||
notifs = findNotifications(resource);
|
||||
} catch (RuntimeException e) {
|
||||
NotCompliantMBeanException x =
|
||||
new NotCompliantMBeanException(e.getMessage());
|
||||
x.initCause(e);
|
||||
throw x;
|
||||
}
|
||||
Descriptor d = getSpecificMBeanDescriptor();
|
||||
boolean anyNotifs = (notifs != null && notifs.length > 0);
|
||||
if (!anyNotifs && ImmutableDescriptor.EMPTY_DESCRIPTOR.equals(d))
|
||||
MBeanNotificationInfo[] notifs = findNotifications(resource);
|
||||
if (notifs == null || notifs.length == 0)
|
||||
return mbi;
|
||||
else {
|
||||
d = ImmutableDescriptor.union(d, mbi.getDescriptor());
|
||||
return new MBeanInfo(mbi.getClassName(),
|
||||
mbi.getDescription(),
|
||||
mbi.getAttributes(),
|
||||
mbi.getConstructors(),
|
||||
mbi.getOperations(),
|
||||
notifs,
|
||||
d);
|
||||
mbi.getDescriptor());
|
||||
}
|
||||
}
|
||||
|
||||
@ -507,145 +438,29 @@ public abstract class MBeanIntrospector<M> {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add to "methods" every public method that has the @ManagedAttribute
|
||||
* or @ManagedOperation annotation, in the given class or any of
|
||||
* its superclasses or superinterfaces.
|
||||
*
|
||||
* We always add superclass or superinterface methods first, so that
|
||||
* the stable sort used by eliminateCovariantMethods will put the
|
||||
* method from the most-derived class last. This means that we will
|
||||
* see the version of the @ManagedAttribute (or ...Operation) annotation
|
||||
* from that method, which might have a different description or whatever.
|
||||
*/
|
||||
public static void getAnnotatedMethods(Class<?> c, List<Method> methods)
|
||||
throws Exception {
|
||||
Class<?> sup = c.getSuperclass();
|
||||
if (sup != null)
|
||||
getAnnotatedMethods(sup, methods);
|
||||
Class<?>[] intfs = c.getInterfaces();
|
||||
for (Class<?> intf : intfs)
|
||||
getAnnotatedMethods(intf, methods);
|
||||
for (Method m : c.getMethods()) {
|
||||
// We are careful not to add m if it is inherited from a parent
|
||||
// class or interface, because duplicate methods lead to nasty
|
||||
// behaviour in eliminateCovariantMethods.
|
||||
if (m.getDeclaringClass() == c &&
|
||||
(m.isAnnotationPresent(ManagedAttribute.class) ||
|
||||
m.isAnnotationPresent(ManagedOperation.class)))
|
||||
methods.add(m);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the array of MBeanNotificationInfo for the given MBean object.
|
||||
* If the object implements NotificationBroadcaster and its
|
||||
* getNotificationInfo() method returns a non-empty array, then that
|
||||
* is the result. Otherwise, if the object has a @NotificationInfo
|
||||
* or @NotificationInfos annotation, then its contents form the result.
|
||||
* Otherwise, the result is null.
|
||||
*/
|
||||
static MBeanNotificationInfo[] findNotifications(Object moi) {
|
||||
if (moi instanceof NotificationBroadcaster) {
|
||||
MBeanNotificationInfo[] mbn =
|
||||
((NotificationBroadcaster) moi).getNotificationInfo();
|
||||
if (mbn != null && mbn.length > 0) {
|
||||
MBeanNotificationInfo[] result =
|
||||
new MBeanNotificationInfo[mbn.length];
|
||||
for (int i = 0; i < mbn.length; i++) {
|
||||
MBeanNotificationInfo ni = mbn[i];
|
||||
if (ni.getClass() != MBeanNotificationInfo.class)
|
||||
ni = (MBeanNotificationInfo) ni.clone();
|
||||
result[i] = ni;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
if (!MBeanInjector.injectsSendNotification(moi))
|
||||
return null;
|
||||
} catch (NotCompliantMBeanException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return findNotificationsFromAnnotations(moi.getClass());
|
||||
}
|
||||
|
||||
public static MBeanNotificationInfo[] findNotificationsFromAnnotations(
|
||||
Class<?> mbeanClass) {
|
||||
Class<?> c = getAnnotatedNotificationInfoClass(mbeanClass);
|
||||
if (c == null)
|
||||
if (!(moi instanceof NotificationBroadcaster))
|
||||
return null;
|
||||
NotificationInfo ni = c.getAnnotation(NotificationInfo.class);
|
||||
NotificationInfos nis = c.getAnnotation(NotificationInfos.class);
|
||||
List<NotificationInfo> list = newList();
|
||||
if (ni != null)
|
||||
list.add(ni);
|
||||
if (nis != null)
|
||||
list.addAll(Arrays.asList(nis.value()));
|
||||
if (list.isEmpty())
|
||||
MBeanNotificationInfo[] mbn =
|
||||
((NotificationBroadcaster) moi).getNotificationInfo();
|
||||
if (mbn == null)
|
||||
return null;
|
||||
List<MBeanNotificationInfo> mbnis = newList();
|
||||
for (NotificationInfo x : list) {
|
||||
// The Descriptor includes any fields explicitly specified by
|
||||
// x.descriptorFields(), plus any fields from the contained
|
||||
// @Description annotation.
|
||||
Descriptor d = new ImmutableDescriptor(x.descriptorFields());
|
||||
d = ImmutableDescriptor.union(
|
||||
d, Introspector.descriptorForAnnotation(x.description()));
|
||||
MBeanNotificationInfo mbni = new MBeanNotificationInfo(
|
||||
x.types(), x.notificationClass().getName(),
|
||||
x.description().value(), d);
|
||||
mbnis.add(mbni);
|
||||
}
|
||||
return mbnis.toArray(new MBeanNotificationInfo[mbnis.size()]);
|
||||
}
|
||||
|
||||
private static final Map<Class<?>, WeakReference<Class<?>>>
|
||||
annotatedNotificationInfoClasses = newWeakHashMap();
|
||||
|
||||
private static Class<?> getAnnotatedNotificationInfoClass(Class<?> baseClass) {
|
||||
synchronized (annotatedNotificationInfoClasses) {
|
||||
WeakReference<Class<?>> wr =
|
||||
annotatedNotificationInfoClasses.get(baseClass);
|
||||
if (wr != null)
|
||||
return wr.get();
|
||||
Class<?> c = null;
|
||||
if (baseClass.isAnnotationPresent(NotificationInfo.class) ||
|
||||
baseClass.isAnnotationPresent(NotificationInfos.class)) {
|
||||
c = baseClass;
|
||||
} else {
|
||||
Class<?>[] intfs = baseClass.getInterfaces();
|
||||
for (Class<?> intf : intfs) {
|
||||
Class<?> c1 = getAnnotatedNotificationInfoClass(intf);
|
||||
if (c1 != null) {
|
||||
if (c != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Class " + baseClass.getName() + " inherits " +
|
||||
"@NotificationInfo(s) from both " +
|
||||
c.getName() + " and " + c1.getName());
|
||||
}
|
||||
c = c1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Record the result of the search. If no @NotificationInfo(s)
|
||||
// were found, c is null, and we store a WeakReference(null).
|
||||
// This prevents us from having to search again and fail again.
|
||||
annotatedNotificationInfoClasses.put(baseClass,
|
||||
new WeakReference<Class<?>>(c));
|
||||
return c;
|
||||
MBeanNotificationInfo[] result =
|
||||
new MBeanNotificationInfo[mbn.length];
|
||||
for (int i = 0; i < mbn.length; i++) {
|
||||
MBeanNotificationInfo ni = mbn[i];
|
||||
if (ni.getClass() != MBeanNotificationInfo.class)
|
||||
ni = (MBeanNotificationInfo) ni.clone();
|
||||
result[i] = ni;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static MBeanConstructorInfo[] findConstructors(Class<?> c) {
|
||||
Constructor<?>[] cons = c.getConstructors();
|
||||
MBeanConstructorInfo[] mbc = new MBeanConstructorInfo[cons.length];
|
||||
for (int i = 0; i < cons.length; i++) {
|
||||
String descr = "Public constructor of the MBean";
|
||||
Description d = cons[i].getAnnotation(Description.class);
|
||||
if (d != null)
|
||||
descr = d.value();
|
||||
final String descr = "Public constructor of the MBean";
|
||||
mbc[i] = new MBeanConstructorInfo(descr, cons[i]);
|
||||
}
|
||||
return mbc;
|
||||
|
||||
@ -37,7 +37,7 @@ import javax.management.MBeanServer;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
import com.sun.jmx.mbeanserver.MXBeanMappingFactory;
|
||||
|
||||
/**
|
||||
* Base class for MBeans. There is one instance of this class for
|
||||
@ -121,8 +121,7 @@ import javax.management.openmbean.MXBeanMappingFactory;
|
||||
public abstract class MBeanSupport<M>
|
||||
implements DynamicMBean2, MBeanRegistration {
|
||||
|
||||
<T> MBeanSupport(T resource, Class<T> mbeanInterfaceType,
|
||||
MXBeanMappingFactory mappingFactory)
|
||||
<T> MBeanSupport(T resource, Class<T> mbeanInterfaceType)
|
||||
throws NotCompliantMBeanException {
|
||||
if (mbeanInterfaceType == null)
|
||||
throw new NotCompliantMBeanException("Null MBean interface");
|
||||
@ -133,14 +132,13 @@ public abstract class MBeanSupport<M>
|
||||
throw new NotCompliantMBeanException(msg);
|
||||
}
|
||||
this.resource = resource;
|
||||
MBeanIntrospector<M> introspector = getMBeanIntrospector(mappingFactory);
|
||||
MBeanIntrospector<M> introspector = getMBeanIntrospector();
|
||||
this.perInterface = introspector.getPerInterface(mbeanInterfaceType);
|
||||
this.mbeanInfo = introspector.getMBeanInfo(resource, perInterface);
|
||||
}
|
||||
|
||||
/** Return the appropriate introspector for this type of MBean. */
|
||||
abstract MBeanIntrospector<M>
|
||||
getMBeanIntrospector(MXBeanMappingFactory mappingFactory);
|
||||
abstract MBeanIntrospector<M> getMBeanIntrospector();
|
||||
|
||||
/**
|
||||
* Return a cookie for this MBean. This cookie will be passed to
|
||||
@ -262,14 +260,10 @@ public abstract class MBeanSupport<M>
|
||||
return resource.getClass().getName();
|
||||
}
|
||||
|
||||
public final Object getWrappedObject() {
|
||||
public final Object getResource() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
public final ClassLoader getWrappedClassLoader() {
|
||||
return resource.getClass().getClassLoader();
|
||||
}
|
||||
|
||||
public final Class<?> getMBeanInterface() {
|
||||
return perInterface.getMBeanInterface();
|
||||
}
|
||||
|
||||
@ -28,26 +28,18 @@ package com.sun.jmx.mbeanserver;
|
||||
import com.sun.jmx.mbeanserver.MBeanIntrospector.MBeanInfoMap;
|
||||
import com.sun.jmx.mbeanserver.MBeanIntrospector.PerInterfaceMap;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import javax.management.Description;
|
||||
import javax.management.Descriptor;
|
||||
import javax.management.ImmutableDescriptor;
|
||||
import javax.management.IntrospectionException;
|
||||
import javax.management.JMX;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.MBeanParameterInfo;
|
||||
import javax.management.ManagedOperation;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
|
||||
import javax.management.openmbean.OpenMBeanOperationInfoSupport;
|
||||
import javax.management.openmbean.OpenMBeanParameterInfo;
|
||||
@ -60,36 +52,10 @@ import javax.management.openmbean.OpenType;
|
||||
* @since 1.6
|
||||
*/
|
||||
class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
/* We keep one MXBeanIntrospector per MXBeanMappingFactory, since the results
|
||||
* of the introspection depend on the factory. The MXBeanIntrospector
|
||||
* has a reference back to the factory, so we wrap it in a WeakReference.
|
||||
* It will be strongly referenced by any MXBeanSupport instances using it;
|
||||
* if there are none then it is OK to gc it.
|
||||
*/
|
||||
private static final
|
||||
Map<MXBeanMappingFactory, WeakReference<MXBeanIntrospector>> map =
|
||||
new WeakHashMap<MXBeanMappingFactory, WeakReference<MXBeanIntrospector>>();
|
||||
private static final MXBeanIntrospector instance = new MXBeanIntrospector();
|
||||
|
||||
static MXBeanIntrospector getInstance(MXBeanMappingFactory factory) {
|
||||
if (factory == null)
|
||||
factory = MXBeanMappingFactory.DEFAULT;
|
||||
synchronized (map) {
|
||||
MXBeanIntrospector intro;
|
||||
WeakReference<MXBeanIntrospector> wr = map.get(factory);
|
||||
if (wr != null) {
|
||||
intro = wr.get();
|
||||
if (intro != null)
|
||||
return intro;
|
||||
}
|
||||
intro = new MXBeanIntrospector(factory);
|
||||
wr = new WeakReference<MXBeanIntrospector>(intro);
|
||||
map.put(factory, wr);
|
||||
return intro;
|
||||
}
|
||||
}
|
||||
|
||||
private MXBeanIntrospector(MXBeanMappingFactory factory) {
|
||||
this.mappingFactory = factory;
|
||||
static MXBeanIntrospector getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -115,7 +81,7 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
|
||||
@Override
|
||||
ConvertingMethod mFrom(Method m) {
|
||||
return ConvertingMethod.from(m, mappingFactory);
|
||||
return ConvertingMethod.from(m);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -176,17 +142,13 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
|
||||
@Override
|
||||
MBeanAttributeInfo getMBeanAttributeInfo(String attributeName,
|
||||
ConvertingMethod getter, ConvertingMethod setter)
|
||||
throws IntrospectionException {
|
||||
ConvertingMethod getter, ConvertingMethod setter) {
|
||||
|
||||
final boolean isReadable = (getter != null);
|
||||
final boolean isWritable = (setter != null);
|
||||
final boolean isIs = isReadable && getName(getter).startsWith("is");
|
||||
|
||||
final String description = getAttributeDescription(
|
||||
attributeName, attributeName,
|
||||
getter == null ? null : getter.getMethod(),
|
||||
setter == null ? null : setter.getMethod());
|
||||
final String description = attributeName;
|
||||
|
||||
final OpenType<?> openType;
|
||||
final Type originalType;
|
||||
@ -235,17 +197,13 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
MBeanOperationInfo getMBeanOperationInfo(String operationName,
|
||||
ConvertingMethod operation) {
|
||||
final Method method = operation.getMethod();
|
||||
String description = operationName;
|
||||
final String description = operationName;
|
||||
/* Ideally this would be an empty string, but
|
||||
OMBOperationInfo constructor forbids that. */
|
||||
Description d = method.getAnnotation(Description.class);
|
||||
if (d != null)
|
||||
description = d.value();
|
||||
OMBOperationInfo constructor forbids that. Also, we
|
||||
could consult an annotation to get a useful
|
||||
description. */
|
||||
|
||||
int impact = MBeanOperationInfo.UNKNOWN;
|
||||
ManagedOperation annot = method.getAnnotation(ManagedOperation.class);
|
||||
if (annot != null)
|
||||
impact = annot.impact().getCode();
|
||||
final int impact = MBeanOperationInfo.UNKNOWN;
|
||||
|
||||
final OpenType<?> returnType = operation.getOpenReturnType();
|
||||
final Type originalReturnType = operation.getGenericReturnType();
|
||||
@ -257,15 +215,8 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
boolean openParameterTypes = true;
|
||||
Annotation[][] annots = method.getParameterAnnotations();
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
String paramName = Introspector.nameForParameter(annots[i]);
|
||||
if (paramName == null)
|
||||
paramName = "p" + i;
|
||||
|
||||
String paramDescription =
|
||||
Introspector.descriptionForParameter(annots[i]);
|
||||
if (paramDescription == null)
|
||||
paramDescription = paramName;
|
||||
|
||||
final String paramName = "p" + i;
|
||||
final String paramDescription = paramName;
|
||||
final OpenType<?> openType = paramTypes[i];
|
||||
final Type originalType = originalParamTypes[i];
|
||||
Descriptor descriptor =
|
||||
@ -292,7 +243,7 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
Descriptor descriptor =
|
||||
typeDescriptor(returnType, originalReturnType);
|
||||
descriptor = ImmutableDescriptor.union(descriptor,
|
||||
Introspector.descriptorForElement(method, false));
|
||||
Introspector.descriptorForElement(method));
|
||||
final MBeanOperationInfo oi;
|
||||
if (openReturnType && openParameterTypes) {
|
||||
/* If the return value and all the parameters can be faithfully
|
||||
@ -343,17 +294,6 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
Descriptor getSpecificMBeanDescriptor() {
|
||||
if (mappingFactory == MXBeanMappingFactory.DEFAULT)
|
||||
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
|
||||
else {
|
||||
return new ImmutableDescriptor(
|
||||
JMX.MXBEAN_MAPPING_FACTORY_CLASS_FIELD + "=" +
|
||||
mappingFactory.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
private static Descriptor typeDescriptor(OpenType<?> openType,
|
||||
Type originalType) {
|
||||
return new ImmutableDescriptor(
|
||||
@ -421,7 +361,5 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
|
||||
private final PerInterfaceMap<ConvertingMethod>
|
||||
perInterfaceMap = new PerInterfaceMap<ConvertingMethod>();
|
||||
|
||||
private final MBeanInfoMap mbeanInfoMap = new MBeanInfoMap();
|
||||
|
||||
private final MXBeanMappingFactory mappingFactory;
|
||||
private static final MBeanInfoMap mbeanInfoMap = new MBeanInfoMap();
|
||||
}
|
||||
|
||||
@ -25,8 +25,6 @@
|
||||
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import com.sun.jmx.remote.util.EnvHelp;
|
||||
import java.io.InvalidObjectException;
|
||||
import static com.sun.jmx.mbeanserver.Util.*;
|
||||
import java.util.Map;
|
||||
import java.lang.ref.WeakReference;
|
||||
@ -85,181 +83,87 @@ import javax.management.openmbean.OpenDataException;
|
||||
*
|
||||
* From the above, it is clear that the logic for getX on an MXBean is
|
||||
* the same as for setX on a proxy, and vice versa.
|
||||
*
|
||||
* The above describes the logic for "plain" MXBeanLookup, represented
|
||||
* by MXBeanLookup.Plain. When namespaces enter the picture, we see
|
||||
* MXBeanLookup.Prefix. Here, the idea is that the name of the ModuleMXBean
|
||||
* might be a//m:m=m. In this case, we don't accept a reference to
|
||||
* an MXBean object, since that would require different namespaces to know
|
||||
* each others' objects. We only accept proxies. Suppose you have a proxy
|
||||
* for a//m:m=m, call it moduleProxy, and you call
|
||||
* moduleProxy.setProduct(productProxy). Then if productProxy is for
|
||||
* a//p:p=p we should convert this to just p:p=p. If productProxy is for
|
||||
* a//b//p:p=p we should convert it to b//p:p=p. Conversely, if getProduct
|
||||
* returns an ObjectName like b//p:p=p then we should convert it into a proxy
|
||||
* for a//b//p:p=p.
|
||||
*/
|
||||
public abstract class MXBeanLookup {
|
||||
public class MXBeanLookup {
|
||||
private MXBeanLookup(MBeanServerConnection mbsc) {
|
||||
this.mbsc = mbsc;
|
||||
}
|
||||
|
||||
static MXBeanLookup lookupFor(MBeanServerConnection mbsc, String prefix) {
|
||||
if (prefix == null)
|
||||
return Plain.lookupFor(mbsc);
|
||||
else
|
||||
return new Prefix(mbsc, prefix);
|
||||
static MXBeanLookup lookupFor(MBeanServerConnection mbsc) {
|
||||
synchronized (mbscToLookup) {
|
||||
WeakReference<MXBeanLookup> weakLookup = mbscToLookup.get(mbsc);
|
||||
MXBeanLookup lookup = (weakLookup == null) ? null : weakLookup.get();
|
||||
if (lookup == null) {
|
||||
lookup = new MXBeanLookup(mbsc);
|
||||
mbscToLookup.put(mbsc, new WeakReference<MXBeanLookup>(lookup));
|
||||
}
|
||||
return lookup;
|
||||
}
|
||||
}
|
||||
|
||||
abstract <T> T objectNameToMXBean(ObjectName name, Class<T> type)
|
||||
throws InvalidObjectException;
|
||||
|
||||
abstract ObjectName mxbeanToObjectName(Object mxbean)
|
||||
throws OpenDataException;
|
||||
|
||||
static class Plain extends MXBeanLookup {
|
||||
Plain(MBeanServerConnection mbsc) {
|
||||
super(mbsc);
|
||||
synchronized <T> T objectNameToMXBean(ObjectName name, Class<T> type) {
|
||||
WeakReference<Object> wr = objectNameToProxy.get(name);
|
||||
if (wr != null) {
|
||||
Object proxy = wr.get();
|
||||
if (type.isInstance(proxy))
|
||||
return type.cast(proxy);
|
||||
}
|
||||
T proxy = JMX.newMXBeanProxy(mbsc, name, type);
|
||||
objectNameToProxy.put(name, new WeakReference<Object>(proxy));
|
||||
return proxy;
|
||||
}
|
||||
|
||||
static Plain lookupFor(MBeanServerConnection mbsc) {
|
||||
synchronized (mbscToLookup) {
|
||||
WeakReference<Plain> weakLookup = mbscToLookup.get(mbsc);
|
||||
Plain lookup = (weakLookup == null) ? null : weakLookup.get();
|
||||
if (lookup == null) {
|
||||
lookup = new Plain(mbsc);
|
||||
mbscToLookup.put(mbsc, new WeakReference<Plain>(lookup));
|
||||
}
|
||||
return lookup;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
synchronized <T> T objectNameToMXBean(ObjectName name, Class<T> type) {
|
||||
WeakReference<Object> wr = objectNameToProxy.get(name);
|
||||
if (wr != null) {
|
||||
Object proxy = wr.get();
|
||||
if (type.isInstance(proxy))
|
||||
return type.cast(proxy);
|
||||
}
|
||||
T proxy = JMX.newMXBeanProxy(mbsc, name, type);
|
||||
objectNameToProxy.put(name, new WeakReference<Object>(proxy));
|
||||
return proxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
synchronized ObjectName mxbeanToObjectName(Object mxbean)
|
||||
throws OpenDataException {
|
||||
String wrong;
|
||||
if (mxbean instanceof Proxy) {
|
||||
InvocationHandler ih = Proxy.getInvocationHandler(mxbean);
|
||||
if (ih instanceof MBeanServerInvocationHandler) {
|
||||
MBeanServerInvocationHandler mbsih =
|
||||
(MBeanServerInvocationHandler) ih;
|
||||
if (mbsih.getMBeanServerConnection().equals(mbsc))
|
||||
return mbsih.getObjectName();
|
||||
else
|
||||
wrong = "proxy for a different MBeanServer";
|
||||
} else
|
||||
wrong = "not a JMX proxy";
|
||||
} else {
|
||||
ObjectName name = mxbeanToObjectName.get(mxbean);
|
||||
if (name != null)
|
||||
return name;
|
||||
wrong = "not an MXBean registered in this MBeanServer";
|
||||
}
|
||||
String s = (mxbean == null) ?
|
||||
"null" : "object of type " + mxbean.getClass().getName();
|
||||
throw new OpenDataException(
|
||||
"Could not convert " + s + " to an ObjectName: " + wrong);
|
||||
// Message will be strange if mxbean is null but it is not
|
||||
// supposed to be.
|
||||
}
|
||||
|
||||
synchronized void addReference(ObjectName name, Object mxbean)
|
||||
throws InstanceAlreadyExistsException {
|
||||
ObjectName existing = mxbeanToObjectName.get(mxbean);
|
||||
if (existing != null) {
|
||||
String multiname = AccessController.doPrivileged(
|
||||
new GetPropertyAction("jmx.mxbean.multiname"));
|
||||
if (!"true".equalsIgnoreCase(multiname)) {
|
||||
throw new InstanceAlreadyExistsException(
|
||||
"MXBean already registered with name " + existing);
|
||||
}
|
||||
}
|
||||
mxbeanToObjectName.put(mxbean, name);
|
||||
}
|
||||
|
||||
synchronized boolean removeReference(ObjectName name, Object mxbean) {
|
||||
if (name.equals(mxbeanToObjectName.get(mxbean))) {
|
||||
mxbeanToObjectName.remove(mxbean);
|
||||
return true;
|
||||
synchronized ObjectName mxbeanToObjectName(Object mxbean)
|
||||
throws OpenDataException {
|
||||
String wrong;
|
||||
if (mxbean instanceof Proxy) {
|
||||
InvocationHandler ih = Proxy.getInvocationHandler(mxbean);
|
||||
if (ih instanceof MBeanServerInvocationHandler) {
|
||||
MBeanServerInvocationHandler mbsih =
|
||||
(MBeanServerInvocationHandler) ih;
|
||||
if (mbsih.getMBeanServerConnection().equals(mbsc))
|
||||
return mbsih.getObjectName();
|
||||
else
|
||||
wrong = "proxy for a different MBeanServer";
|
||||
} else
|
||||
return false;
|
||||
/* removeReference can be called when the above condition fails,
|
||||
* notably if you try to register the same MXBean twice.
|
||||
*/
|
||||
wrong = "not a JMX proxy";
|
||||
} else {
|
||||
ObjectName name = mxbeanToObjectName.get(mxbean);
|
||||
if (name != null)
|
||||
return name;
|
||||
wrong = "not an MXBean registered in this MBeanServer";
|
||||
}
|
||||
|
||||
private final WeakIdentityHashMap<Object, ObjectName>
|
||||
mxbeanToObjectName = WeakIdentityHashMap.make();
|
||||
private final Map<ObjectName, WeakReference<Object>>
|
||||
objectNameToProxy = newMap();
|
||||
private static WeakIdentityHashMap<MBeanServerConnection,
|
||||
WeakReference<Plain>>
|
||||
mbscToLookup = WeakIdentityHashMap.make();
|
||||
String s = (mxbean == null) ?
|
||||
"null" : "object of type " + mxbean.getClass().getName();
|
||||
throw new OpenDataException(
|
||||
"Could not convert " + s + " to an ObjectName: " + wrong);
|
||||
// Message will be strange if mxbean is null but it is not
|
||||
// supposed to be.
|
||||
}
|
||||
|
||||
private static class Prefix extends MXBeanLookup {
|
||||
private final String prefix;
|
||||
|
||||
Prefix(MBeanServerConnection mbsc, String prefix) {
|
||||
super(mbsc);
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
<T> T objectNameToMXBean(ObjectName name, Class<T> type)
|
||||
throws InvalidObjectException {
|
||||
String domain = prefix + name.getDomain();
|
||||
try {
|
||||
name = name.withDomain(domain);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw EnvHelp.initCause(
|
||||
new InvalidObjectException(e.getMessage()), e);
|
||||
synchronized void addReference(ObjectName name, Object mxbean)
|
||||
throws InstanceAlreadyExistsException {
|
||||
ObjectName existing = mxbeanToObjectName.get(mxbean);
|
||||
if (existing != null) {
|
||||
String multiname = AccessController.doPrivileged(
|
||||
new GetPropertyAction("jmx.mxbean.multiname"));
|
||||
if (!"true".equalsIgnoreCase(multiname)) {
|
||||
throw new InstanceAlreadyExistsException(
|
||||
"MXBean already registered with name " + existing);
|
||||
}
|
||||
return JMX.newMXBeanProxy(mbsc, name, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
ObjectName mxbeanToObjectName(Object mxbean)
|
||||
throws OpenDataException {
|
||||
ObjectName name = proxyToObjectName(mxbean);
|
||||
String domain = name.getDomain();
|
||||
if (!domain.startsWith(prefix)) {
|
||||
throw new OpenDataException(
|
||||
"Proxy's name does not start with " +
|
||||
prefix + ": " + name);
|
||||
}
|
||||
try {
|
||||
name = name.withDomain(domain.substring(prefix.length()));
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw EnvHelp.initCause(
|
||||
new OpenDataException(e.getMessage()), e);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
mxbeanToObjectName.put(mxbean, name);
|
||||
}
|
||||
|
||||
ObjectName proxyToObjectName(Object proxy) {
|
||||
InvocationHandler ih = Proxy.getInvocationHandler(proxy);
|
||||
if (ih instanceof MBeanServerInvocationHandler) {
|
||||
MBeanServerInvocationHandler mbsih =
|
||||
(MBeanServerInvocationHandler) ih;
|
||||
if (mbsih.getMBeanServerConnection().equals(mbsc))
|
||||
return mbsih.getObjectName();
|
||||
}
|
||||
return null;
|
||||
synchronized boolean removeReference(ObjectName name, Object mxbean) {
|
||||
if (name.equals(mxbeanToObjectName.get(mxbean))) {
|
||||
mxbeanToObjectName.remove(mxbean);
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
/* removeReference can be called when the above condition fails,
|
||||
* notably if you try to register the same MXBean twice.
|
||||
*/
|
||||
}
|
||||
|
||||
static MXBeanLookup getLookup() {
|
||||
@ -273,5 +177,12 @@ public abstract class MXBeanLookup {
|
||||
private static final ThreadLocal<MXBeanLookup> currentLookup =
|
||||
new ThreadLocal<MXBeanLookup>();
|
||||
|
||||
final MBeanServerConnection mbsc;
|
||||
private final MBeanServerConnection mbsc;
|
||||
private final WeakIdentityHashMap<Object, ObjectName>
|
||||
mxbeanToObjectName = WeakIdentityHashMap.make();
|
||||
private final Map<ObjectName, WeakReference<Object>>
|
||||
objectNameToProxy = newMap();
|
||||
private static final WeakIdentityHashMap<MBeanServerConnection,
|
||||
WeakReference<MXBeanLookup>>
|
||||
mbscToLookup = WeakIdentityHashMap.make();
|
||||
}
|
||||
|
||||
@ -23,10 +23,12 @@
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package javax.management.openmbean;
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import java.io.InvalidObjectException;
|
||||
import java.lang.reflect.Type;
|
||||
import javax.management.openmbean.OpenDataException;
|
||||
import javax.management.openmbean.OpenType;
|
||||
|
||||
/**
|
||||
* <p>A custom mapping between Java types and Open types for use in MXBeans.
|
||||
@ -166,12 +168,10 @@ public abstract class MXBeanMapping {
|
||||
if (javaType instanceof Class<?> && ((Class<?>) javaType).isPrimitive())
|
||||
return (Class<?>) javaType;
|
||||
try {
|
||||
String className = OpenType.validClassName(openType.getClassName());
|
||||
String className = openType.getClassName();
|
||||
return Class.forName(className, false, null);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e); // should not happen
|
||||
} catch (OpenDataException e) {
|
||||
throw new IllegalArgumentException("Bad OpenType: " + openType, e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,8 +23,10 @@
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package javax.management.openmbean;
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import javax.management.openmbean.*;
|
||||
import com.sun.jmx.mbeanserver.MXBeanMapping;
|
||||
import com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
@ -100,49 +102,6 @@ public abstract class MXBeanMappingFactory {
|
||||
public static final MXBeanMappingFactory DEFAULT =
|
||||
new DefaultMXBeanMappingFactory();
|
||||
|
||||
/**
|
||||
* <p>Determine the appropriate MXBeanMappingFactory to use for the given
|
||||
* MXBean interface, based on its annotations. If the interface has an
|
||||
* {@link MXBeanMappingFactoryClass @MXBeanMappingFactoryClass} annotation,
|
||||
* that is used to determine the MXBeanMappingFactory. Otherwise, if the
|
||||
* package containing the interface has such an annotation, that is used.
|
||||
* Otherwise the MXBeanMappingFactory is the {@linkplain #DEFAULT default}
|
||||
* one.</p>
|
||||
*
|
||||
* @param intf the MXBean interface for which to determine the
|
||||
* MXBeanMappingFactory.
|
||||
*
|
||||
* @return the MXBeanMappingFactory for the given MXBean interface.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code intf} is null, or if an
|
||||
* exception occurs while trying constructing an MXBeanMappingFactory
|
||||
* based on an annotation. In the second case, the exception will appear
|
||||
* in the {@linkplain Throwable#getCause() cause chain} of the
|
||||
* {@code IllegalArgumentException}.
|
||||
*/
|
||||
public static MXBeanMappingFactory forInterface(Class<?> intf) {
|
||||
if (intf == null)
|
||||
throw new IllegalArgumentException("Null interface");
|
||||
MXBeanMappingFactoryClass annot =
|
||||
intf.getAnnotation(MXBeanMappingFactoryClass.class);
|
||||
if (annot == null) {
|
||||
Package p = intf.getPackage();
|
||||
if (p != null)
|
||||
annot = p.getAnnotation(MXBeanMappingFactoryClass.class);
|
||||
}
|
||||
if (annot == null)
|
||||
return MXBeanMappingFactory.DEFAULT;
|
||||
Class<? extends MXBeanMappingFactory> factoryClass = annot.value();
|
||||
try {
|
||||
return annot.value().newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException(
|
||||
"Could not instantiate MXBeanMappingFactory " +
|
||||
factoryClass.getName() +
|
||||
" from @MXBeanMappingFactoryClass", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the mapping for the given Java type. Typically, a
|
||||
* mapping factory will return mappings for types it handles, and
|
||||
@ -32,10 +32,8 @@ import java.util.Map;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
|
||||
/**
|
||||
<p>Helper class for an {@link InvocationHandler} that forwards methods from an
|
||||
@ -47,7 +45,7 @@ import javax.management.openmbean.MXBeanMappingFactory;
|
||||
@since 1.6
|
||||
*/
|
||||
public class MXBeanProxy {
|
||||
public MXBeanProxy(Class<?> mxbeanInterface, MXBeanMappingFactory factory) {
|
||||
public MXBeanProxy(Class<?> mxbeanInterface) {
|
||||
|
||||
if (mxbeanInterface == null)
|
||||
throw new IllegalArgumentException("Null parameter");
|
||||
@ -55,7 +53,7 @@ public class MXBeanProxy {
|
||||
final MBeanAnalyzer<ConvertingMethod> analyzer;
|
||||
try {
|
||||
analyzer =
|
||||
MXBeanIntrospector.getInstance(factory).getAnalyzer(mxbeanInterface);
|
||||
MXBeanIntrospector.getInstance().getAnalyzer(mxbeanInterface);
|
||||
} catch (NotCompliantMBeanException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
@ -63,7 +61,7 @@ public class MXBeanProxy {
|
||||
}
|
||||
|
||||
private class Visitor
|
||||
implements MBeanAnalyzer.MBeanVisitor<ConvertingMethod, RuntimeException> {
|
||||
implements MBeanAnalyzer.MBeanVisitor<ConvertingMethod> {
|
||||
public void visitAttribute(String attributeName,
|
||||
ConvertingMethod getter,
|
||||
ConvertingMethod setter) {
|
||||
@ -161,8 +159,7 @@ public class MXBeanProxy {
|
||||
|
||||
Handler handler = handlerMap.get(method);
|
||||
ConvertingMethod cm = handler.getConvertingMethod();
|
||||
String prefix = extractPrefix(name);
|
||||
MXBeanLookup lookup = MXBeanLookup.lookupFor(mbsc, prefix);
|
||||
MXBeanLookup lookup = MXBeanLookup.lookupFor(mbsc);
|
||||
MXBeanLookup oldLookup = MXBeanLookup.getLookup();
|
||||
try {
|
||||
MXBeanLookup.setLookup(lookup);
|
||||
@ -174,17 +171,5 @@ public class MXBeanProxy {
|
||||
}
|
||||
}
|
||||
|
||||
private static String extractPrefix(ObjectName name)
|
||||
throws MalformedObjectNameException {
|
||||
String domain = name.getDomain();
|
||||
int slashslash = domain.lastIndexOf("//");
|
||||
if (slashslash > 0 && domain.charAt(slashslash - 1) == '/')
|
||||
slashslash--;
|
||||
if (slashslash >= 0)
|
||||
return domain.substring(0, slashslash + 2);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
private final Map<Method, Handler> handlerMap = newMap();
|
||||
}
|
||||
|
||||
@ -35,7 +35,6 @@ import javax.management.JMX;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
|
||||
/**
|
||||
* Base class for MXBeans.
|
||||
@ -62,16 +61,14 @@ public class MXBeanSupport extends MBeanSupport<ConvertingMethod> {
|
||||
if it does not implement the class {@code mxbeanInterface} or if
|
||||
that class is not a valid MXBean interface.
|
||||
*/
|
||||
public <T> MXBeanSupport(T resource, Class<T> mxbeanInterface,
|
||||
MXBeanMappingFactory mappingFactory)
|
||||
public <T> MXBeanSupport(T resource, Class<T> mxbeanInterface)
|
||||
throws NotCompliantMBeanException {
|
||||
super(resource, mxbeanInterface, mappingFactory);
|
||||
super(resource, mxbeanInterface);
|
||||
}
|
||||
|
||||
@Override
|
||||
MBeanIntrospector<ConvertingMethod>
|
||||
getMBeanIntrospector(MXBeanMappingFactory mappingFactory) {
|
||||
return MXBeanIntrospector.getInstance(mappingFactory);
|
||||
MBeanIntrospector<ConvertingMethod> getMBeanIntrospector() {
|
||||
return MXBeanIntrospector.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -159,8 +156,8 @@ public class MXBeanSupport extends MBeanSupport<ConvertingMethod> {
|
||||
// eventually we could have some logic to supply a default name
|
||||
|
||||
synchronized (lock) {
|
||||
this.mxbeanLookup = MXBeanLookup.Plain.lookupFor(server);
|
||||
this.mxbeanLookup.addReference(name, getWrappedObject());
|
||||
this.mxbeanLookup = MXBeanLookup.lookupFor(server);
|
||||
this.mxbeanLookup.addReference(name, getResource());
|
||||
this.objectName = name;
|
||||
}
|
||||
}
|
||||
@ -169,19 +166,13 @@ public class MXBeanSupport extends MBeanSupport<ConvertingMethod> {
|
||||
public void unregister() {
|
||||
synchronized (lock) {
|
||||
if (mxbeanLookup != null) {
|
||||
if (mxbeanLookup.removeReference(objectName, getWrappedObject()))
|
||||
if (mxbeanLookup.removeReference(objectName, getResource()))
|
||||
objectName = null;
|
||||
}
|
||||
// XXX: need to revisit the whole register/unregister logic in
|
||||
// the face of wrapping. The mxbeanLookup!=null test is a hack.
|
||||
// If you wrap an MXBean in a MyWrapperMBean and register it,
|
||||
// the lookup table should contain the wrapped object. But that
|
||||
// implies that MyWrapperMBean calls register, which today it
|
||||
// can't within the public API.
|
||||
}
|
||||
}
|
||||
private final Object lock = new Object(); // for mxbeanLookup and objectName
|
||||
|
||||
private MXBeanLookup.Plain mxbeanLookup;
|
||||
private MXBeanLookup mxbeanLookup;
|
||||
private ObjectName objectName;
|
||||
}
|
||||
|
||||
@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-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 com.sun.jmx.mbeanserver;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.Notification;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
|
||||
/**
|
||||
* <p>A variant of {@code StandardMBeanSupport} where the only
|
||||
* methods included are public getters. This is used by
|
||||
* {@code QueryNotificationFilter} to pretend that a Notification is
|
||||
* an MBean so it can have a query evaluated on it. Standard queries
|
||||
* never set attributes or invoke methods but custom queries could and
|
||||
* we don't want to allow that. Also we don't want to fail if a
|
||||
* Notification happens to have inconsistent types in a pair of getX and
|
||||
* setX methods, and we want to include the Object.getClass() method.
|
||||
*/
|
||||
public class NotificationMBeanSupport extends StandardMBeanSupport {
|
||||
public <T extends Notification> NotificationMBeanSupport(T n)
|
||||
throws NotCompliantMBeanException {
|
||||
super(n, Util.<Class<T>>cast(n.getClass()));
|
||||
}
|
||||
|
||||
@Override
|
||||
MBeanIntrospector<Method> getMBeanIntrospector(MXBeanMappingFactory ignored) {
|
||||
return introspector;
|
||||
}
|
||||
|
||||
private static class Introspector extends StandardMBeanIntrospector {
|
||||
@Override
|
||||
void checkCompliance(Class<?> mbeanType) {}
|
||||
|
||||
@Override
|
||||
List<Method> getMethods(final Class<?> mbeanType)
|
||||
throws Exception {
|
||||
List<Method> methods = new ArrayList<Method>();
|
||||
for (Method m : mbeanType.getMethods()) {
|
||||
String name = m.getName();
|
||||
Class<?> ret = m.getReturnType();
|
||||
if (m.getParameterTypes().length == 0) {
|
||||
if ((name.startsWith("is") && name.length() > 2 &&
|
||||
ret == boolean.class) ||
|
||||
(name.startsWith("get") && name.length() > 3 &&
|
||||
ret != void.class)) {
|
||||
methods.add(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
return methods;
|
||||
}
|
||||
|
||||
}
|
||||
private static final MBeanIntrospector<Method> introspector =
|
||||
new Introspector();
|
||||
}
|
||||
@ -1,186 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-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 com.sun.jmx.mbeanserver;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.DynamicMBean;
|
||||
import javax.management.DynamicWrapperMBean;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.ListenerNotFoundException;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanNotificationInfo;
|
||||
import javax.management.MBeanRegistration;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.NotificationBroadcasterSupport;
|
||||
import javax.management.NotificationEmitter;
|
||||
import javax.management.NotificationFilter;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.ReflectionException;
|
||||
|
||||
/**
|
||||
* Create wrappers for DynamicMBean that implement NotificationEmitter
|
||||
* and SendNotification.
|
||||
*/
|
||||
public class NotifySupport
|
||||
implements DynamicMBean2, NotificationEmitter, MBeanRegistration {
|
||||
|
||||
private final DynamicMBean mbean;
|
||||
private final NotificationBroadcasterSupport nbs;
|
||||
|
||||
public static DynamicMBean wrap(
|
||||
DynamicMBean mbean, NotificationBroadcasterSupport nbs) {
|
||||
return new NotifySupport(mbean, nbs);
|
||||
}
|
||||
|
||||
private NotifySupport(DynamicMBean mbean, NotificationBroadcasterSupport nbs) {
|
||||
this.mbean = mbean;
|
||||
this.nbs = nbs;
|
||||
}
|
||||
|
||||
public static NotificationBroadcasterSupport getNB(DynamicMBean mbean) {
|
||||
if (mbean instanceof NotifySupport)
|
||||
return ((NotifySupport) mbean).nbs;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
if (mbean instanceof DynamicMBean2)
|
||||
return ((DynamicMBean2) mbean).getClassName();
|
||||
Object w = mbean;
|
||||
if (w instanceof DynamicWrapperMBean)
|
||||
w = ((DynamicWrapperMBean) w).getWrappedObject();
|
||||
return w.getClass().getName();
|
||||
}
|
||||
|
||||
public void preRegister2(MBeanServer mbs, ObjectName name) throws Exception {
|
||||
if (mbean instanceof DynamicMBean2)
|
||||
((DynamicMBean2) mbean).preRegister2(mbs, name);
|
||||
}
|
||||
|
||||
public void registerFailed() {
|
||||
if (mbean instanceof DynamicMBean2)
|
||||
((DynamicMBean2) mbean).registerFailed();
|
||||
}
|
||||
|
||||
public Object getWrappedObject() {
|
||||
if (mbean instanceof DynamicWrapperMBean)
|
||||
return ((DynamicWrapperMBean) mbean).getWrappedObject();
|
||||
else
|
||||
return mbean;
|
||||
}
|
||||
|
||||
public ClassLoader getWrappedClassLoader() {
|
||||
if (mbean instanceof DynamicWrapperMBean)
|
||||
return ((DynamicWrapperMBean) mbean).getWrappedClassLoader();
|
||||
else
|
||||
return mbean.getClass().getClassLoader();
|
||||
}
|
||||
|
||||
public Object getAttribute(String attribute) throws AttributeNotFoundException,
|
||||
MBeanException,
|
||||
ReflectionException {
|
||||
return mbean.getAttribute(attribute);
|
||||
}
|
||||
|
||||
public void setAttribute(Attribute attribute) throws AttributeNotFoundException,
|
||||
InvalidAttributeValueException,
|
||||
MBeanException,
|
||||
ReflectionException {
|
||||
mbean.setAttribute(attribute);
|
||||
}
|
||||
|
||||
public AttributeList setAttributes(AttributeList attributes) {
|
||||
return mbean.setAttributes(attributes);
|
||||
}
|
||||
|
||||
public Object invoke(String actionName, Object[] params, String[] signature)
|
||||
throws MBeanException, ReflectionException {
|
||||
return mbean.invoke(actionName, params, signature);
|
||||
}
|
||||
|
||||
public MBeanInfo getMBeanInfo() {
|
||||
return mbean.getMBeanInfo();
|
||||
}
|
||||
|
||||
public AttributeList getAttributes(String[] attributes) {
|
||||
return mbean.getAttributes(attributes);
|
||||
}
|
||||
|
||||
public void removeNotificationListener(NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
Object handback) throws ListenerNotFoundException {
|
||||
nbs.removeNotificationListener(listener, filter, handback);
|
||||
}
|
||||
|
||||
public void removeNotificationListener(NotificationListener listener)
|
||||
throws ListenerNotFoundException {
|
||||
nbs.removeNotificationListener(listener);
|
||||
}
|
||||
|
||||
public MBeanNotificationInfo[] getNotificationInfo() {
|
||||
return nbs.getNotificationInfo();
|
||||
}
|
||||
|
||||
public void addNotificationListener(NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
Object handback) {
|
||||
nbs.addNotificationListener(listener, filter, handback);
|
||||
}
|
||||
|
||||
public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception {
|
||||
if (mbr() != null)
|
||||
return mbr().preRegister(server, name);
|
||||
else
|
||||
return name;
|
||||
}
|
||||
|
||||
public void postRegister(Boolean registrationDone) {
|
||||
if (mbr() != null)
|
||||
mbr().postRegister(registrationDone);
|
||||
}
|
||||
|
||||
public void preDeregister() throws Exception {
|
||||
if (mbr() != null)
|
||||
mbr().preDeregister();
|
||||
}
|
||||
|
||||
public void postDeregister() {
|
||||
if (mbr() != null)
|
||||
mbr().postDeregister();
|
||||
}
|
||||
|
||||
private MBeanRegistration mbr() {
|
||||
if (mbean instanceof MBeanRegistration)
|
||||
return (MBeanRegistration) mbean;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* 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
|
||||
@ -231,7 +231,7 @@ final class PerInterface<M> {
|
||||
/**
|
||||
* Visitor that sets up the method maps (operations, getters, setters).
|
||||
*/
|
||||
private class InitMaps implements MBeanAnalyzer.MBeanVisitor<M, RuntimeException> {
|
||||
private class InitMaps implements MBeanAnalyzer.MBeanVisitor<M> {
|
||||
public void visitAttribute(String attributeName,
|
||||
M getter,
|
||||
M setter) {
|
||||
|
||||
@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-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 com.sun.jmx.mbeanserver;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
/**
|
||||
* <p>A factory for ThreadPoolExecutor objects that allows the same object to
|
||||
* be shared by all users of the factory that are in the same ThreadGroup.</p>
|
||||
*/
|
||||
// We return a ThreadPoolExecutor rather than the more general ExecutorService
|
||||
// because we need to be able to call allowCoreThreadTimeout so that threads in
|
||||
// the pool will eventually be destroyed when the pool is no longer in use.
|
||||
// Otherwise these threads would keep the ThreadGroup alive forever.
|
||||
public class PerThreadGroupPool<T extends ThreadPoolExecutor> {
|
||||
private final WeakIdentityHashMap<ThreadGroup, WeakReference<T>> map =
|
||||
WeakIdentityHashMap.make();
|
||||
|
||||
public static interface Create<T extends ThreadPoolExecutor> {
|
||||
public T createThreadPool(ThreadGroup group);
|
||||
}
|
||||
|
||||
private PerThreadGroupPool() {}
|
||||
|
||||
public static <T extends ThreadPoolExecutor> PerThreadGroupPool<T> make() {
|
||||
return new PerThreadGroupPool<T>();
|
||||
}
|
||||
|
||||
public synchronized T getThreadPoolExecutor(Create<T> create) {
|
||||
// Find out if there's already an existing executor for the calling
|
||||
// thread and reuse it. Otherwise, create a new one and store it in
|
||||
// the executors map. If there is a SecurityManager, the group of
|
||||
// System.getSecurityManager() is used, else the group of the calling
|
||||
// thread.
|
||||
SecurityManager s = System.getSecurityManager();
|
||||
ThreadGroup group = (s != null) ? s.getThreadGroup() :
|
||||
Thread.currentThread().getThreadGroup();
|
||||
WeakReference<T> wr = map.get(group);
|
||||
T executor = (wr == null) ? null : wr.get();
|
||||
if (executor == null) {
|
||||
executor = create.createThreadPool(group);
|
||||
executor.allowCoreThreadTimeOut(true);
|
||||
map.put(group, new WeakReference<T>(executor));
|
||||
}
|
||||
return executor;
|
||||
}
|
||||
}
|
||||
@ -396,7 +396,7 @@ public class Repository {
|
||||
|
||||
// Set domain to default if domain is empty and not already set
|
||||
if (dom.length() == 0)
|
||||
name = ObjectName.valueOf(domain + name.toString());
|
||||
name = Util.newObjectName(domain + name.toString());
|
||||
|
||||
// Do we have default domain ?
|
||||
if (dom == domain) { // ES: OK (dom & domain are interned)
|
||||
@ -573,7 +573,7 @@ public class Repository {
|
||||
// Pattern matching in the domain name (*, ?)
|
||||
final String dom2Match = name.getDomain();
|
||||
for (String dom : domainTb.keySet()) {
|
||||
if (Util.wildpathmatch(dom, dom2Match)) {
|
||||
if (Util.wildmatch(dom, dom2Match)) {
|
||||
final Map<String,NamedObject> moiTb = domainTb.get(dom);
|
||||
if (allNames)
|
||||
result.addAll(moiTb.values());
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2005 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
|
||||
@ -35,7 +35,6 @@ import javax.management.IntrospectionException;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.ManagedOperation;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.NotificationBroadcaster;
|
||||
import javax.management.NotificationBroadcasterSupport;
|
||||
@ -119,32 +118,22 @@ class StandardMBeanIntrospector extends MBeanIntrospector<Method> {
|
||||
|
||||
@Override
|
||||
MBeanAttributeInfo getMBeanAttributeInfo(String attributeName,
|
||||
Method getter, Method setter) throws IntrospectionException {
|
||||
Method getter, Method setter) {
|
||||
|
||||
String description = getAttributeDescription(
|
||||
attributeName, "Attribute exposed for management",
|
||||
getter, setter);
|
||||
return new MBeanAttributeInfo(attributeName, description,
|
||||
getter, setter);
|
||||
final String description = "Attribute exposed for management";
|
||||
try {
|
||||
return new MBeanAttributeInfo(attributeName, description,
|
||||
getter, setter);
|
||||
} catch (IntrospectionException e) {
|
||||
throw new RuntimeException(e); // should not happen
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
MBeanOperationInfo getMBeanOperationInfo(String operationName,
|
||||
Method operation) {
|
||||
final String defaultDescription = "Operation exposed for management";
|
||||
String description = Introspector.descriptionForElement(operation);
|
||||
if (description == null)
|
||||
description = defaultDescription;
|
||||
|
||||
int impact = MBeanOperationInfo.UNKNOWN;
|
||||
ManagedOperation annot = operation.getAnnotation(ManagedOperation.class);
|
||||
if (annot != null)
|
||||
impact = annot.impact().getCode();
|
||||
|
||||
MBeanOperationInfo mboi = new MBeanOperationInfo(description, operation);
|
||||
return new MBeanOperationInfo(
|
||||
mboi.getName(), mboi.getDescription(), mboi.getSignature(),
|
||||
mboi.getReturnType(), impact, mboi.getDescriptor());
|
||||
final String description = "Operation exposed for management";
|
||||
return new MBeanOperationInfo(description, operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -31,7 +31,6 @@ import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
|
||||
/**
|
||||
* Base class for Standard MBeans.
|
||||
@ -58,11 +57,11 @@ public class StandardMBeanSupport extends MBeanSupport<Method> {
|
||||
*/
|
||||
public <T> StandardMBeanSupport(T resource, Class<T> mbeanInterfaceType)
|
||||
throws NotCompliantMBeanException {
|
||||
super(resource, mbeanInterfaceType, (MXBeanMappingFactory) null);
|
||||
super(resource, mbeanInterfaceType);
|
||||
}
|
||||
|
||||
@Override
|
||||
MBeanIntrospector<Method> getMBeanIntrospector(MXBeanMappingFactory ignored) {
|
||||
MBeanIntrospector<Method> getMBeanIntrospector() {
|
||||
return StandardMBeanIntrospector.getInstance();
|
||||
}
|
||||
|
||||
@ -84,14 +83,13 @@ public class StandardMBeanSupport extends MBeanSupport<Method> {
|
||||
@Override
|
||||
public MBeanInfo getMBeanInfo() {
|
||||
MBeanInfo mbi = super.getMBeanInfo();
|
||||
Class<?> resourceClass = getWrappedObject().getClass();
|
||||
if (!getMBeanInterface().isInterface() ||
|
||||
StandardMBeanIntrospector.isDefinitelyImmutableInfo(resourceClass))
|
||||
Class<?> resourceClass = getResource().getClass();
|
||||
if (StandardMBeanIntrospector.isDefinitelyImmutableInfo(resourceClass))
|
||||
return mbi;
|
||||
return new MBeanInfo(mbi.getClassName(), mbi.getDescription(),
|
||||
mbi.getAttributes(), mbi.getConstructors(),
|
||||
mbi.getOperations(),
|
||||
MBeanIntrospector.findNotifications(getWrappedObject()),
|
||||
MBeanIntrospector.findNotifications(getResource()),
|
||||
mbi.getDescriptor());
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,8 +25,6 @@
|
||||
|
||||
package com.sun.jmx.mbeanserver;
|
||||
|
||||
import com.sun.jmx.defaults.JmxProperties;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@ -40,25 +38,18 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.logging.Level;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MBeanServerDelegate;
|
||||
import javax.management.MBeanServerFactory;
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.loading.ClassLoaderRepository;
|
||||
import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR;
|
||||
|
||||
public class Util {
|
||||
private final static int NAMESPACE_SEPARATOR_LENGTH =
|
||||
NAMESPACE_SEPARATOR.length();
|
||||
public final static char[] ILLEGAL_MBEANSERVER_NAME_CHARS=";:*?".
|
||||
toCharArray();
|
||||
|
||||
public static ObjectName newObjectName(String string) {
|
||||
try {
|
||||
return new ObjectName(string);
|
||||
} catch (MalformedObjectNameException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
static <K, V> Map<K, V> newMap() {
|
||||
return new HashMap<K, V>();
|
||||
@ -89,10 +80,6 @@ public class Util {
|
||||
return new LinkedHashMap<K, V>();
|
||||
}
|
||||
|
||||
static <K, V> WeakHashMap<K, V> newWeakHashMap() {
|
||||
return new WeakHashMap<K, V>();
|
||||
}
|
||||
|
||||
static <E> Set<E> newSet() {
|
||||
return new HashSet<E>();
|
||||
}
|
||||
@ -251,451 +238,4 @@ public class Util {
|
||||
public static boolean wildmatch(String str, String pat) {
|
||||
return wildmatch(str,pat,0,str.length(),0,pat.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a string against a pattern, as a name space path.
|
||||
* This is a special matching where * and ?? don't match //.
|
||||
* The string is split in sub-strings separated by //, and the
|
||||
* pattern is split in sub-patterns separated by //. Each sub-string
|
||||
* is matched against its corresponding sub-pattern.
|
||||
* so <elt-1>//<elt2>//...//<elt-n> matches <pat-1>//<pat-2>//...//<pat-q>
|
||||
* only if n==q and for ( i = 1 => n) elt-i matches pat-i.
|
||||
*
|
||||
* In addition, if we encounter a pattern element which is exactly
|
||||
* **, it can match any number of path-elements - but it must match at
|
||||
* least one element.
|
||||
* When we encounter such a meta-wildcard, we remember its position
|
||||
* and the position in the string path, and we advance both the pattern
|
||||
* and the string. Later, if we encounter a mismatch in pattern & string,
|
||||
* we rewind the position in pattern to just after the meta-wildcard,
|
||||
* and we backtrack the string to i+1 element after the position
|
||||
* we had when we first encountered the meta-wildcard, i being the
|
||||
* position when we last backtracked the string.
|
||||
*
|
||||
* The backtracking logic is an adaptation of the logic in wildmatch
|
||||
* above.
|
||||
* See test/javax/mangement/ObjectName/ApplyWildcardTest.java
|
||||
*
|
||||
* Note: this thing is called 'wild' - and that's for a reason ;-)
|
||||
**/
|
||||
public static boolean wildpathmatch(String str, String pat) {
|
||||
final int strlen = str.length();
|
||||
final int patlen = pat.length();
|
||||
int stri = 0;
|
||||
int pati = 0;
|
||||
|
||||
int starstri; // index for backtrack if "**" attempt fails
|
||||
int starpati; // index for backtrack if "**" attempt fails
|
||||
|
||||
starstri = starpati = -1;
|
||||
|
||||
while (true) {
|
||||
// System.out.println("pati="+pati+", stri="+stri);
|
||||
final int strend = str.indexOf(NAMESPACE_SEPARATOR, stri);
|
||||
final int patend = pat.indexOf(NAMESPACE_SEPARATOR, pati);
|
||||
|
||||
// no // remaining in either string or pattern: simple wildmatch
|
||||
// until end of string.
|
||||
if (strend == -1 && patend == -1) {
|
||||
// System.out.println("last sub pattern, last sub element...");
|
||||
// System.out.println("wildmatch("+str.substring(stri,strlen)+
|
||||
// ","+pat.substring(pati,patlen)+")");
|
||||
return wildmatch(str,pat,stri,strlen,pati,patlen);
|
||||
}
|
||||
|
||||
// no // remaining in string, but at least one remaining in
|
||||
// pattern
|
||||
// => no match
|
||||
if (strend == -1) {
|
||||
// System.out.println("pattern has more // than string...");
|
||||
return false;
|
||||
}
|
||||
|
||||
// strend is != -1, but patend might.
|
||||
// detect wildcard **
|
||||
if (patend == pati+2 && pat.charAt(pati)=='*' &&
|
||||
pat.charAt(pati+1)=='*') {
|
||||
// if we reach here we know that neither strend nor patend are
|
||||
// equals to -1.
|
||||
stri = strend + NAMESPACE_SEPARATOR_LENGTH;
|
||||
pati = patend + NAMESPACE_SEPARATOR_LENGTH;
|
||||
starpati = pati; // position just after **// in pattern
|
||||
starstri = stri; // we eat 1 element in string, and remember
|
||||
// the position for backtracking and eating
|
||||
// one more element if needed.
|
||||
// System.out.println("starpati="+pati);
|
||||
continue;
|
||||
}
|
||||
|
||||
// This is a bit hacky: * can match // when // is at the end
|
||||
// of the string, so we include the // delimiter in the pattern
|
||||
// matching. Either we're in the middle of the path, so including
|
||||
// // both at the end of the pattern and at the end of the string
|
||||
// has no effect - match(*//,dfsd//) is equivalent to match(*,dfsd)
|
||||
// or we're at the end of the pattern path, in which case
|
||||
// including // at the end of the string will have the desired
|
||||
// effect (provided that we detect the end of matching correctly,
|
||||
// see further on).
|
||||
//
|
||||
final int endpat =
|
||||
((patend > -1)?patend+NAMESPACE_SEPARATOR_LENGTH:patlen);
|
||||
final int endstr =
|
||||
((strend > -1)?strend+NAMESPACE_SEPARATOR_LENGTH:strlen);
|
||||
|
||||
// if we reach the end of the pattern, or if elt-i & pat-i
|
||||
// don't match, we have a mismatch.
|
||||
|
||||
// Note: we know that strend != -1, therefore patend==-1
|
||||
// indicates a mismatch unless pattern can match
|
||||
// a // at the end, and strend+2=strlen.
|
||||
// System.out.println("wildmatch("+str.substring(stri,endstr)+","+
|
||||
// pat.substring(pati,endpat)+")");
|
||||
if (!wildmatch(str,pat,stri,endstr,pati,endpat)) {
|
||||
|
||||
// System.out.println("nomatch");
|
||||
// if we have a mismatch and didn't encounter any meta-wildcard,
|
||||
// we return false. String & pattern don't match.
|
||||
if (starpati < 0) return false;
|
||||
|
||||
// If we reach here, we had a meta-wildcard.
|
||||
// We need to backtrack to the wildcard, and make it eat an
|
||||
// additional string element.
|
||||
//
|
||||
stri = str.indexOf(NAMESPACE_SEPARATOR, starstri);
|
||||
// System.out.println("eating one additional element? "+stri);
|
||||
|
||||
// If there's no more elements to eat, string and pattern
|
||||
// don't match => return false.
|
||||
if (stri == -1) return false;
|
||||
|
||||
// Backtrack to where we were when we last matched against
|
||||
// the meta-wildcard, make it eat an additional path element,
|
||||
// remember the new positions, and continue from there...
|
||||
//
|
||||
stri = stri + NAMESPACE_SEPARATOR_LENGTH;
|
||||
starstri = stri;
|
||||
pati = starpati;
|
||||
// System.out.println("skiping to stri="+stri);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Here we know that strend > -1 but we can have patend == -1.
|
||||
//
|
||||
// So if we reach here, we know pat-i+//? has matched
|
||||
// elt-i+//
|
||||
//
|
||||
// If patend==-1, we know that there was no delimiter
|
||||
// at the end of the pattern, that we are at the last pattern,
|
||||
// and therefore that pat-i has matched elt-i+//
|
||||
//
|
||||
// In that case we can consider that we have a match only if
|
||||
// elt-i is also the last path element in the string, which is
|
||||
// equivalent to saying that strend+2==strlen.
|
||||
//
|
||||
if (patend == -1 && starpati == -1)
|
||||
return (strend+NAMESPACE_SEPARATOR_LENGTH==strlen);
|
||||
|
||||
// patend != -1, or starpati > -1 so there remains something
|
||||
// to match.
|
||||
|
||||
// go to next pair: elt-(i+1) pat-(i+1);
|
||||
stri = strend + NAMESPACE_SEPARATOR_LENGTH;
|
||||
pati = (patend==-1)?pati:(patend + NAMESPACE_SEPARATOR_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the ObjectName's {@code domain} is selected by the
|
||||
* given {@code pattern}.
|
||||
*/
|
||||
public static boolean isDomainSelected(String domain, String pattern) {
|
||||
if (domain == null || pattern == null)
|
||||
throw new IllegalArgumentException("null");
|
||||
return Util.wildpathmatch(domain,pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters a set of ObjectName according to a given pattern.
|
||||
*
|
||||
* @param pattern the pattern that the returned names must match.
|
||||
* @param all the set of names to filter.
|
||||
* @return a set of ObjectName from which non matching names
|
||||
* have been removed.
|
||||
*/
|
||||
public static Set<ObjectName> filterMatchingNames(ObjectName pattern,
|
||||
Set<ObjectName> all) {
|
||||
// If no pattern, just return all names
|
||||
if (pattern == null
|
||||
|| all.isEmpty()
|
||||
|| ObjectName.WILDCARD.equals(pattern))
|
||||
return all;
|
||||
|
||||
// If there's a pattern, do the matching.
|
||||
final Set<ObjectName> res = equivalentEmptySet(all);
|
||||
for (ObjectName n : all) if (pattern.apply(n)) res.add(n);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Filters a set of ObjectInstance according to a given pattern.
|
||||
*
|
||||
* @param pattern the pattern that the returned names must match.
|
||||
* @param all the set of instances to filter.
|
||||
* @return a set of ObjectInstance from which non matching instances
|
||||
* have been removed.
|
||||
*/
|
||||
public static Set<ObjectInstance>
|
||||
filterMatchingInstances(ObjectName pattern,
|
||||
Set<ObjectInstance> all) {
|
||||
// If no pattern, just return all names
|
||||
if (pattern == null
|
||||
|| all.isEmpty()
|
||||
|| ObjectName.WILDCARD.equals(pattern))
|
||||
return all;
|
||||
|
||||
// If there's a pattern, do the matching.
|
||||
final Set<ObjectInstance> res = equivalentEmptySet(all);
|
||||
for (ObjectInstance n : all) {
|
||||
if (n == null) continue;
|
||||
if (pattern.apply(n.getObjectName()))
|
||||
res.add(n);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* An abstract ClassLoaderRepository that contains a single class loader.
|
||||
**/
|
||||
private final static class SingleClassLoaderRepository
|
||||
implements ClassLoaderRepository {
|
||||
private final ClassLoader singleLoader;
|
||||
|
||||
SingleClassLoaderRepository(ClassLoader loader) {
|
||||
this.singleLoader = loader;
|
||||
}
|
||||
|
||||
ClassLoader getSingleClassLoader() {
|
||||
return singleLoader;
|
||||
}
|
||||
|
||||
private Class<?> loadClass(String className, ClassLoader loader)
|
||||
throws ClassNotFoundException {
|
||||
return Class.forName(className, false, loader);
|
||||
}
|
||||
|
||||
public Class<?> loadClass(String className)
|
||||
throws ClassNotFoundException {
|
||||
return loadClass(className, getSingleClassLoader());
|
||||
}
|
||||
|
||||
public Class<?> loadClassWithout(ClassLoader exclude,
|
||||
String className) throws ClassNotFoundException {
|
||||
final ClassLoader loader = getSingleClassLoader();
|
||||
if (exclude != null && exclude.equals(loader))
|
||||
throw new ClassNotFoundException(className);
|
||||
return loadClass(className, loader);
|
||||
}
|
||||
|
||||
public Class<?> loadClassBefore(ClassLoader stop, String className)
|
||||
throws ClassNotFoundException {
|
||||
return loadClassWithout(stop, className);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a ClassLoaderRepository that contains a single class loader.
|
||||
* @param loader the class loader contained in the returned repository.
|
||||
* @return a ClassLoaderRepository that contains the single loader.
|
||||
*/
|
||||
public static ClassLoaderRepository getSingleClassLoaderRepository(
|
||||
final ClassLoader loader) {
|
||||
return new SingleClassLoaderRepository(loader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the given MBeanServer that should be put in a
|
||||
* permission you need.
|
||||
* This corresponds to the
|
||||
* {@code *[;mbeanServerName=<mbeanServerName>[;*]]} property
|
||||
* embedded in the MBeanServerId attribute of the
|
||||
* server's {@link MBeanServerDelegate}.
|
||||
*
|
||||
* @param server The MBean server
|
||||
* @return the name of the MBeanServer, or "*" if the name couldn't be
|
||||
* obtained, or {@value MBeanServerFactory#DEFAULT_MBEANSERVER_NAME}
|
||||
* if there was no name.
|
||||
*/
|
||||
public static String getMBeanServerSecurityName(MBeanServer server) {
|
||||
final String notfound = "*";
|
||||
try {
|
||||
final String mbeanServerId = (String)
|
||||
server.getAttribute(MBeanServerDelegate.DELEGATE_NAME,
|
||||
"MBeanServerId");
|
||||
final String found = extractMBeanServerName(mbeanServerId);
|
||||
if (found.length()==0)
|
||||
return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME;
|
||||
return found;
|
||||
} catch (Exception x) {
|
||||
logshort("Failed to retrieve MBeanServerName for server, " +
|
||||
"using \"*\"",x);
|
||||
return notfound;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the MBeanServer embedded in the given
|
||||
* mbeanServerId. If the given mbeanServerId doesn't contain any name,
|
||||
* an empty String is returned.
|
||||
* The MBeanServerId is expected to be of the form:
|
||||
* {@code *[;mbeanServerName=<mbeanServerName>[;*]]}
|
||||
* @param mbeanServerId The MBean server ID
|
||||
* @return the name of the MBeanServer if found, or "" if the name was
|
||||
* not present in the mbeanServerId.
|
||||
*/
|
||||
public static String extractMBeanServerName(String mbeanServerId) {
|
||||
if (mbeanServerId==null) return "";
|
||||
final String beginMarker=";mbeanServerName=";
|
||||
final String endMarker=";";
|
||||
final int found = mbeanServerId.indexOf(beginMarker);
|
||||
if (found < 0) return "";
|
||||
final int start = found + beginMarker.length();
|
||||
final int stop = mbeanServerId.indexOf(endMarker, start);
|
||||
return mbeanServerId.substring(start,
|
||||
(stop < 0 ? mbeanServerId.length() : stop));
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the given mbeanServerName into the given mbeanServerId.
|
||||
* If mbeanServerName is null, empty, or equals to "-", the returned
|
||||
* mbeanServerId will not contain any mbeanServerName.
|
||||
* @param mbeanServerId The mbeanServerId in which to insert
|
||||
* mbeanServerName
|
||||
* @param mbeanServerName The mbeanServerName
|
||||
* @return an mbeanServerId containing the given mbeanServerName
|
||||
* @throws IllegalArgumentException if mbeanServerId already contains
|
||||
* a different name, or if the given mbeanServerName is not valid.
|
||||
*/
|
||||
public static String insertMBeanServerName(String mbeanServerId,
|
||||
String mbeanServerName) {
|
||||
final String found = extractMBeanServerName(mbeanServerId);
|
||||
if (found.length() > 0 &&
|
||||
found.equals(checkServerName(mbeanServerName)))
|
||||
return mbeanServerId;
|
||||
if (found.length() > 0 && !isMBeanServerNameUndefined(found))
|
||||
throw new IllegalArgumentException(
|
||||
"MBeanServerName already defined");
|
||||
if (isMBeanServerNameUndefined(mbeanServerName))
|
||||
return mbeanServerId;
|
||||
final String beginMarker=";mbeanServerName=";
|
||||
return mbeanServerId+beginMarker+checkServerName(mbeanServerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given mbeanServerName corresponds to an
|
||||
* undefined MBeanServerName.
|
||||
* The mbeanServerName is considered undefined if it is one of:
|
||||
* {@code null} or {@value MBeanServerFactory#DEFAULT_MBEANSERVER_NAME}.
|
||||
* @param mbeanServerName The mbeanServerName, as returned by
|
||||
* {@link #extractMBeanServerName(String)}.
|
||||
* @return true if the given name corresponds to one of the forms that
|
||||
* denotes an undefined MBeanServerName.
|
||||
*/
|
||||
public static boolean isMBeanServerNameUndefined(String mbeanServerName) {
|
||||
return mbeanServerName == null ||
|
||||
MBeanServerFactory.DEFAULT_MBEANSERVER_NAME.equals(mbeanServerName);
|
||||
}
|
||||
/**
|
||||
* Check that the provided mbeanServername is syntactically valid.
|
||||
* @param mbeanServerName An mbeanServerName, or {@code null}.
|
||||
* @return mbeanServerName, or {@value
|
||||
* MBeanServerFactory#DEFAULT_MBEANSERVER_NAME} if {@code mbeanServerName}
|
||||
* is {@code null}.
|
||||
* @throws IllegalArgumentException if mbeanServerName contains illegal
|
||||
* characters, or is empty, or is {@code "-"}.
|
||||
* Illegal characters are {@link #ILLEGAL_MBEANSERVER_NAME_CHARS}.
|
||||
*/
|
||||
public static String checkServerName(String mbeanServerName) {
|
||||
if ("".equals(mbeanServerName))
|
||||
throw new IllegalArgumentException(
|
||||
"\"\" is not a valid MBean server name");
|
||||
if ("-".equals(mbeanServerName))
|
||||
throw new IllegalArgumentException(
|
||||
"\"-\" is not a valid MBean server name");
|
||||
if (isMBeanServerNameUndefined(mbeanServerName))
|
||||
return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME;
|
||||
for (char c : ILLEGAL_MBEANSERVER_NAME_CHARS) {
|
||||
if (mbeanServerName.indexOf(c) >= 0)
|
||||
throw new IllegalArgumentException(
|
||||
"invalid character in MBeanServer name: "+c);
|
||||
}
|
||||
return mbeanServerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the MBeanServer name that should be put in a permission you need.
|
||||
*
|
||||
* @param delegate The MBeanServerDelegate
|
||||
* @return The MBeanServer name - or {@value
|
||||
* MBeanServerFactory#DEFAULT_MBEANSERVER_NAME} if there was no name.
|
||||
*/
|
||||
public static String getMBeanServerSecurityName(
|
||||
MBeanServerDelegate delegate) {
|
||||
try {
|
||||
final String serverName = delegate.getMBeanServerName();
|
||||
if (isMBeanServerNameUndefined(serverName))
|
||||
return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME;
|
||||
return serverName;
|
||||
} catch (Exception x) {
|
||||
logshort("Failed to retrieve MBeanServerName from delegate, " +
|
||||
"using \"*\"",x);
|
||||
return "*";
|
||||
}
|
||||
}
|
||||
|
||||
// Log the exception and its causes without logging the 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
|
||||
// called in those cases where the exception might not be abnormal.
|
||||
private static void logshort(String msg, Throwable t) {
|
||||
if (JmxProperties.MISC_LOGGER.isLoggable(Level.FINE)) {
|
||||
StringBuilder toprint = new StringBuilder(msg);
|
||||
do {
|
||||
toprint.append("\nCaused By: ").append(String.valueOf(t));
|
||||
} while ((t=t.getCause())!=null);
|
||||
JmxProperties.MISC_LOGGER.fine(toprint.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> Set<T> cloneSet(Set<T> set) {
|
||||
if (set instanceof SortedSet<?>) {
|
||||
@SuppressWarnings("unchecked")
|
||||
SortedSet<T> sset = (SortedSet<T>) set;
|
||||
set = new TreeSet<T>(sset.comparator());
|
||||
set.addAll(sset);
|
||||
} else
|
||||
set = new HashSet<T>(set);
|
||||
return set;
|
||||
}
|
||||
|
||||
public static <T> Set<T> equivalentEmptySet(Set<T> set) {
|
||||
if (set instanceof SortedSet<?>) {
|
||||
@SuppressWarnings("unchecked")
|
||||
SortedSet<T> sset = (SortedSet<T>) set;
|
||||
set = new TreeSet<T>(sset.comparator());
|
||||
} else
|
||||
set = new HashSet<T>();
|
||||
return set;
|
||||
}
|
||||
|
||||
// This exception is used when wrapping a class that throws IOException
|
||||
// in a class that doesn't.
|
||||
// The typical example for this are JMXNamespaces, when the sub
|
||||
// MBeanServer can be remote.
|
||||
//
|
||||
public static RuntimeException newRuntimeIOException(IOException io) {
|
||||
final String msg = "Communication failed with underlying resource: "+
|
||||
io.getMessage();
|
||||
return new RuntimeException(msg,io);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,463 +0,0 @@
|
||||
/*
|
||||
* 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 com.sun.jmx.namespace;
|
||||
|
||||
import com.sun.jmx.defaults.JmxProperties;
|
||||
import com.sun.jmx.mbeanserver.Util;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.ListenerNotFoundException;
|
||||
import javax.management.MBeanPermission;
|
||||
import javax.management.MBeanServerDelegate;
|
||||
import javax.management.MBeanServerNotification;
|
||||
import javax.management.Notification;
|
||||
import javax.management.NotificationFilter;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.QueryExp;
|
||||
import javax.management.namespace.JMXDomain;
|
||||
|
||||
/**
|
||||
* A DomainInterceptor wraps a JMXDomain.
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
public class DomainInterceptor extends HandlerInterceptor<JMXDomain> {
|
||||
|
||||
// TODO: Ideally DomainInterceptor should be replaced by
|
||||
// something at Repository level.
|
||||
// The problem there will be that we may need to
|
||||
// reinstantiate the 'queryPerformedByRepos' boolean
|
||||
// [or we will need to wrap the repository in
|
||||
// a 'RepositoryInterceptor'?]
|
||||
// Also there's no real need for a DomainInterceptor to
|
||||
// extend RewritingMBeanServerConnection.
|
||||
|
||||
|
||||
/**
|
||||
* A logger for this class.
|
||||
**/
|
||||
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
|
||||
|
||||
private final String domainName;
|
||||
private volatile ObjectName ALL;
|
||||
private final String serverName;
|
||||
private volatile NotificationListener mbsListener;
|
||||
|
||||
private static class PatternNotificationFilter
|
||||
implements NotificationFilter {
|
||||
|
||||
final ObjectName pattern;
|
||||
public PatternNotificationFilter(ObjectName pattern) {
|
||||
this.pattern = pattern==null?ObjectName.WILDCARD:pattern;
|
||||
}
|
||||
|
||||
public boolean isNotificationEnabled(Notification notification) {
|
||||
if (!(notification instanceof MBeanServerNotification))
|
||||
return false;
|
||||
final MBeanServerNotification mbsn =
|
||||
(MBeanServerNotification) notification;
|
||||
if (pattern.apply(mbsn.getMBeanName()))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static final long serialVersionUID = 7409950927025262111L;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of NamespaceInterceptor
|
||||
*/
|
||||
public DomainInterceptor(String serverName,
|
||||
JMXDomain handler,
|
||||
String domainName) {
|
||||
super(handler);
|
||||
this.domainName = domainName;
|
||||
this.serverName = serverName;
|
||||
ALL = ObjectName.valueOf(domainName+":*");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getClass().getName()+"(parent="+serverName+
|
||||
", domain="+this.domainName+")";
|
||||
}
|
||||
|
||||
final void connectDelegate(final MBeanServerDelegate delegate)
|
||||
throws InstanceNotFoundException {
|
||||
final NotificationFilter filter =
|
||||
new PatternNotificationFilter(getPatternFor(null));
|
||||
synchronized (this) {
|
||||
if (mbsListener == null) {
|
||||
mbsListener = new NotificationListener() {
|
||||
public void handleNotification(Notification notification,
|
||||
Object handback) {
|
||||
if (filter.isNotificationEnabled(notification))
|
||||
delegate.sendNotification(notification);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
getHandlerInterceptorMBean().
|
||||
addMBeanServerNotificationListener(mbsListener, filter);
|
||||
}
|
||||
|
||||
final void disconnectDelegate()
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
final NotificationListener l;
|
||||
synchronized (this) {
|
||||
l = mbsListener;
|
||||
if (l == null) return;
|
||||
mbsListener = null;
|
||||
}
|
||||
getHandlerInterceptorMBean().removeMBeanServerNotificationListener(l);
|
||||
}
|
||||
|
||||
public final void addPostRegisterTask(Queue<Runnable> queue,
|
||||
final MBeanServerDelegate delegate) {
|
||||
if (queue == null)
|
||||
throw new IllegalArgumentException("task queue must not be null");
|
||||
final Runnable task1 = new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
connectDelegate(delegate);
|
||||
} catch (Exception x) {
|
||||
throw new UnsupportedOperationException(
|
||||
"notification forwarding",x);
|
||||
}
|
||||
}
|
||||
};
|
||||
queue.add(task1);
|
||||
}
|
||||
|
||||
public final void addPostDeregisterTask(Queue<Runnable> queue,
|
||||
final MBeanServerDelegate delegate) {
|
||||
if (queue == null)
|
||||
throw new IllegalArgumentException("task queue must not be null");
|
||||
final Runnable task1 = new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
disconnectDelegate();
|
||||
} catch (Exception x) {
|
||||
throw new UnsupportedOperationException(
|
||||
"notification forwarding",x);
|
||||
}
|
||||
}
|
||||
};
|
||||
queue.add(task1);
|
||||
}
|
||||
|
||||
// No name conversion for JMXDomains...
|
||||
// Throws IllegalArgumentException if targetName.getDomain() is not
|
||||
// in the domain handled.
|
||||
//
|
||||
@Override
|
||||
protected ObjectName toSource(ObjectName targetName) {
|
||||
if (targetName == null) return null;
|
||||
if (targetName.isDomainPattern()) return targetName;
|
||||
final String targetDomain = targetName.getDomain();
|
||||
|
||||
// TODO: revisit this. RuntimeOperationsException may be better?
|
||||
//
|
||||
if (!targetDomain.equals(domainName))
|
||||
throw new IllegalArgumentException(targetName.toString());
|
||||
return targetName;
|
||||
}
|
||||
|
||||
// No name conversion for JMXDomains...
|
||||
@Override
|
||||
protected ObjectName toTarget(ObjectName sourceName) {
|
||||
return sourceName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* No rewriting: always return sources - stripping instances for which
|
||||
* the caller doesn't have permissions.
|
||||
**/
|
||||
@Override
|
||||
Set<ObjectInstance> processOutputInstances(Set<ObjectInstance> sources) {
|
||||
if (sources == null || sources.isEmpty() || !checkOn())
|
||||
return sources;
|
||||
final Set<ObjectInstance> res = Util.equivalentEmptySet(sources);
|
||||
for (ObjectInstance o : sources) {
|
||||
if (checkQuery(o.getObjectName(), "queryMBeans"))
|
||||
res.add(o);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* No rewriting: always return sourceNames - stripping names for which
|
||||
* the caller doesn't have permissions.
|
||||
**/
|
||||
@Override
|
||||
Set<ObjectName> processOutputNames(Set<ObjectName> sourceNames) {
|
||||
if (sourceNames == null || sourceNames.isEmpty() || !checkOn())
|
||||
return sourceNames;
|
||||
final Set<ObjectName> res = Util.equivalentEmptySet(sourceNames);
|
||||
for (ObjectName o : sourceNames) {
|
||||
if (checkQuery(o, "queryNames"))
|
||||
res.add(o);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/** No rewriting: always return source **/
|
||||
@Override
|
||||
ObjectInstance processOutputInstance(ObjectInstance source) {
|
||||
return source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
|
||||
try {
|
||||
// We don't trust the wrapped JMXDomain...
|
||||
final ObjectName pattern = getPatternFor(name);
|
||||
final Set<ObjectName> res = super.queryNames(pattern,query);
|
||||
return Util.filterMatchingNames(pattern,res);
|
||||
} catch (Exception x) {
|
||||
if (LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("Unexpected exception raised in queryNames: "+x);
|
||||
LOG.log(Level.FINEST,"Unexpected exception raised in queryNames",x);
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if (name == null) return ALL;
|
||||
if (name.getDomain().equals(domainName)) return name;
|
||||
return name.withDomain(domainName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
|
||||
try {
|
||||
// We don't trust the wrapped JMXDomain...
|
||||
final ObjectName pattern = getPatternFor(name);
|
||||
final Set<ObjectInstance> res = super.queryMBeans(pattern,query);
|
||||
return Util.filterMatchingInstances(pattern,res);
|
||||
} catch (Exception x) {
|
||||
if (LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("Unexpected exception raised in queryNames: "+x);
|
||||
LOG.log(Level.FINEST,"Unexpected exception raised in queryNames",x);
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultDomain() {
|
||||
return domainName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getDomains() {
|
||||
return new String[] {domainName};
|
||||
}
|
||||
|
||||
// We call getMBeanCount() on the namespace rather than on the
|
||||
// source server in order to avoid counting MBeans which are not
|
||||
// in the domain.
|
||||
@Override
|
||||
public Integer getMBeanCount() {
|
||||
return getHandlerInterceptorMBean().getMBeanCount();
|
||||
}
|
||||
|
||||
private boolean checkOn() {
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
return (sm != null);
|
||||
}
|
||||
|
||||
//
|
||||
// Implements permission checks.
|
||||
//
|
||||
@Override
|
||||
void check(ObjectName routingName, String member, String action) {
|
||||
if (!checkOn()) return;
|
||||
final String act = (action==null)?"-":action;
|
||||
if("queryMBeans".equals(act) || "queryNames".equals(act)) {
|
||||
// This is tricky. check with 3 parameters is called
|
||||
// by queryNames/queryMBeans before performing the query.
|
||||
// At this point we must check with no class name.
|
||||
// Therefore we pass a className of "-".
|
||||
// The filtering will be done later - processOutputNames and
|
||||
// processOutputInstance will call checkQuery.
|
||||
//
|
||||
check(routingName, "-", "-", act);
|
||||
} else {
|
||||
// This is also tricky:
|
||||
// passing null here will cause check to retrieve the classname,
|
||||
// if needed.
|
||||
check(routingName, null, member, act);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Implements permission checks.
|
||||
//
|
||||
@Override
|
||||
void checkCreate(ObjectName routingName, String className, String action) {
|
||||
if (!checkOn()) return;
|
||||
check(routingName,className,"-",action);
|
||||
}
|
||||
|
||||
//
|
||||
// Implements permission checks.
|
||||
//
|
||||
void check(ObjectName routingName, String className, String member,
|
||||
String action) {
|
||||
if (!checkOn()) return;
|
||||
final MBeanPermission perm;
|
||||
|
||||
final String act = (action==null)?"-":action;
|
||||
if ("getDomains".equals(act)) { // ES: OK
|
||||
perm = new MBeanPermission(serverName,"-",member,
|
||||
routingName,act);
|
||||
} else {
|
||||
final String clazz =
|
||||
(className==null)?getClassName(routingName):className;
|
||||
perm = new MBeanPermission(serverName,clazz,member,
|
||||
routingName,act);
|
||||
}
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null)
|
||||
sm.checkPermission(perm);
|
||||
}
|
||||
|
||||
String getClassName(ObjectName routingName) {
|
||||
if (routingName == null || routingName.isPattern()) return "-";
|
||||
try {
|
||||
return getHandlerInterceptorMBean().getSourceServer().
|
||||
getObjectInstance(routingName).getClassName();
|
||||
} catch (InstanceNotFoundException ex) {
|
||||
LOG.finest("Can't get class name for "+routingName+
|
||||
", using \"-\". Cause is: "+ex);
|
||||
return "-";
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Implements permission filters for attributes...
|
||||
//
|
||||
@Override
|
||||
AttributeList checkAttributes(ObjectName routingName,
|
||||
AttributeList attributes, String action) {
|
||||
if (!checkOn()) return attributes;
|
||||
final String className = getClassName(routingName);
|
||||
check(routingName,className,"-",action);
|
||||
if (attributes == null || attributes.isEmpty()) return attributes;
|
||||
final AttributeList res = new AttributeList();
|
||||
for (Attribute at : attributes.asList()) {
|
||||
try {
|
||||
check(routingName,className,at.getName(),action);
|
||||
res.add(at);
|
||||
} catch (SecurityException x) { // DLS: OK
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//
|
||||
// Implements permission filters for attributes...
|
||||
//
|
||||
@Override
|
||||
String[] checkAttributes(ObjectName routingName, String[] attributes,
|
||||
String action) {
|
||||
if (!checkOn()) return attributes;
|
||||
final String className = getClassName(routingName);
|
||||
check(routingName,className,"-",action);
|
||||
if (attributes == null || attributes.length==0) return attributes;
|
||||
final List<String> res = new ArrayList<String>(attributes.length);
|
||||
for (String at : attributes) {
|
||||
try {
|
||||
check(routingName,className,at,action);
|
||||
res.add(at);
|
||||
} catch (SecurityException x) { // DLS: OK
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return res.toArray(new String[res.size()]);
|
||||
}
|
||||
|
||||
//
|
||||
// Implements permission filters for domains...
|
||||
//
|
||||
@Override
|
||||
String[] checkDomains(String[] domains, String action) {
|
||||
if (domains == null || domains.length==0 || !checkOn())
|
||||
return domains;
|
||||
int count=0;
|
||||
for (int i=0;i<domains.length;i++) {
|
||||
try {
|
||||
check(ObjectName.valueOf(domains[i]+":x=x"),"-",
|
||||
"-","getDomains");
|
||||
} catch (SecurityException x) { // DLS: OK
|
||||
count++;
|
||||
domains[i]=null;
|
||||
}
|
||||
}
|
||||
if (count == 0) return domains;
|
||||
final String[] res = new String[domains.length-count];
|
||||
count = 0;
|
||||
for (int i=0;i<domains.length;i++)
|
||||
if (domains[i]!=null) res[count++]=domains[i];
|
||||
return res;
|
||||
}
|
||||
|
||||
//
|
||||
// Implements permission filters for queries...
|
||||
//
|
||||
@Override
|
||||
boolean checkQuery(ObjectName routingName, String action) {
|
||||
try {
|
||||
final String className = getClassName(routingName);
|
||||
check(routingName,className,"-",action);
|
||||
return true;
|
||||
} catch (SecurityException x) { // DLS: OK
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,734 +0,0 @@
|
||||
/*
|
||||
* 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 com.sun.jmx.namespace;
|
||||
|
||||
|
||||
import com.sun.jmx.defaults.JmxProperties;
|
||||
import com.sun.jmx.interceptor.MBeanServerInterceptor;
|
||||
|
||||
import com.sun.jmx.mbeanserver.Util;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.IntrospectionException;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.ListenerNotFoundException;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanRegistrationException;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.NotificationFilter;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.OperationsException;
|
||||
import javax.management.QueryExp;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.RuntimeOperationsException;
|
||||
import javax.management.loading.ClassLoaderRepository;
|
||||
import javax.management.namespace.JMXNamespace;
|
||||
|
||||
/**
|
||||
* This interceptor wraps a JMXNamespace, and performs
|
||||
* {@code ObjectName} rewriting. {@code HandlerInterceptor} are
|
||||
* created and managed by a {@link NamespaceDispatchInterceptor} or a
|
||||
* {@link DomainDispatchInterceptor}.
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
public abstract class HandlerInterceptor<T extends JMXNamespace>
|
||||
extends RoutingMBeanServerConnection<MBeanServer>
|
||||
implements MBeanServerInterceptor {
|
||||
|
||||
/**
|
||||
* A logger for this class.
|
||||
**/
|
||||
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
|
||||
|
||||
// The wrapped JMXNamespace
|
||||
private final T handler;
|
||||
|
||||
/**
|
||||
* Creates a new instance of HandlerInterceptor
|
||||
*/
|
||||
public HandlerInterceptor(T handler) {
|
||||
if (handler == null) throw new IllegalArgumentException("null");
|
||||
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
|
||||
protected MBeanServer source() {
|
||||
return handler.getSourceServer();
|
||||
}
|
||||
|
||||
// The MBeanServer on which getClassLoader / getClassLoaderFor
|
||||
// will be called.
|
||||
// The NamespaceInterceptor overrides this method - so that it
|
||||
// getClassLoader / getClassLoaderFor don't trigger the loop
|
||||
// detection mechanism.
|
||||
//
|
||||
MBeanServer getServerForLoading() {
|
||||
return source();
|
||||
}
|
||||
|
||||
// The namespace or domain handler - this either a JMXNamespace or a
|
||||
// a JMXDomain
|
||||
T getHandlerInterceptorMBean() {
|
||||
return handler;
|
||||
}
|
||||
|
||||
// If the underlying JMXNamespace throws an IO, the IO will be
|
||||
// wrapped in a RuntimeOperationsException.
|
||||
RuntimeException handleIOException(IOException x,String fromMethodName,
|
||||
Object... params) {
|
||||
// Must do something here?
|
||||
if (LOG.isLoggable(Level.FINEST)) {
|
||||
LOG.finest("IO Exception in "+fromMethodName+": "+x+
|
||||
" - "+" rethrowing as RuntimeOperationsException.");
|
||||
}
|
||||
throw new RuntimeOperationsException(
|
||||
Util.newRuntimeIOException(x));
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public AttributeList getAttributes(ObjectName name, String[] attributes)
|
||||
throws InstanceNotFoundException, ReflectionException {
|
||||
try {
|
||||
final String[] authorized =
|
||||
checkAttributes(name,attributes,"getAttribute");
|
||||
final AttributeList attrList =
|
||||
super.getAttributes(name,authorized);
|
||||
return attrList;
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"getAttributes",name,attributes);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public ClassLoader getClassLoaderFor(ObjectName mbeanName)
|
||||
throws InstanceNotFoundException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(mbeanName);
|
||||
try {
|
||||
check(mbeanName,null,"getClassLoaderFor");
|
||||
return getServerForLoading().getClassLoaderFor(sourceName);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// From MBeanServer
|
||||
public ClassLoader getClassLoader(ObjectName loaderName)
|
||||
throws InstanceNotFoundException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(loaderName);
|
||||
try {
|
||||
check(loaderName,null,"getClassLoader");
|
||||
return getServerForLoading().getClassLoader(sourceName);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServer
|
||||
public ObjectInstance registerMBean(Object object, ObjectName name)
|
||||
throws InstanceAlreadyExistsException, MBeanRegistrationException,
|
||||
NotCompliantMBeanException {
|
||||
final ObjectName sourceName = newSourceMBeanName(name);
|
||||
try {
|
||||
checkCreate(name,object.getClass().getName(),"registerMBean");
|
||||
return processOutputInstance(
|
||||
source().registerMBean(object,sourceName));
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public void removeNotificationListener(ObjectName name, ObjectName listener)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
try {
|
||||
check(name,null,"removeNotificationListener");
|
||||
super.removeNotificationListener(name,listener);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"removeNotificationListener",name,listener);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public String getDefaultDomain() {
|
||||
try {
|
||||
return super.getDefaultDomain();
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"getDefaultDomain");
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public String[] getDomains() {
|
||||
try {
|
||||
check(null,null,"getDomains");
|
||||
final String[] domains = super.getDomains();
|
||||
return checkDomains(domains,"getDomains");
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"getDomains");
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public Integer getMBeanCount() {
|
||||
try {
|
||||
return super.getMBeanCount();
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"getMBeanCount");
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public void setAttribute(ObjectName name, Attribute attribute)
|
||||
throws InstanceNotFoundException, AttributeNotFoundException,
|
||||
InvalidAttributeValueException, MBeanException,
|
||||
ReflectionException {
|
||||
try {
|
||||
check(name,
|
||||
(attribute==null?null:attribute.getName()),
|
||||
"setAttribute");
|
||||
super.setAttribute(name,attribute);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"setAttribute",name, attribute);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
|
||||
if (name == null) name=ObjectName.WILDCARD;
|
||||
try {
|
||||
checkPattern(name,null,"queryNames");
|
||||
return super.queryNames(name,query);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"queryNames",name, query);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
|
||||
if (name == null) name=ObjectName.WILDCARD;
|
||||
try {
|
||||
checkPattern(name,null,"queryMBeans");
|
||||
return super.queryMBeans(name,query);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"queryMBeans",name, query);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public boolean isInstanceOf(ObjectName name, String className)
|
||||
throws InstanceNotFoundException {
|
||||
try {
|
||||
check(name, null, "isInstanceOf");
|
||||
return super.isInstanceOf(name, className);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"isInstanceOf",name, className);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public ObjectInstance createMBean(String className, ObjectName name)
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException {
|
||||
try {
|
||||
checkCreate(name, className, "instantiate");
|
||||
checkCreate(name, className, "registerMBean");
|
||||
return super.createMBean(className, name);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"createMBean",className, name);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public ObjectInstance createMBean(String className, ObjectName name,
|
||||
ObjectName loaderName)
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException, InstanceNotFoundException {
|
||||
try {
|
||||
checkCreate(name, className, "instantiate");
|
||||
checkCreate(name, className, "registerMBean");
|
||||
return super.createMBean(className, name, loaderName);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"createMBean",className, name, loaderName);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public Object getAttribute(ObjectName name, String attribute)
|
||||
throws MBeanException, AttributeNotFoundException,
|
||||
InstanceNotFoundException, ReflectionException {
|
||||
try {
|
||||
check(name, attribute, "getAttribute");
|
||||
return super.getAttribute(name, attribute);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"getAttribute",name, attribute);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public void removeNotificationListener(ObjectName name, ObjectName listener,
|
||||
NotificationFilter filter, Object handback)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
try {
|
||||
check(name,null,"removeNotificationListener");
|
||||
super.removeNotificationListener(name, listener, filter, handback);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"removeNotificationListener",name,
|
||||
listener, filter, handback);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public void removeNotificationListener(ObjectName name,
|
||||
NotificationListener listener, NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
try {
|
||||
check(name,null,"removeNotificationListener");
|
||||
super.removeNotificationListener(name, listener, filter, handback);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"removeNotificationListener",name,
|
||||
listener, filter, handback);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public void removeNotificationListener(ObjectName name,
|
||||
NotificationListener listener)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
try {
|
||||
check(name,null,"removeNotificationListener");
|
||||
super.removeNotificationListener(name, listener);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"removeNotificationListener",name,
|
||||
listener);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public void addNotificationListener(ObjectName name,
|
||||
NotificationListener listener, NotificationFilter filter,
|
||||
Object handback) throws InstanceNotFoundException {
|
||||
try {
|
||||
check(name,null,"addNotificationListener");
|
||||
super.addNotificationListener(name, listener, filter, handback);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"addNotificationListener",name,
|
||||
listener, filter, handback);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public void addNotificationListener(ObjectName name, ObjectName listener,
|
||||
NotificationFilter filter, Object handback)
|
||||
throws InstanceNotFoundException {
|
||||
try {
|
||||
check(name,null,"addNotificationListener");
|
||||
super.addNotificationListener(name, listener, filter, handback);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"addNotificationListener",name,
|
||||
listener, filter, handback);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public boolean isRegistered(ObjectName name) {
|
||||
try {
|
||||
return super.isRegistered(name);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"isRegistered",name);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public void unregisterMBean(ObjectName name)
|
||||
throws InstanceNotFoundException, MBeanRegistrationException {
|
||||
try {
|
||||
check(name, null, "unregisterMBean");
|
||||
super.unregisterMBean(name);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"unregisterMBean",name);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public MBeanInfo getMBeanInfo(ObjectName name)
|
||||
throws InstanceNotFoundException, IntrospectionException,
|
||||
ReflectionException {
|
||||
try {
|
||||
check(name, null, "getMBeanInfo");
|
||||
return super.getMBeanInfo(name);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"getMBeanInfo",name);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public ObjectInstance getObjectInstance(ObjectName name)
|
||||
throws InstanceNotFoundException {
|
||||
try {
|
||||
check(name, null, "getObjectInstance");
|
||||
return super.getObjectInstance(name);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"getObjectInstance",name);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public ObjectInstance createMBean(String className, ObjectName name,
|
||||
Object[] params, String[] signature)
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException {
|
||||
try {
|
||||
checkCreate(name, className, "instantiate");
|
||||
checkCreate(name, className, "registerMBean");
|
||||
return super.createMBean(className, name, params, signature);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"createMBean",className, name,
|
||||
params, signature);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public ObjectInstance createMBean(String className, ObjectName name,
|
||||
ObjectName loaderName, Object[] params, String[] signature)
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException, InstanceNotFoundException {
|
||||
try {
|
||||
checkCreate(name, className, "instantiate");
|
||||
checkCreate(name, className, "registerMBean");
|
||||
return super.createMBean(className, name, loaderName, params,
|
||||
signature);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"createMBean",className, name,loaderName,
|
||||
params, signature);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public AttributeList setAttributes(ObjectName name,AttributeList attributes)
|
||||
throws InstanceNotFoundException, ReflectionException {
|
||||
try {
|
||||
final AttributeList authorized =
|
||||
checkAttributes(name, attributes, "setAttribute");
|
||||
return super.setAttributes(name, authorized);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"setAttributes",name, attributes);
|
||||
}
|
||||
}
|
||||
|
||||
// From MBeanServerConnection: catch & handles IOException
|
||||
@Override
|
||||
public Object invoke(ObjectName name, String operationName, Object[] params,
|
||||
String[] signature)
|
||||
throws InstanceNotFoundException, MBeanException, ReflectionException {
|
||||
try {
|
||||
check(name, operationName, "invoke");
|
||||
return super.invoke(name, operationName, params, signature);
|
||||
} catch (IOException ex) {
|
||||
throw handleIOException(ex,"invoke",name, operationName,
|
||||
params, signature);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// These methods are inherited from MBeanServer....
|
||||
//
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
public Object instantiate(String className)
|
||||
throws ReflectionException, MBeanException {
|
||||
if (LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("call to unsupported instantiate method: " +
|
||||
"trowing UnsupportedOperationException");
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
public Object instantiate(String className, ObjectName loaderName)
|
||||
throws ReflectionException, MBeanException,
|
||||
InstanceNotFoundException {
|
||||
if (LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("call to unsupported method: instantiate(...) -" +
|
||||
"throwing UnsupportedOperationException");
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
public Object instantiate(String className, Object[] params,
|
||||
String[] signature) throws ReflectionException, MBeanException {
|
||||
if (LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("call to unsupported method: instantiate(...) -" +
|
||||
"throwing UnsupportedOperationException");
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
public Object instantiate(String className, ObjectName loaderName,
|
||||
Object[] params, String[] signature)
|
||||
throws ReflectionException, MBeanException,
|
||||
InstanceNotFoundException {
|
||||
if (LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("call to unsupported method: instantiate(...) -" +
|
||||
"throwing UnsupportedOperationException");
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
@Deprecated
|
||||
public ObjectInputStream deserialize(ObjectName name, byte[] data)
|
||||
throws InstanceNotFoundException, OperationsException {
|
||||
if (LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("call to unsupported method: deserialize(...) -" +
|
||||
"throwing UnsupportedOperationException");
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
@Deprecated
|
||||
public ObjectInputStream deserialize(String className, byte[] data)
|
||||
throws OperationsException, ReflectionException {
|
||||
if (LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("call to unsupported method: deserialize(...) -" +
|
||||
"throwing UnsupportedOperationException");
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
@Deprecated
|
||||
public ObjectInputStream deserialize(String className,
|
||||
ObjectName loaderName, byte[] data)
|
||||
throws InstanceNotFoundException, OperationsException,
|
||||
ReflectionException {
|
||||
if (LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("call to unsupported method: deserialize(...) -" +
|
||||
"throwing UnsupportedOperationException");
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should never be called.
|
||||
* Throws UnsupportedOperationException.
|
||||
*/
|
||||
public ClassLoaderRepository getClassLoaderRepository() {
|
||||
if (LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("call to unsupported method: getClassLoaderRepository() -" +
|
||||
"throwing UnsupportedOperationException");
|
||||
throw new UnsupportedOperationException("Not applicable.");
|
||||
}
|
||||
|
||||
static RuntimeException newUnsupportedException(String namespace) {
|
||||
return new RuntimeOperationsException(
|
||||
new UnsupportedOperationException(
|
||||
"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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -1,220 +0,0 @@
|
||||
/*
|
||||
* 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 com.sun.jmx.namespace;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.namespace.JMXNamespace;
|
||||
import javax.management.namespace.JMXNamespacePermission;
|
||||
|
||||
/**
|
||||
* A NamespaceInterceptor wraps a JMXNamespace, performing
|
||||
* ObjectName rewriting.
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
public class NamespaceInterceptor extends HandlerInterceptor<JMXNamespace> {
|
||||
|
||||
|
||||
// The target name space in which the NamepsaceHandler is mounted.
|
||||
private final String targetNs;
|
||||
|
||||
private final String serverName;
|
||||
|
||||
private final ObjectNameRouter proc;
|
||||
|
||||
/**
|
||||
* Creates a new instance of NamespaceInterceptor
|
||||
*/
|
||||
public NamespaceInterceptor(
|
||||
String serverName,
|
||||
JMXNamespace handler,
|
||||
String targetNamespace) {
|
||||
super(handler);
|
||||
this.serverName = serverName;
|
||||
this.targetNs =
|
||||
ObjectNameRouter.normalizeNamespacePath(targetNamespace,
|
||||
true, true, false);
|
||||
proc = new ObjectNameRouter(targetNamespace, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getClass().getName()+"(parent="+serverName+
|
||||
", namespace="+this.targetNs+")";
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will send a probe to detect self-linking name spaces.
|
||||
* A self linking namespace is a namespace that links back directly
|
||||
* on itslef. Calling a method on such a name space always results
|
||||
* in an infinite loop going through:
|
||||
* [1]MBeanServer -> [2]NamespaceDispatcher -> [3]NamespaceInterceptor
|
||||
* [4]JMXNamespace -> { network // or cd // or ... } -> [5]MBeanServer
|
||||
* with exactly the same request than [1]...
|
||||
*
|
||||
* The namespace interceptor [2] tries to detect such condition the
|
||||
* *first time* that the connection is used. It does so by setting
|
||||
* a flag, and sending a queryNames() through the name space. If the
|
||||
* queryNames comes back, it knows that there's a loop.
|
||||
*
|
||||
* 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).
|
||||
*/
|
||||
private MBeanServer connection() {
|
||||
final MBeanServer c = super.source();
|
||||
if (c != null) return c;
|
||||
// should not come here
|
||||
throw new NullPointerException("getMBeanServerConnection");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected MBeanServer source() {
|
||||
return connection();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MBeanServer getServerForLoading() {
|
||||
// don't want to send probe on getClassLoader/getClassLoaderFor
|
||||
return super.source();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ObjectName toSource(ObjectName targetName) {
|
||||
return proc.toSourceContext(targetName, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ObjectName toTarget(ObjectName sourceName) {
|
||||
return proc.toTargetContext(sourceName, false);
|
||||
}
|
||||
|
||||
//
|
||||
// Implements permission checks.
|
||||
//
|
||||
@Override
|
||||
void check(ObjectName routingName, String member, String action) {
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
if (sm == null) return;
|
||||
if ("getDomains".equals(action)) return;
|
||||
final JMXNamespacePermission perm =
|
||||
new JMXNamespacePermission(serverName,member,
|
||||
routingName,action);
|
||||
sm.checkPermission(perm);
|
||||
}
|
||||
|
||||
@Override
|
||||
void checkCreate(ObjectName routingName, String className, String action) {
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
if (sm == null) return;
|
||||
final JMXNamespacePermission perm =
|
||||
new JMXNamespacePermission(serverName,className,
|
||||
routingName,action);
|
||||
sm.checkPermission(perm);
|
||||
}
|
||||
|
||||
//
|
||||
// Implements permission filters for attributes...
|
||||
//
|
||||
@Override
|
||||
AttributeList checkAttributes(ObjectName routingName,
|
||||
AttributeList attributes, String action) {
|
||||
check(routingName,null,action);
|
||||
if (attributes == null || attributes.isEmpty()) return attributes;
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
if (sm == null) return attributes;
|
||||
final AttributeList res = new AttributeList();
|
||||
for (Attribute at : attributes.asList()) {
|
||||
try {
|
||||
check(routingName,at.getName(),action);
|
||||
res.add(at);
|
||||
} catch (SecurityException x) { // DLS: OK
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//
|
||||
// Implements permission filters for attributes...
|
||||
//
|
||||
@Override
|
||||
String[] checkAttributes(ObjectName routingName, String[] attributes,
|
||||
String action) {
|
||||
check(routingName,null,action);
|
||||
if (attributes == null || attributes.length==0) return attributes;
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
if (sm == null) return attributes;
|
||||
final List<String> res = new ArrayList<String>(attributes.length);
|
||||
for (String at : attributes) {
|
||||
try {
|
||||
check(routingName,at,action);
|
||||
res.add(at);
|
||||
} catch (SecurityException x) { // DLS: OK
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return res.toArray(new String[res.size()]);
|
||||
}
|
||||
|
||||
//
|
||||
// Implements permission filters for domains...
|
||||
//
|
||||
@Override
|
||||
String[] checkDomains(String[] domains, String action) {
|
||||
// in principle, this method is never called because
|
||||
// getDomains() will never be called - since there's
|
||||
// no way that MBeanServer.getDomains() can be routed
|
||||
// to a NamespaceInterceptor.
|
||||
//
|
||||
// This is also why there's no getDomains() in a
|
||||
// JMXNamespacePermission...
|
||||
//
|
||||
return super.checkDomains(domains, action);
|
||||
}
|
||||
|
||||
//
|
||||
// Implements permission filters for queries...
|
||||
//
|
||||
@Override
|
||||
boolean checkQuery(ObjectName routingName, String action) {
|
||||
try {
|
||||
check(routingName,null,action);
|
||||
return true;
|
||||
} catch (SecurityException x) { // DLS: OK
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,175 +0,0 @@
|
||||
/*
|
||||
* 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 com.sun.jmx.namespace;
|
||||
|
||||
import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR;
|
||||
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
/**
|
||||
* The ObjectNameRouter is used to rewrite routing object names.
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
public class ObjectNameRouter {
|
||||
|
||||
private static final int NAMESPACE_SEPARATOR_LENGTH =
|
||||
NAMESPACE_SEPARATOR.length();
|
||||
|
||||
final String targetPrefix;
|
||||
final String sourcePrefix;
|
||||
final int slen;
|
||||
final int tlen;
|
||||
final boolean identity;
|
||||
|
||||
/** Creates a new instance of ObjectNameRouter */
|
||||
public ObjectNameRouter(final String remove, final String add) {
|
||||
this.targetPrefix = (remove==null?"":remove);
|
||||
this.sourcePrefix = (add==null?"":add);
|
||||
tlen = targetPrefix.length();
|
||||
slen = sourcePrefix.length();
|
||||
identity = targetPrefix.equals(sourcePrefix);
|
||||
}
|
||||
|
||||
public final ObjectName toTargetContext(ObjectName sourceName,
|
||||
boolean removeLeadingSeparators) {
|
||||
if (sourceName == null) return null;
|
||||
if (identity) return sourceName;
|
||||
String srcDomain = sourceName.getDomain();
|
||||
|
||||
// if the ObjectName starts with // and removeLeadingSeparators is
|
||||
// true, then recursively strip leading //.
|
||||
// Otherwise, do not rewrite ObjectName.
|
||||
//
|
||||
if (srcDomain.startsWith(NAMESPACE_SEPARATOR)) {
|
||||
if (!removeLeadingSeparators) return sourceName;
|
||||
else srcDomain = normalizeDomain(srcDomain,true);
|
||||
}
|
||||
if (slen != 0) {
|
||||
if (!srcDomain.startsWith(sourcePrefix) ||
|
||||
!srcDomain.startsWith(NAMESPACE_SEPARATOR,slen))
|
||||
throw new IllegalArgumentException(
|
||||
"ObjectName does not start with expected prefix "
|
||||
+ sourcePrefix + ": " +
|
||||
String.valueOf(sourceName));
|
||||
srcDomain = srcDomain.substring(slen+NAMESPACE_SEPARATOR_LENGTH);
|
||||
}
|
||||
final String targetDomain =
|
||||
(tlen>0?targetPrefix+NAMESPACE_SEPARATOR+srcDomain:srcDomain);
|
||||
return sourceName.withDomain(targetDomain);
|
||||
}
|
||||
|
||||
public final ObjectName toSourceContext(ObjectName targetName,
|
||||
boolean removeLeadingSeparators) {
|
||||
if (targetName == null) return null;
|
||||
if (identity) return targetName;
|
||||
String targetDomain = targetName.getDomain();
|
||||
if (targetDomain.startsWith(NAMESPACE_SEPARATOR)) {
|
||||
if (!removeLeadingSeparators) return targetName;
|
||||
else targetDomain =
|
||||
normalizeDomain(targetDomain,true);
|
||||
}
|
||||
if (tlen != 0) {
|
||||
if (!targetDomain.startsWith(targetPrefix) ||
|
||||
!targetDomain.startsWith(NAMESPACE_SEPARATOR,tlen))
|
||||
throw new IllegalArgumentException(
|
||||
"ObjectName does not start with expected prefix "
|
||||
+ targetPrefix + ": " +
|
||||
String.valueOf(targetName));
|
||||
targetDomain = targetDomain.
|
||||
substring(tlen+NAMESPACE_SEPARATOR_LENGTH);
|
||||
}
|
||||
final String sourceDomain =
|
||||
(slen>0?sourcePrefix+NAMESPACE_SEPARATOR+targetDomain:
|
||||
targetDomain);
|
||||
return targetName.withDomain(sourceDomain);
|
||||
}
|
||||
|
||||
public final ObjectInstance toTargetContext(ObjectInstance sourceMoi,
|
||||
boolean removeLeadingSeparators) {
|
||||
if (sourceMoi == null) return null;
|
||||
if (identity) return sourceMoi;
|
||||
return new ObjectInstance(
|
||||
toTargetContext(sourceMoi.getObjectName(),
|
||||
removeLeadingSeparators),
|
||||
sourceMoi.getClassName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes leading, trailing, or duplicate // in a name space path.
|
||||
**/
|
||||
public static String normalizeDomain(String domain,
|
||||
boolean removeLeadingSep) {
|
||||
return normalizeNamespacePath(domain,removeLeadingSep,false,true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes leading, trailing, or duplicate // in a name space path.
|
||||
**/
|
||||
public static String normalizeNamespacePath(String namespacePath,
|
||||
boolean removeLeadingSep,
|
||||
boolean removeTrailingSep,
|
||||
boolean endsWithDomain) {
|
||||
if (namespacePath.equals(""))
|
||||
return "";
|
||||
final String[] components = namespacePath.split(NAMESPACE_SEPARATOR);
|
||||
final StringBuilder b =
|
||||
new StringBuilder(namespacePath.length()+NAMESPACE_SEPARATOR_LENGTH);
|
||||
String sep = null;
|
||||
if (!removeLeadingSep && namespacePath.startsWith(NAMESPACE_SEPARATOR))
|
||||
b.append(NAMESPACE_SEPARATOR);
|
||||
int count = 0;
|
||||
for (int i=0; i<components.length; i++) {
|
||||
final String n=components[i];
|
||||
if (n.equals("")) continue;
|
||||
if (n.startsWith("/")||n.endsWith("/")) {
|
||||
// throw exception unless we're looking at the last domain
|
||||
// part of the ObjectName
|
||||
if (! (endsWithDomain && i==(components.length-1))) {
|
||||
throw new IllegalArgumentException(n+
|
||||
" is not a valid name space identifier");
|
||||
} else {
|
||||
// There's a dirty little corner case when the domain
|
||||
// part (last item) is exactly '/' - in that case we must
|
||||
// not append '//'
|
||||
//
|
||||
removeTrailingSep = removeTrailingSep || n.equals("/");
|
||||
}
|
||||
}
|
||||
if (sep != null) b.append(sep);
|
||||
b.append(n);
|
||||
sep = NAMESPACE_SEPARATOR;
|
||||
count++;
|
||||
}
|
||||
if (!removeTrailingSep && namespacePath.endsWith(NAMESPACE_SEPARATOR)
|
||||
&& count > 0)
|
||||
b.append(NAMESPACE_SEPARATOR);
|
||||
return b.toString();
|
||||
}
|
||||
}
|
||||
@ -1,106 +0,0 @@
|
||||
/*
|
||||
* 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 com.sun.jmx.namespace;
|
||||
|
||||
|
||||
import com.sun.jmx.defaults.JmxProperties;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.management.MBeanServerConnection;
|
||||
|
||||
|
||||
/**
|
||||
* A RoutingConnectionProxy is an MBeanServerConnection proxy that proxies a
|
||||
* source name space in a source MBeanServerConnection.
|
||||
* It wraps a source MBeanServerConnection, and rewrites routing
|
||||
* ObjectNames. It is used to implement
|
||||
* {@code JMXNamespaces.narrowToNamespace(MBeanServerConnection)}.
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
// See class hierarchy and detailled explanations in RoutingProxy in this
|
||||
// package.
|
||||
//
|
||||
public class RoutingConnectionProxy
|
||||
extends RoutingProxy<MBeanServerConnection> {
|
||||
|
||||
/**
|
||||
* A logger for this class.
|
||||
**/
|
||||
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance of RoutingConnectionProxy
|
||||
*/
|
||||
public RoutingConnectionProxy(MBeanServerConnection source,
|
||||
String sourceDir,
|
||||
String targetDir,
|
||||
boolean probe) {
|
||||
super(source, sourceDir, targetDir, probe);
|
||||
|
||||
if (LOG.isLoggable(Level.FINER))
|
||||
LOG.finer("RoutingConnectionProxy for " + getSourceNamespace() +
|
||||
" created");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final String targetNs = getTargetNamespace();
|
||||
final String sourceNs = getSourceNamespace();
|
||||
String wrapped = String.valueOf(source());
|
||||
if ("".equals(targetNs)) {
|
||||
return "JMXNamespaces.narrowToNamespace("+
|
||||
wrapped+", \""+
|
||||
sourceNs+"\")";
|
||||
}
|
||||
return this.getClass().getSimpleName()+"("+wrapped+", \""+
|
||||
sourceNs+"\", \""+
|
||||
targetNs+"\")";
|
||||
}
|
||||
|
||||
static final RoutingProxyFactory
|
||||
<MBeanServerConnection,RoutingConnectionProxy>
|
||||
FACTORY = new RoutingProxyFactory
|
||||
<MBeanServerConnection,RoutingConnectionProxy>() {
|
||||
|
||||
public RoutingConnectionProxy newInstance(MBeanServerConnection source,
|
||||
String sourcePath, String targetPath, boolean probe) {
|
||||
return new RoutingConnectionProxy(source,sourcePath,
|
||||
targetPath, probe);
|
||||
}
|
||||
};
|
||||
|
||||
public static MBeanServerConnection cd(
|
||||
MBeanServerConnection source, String sourcePath, boolean probe) {
|
||||
return RoutingProxy.cd(RoutingConnectionProxy.class, FACTORY,
|
||||
source, sourcePath, probe);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,556 +0,0 @@
|
||||
/*
|
||||
* 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 com.sun.jmx.namespace;
|
||||
|
||||
import com.sun.jmx.defaults.JmxProperties;
|
||||
import com.sun.jmx.mbeanserver.Util;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.IntrospectionException;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.JMRuntimeException;
|
||||
import javax.management.ListenerNotFoundException;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanRegistrationException;
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.NotificationFilter;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.QueryExp;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.RuntimeMBeanException;
|
||||
import javax.management.RuntimeOperationsException;
|
||||
|
||||
/**
|
||||
* A RoutingMBeanServerConnection wraps a MBeanServerConnection, defining
|
||||
* abstract methods that can be implemented by subclasses to rewrite
|
||||
* routing ObjectNames. It is used to implement
|
||||
* HandlerInterceptors (wrapping JMXNamespace instances) and routing
|
||||
* proxies (used to implement cd operations).
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
public abstract class RoutingMBeanServerConnection<T extends MBeanServerConnection>
|
||||
implements MBeanServerConnection {
|
||||
|
||||
/**
|
||||
* A logger for this class.
|
||||
**/
|
||||
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
|
||||
|
||||
/**
|
||||
* Creates a new instance of RoutingMBeanServerConnection
|
||||
*/
|
||||
public RoutingMBeanServerConnection() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @throws IllegalArgumentException if the name cannot be converted.
|
||||
**/
|
||||
protected abstract ObjectName toSource(ObjectName targetName);
|
||||
/**
|
||||
* 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.
|
||||
* @throws IllegalArgumentException if the name cannot be converted.
|
||||
**/
|
||||
protected abstract ObjectName toTarget(ObjectName sourceName);
|
||||
|
||||
/**
|
||||
* Can be overridden by subclasses to check the validity of a new
|
||||
* ObjectName used in createMBean or registerMBean.
|
||||
* This method is typically used by subclasses which might require
|
||||
* special handling for "null";
|
||||
**/
|
||||
protected ObjectName newSourceMBeanName(ObjectName targetName)
|
||||
throws MBeanRegistrationException {
|
||||
try {
|
||||
return toSource(targetName);
|
||||
} catch (Exception x) {
|
||||
throw new MBeanRegistrationException(x,"Illegal MBean Name");
|
||||
}
|
||||
}
|
||||
|
||||
// Calls toSource(), Wraps IllegalArgumentException.
|
||||
ObjectName toSourceOrRuntime(ObjectName targetName) {
|
||||
try {
|
||||
return toSource(targetName);
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Wraps given exception if needed.
|
||||
RuntimeException makeCompliantRuntimeException(Exception x) {
|
||||
if (x instanceof SecurityException) return (SecurityException)x;
|
||||
if (x instanceof JMRuntimeException) return (JMRuntimeException)x;
|
||||
if (x instanceof RuntimeException)
|
||||
return new RuntimeOperationsException((RuntimeException)x);
|
||||
if (x instanceof IOException)
|
||||
return Util.newRuntimeIOException((IOException)x);
|
||||
// shouldn't come here...
|
||||
final RuntimeException x2 = new UndeclaredThrowableException(x);
|
||||
return new RuntimeOperationsException(x2);
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public AttributeList getAttributes(ObjectName name, String[] attributes)
|
||||
throws InstanceNotFoundException, ReflectionException, IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
return source().getAttributes(sourceName, attributes);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public Object invoke(ObjectName name, String operationName, Object[] params,
|
||||
String[] signature)
|
||||
throws InstanceNotFoundException, MBeanException, ReflectionException,
|
||||
IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
final Object result =
|
||||
source().invoke(sourceName,operationName,params,
|
||||
signature);
|
||||
return result;
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public void unregisterMBean(ObjectName name)
|
||||
throws InstanceNotFoundException, MBeanRegistrationException,
|
||||
IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
source().unregisterMBean(sourceName);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public MBeanInfo getMBeanInfo(ObjectName name)
|
||||
throws InstanceNotFoundException, IntrospectionException,
|
||||
ReflectionException, IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
return source().getMBeanInfo(sourceName);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public ObjectInstance getObjectInstance(ObjectName name)
|
||||
throws InstanceNotFoundException, IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
return processOutputInstance(
|
||||
source().getObjectInstance(sourceName));
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public boolean isRegistered(ObjectName name) throws IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
return source().isRegistered(sourceName);
|
||||
} catch (RuntimeMBeanException x) {
|
||||
throw new RuntimeOperationsException(x.getTargetException());
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public void setAttribute(ObjectName name, Attribute attribute)
|
||||
throws InstanceNotFoundException, AttributeNotFoundException,
|
||||
InvalidAttributeValueException, MBeanException,
|
||||
ReflectionException, IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
source().setAttribute(sourceName,attribute);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public ObjectInstance createMBean(String className,
|
||||
ObjectName name, ObjectName loaderName,
|
||||
Object[] params, String[] signature)
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException, InstanceNotFoundException, IOException {
|
||||
final ObjectName sourceName = newSourceMBeanName(name);
|
||||
// Loader Name is already a sourceLoaderName.
|
||||
final ObjectName sourceLoaderName = loaderName;
|
||||
try {
|
||||
final ObjectInstance instance =
|
||||
source().createMBean(className,sourceName,
|
||||
sourceLoaderName,
|
||||
params,signature);
|
||||
return processOutputInstance(instance);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public ObjectInstance createMBean(String className, ObjectName name,
|
||||
Object[] params, String[] signature)
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException, IOException {
|
||||
final ObjectName sourceName = newSourceMBeanName(name);
|
||||
try {
|
||||
return processOutputInstance(source().createMBean(className,
|
||||
sourceName,params,signature));
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public ObjectInstance createMBean(String className, ObjectName name,
|
||||
ObjectName loaderName)
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException, InstanceNotFoundException, IOException {
|
||||
final ObjectName sourceName = newSourceMBeanName(name);
|
||||
// Loader Name is already a source Loader Name.
|
||||
final ObjectName sourceLoaderName = loaderName;
|
||||
try {
|
||||
return processOutputInstance(source().createMBean(className,
|
||||
sourceName,sourceLoaderName));
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public ObjectInstance createMBean(String className, ObjectName name)
|
||||
throws ReflectionException, InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException, MBeanException,
|
||||
NotCompliantMBeanException, IOException {
|
||||
final ObjectName sourceName = newSourceMBeanName(name);
|
||||
try {
|
||||
return processOutputInstance(source().
|
||||
createMBean(className,sourceName));
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public Object getAttribute(ObjectName name, String attribute)
|
||||
throws MBeanException, AttributeNotFoundException,
|
||||
InstanceNotFoundException, ReflectionException, IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
return source().getAttribute(sourceName,attribute);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public boolean isInstanceOf(ObjectName name, String className)
|
||||
throws InstanceNotFoundException, IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
return source().isInstanceOf(sourceName,className);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public AttributeList setAttributes(ObjectName name, AttributeList attributes)
|
||||
throws InstanceNotFoundException, ReflectionException, IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
return source().
|
||||
setAttributes(sourceName,attributes);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Return names in the target's context.
|
||||
Set<ObjectInstance> processOutputInstances(Set<ObjectInstance> sources) {
|
||||
|
||||
final Set<ObjectInstance> result = Util.equivalentEmptySet(sources);
|
||||
for (ObjectInstance i : sources) {
|
||||
try {
|
||||
final ObjectInstance target = processOutputInstance(i);
|
||||
if (excludesFromResult(target.getObjectName(), "queryMBeans"))
|
||||
continue;
|
||||
result.add(target);
|
||||
} catch (Exception x) {
|
||||
if (LOG.isLoggable(Level.FINE)) {
|
||||
LOG.fine("Skiping returned item: " +
|
||||
"Unexpected exception while processing " +
|
||||
"ObjectInstance: " + x);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Return names in the target's context.
|
||||
ObjectInstance processOutputInstance(ObjectInstance source) {
|
||||
if (source == null) return null;
|
||||
final ObjectName sourceName = source.getObjectName();
|
||||
try {
|
||||
final ObjectName targetName = toTarget(sourceName);
|
||||
return new ObjectInstance(targetName,source.getClassName());
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns names in the target's context.
|
||||
Set<ObjectName> processOutputNames(Set<ObjectName> sourceNames) {
|
||||
|
||||
final Set<ObjectName> names = Util.equivalentEmptySet(sourceNames);
|
||||
for (ObjectName n : sourceNames) {
|
||||
try {
|
||||
final ObjectName targetName = toTarget(n);
|
||||
if (excludesFromResult(targetName, "queryNames")) continue;
|
||||
names.add(targetName);
|
||||
} catch (Exception x) {
|
||||
if (LOG.isLoggable(Level.FINE)) {
|
||||
LOG.fine("Skiping returned item: " +
|
||||
"Unexpected exception while processing " +
|
||||
"ObjectInstance: " + x);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public Set<ObjectInstance> queryMBeans(ObjectName name,
|
||||
QueryExp query) throws IOException {
|
||||
if (name == null) name=ObjectName.WILDCARD;
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
return processOutputInstances(
|
||||
source().queryMBeans(sourceName,query));
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
|
||||
public Set<ObjectName> queryNames(ObjectName name, QueryExp query)
|
||||
throws IOException {
|
||||
if (name == null) name=ObjectName.WILDCARD;
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
final Set<ObjectName> tmp = source().queryNames(sourceName,query);
|
||||
final Set<ObjectName> out = processOutputNames(tmp);
|
||||
//System.err.println("queryNames: out: "+out);
|
||||
return out;
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public void removeNotificationListener(ObjectName name,
|
||||
NotificationListener listener)
|
||||
throws InstanceNotFoundException,
|
||||
ListenerNotFoundException, IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
source().removeNotificationListener(sourceName,listener);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public void addNotificationListener(ObjectName name, ObjectName listener,
|
||||
NotificationFilter filter, Object handback)
|
||||
throws InstanceNotFoundException, IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
// Listener name is already a source listener name.
|
||||
try {
|
||||
source().addNotificationListener(sourceName,listener,
|
||||
filter,handback);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public void addNotificationListener(ObjectName name,
|
||||
NotificationListener listener, NotificationFilter filter,
|
||||
Object handback) throws InstanceNotFoundException, IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
source().addNotificationListener(sourceName, listener, filter,
|
||||
handback);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// from MBeanServerConnection
|
||||
public void removeNotificationListener(ObjectName name,
|
||||
NotificationListener listener, NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException,
|
||||
IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
source().removeNotificationListener(sourceName,listener,filter,
|
||||
handback);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public void removeNotificationListener(ObjectName name, ObjectName listener,
|
||||
NotificationFilter filter, Object handback)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException,
|
||||
IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
source().removeNotificationListener(sourceName,listener,
|
||||
filter,handback);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public void removeNotificationListener(ObjectName name, ObjectName listener)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException,
|
||||
IOException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
// listener name is already a source name...
|
||||
final ObjectName sourceListener = listener;
|
||||
try {
|
||||
source().removeNotificationListener(sourceName,sourceListener);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public Integer getMBeanCount() throws IOException {
|
||||
try {
|
||||
return source().getMBeanCount();
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public String[] getDomains() throws IOException {
|
||||
try {
|
||||
return source().getDomains();
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// from MBeanServerConnection
|
||||
public String getDefaultDomain() throws IOException {
|
||||
try {
|
||||
return source().getDefaultDomain();
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,395 +0,0 @@
|
||||
/*
|
||||
* 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 com.sun.jmx.namespace;
|
||||
|
||||
import com.sun.jmx.defaults.JmxProperties;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanRegistrationException;
|
||||
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.namespace.JMXNamespaces;
|
||||
|
||||
|
||||
/**
|
||||
* A RoutingProxy narrows on a given name space in a
|
||||
* source object implementing MBeanServerConnection.
|
||||
* It is used to implement
|
||||
* {@code JMXNamespaces.narrowToNamespace(...)}.
|
||||
* This abstract class has two concrete subclasses:
|
||||
* <p>{@link RoutingConnectionProxy}: to narrow down into an
|
||||
* 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>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @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...
|
||||
//
|
||||
// Finally, in order to avoid too many layers of wrapping,
|
||||
// RoutingConnectionProxy and RoutingServerProxy can be created through a
|
||||
// factory method that can concatenate namespace paths 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>
|
||||
extends RoutingMBeanServerConnection<T> {
|
||||
|
||||
/**
|
||||
* A logger for this class.
|
||||
**/
|
||||
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
|
||||
|
||||
// The source MBeanServerConnection
|
||||
private final T source;
|
||||
|
||||
// The name space we're narrowing to (usually some name space in
|
||||
// the source MBeanServerConnection), e.g. "a" for the namespace
|
||||
// "a//". This is empty in the case of ClientContext described above.
|
||||
private final String sourceNs;
|
||||
|
||||
// The name space we pretend to be mounted in. This is empty except
|
||||
// in the case of ClientContext described above (where it will be
|
||||
// something like "jmx.context//foo=bar".
|
||||
private final String targetNs;
|
||||
|
||||
// The name of the JMXNamespace that handles the source name space
|
||||
private final ObjectName handlerName;
|
||||
private final ObjectNameRouter router;
|
||||
private volatile String defaultDomain = null;
|
||||
|
||||
/**
|
||||
* Creates a new instance of RoutingProxy
|
||||
*/
|
||||
protected RoutingProxy(T source,
|
||||
String sourceNs,
|
||||
String targetNs,
|
||||
boolean probe) {
|
||||
if (source == null) throw new IllegalArgumentException("null");
|
||||
this.sourceNs = JMXNamespaces.normalizeNamespaceName(sourceNs);
|
||||
|
||||
// Usually sourceNs is not null, except when implementing
|
||||
// Client Contexts
|
||||
//
|
||||
if (sourceNs.equals("")) {
|
||||
this.handlerName = null;
|
||||
} else {
|
||||
// System.err.println("sourceNs: "+sourceNs);
|
||||
this.handlerName =
|
||||
JMXNamespaces.getNamespaceObjectName(this.sourceNs);
|
||||
if (probe) {
|
||||
try {
|
||||
if (!source.isRegistered(handlerName)) {
|
||||
InstanceNotFoundException infe =
|
||||
new InstanceNotFoundException(handlerName);
|
||||
throw new IllegalArgumentException(sourceNs +
|
||||
": no such name space", infe);
|
||||
}
|
||||
} catch (IOException x) {
|
||||
throw new IllegalArgumentException("source stale: "+x,x);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.source = source;
|
||||
this.targetNs = (targetNs==null?"":
|
||||
JMXNamespaces.normalizeNamespaceName(targetNs));
|
||||
this.router =
|
||||
new ObjectNameRouter(this.targetNs,this.sourceNs);
|
||||
|
||||
if (LOG.isLoggable(Level.FINER))
|
||||
LOG.finer("RoutingProxy for " + this.sourceNs + " created");
|
||||
}
|
||||
|
||||
@Override
|
||||
public T source() { return source; }
|
||||
|
||||
@Override
|
||||
public ObjectName toSource(ObjectName targetName) {
|
||||
if (targetName == null) return null;
|
||||
if (targetName.getDomain().equals("") && targetNs.equals("")) {
|
||||
try {
|
||||
if (defaultDomain == null)
|
||||
defaultDomain = getDefaultDomain();
|
||||
} catch(Exception x) {
|
||||
LOG.log(Level.FINEST,"Failed to get default domain",x);
|
||||
}
|
||||
if (defaultDomain != null)
|
||||
targetName = targetName.withDomain(defaultDomain);
|
||||
}
|
||||
return router.toSourceContext(targetName,true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ObjectName newSourceMBeanName(ObjectName targetName)
|
||||
throws MBeanRegistrationException {
|
||||
if (targetName != null) return super.newSourceMBeanName(targetName);
|
||||
|
||||
// OK => we can accept null if sourceNs is empty.
|
||||
if (sourceNs.equals("")) return null;
|
||||
|
||||
throw new MBeanRegistrationException(
|
||||
new IllegalArgumentException(
|
||||
"Can't use null ObjectName with namespaces"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectName toTarget(ObjectName sourceName) {
|
||||
if (sourceName == null) return null;
|
||||
return router.toTargetContext(sourceName,false);
|
||||
}
|
||||
|
||||
private Object getAttributeFromHandler(String attributeName)
|
||||
throws IOException {
|
||||
|
||||
try {
|
||||
return source().getAttribute(handlerName,attributeName);
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
} catch (IOException x) {
|
||||
throw x;
|
||||
} catch (MBeanException ex) {
|
||||
throw new IOException("Failed to get "+attributeName+": "+
|
||||
ex.getCause(),
|
||||
ex.getCause());
|
||||
} catch (Exception ex) {
|
||||
throw new IOException("Failed to get "+attributeName+": "+
|
||||
ex,ex);
|
||||
}
|
||||
}
|
||||
|
||||
// We cannot call getMBeanCount() on the underlying
|
||||
// MBeanServerConnection, because it would return the number of
|
||||
// 'top-level' MBeans, not the number of MBeans in the name space
|
||||
// we are narrowing to. Instead we're calling getMBeanCount() on
|
||||
// the JMXNamespace that handles the source name space.
|
||||
//
|
||||
// There is however one particular case when the sourceNs is empty.
|
||||
// In that case, there's no handler - and the 'source' is the top
|
||||
// level namespace. In that particular case, handlerName will be null,
|
||||
// and we directly invoke the top level source().
|
||||
// This later complex case is only used when implementing ClientContexts.
|
||||
//
|
||||
@Override
|
||||
public Integer getMBeanCount() throws IOException {
|
||||
try {
|
||||
if (handlerName == null) return source().getMBeanCount();
|
||||
return (Integer) getAttributeFromHandler("MBeanCount");
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// We cannot call getDomains() on the underlying
|
||||
// MBeanServerConnection, because it would return the domains of
|
||||
// 'top-level' MBeans, not the domains of MBeans in the name space
|
||||
// we are narrowing to. Instead we're calling getDomains() on
|
||||
// the JMXNamespace that handles the source name space.
|
||||
//
|
||||
// There is however one particular case when the sourceNs is empty.
|
||||
// In that case, there's no handler - and the 'source' is the top
|
||||
// level namespace. In that particular case, handlerName will be null,
|
||||
// and we directly invoke the top level source().
|
||||
// This later complex case is only used when implementing ClientContexts.
|
||||
//
|
||||
@Override
|
||||
public String[] getDomains() throws IOException {
|
||||
try {
|
||||
if (handlerName == null) return source().getDomains();
|
||||
return (String[]) getAttributeFromHandler("Domains");
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// We cannot call getDefaultDomain() on the underlying
|
||||
// MBeanServerConnection, because it would return the default domain of
|
||||
// 'top-level' namespace, not the default domain in the name space
|
||||
// we are narrowing to. Instead we're calling getDefaultDomain() on
|
||||
// the JMXNamespace that handles the source name space.
|
||||
//
|
||||
// There is however one particular case when the sourceNs is empty.
|
||||
// In that case, there's no handler - and the 'source' is the top
|
||||
// level namespace. In that particular case, handlerName will be null,
|
||||
// and we directly invoke the top level source().
|
||||
// This later complex case is only used when implementing ClientContexts.
|
||||
//
|
||||
@Override
|
||||
public String getDefaultDomain() throws IOException {
|
||||
try {
|
||||
if (handlerName == null) {
|
||||
defaultDomain = source().getDefaultDomain();
|
||||
} else {
|
||||
defaultDomain =(String)
|
||||
getAttributeFromHandler("DefaultDomain");
|
||||
}
|
||||
return defaultDomain;
|
||||
} catch (RuntimeException ex) {
|
||||
throw makeCompliantRuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public String getSourceNamespace() {
|
||||
return sourceNs;
|
||||
}
|
||||
|
||||
public String getTargetNamespace() {
|
||||
return targetNs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString()+", sourceNs="+
|
||||
sourceNs + (targetNs.equals("")?"":
|
||||
(" 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>> {
|
||||
public R newInstance(
|
||||
T source, String sourcePath, String targetPath, boolean probe);
|
||||
}
|
||||
|
||||
// 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, boolean probe) {
|
||||
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, "", probe);
|
||||
}
|
||||
// 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, "", probe);
|
||||
}
|
||||
}
|
||||
@ -1,576 +0,0 @@
|
||||
/*
|
||||
* 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 com.sun.jmx.namespace;
|
||||
|
||||
|
||||
import com.sun.jmx.mbeanserver.Util;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.IntrospectionException;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.ListenerNotFoundException;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanRegistrationException;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.NotificationFilter;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.OperationsException;
|
||||
import javax.management.QueryExp;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.loading.ClassLoaderRepository;
|
||||
|
||||
/**
|
||||
* A RoutingServerProxy is an MBeanServer proxy that proxies a
|
||||
* source name space in a source MBeanServer.
|
||||
* It wraps a source MBeanServer, and rewrites routing ObjectNames.
|
||||
* It is typically use for implementing 'cd' operations, and
|
||||
* will add the source name space to routing ObjectNames at input,
|
||||
* and remove it at output.
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
// See class hierarchy and detailled explanations in RoutingProxy in this
|
||||
// package.
|
||||
//
|
||||
public class RoutingServerProxy
|
||||
extends RoutingProxy<MBeanServer>
|
||||
implements MBeanServer {
|
||||
|
||||
public RoutingServerProxy(MBeanServer source,
|
||||
String sourceNs,
|
||||
String targetNs,
|
||||
boolean probe) {
|
||||
super(source, sourceNs, targetNs, probe);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called each time an IOException is raised when
|
||||
* trying to forward an operation to the underlying
|
||||
* MBeanServerConnection, as a result of calling
|
||||
* {@link #getMBeanServerConnection()} or as a result of invoking the
|
||||
* operation on the returned connection.
|
||||
* Subclasses may redefine this method if they need to perform any
|
||||
* specific handling of IOException (logging etc...).
|
||||
* @param x The raised IOException.
|
||||
* @param method The name of the method in which the exception was
|
||||
* raised. This is one of the methods of the MBeanServer
|
||||
* interface.
|
||||
* @return A RuntimeException that should be thrown by the caller.
|
||||
* In this default implementation, this is an
|
||||
* {@link UndeclaredThrowableException} wrapping <var>x</var>.
|
||||
**/
|
||||
protected RuntimeException handleIOException(IOException x,
|
||||
String method) {
|
||||
return Util.newRuntimeIOException(x);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------
|
||||
//--------------------------------------------
|
||||
//
|
||||
// Implementation of the MBeanServer interface
|
||||
//
|
||||
//--------------------------------------------
|
||||
//--------------------------------------------
|
||||
@Override
|
||||
public void addNotificationListener(ObjectName name,
|
||||
NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException {
|
||||
try {
|
||||
super.addNotificationListener(name, listener,
|
||||
filter, handback);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"addNotificationListener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNotificationListener(ObjectName name,
|
||||
ObjectName listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException {
|
||||
try {
|
||||
super.addNotificationListener(name, listener,
|
||||
filter, handback);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"addNotificationListener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInstance createMBean(String className, ObjectName name)
|
||||
throws
|
||||
ReflectionException,
|
||||
InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException,
|
||||
MBeanException,
|
||||
NotCompliantMBeanException {
|
||||
try {
|
||||
return super.createMBean(className, name);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"createMBean");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInstance createMBean(String className, ObjectName name,
|
||||
Object params[], String signature[])
|
||||
throws
|
||||
ReflectionException,
|
||||
InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException,
|
||||
MBeanException,
|
||||
NotCompliantMBeanException {
|
||||
try {
|
||||
return super.createMBean(className, name,
|
||||
params, signature);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"createMBean");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInstance createMBean(String className,
|
||||
ObjectName name,
|
||||
ObjectName loaderName)
|
||||
throws
|
||||
ReflectionException,
|
||||
InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException,
|
||||
MBeanException,
|
||||
NotCompliantMBeanException,
|
||||
InstanceNotFoundException {
|
||||
try {
|
||||
return super.createMBean(className, name, loaderName);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"createMBean");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInstance createMBean(String className,
|
||||
ObjectName name,
|
||||
ObjectName loaderName,
|
||||
Object params[],
|
||||
String signature[])
|
||||
throws
|
||||
ReflectionException,
|
||||
InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException,
|
||||
MBeanException,
|
||||
NotCompliantMBeanException,
|
||||
InstanceNotFoundException {
|
||||
try {
|
||||
return super.createMBean(className, name, loaderName,
|
||||
params, signature);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"createMBean");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated see {@link MBeanServer#deserialize(ObjectName,byte[])
|
||||
* MBeanServer}
|
||||
**/
|
||||
@Deprecated
|
||||
public ObjectInputStream deserialize(ObjectName name, byte[] data)
|
||||
throws InstanceNotFoundException, OperationsException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(name);
|
||||
try {
|
||||
return source().deserialize(sourceName,data);
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated see {@link MBeanServer#deserialize(String,byte[])
|
||||
* MBeanServer}
|
||||
*/
|
||||
@Deprecated
|
||||
public ObjectInputStream deserialize(String className, byte[] data)
|
||||
throws OperationsException, ReflectionException {
|
||||
try {
|
||||
return source().deserialize(className,data);
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated see {@link MBeanServer#deserialize(String,ObjectName,byte[])
|
||||
* MBeanServer}
|
||||
*/
|
||||
@Deprecated
|
||||
public ObjectInputStream deserialize(String className,
|
||||
ObjectName loaderName,
|
||||
byte[] data)
|
||||
throws
|
||||
InstanceNotFoundException,
|
||||
OperationsException,
|
||||
ReflectionException {
|
||||
try {
|
||||
return source().deserialize(className,loaderName,data);
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(ObjectName name, String attribute)
|
||||
throws
|
||||
MBeanException,
|
||||
AttributeNotFoundException,
|
||||
InstanceNotFoundException,
|
||||
ReflectionException {
|
||||
try {
|
||||
return super.getAttribute(name, attribute);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"getAttribute");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeList getAttributes(ObjectName name, String[] attributes)
|
||||
throws InstanceNotFoundException, ReflectionException {
|
||||
try {
|
||||
return super.getAttributes(name, attributes);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"getAttributes");
|
||||
}
|
||||
}
|
||||
|
||||
public ClassLoader getClassLoader(ObjectName loaderName)
|
||||
throws InstanceNotFoundException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(loaderName);
|
||||
try {
|
||||
return source().getClassLoader(sourceName);
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
public ClassLoader getClassLoaderFor(ObjectName mbeanName)
|
||||
throws InstanceNotFoundException {
|
||||
final ObjectName sourceName = toSourceOrRuntime(mbeanName);
|
||||
try {
|
||||
return source().getClassLoaderFor(sourceName);
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
public ClassLoaderRepository getClassLoaderRepository() {
|
||||
try {
|
||||
return source().getClassLoaderRepository();
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultDomain() {
|
||||
try {
|
||||
return super.getDefaultDomain();
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"getDefaultDomain");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getDomains() {
|
||||
try {
|
||||
return super.getDomains();
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"getDomains");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getMBeanCount() {
|
||||
try {
|
||||
return super.getMBeanCount();
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"getMBeanCount");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MBeanInfo getMBeanInfo(ObjectName name)
|
||||
throws
|
||||
InstanceNotFoundException,
|
||||
IntrospectionException,
|
||||
ReflectionException {
|
||||
try {
|
||||
return super.getMBeanInfo(name);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"getMBeanInfo");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInstance getObjectInstance(ObjectName name)
|
||||
throws InstanceNotFoundException {
|
||||
try {
|
||||
return super.getObjectInstance(name);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"getObjectInstance");
|
||||
}
|
||||
}
|
||||
|
||||
public Object instantiate(String className)
|
||||
throws ReflectionException, MBeanException {
|
||||
try {
|
||||
return source().instantiate(className);
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
public Object instantiate(String className,
|
||||
Object params[],
|
||||
String signature[])
|
||||
throws ReflectionException, MBeanException {
|
||||
try {
|
||||
return source().instantiate(className,
|
||||
params,signature);
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
public Object instantiate(String className, ObjectName loaderName)
|
||||
throws ReflectionException, MBeanException,
|
||||
InstanceNotFoundException {
|
||||
final ObjectName srcLoaderName = toSourceOrRuntime(loaderName);
|
||||
try {
|
||||
return source().instantiate(className,srcLoaderName);
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
public Object instantiate(String className, ObjectName loaderName,
|
||||
Object params[], String signature[])
|
||||
throws ReflectionException, MBeanException,
|
||||
InstanceNotFoundException {
|
||||
final ObjectName srcLoaderName = toSourceOrRuntime(loaderName);
|
||||
try {
|
||||
return source().instantiate(className,srcLoaderName,
|
||||
params,signature);
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(ObjectName name, String operationName,
|
||||
Object params[], String signature[])
|
||||
throws
|
||||
InstanceNotFoundException,
|
||||
MBeanException,
|
||||
ReflectionException {
|
||||
try {
|
||||
return super.invoke(name,operationName,params,signature);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"invoke");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInstanceOf(ObjectName name, String className)
|
||||
throws InstanceNotFoundException {
|
||||
try {
|
||||
return super.isInstanceOf(name, className);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"isInstanceOf");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegistered(ObjectName name) {
|
||||
try {
|
||||
return super.isRegistered(name);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"isRegistered");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
|
||||
try {
|
||||
return super.queryMBeans(name, query);
|
||||
} catch (IOException x) {
|
||||
handleIOException(x,"queryMBeans");
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
|
||||
try {
|
||||
return super.queryNames(name, query);
|
||||
} catch (IOException x) {
|
||||
handleIOException(x,"queryNames");
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
public ObjectInstance registerMBean(Object object, ObjectName name)
|
||||
throws
|
||||
InstanceAlreadyExistsException,
|
||||
MBeanRegistrationException,
|
||||
NotCompliantMBeanException {
|
||||
final ObjectName sourceName = newSourceMBeanName(name);
|
||||
try {
|
||||
return processOutputInstance(
|
||||
source().registerMBean(object,sourceName));
|
||||
} catch (RuntimeException x) {
|
||||
throw makeCompliantRuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotificationListener(ObjectName name,
|
||||
NotificationListener listener)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
try {
|
||||
super.removeNotificationListener(name, listener);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"removeNotificationListener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotificationListener(ObjectName name,
|
||||
NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
try {
|
||||
super.removeNotificationListener(name, listener,
|
||||
filter, handback);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"removeNotificationListener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotificationListener(ObjectName name,
|
||||
ObjectName listener)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
try {
|
||||
super.removeNotificationListener(name, listener);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"removeNotificationListener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotificationListener(ObjectName name,
|
||||
ObjectName listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException {
|
||||
try {
|
||||
super.removeNotificationListener(name, listener,
|
||||
filter, handback);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"removeNotificationListener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(ObjectName name, Attribute attribute)
|
||||
throws
|
||||
InstanceNotFoundException,
|
||||
AttributeNotFoundException,
|
||||
InvalidAttributeValueException,
|
||||
MBeanException,
|
||||
ReflectionException {
|
||||
try {
|
||||
super.setAttribute(name, attribute);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"setAttribute");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeList setAttributes(ObjectName name,
|
||||
AttributeList attributes)
|
||||
throws InstanceNotFoundException, ReflectionException {
|
||||
try {
|
||||
return super.setAttributes(name, attributes);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"setAttributes");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterMBean(ObjectName name)
|
||||
throws InstanceNotFoundException, MBeanRegistrationException {
|
||||
try {
|
||||
super.unregisterMBean(name);
|
||||
} catch (IOException x) {
|
||||
throw handleIOException(x,"unregisterMBean");
|
||||
}
|
||||
}
|
||||
|
||||
static final RoutingProxyFactory<MBeanServer,RoutingServerProxy>
|
||||
FACTORY = new RoutingProxyFactory<MBeanServer,RoutingServerProxy>() {
|
||||
|
||||
public RoutingServerProxy newInstance(MBeanServer source,
|
||||
String sourcePath, String targetPath, boolean probe) {
|
||||
return new RoutingServerProxy(
|
||||
source, sourcePath, targetPath, probe);
|
||||
}
|
||||
};
|
||||
|
||||
public static MBeanServer cd(
|
||||
MBeanServer source, String sourcePath, boolean probe) {
|
||||
return RoutingProxy.cd(RoutingServerProxy.class, FACTORY,
|
||||
source, sourcePath, probe);
|
||||
}
|
||||
}
|
||||
@ -1,45 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>The <code>com.sun.jmx.namespace</code> package</title>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
</head>
|
||||
<body bgcolor="white">
|
||||
<p>The <code>com.sun.jmx.namespace</code> package contains
|
||||
sun specific implementation classes used to implement the
|
||||
JMX namespaces.
|
||||
</p>
|
||||
<p><b>DO NOT USE THESE CLASSES DIRECTLY</b></p>
|
||||
<p><b>
|
||||
This API is a Sun internal API and is subject to changes without notice.
|
||||
</b></p>
|
||||
<p>The public API through wich these proprietary classes can be
|
||||
invoked is located in <code>javax.management.namespace</code>
|
||||
package.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,150 +0,0 @@
|
||||
/*
|
||||
* 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 com.sun.jmx.namespace.serial;
|
||||
|
||||
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
/**
|
||||
* Class DefaultRewritingProcessor. Rewrite ObjectName in input & output
|
||||
* parameters.
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
// We know that rewriting using serialization is costly.
|
||||
// This object tries to determine whether an object needs rewriting prior
|
||||
// to rewriting, and rewrites by creating a new object in those cases
|
||||
// where we know how to recreate a new object (e.g. a Notification).
|
||||
// Rewriting is however usually not used - so this object is just a
|
||||
// skeleton that eventually uses serialization...
|
||||
//
|
||||
class DefaultRewritingProcessor extends RewritingProcessor {
|
||||
|
||||
|
||||
private static enum RewriteMode {
|
||||
INPUT, // Input from target to source (parameters)
|
||||
OUTPUT // Output from source to target (results)
|
||||
};
|
||||
|
||||
private final boolean identity;
|
||||
|
||||
public DefaultRewritingProcessor(String targetDirName) {
|
||||
this(targetDirName,null);
|
||||
}
|
||||
|
||||
/** Creates a new instance of SerialParamProcessor */
|
||||
public DefaultRewritingProcessor(final String remove, final String add) {
|
||||
super(new SerialRewritingProcessor(remove, add));
|
||||
identity = remove.equals(add);
|
||||
}
|
||||
|
||||
private ObjectName rewriteObjectName(RewriteMode mode,
|
||||
ObjectName name) {
|
||||
return changeContext(mode, name);
|
||||
}
|
||||
|
||||
private ObjectInstance rewriteObjectInstance(RewriteMode mode,
|
||||
ObjectInstance moi) {
|
||||
final ObjectName srcName = moi.getObjectName();
|
||||
final ObjectName targetName = changeContext(mode,srcName);
|
||||
if (targetName == srcName) return moi;
|
||||
return new ObjectInstance(targetName,moi.getClassName());
|
||||
}
|
||||
|
||||
|
||||
private Object processObject(RewriteMode mode, Object obj) {
|
||||
if (obj == null) return null;
|
||||
|
||||
// Some things which will always needs rewriting:
|
||||
// ObjectName, ObjectInstance, and Notifications.
|
||||
// Take care of those we can handle here...
|
||||
//
|
||||
if (obj instanceof ObjectName)
|
||||
return rewriteObjectName(mode,(ObjectName) obj);
|
||||
else if (obj instanceof ObjectInstance)
|
||||
return rewriteObjectInstance(mode,(ObjectInstance) obj);
|
||||
|
||||
// TODO: add other standard JMX classes - like e.g. MBeanInfo...
|
||||
//
|
||||
|
||||
// Well, the object may contain an ObjectName => pass it to
|
||||
// our serial rewriting delegate...
|
||||
//
|
||||
return processAnyObject(mode,obj);
|
||||
}
|
||||
|
||||
|
||||
private Object processAnyObject(RewriteMode mode, Object obj) {
|
||||
switch (mode) {
|
||||
case INPUT:
|
||||
return super.rewriteInput(obj);
|
||||
case OUTPUT:
|
||||
return super.rewriteOutput(obj);
|
||||
default: // can't happen.
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
private ObjectName changeContext(RewriteMode mode, ObjectName name) {
|
||||
switch (mode) {
|
||||
case INPUT:
|
||||
return toSourceContext(name);
|
||||
case OUTPUT:
|
||||
return toTargetContext(name);
|
||||
default: // can't happen.
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectName toTargetContext(ObjectName srcName) {
|
||||
if (identity) return srcName;
|
||||
return super.toTargetContext(srcName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectName toSourceContext(ObjectName targetName) {
|
||||
if (identity) return targetName;
|
||||
return super.toSourceContext(targetName);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> T rewriteInput(T input) {
|
||||
if (identity) return input;
|
||||
return (T) processObject(RewriteMode.INPUT,input);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> T rewriteOutput(T result) {
|
||||
if (identity) return result;
|
||||
return (T) processObject(RewriteMode.OUTPUT,result);
|
||||
}
|
||||
}
|
||||
@ -1,74 +0,0 @@
|
||||
/*
|
||||
* 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 com.sun.jmx.namespace.serial;
|
||||
|
||||
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
/**
|
||||
* Class RoutingOnlyProcessor. A RewritingProcessor that uses
|
||||
* Java Serialization to rewrite ObjectNames contained in
|
||||
* input & results...
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
class IdentityProcessor extends RewritingProcessor {
|
||||
|
||||
|
||||
/** Creates a new instance of SerialRewritingProcessor */
|
||||
public IdentityProcessor() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T rewriteOutput(T result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T rewriteInput(T input) {
|
||||
return input;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ObjectName toTargetContext(ObjectName sourceName) {
|
||||
return sourceName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ObjectInstance toTargetContext(ObjectInstance sourceMoi) {
|
||||
return sourceMoi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ObjectName toSourceContext(ObjectName targetName) {
|
||||
return targetName;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,145 +0,0 @@
|
||||
/*
|
||||
* 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 com.sun.jmx.namespace.serial;
|
||||
|
||||
import com.sun.jmx.defaults.JmxProperties;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
/**
|
||||
* The JMXNamespaceContext class is used to implement a thread local
|
||||
* serialization / deserialization context for namespaces.
|
||||
* <p>
|
||||
* This class is consulted by {@link javax.management.ObjectName} at
|
||||
* serialization / deserialization time.
|
||||
* The serialization or deserialization context is established by
|
||||
* by the {@link SerialRewritingProcessor} defined in this package.
|
||||
* <p>
|
||||
* These classes are Sun proprietary APIs, subject to change without
|
||||
* notice. Do not use these classes directly.
|
||||
* The public API to rewrite ObjectNames embedded in parameters is
|
||||
* defined in {@link javax.management.namespace.JMXNamespaces}.
|
||||
*
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
public class JMXNamespaceContext {
|
||||
|
||||
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
|
||||
|
||||
public final String prefixToRemove;
|
||||
public final String prefixToAdd;
|
||||
|
||||
private JMXNamespaceContext(String add, String remove) {
|
||||
prefixToRemove = (remove==null?"":remove);
|
||||
prefixToAdd = (add==null?"":add);
|
||||
}
|
||||
|
||||
private final static class SerialContext {
|
||||
private JMXNamespaceContext serializationContext;
|
||||
private JMXNamespaceContext deserializationContext;
|
||||
public SerialContext(){
|
||||
serializationContext = new JMXNamespaceContext("","");
|
||||
deserializationContext = new JMXNamespaceContext("","");
|
||||
}
|
||||
}
|
||||
|
||||
private final static ThreadLocal<SerialContext> prefix =
|
||||
new ThreadLocal<SerialContext>() {
|
||||
@Override
|
||||
protected SerialContext initialValue() {
|
||||
return new SerialContext();
|
||||
}
|
||||
};
|
||||
|
||||
public static JMXNamespaceContext getSerializationContext() {
|
||||
return prefix.get().serializationContext;
|
||||
}
|
||||
|
||||
public static JMXNamespaceContext getDeserializationContext() {
|
||||
return prefix.get().deserializationContext;
|
||||
}
|
||||
|
||||
private static String[] setSerializationContext(String oldPrefix,
|
||||
String newPrefix) {
|
||||
final SerialContext c = prefix.get();
|
||||
JMXNamespaceContext dc = c.serializationContext;
|
||||
String[] old = {dc.prefixToRemove, dc.prefixToAdd};
|
||||
c.serializationContext = new JMXNamespaceContext(newPrefix,oldPrefix);
|
||||
return old;
|
||||
}
|
||||
|
||||
private static String[] setDeserializationContext(String oldPrefix,
|
||||
String newPrefix) {
|
||||
final SerialContext c = prefix.get();
|
||||
JMXNamespaceContext dc = c.deserializationContext;
|
||||
String[] old = {dc.prefixToRemove, dc.prefixToAdd};
|
||||
c.deserializationContext = new JMXNamespaceContext(newPrefix,oldPrefix);
|
||||
return old;
|
||||
}
|
||||
|
||||
static void serialize(ObjectOutputStream stream, Object obj,
|
||||
String prefixToRemove, String prefixToAdd)
|
||||
throws IOException {
|
||||
final String[] old =
|
||||
setSerializationContext(prefixToRemove,prefixToAdd);
|
||||
try {
|
||||
stream.writeObject(obj);
|
||||
} finally {
|
||||
try {
|
||||
setSerializationContext(old[0],old[1]);
|
||||
} catch (Exception x) {
|
||||
LOG.log(Level.FINEST,
|
||||
"failed to restore serialization context",x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Object deserialize(ObjectInputStream stream,
|
||||
String prefixToRemove,
|
||||
String prefixToAdd)
|
||||
throws IOException, ClassNotFoundException {
|
||||
final String[] old =
|
||||
setDeserializationContext(prefixToRemove,prefixToAdd);
|
||||
try {
|
||||
return stream.readObject();
|
||||
} finally {
|
||||
try {
|
||||
setDeserializationContext(old[0],old[1]);
|
||||
} catch (Exception x) {
|
||||
LOG.log(Level.FINEST,
|
||||
"failed to restore serialization context",x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,362 +0,0 @@
|
||||
/*
|
||||
* 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 com.sun.jmx.namespace.serial;
|
||||
|
||||
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
/**
|
||||
* An object that can rewrite ObjectNames contained in input/output
|
||||
* parameters when entering/leaving a {@link javax.management.namespace
|
||||
* namespace}.
|
||||
* <p>When entering a {@link javax.management.namespace
|
||||
* namespace}, the {@code namespace} prefix is stripped from
|
||||
* ObjectNames contained in input parameters. When leaving a
|
||||
* {@code namespace},
|
||||
* the {@code namespace} prefix is prepended to the ObjectNames contained in
|
||||
* the result parameters returned from that {@code namespace}.
|
||||
* </p>
|
||||
* <p>Objects that need to perform these operations usually use a
|
||||
* {@code RewritingProcessor} for that purpose.<br>
|
||||
* The {@code RewritingProcessor} allows a somewhat larger
|
||||
* transformation in which part of a prefix {@link #newRewritingProcessor
|
||||
* remove} can be replaced by another prefix {@link #newRewritingProcessor
|
||||
* add}. The transformation described above correspond to the case where
|
||||
* {@code remove} is the stripped {@link javax.management.namespace
|
||||
* namespace} prefix (removed when entering the {@code namespace}) and
|
||||
* {@code add} is the empty String {@code ""}.
|
||||
* <br>
|
||||
* It is interesting to note that {@link
|
||||
* javax.management.JMXNamespaces#narrowToNamespace narrowToNamespace}
|
||||
* operations use the inverse transformation (that is, {@code remove} is
|
||||
* the empty String {@code ""} and {@code add} is the {@link
|
||||
* javax.management.namespace namespace} prefix).
|
||||
* <br>
|
||||
* On a more general scale, {@link #rewriteInput rewriteInput} removes
|
||||
* {@link #newRewritingProcessor remove} and the prepend {@link
|
||||
* #newRewritingProcessor add}, and {@link #rewriteOutput rewriteOutput}
|
||||
* does the opposite, removing {@link #newRewritingProcessor add}, and
|
||||
* then adding {@link #newRewritingProcessor remove}.
|
||||
* <br>
|
||||
* An implementation of {@code RewritingProcessor} should make sure that
|
||||
* <code>rewriteInput(rewriteOutput(x,clp),clp)</code> and
|
||||
* <code>rewriteOutput(rewriteInput(x,clp),clp)</code> always return
|
||||
* {@code x} or an exact clone of {@code x}.
|
||||
* </p>
|
||||
* <p>A default implementation of {@code RewritingProcessor} based on
|
||||
* Java Object Serialization can be
|
||||
* obtained from {@link #newRewritingProcessor newRewritingProcessor}.
|
||||
* </p>
|
||||
* <p>
|
||||
* By default, the instances of {@code RewritingProcessor} returned by
|
||||
* {@link #newRewritingProcessor newRewritingProcessor} will rewrite
|
||||
* ObjectNames contained in instances of classes they don't know about by
|
||||
* serializing and then deserializing such object instances. This will
|
||||
* happen even if such instances don't - or can't contain ObjectNames,
|
||||
* because the default implementation of {@code RewritingProcessor} will
|
||||
* not be able to determine whether instances of such classes can/do contain
|
||||
* instance of ObjectNames before serializing/deserializing them.
|
||||
* </p>
|
||||
* <p>If you are using custom classes that the default implementation of
|
||||
* {@code RewritingProcessor} don't know about, it can be interesting to
|
||||
* prevent an instance of {@code RewritingProcessor} to serialize/deserialize
|
||||
* instances of such classes for nothing. In that case, you could customize
|
||||
* the behavior of such a {@code RewritingProcessor} by wrapping it in a
|
||||
* custom subclass of {@code RewritingProcessor} as shown below:
|
||||
* <pre>
|
||||
* public class MyRewritingProcessor extends RewritingProcessor {
|
||||
* MyRewritingProcessor(String remove, String add) {
|
||||
* this(RewritingProcessor.newRewritingProcessor(remove,add));
|
||||
* }
|
||||
* MyRewritingProcessor(RewritingProcessor delegate) {
|
||||
* super(delegate);
|
||||
* }
|
||||
*
|
||||
* <T> T rewriteInput(T input) {
|
||||
* if (input == null) return null;
|
||||
* if (MyClass.equals(input.getClass())) {
|
||||
* // I know that MyClass doesn't contain any ObjectName
|
||||
* return (T) input;
|
||||
* }
|
||||
* return super.rewriteInput(input);
|
||||
* }
|
||||
* <T> T rewriteOutput(T result) {
|
||||
* if (result == null) return null;
|
||||
* if (MyClass.equals(result.getClass())) {
|
||||
* // I know that MyClass doesn't contain any ObjectName
|
||||
* return (T) result;
|
||||
* }
|
||||
* return super.rewriteOutput(result);
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
* </p>
|
||||
* <p>Such a subclass may also provide an alternate way of rewriting
|
||||
* custom subclasses for which rewriting is needed - for instance:
|
||||
* <pre>
|
||||
* public class MyRewritingProcessor extends RewritingProcessor {
|
||||
* MyRewritingProcessor(String remove, String add) {
|
||||
* this(RewritingProcessor.newRewritingProcessor(remove,add));
|
||||
* }
|
||||
* MyRewritingProcessor(RewritingProcessor delegate) {
|
||||
* super(delegate);
|
||||
* }
|
||||
*
|
||||
* <T> T rewriteInput(T input) {
|
||||
* if (input == null) return null;
|
||||
* if (MyClass.equals(input.getClass())) {
|
||||
* // I know that MyClass doesn't contain any ObjectName
|
||||
* return (T) input;
|
||||
* } else if (MyOtherClass.equals(input.getClass())) {
|
||||
* // Returns a new instance in which ObjectNames have been
|
||||
* // replaced.
|
||||
* final ObjectName aname = ((MyOtherClass)input).getName();
|
||||
* return (T) (new MyOtherClass(super.rewriteInput(aname)));
|
||||
* }
|
||||
* return super.rewriteInput(input,clp);
|
||||
* }
|
||||
* <T> T rewriteOutput(T result) {
|
||||
* if (result == null) return null;
|
||||
* if (MyClass.equals(result.getClass())) {
|
||||
* // I know that MyClass doesn't contain any ObjectName
|
||||
* return (T) result;
|
||||
* } else if (MyOtherClass.equals(result.getClass())) {
|
||||
* // Returns a new instance in which ObjectNames have been
|
||||
* // replaced.
|
||||
* final ObjectName aname = ((MyOtherClass)result).getName();
|
||||
* return (T) (new MyOtherClass(super.rewriteOutput(aname)));
|
||||
* }
|
||||
* return super.rewriteOutput(result,clp);
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
* </p>
|
||||
* <p>If your application only uses {@link javax.management.MXBean MXBeans},
|
||||
* or MBeans using simple types, and doesn't define any custom subclass of
|
||||
* {@link javax.management.Notification}, you should never write such
|
||||
* such {@code RewitingProcessor} implementations.
|
||||
* </p>
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
public abstract class RewritingProcessor {
|
||||
/**
|
||||
* A logger for this class.
|
||||
**/
|
||||
private final RewritingProcessor delegate;
|
||||
|
||||
/**
|
||||
* Creates a new instance of RewritingProcessor.
|
||||
* <p>This is equivalent to calling {@link
|
||||
* #RewritingProcessor(RewritingProcessor) RewritingProcessor(null)}.
|
||||
* </p>
|
||||
**/
|
||||
protected RewritingProcessor() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of RewritingProcessor, with a delegate.
|
||||
* @param delegate a {@code RewritingProcessor} to which all the
|
||||
* calls will be delegated. When implementing a subclass
|
||||
* of {@code RewritingProcessor}, calling {@link
|
||||
* #rewriteInput super.rewriteInput} will invoke
|
||||
* {@code delegate.rewriteInput} and calling {@link
|
||||
* #rewriteOutput super.rewriteOutput} will invoke
|
||||
* {@code delegate.rewriteOutput}.
|
||||
*
|
||||
**/
|
||||
protected RewritingProcessor(RewritingProcessor delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrites ObjectNames when {@link RewritingProcessor leaving} a {@link
|
||||
* javax.management.namespace namespace}.
|
||||
* <p>
|
||||
* Returns {@code obj}, if it is known that {@code obj} doesn't contain
|
||||
* any ObjectName, or a new copied instance of {@code obj} in which
|
||||
* ObjectNames (if any) will have been rewritten, if {@code obj} contains
|
||||
* ObjectNames, or if it is not known whether {@code obj} contains
|
||||
* ObjectNames or not.
|
||||
* </p>
|
||||
* <p>
|
||||
* The default implementation of this method is as follows: if the
|
||||
* {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code
|
||||
* null}, throws an {@link IllegalArgumentException}. Otherwise,
|
||||
* returns {@code delegate.rewriteOutput(obj)}.
|
||||
* </p>
|
||||
* <p>This behavior can be overridden by subclasses as shown in this
|
||||
* class {@link RewritingProcessor description}.
|
||||
* </p>
|
||||
* @param obj The result to be rewritten if needed.
|
||||
*
|
||||
* @return {@code obj}, or a clone of {@code obj} in which ObjectNames
|
||||
* have been rewritten. See this class {@link RewritingProcessor
|
||||
* description} for more details.
|
||||
* @throws IllegalArgumentException if this implementation does not know
|
||||
* how to rewrite the object.
|
||||
**/
|
||||
public <T> T rewriteOutput(T obj) {
|
||||
if (obj == null) return null;
|
||||
if (delegate != null)
|
||||
return delegate.rewriteOutput(obj);
|
||||
throw new IllegalArgumentException("can't rewrite "+
|
||||
obj.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrites ObjectNames when {@link RewritingProcessor entering} a {@link
|
||||
* javax.management.namespace namespace}.
|
||||
* <p>
|
||||
* Returns {@code obj}, if it is known that {@code obj} doesn't contain
|
||||
* any ObjectName, or a new copied instance of {@code obj} in which
|
||||
* ObjectNames (if any) will have been rewritten, if {@code obj} contains
|
||||
* ObjectNames, or if it is not known whether {@code obj} contains
|
||||
* ObjectNames or not.
|
||||
* </p>
|
||||
* <p>
|
||||
* The default implementation of this method is as follows: if the
|
||||
* {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code
|
||||
* null}, throws an {@link IllegalArgumentException}. Otherwise,
|
||||
* returns {@code delegate.rewriteInput(obj)}.
|
||||
* </p>
|
||||
* <p>This behavior can be overridden by subclasses as shown in this
|
||||
* class {@link RewritingProcessor description}.
|
||||
* </p>
|
||||
* @param obj The result to be rewritten if needed.
|
||||
* @return {@code obj}, or a clone of {@code obj} in which ObjectNames
|
||||
* have been rewritten. See this class {@link RewritingProcessor
|
||||
* description} for more details.
|
||||
* @throws IllegalArgumentException if this implementation does not know
|
||||
* how to rewrite the object.
|
||||
**/
|
||||
public <T> T rewriteInput(T obj) {
|
||||
if (obj == null) return null;
|
||||
if (delegate != null)
|
||||
return delegate.rewriteInput(obj);
|
||||
throw new IllegalArgumentException("can't rewrite "+
|
||||
obj.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a routing ObjectName from the target (calling) context to
|
||||
* the source (called) context when {@link RewritingProcessor entering} a
|
||||
* {@link javax.management.namespace namespace}.
|
||||
* <p>
|
||||
* The default implementation of this method is as follows: if the
|
||||
* {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code
|
||||
* null}, throws an {@link IllegalArgumentException}. Otherwise,
|
||||
* returns {@code delegate.toSourceContext(targetName)}.
|
||||
* </p>
|
||||
* <p>This behavior can be overridden by subclasses as shown in this
|
||||
* class {@link RewritingProcessor description}.
|
||||
* </p>
|
||||
* @param targetName The routing target ObjectName to translate.
|
||||
* @return The ObjectName translated to the source context.
|
||||
* @throws IllegalArgumentException if this implementation does not know
|
||||
* how to rewrite the object.
|
||||
**/
|
||||
public ObjectName toSourceContext(ObjectName targetName) {
|
||||
if (delegate != null)
|
||||
return delegate.toSourceContext(targetName);
|
||||
throw new IllegalArgumentException("can't rewrite targetName: "+
|
||||
" no delegate.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate an ObjectName returned from the source context into
|
||||
* the target (calling) context when {@link RewritingProcessor leaving} a
|
||||
* {@link javax.management.namespace namespace}.
|
||||
* <p>
|
||||
* The default implementation of this method is as follows: if the
|
||||
* {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code
|
||||
* null}, throws an {@link IllegalArgumentException}. Otherwise,
|
||||
* returns {@code delegate.toTargetContext(sourceName)}.
|
||||
* </p>
|
||||
* <p>This behavior can be overridden by subclasses as shown in this
|
||||
* class {@link RewritingProcessor description}.
|
||||
* </p>
|
||||
* @param sourceName The routing source ObjectName to translate to the
|
||||
* target context.
|
||||
* @return The ObjectName translated to the target context.
|
||||
* @throws IllegalArgumentException if this implementation does not know
|
||||
* how to rewrite the object.
|
||||
**/
|
||||
public ObjectName toTargetContext(ObjectName sourceName) {
|
||||
if (delegate != null)
|
||||
return delegate.toTargetContext(sourceName);
|
||||
throw new IllegalArgumentException("can't rewrite sourceName: "+
|
||||
" no delegate.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate an ObjectInstance returned from the source context into
|
||||
* the target (calling) context when {@link RewritingProcessor leaving} a
|
||||
* {@link javax.management.namespace namespace}.
|
||||
* <p>
|
||||
* The default implementation of this method is as follows: if the
|
||||
* {@link #RewritingProcessor(RewritingProcessor) delegate} is {@code
|
||||
* null}, throws an {@link IllegalArgumentException}. Otherwise,
|
||||
* returns {@code delegate.toTargetContext(sourceMoi)}.
|
||||
* </p>
|
||||
* <p>This behavior can be overridden by subclasses as shown in this
|
||||
* class {@link RewritingProcessor description}.
|
||||
* </p>
|
||||
* @param sourceMoi The routing source ObjectInstance to translate.
|
||||
* @return The ObjectInstance translated to the target context.
|
||||
* @throws IllegalArgumentException if this implementation does not know
|
||||
* how to rewrite the object.
|
||||
**/
|
||||
public ObjectInstance toTargetContext(ObjectInstance sourceMoi) {
|
||||
if (delegate != null)
|
||||
return delegate.toTargetContext(sourceMoi);
|
||||
throw new IllegalArgumentException("can't rewrite sourceName: "+
|
||||
" no delegate.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new default instance of {@link RewritingProcessor}.
|
||||
* @param remove The prefix to remove from {@link ObjectName ObjectNames}
|
||||
* when {@link RewritingProcessor entering} the {@link
|
||||
* javax.management.namespace namespace}.
|
||||
* @param add The prefix to add to {@link ObjectName ObjectNames}
|
||||
* when {@link RewritingProcessor entering} the {@link
|
||||
* javax.management.namespace namespace} (this is performed
|
||||
* after having removed the {@code remove} prefix.
|
||||
* @return A new {@link RewritingProcessor} processor object that will
|
||||
* perform the requested operation, using Java serialization if
|
||||
* necessary.
|
||||
**/
|
||||
public static RewritingProcessor newRewritingProcessor(String remove,
|
||||
String add) {
|
||||
return new DefaultRewritingProcessor(remove,add);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,74 +0,0 @@
|
||||
/*
|
||||
* 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 com.sun.jmx.namespace.serial;
|
||||
|
||||
import com.sun.jmx.namespace.ObjectNameRouter;
|
||||
|
||||
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
/**
|
||||
* Class RoutingOnlyProcessor. A RewritingProcessor that uses
|
||||
* Java Serialization to rewrite ObjectNames contained in
|
||||
* input and results...
|
||||
*
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
class RoutingOnlyProcessor extends RewritingProcessor {
|
||||
|
||||
final ObjectNameRouter router;
|
||||
|
||||
public RoutingOnlyProcessor(String targetDirName) {
|
||||
this(targetDirName,null);
|
||||
}
|
||||
|
||||
/** Creates a new instance of RoutingOnlyProcessor */
|
||||
public RoutingOnlyProcessor(final String remove, final String add) {
|
||||
super(new IdentityProcessor());
|
||||
if (remove == null || add == null)
|
||||
throw new IllegalArgumentException("Null argument");
|
||||
router = new ObjectNameRouter(remove,add);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ObjectName toTargetContext(ObjectName sourceName) {
|
||||
return router.toTargetContext(sourceName,false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ObjectName toSourceContext(ObjectName targetName) {
|
||||
return router.toSourceContext(targetName,false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ObjectInstance toTargetContext(ObjectInstance sourceMoi) {
|
||||
return router.toTargetContext(sourceMoi,false);
|
||||
}
|
||||
}
|
||||
@ -1,172 +0,0 @@
|
||||
/*
|
||||
* 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 com.sun.jmx.namespace.serial;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InvalidClassException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.ObjectStreamClass;
|
||||
import java.io.OutputStream;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
import javax.management.ObjectName;
|
||||
|
||||
/**
|
||||
* Class SerialRewritingProcessor. A RewritingProcessor that uses
|
||||
* Java Serialization to rewrite ObjectNames contained in
|
||||
* input & results...
|
||||
* <p><b>
|
||||
* This API is a Sun internal API and is subject to changes without notice.
|
||||
* </b></p>
|
||||
* @since 1.7
|
||||
*/
|
||||
class SerialRewritingProcessor extends RewritingProcessor {
|
||||
|
||||
|
||||
private static class CloneOutput extends ObjectOutputStream {
|
||||
Queue<Class<?>> classQueue = new LinkedList<Class<?>>();
|
||||
|
||||
CloneOutput(OutputStream out) throws IOException {
|
||||
super(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void annotateClass(Class<?> c) {
|
||||
classQueue.add(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void annotateProxyClass(Class<?> c) {
|
||||
classQueue.add(c);
|
||||
}
|
||||
}
|
||||
|
||||
private static class CloneInput extends ObjectInputStream {
|
||||
private final CloneOutput output;
|
||||
|
||||
CloneInput(InputStream in, CloneOutput output) throws IOException {
|
||||
super(in);
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> resolveClass(ObjectStreamClass osc)
|
||||
throws IOException, ClassNotFoundException {
|
||||
Class<?> c = output.classQueue.poll();
|
||||
String expected = osc.getName();
|
||||
String found = (c == null) ? null : c.getName();
|
||||
if (!expected.equals(found)) {
|
||||
throw new InvalidClassException("Classes desynchronized: " +
|
||||
"found " + found + " when expecting " + expected);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> resolveProxyClass(String[] interfaceNames)
|
||||
throws IOException, ClassNotFoundException {
|
||||
return output.classQueue.poll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final String targetPrefix;
|
||||
final String sourcePrefix;
|
||||
final boolean identity;
|
||||
|
||||
|
||||
public SerialRewritingProcessor(String targetDirName) {
|
||||
this(targetDirName,null);
|
||||
}
|
||||
|
||||
/** Creates a new instance of SerialRewritingProcessor */
|
||||
public SerialRewritingProcessor(final String remove, final String add) {
|
||||
super(new RoutingOnlyProcessor(remove,add));
|
||||
this.targetPrefix = remove;
|
||||
this.sourcePrefix = add;
|
||||
identity = targetPrefix.equals(sourcePrefix);
|
||||
}
|
||||
|
||||
private <T> T switchContext(T result, String from,String to)
|
||||
throws IOException, ClassNotFoundException {
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
final CloneOutput ostream = new CloneOutput(baos);
|
||||
|
||||
JMXNamespaceContext.serialize(ostream,result,from,null);
|
||||
ostream.flush();
|
||||
|
||||
final byte[] bytes = baos.toByteArray();
|
||||
final ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
|
||||
final CloneInput istream = new CloneInput(bais, ostream);
|
||||
@SuppressWarnings("unchecked")
|
||||
final T clone = (T) JMXNamespaceContext.deserialize(istream,null,to);
|
||||
return clone;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T rewriteOutput(T result) {
|
||||
if (identity) return result;
|
||||
return (T) processOutput(result);
|
||||
}
|
||||
|
||||
private Object processOutput(Object result) {
|
||||
try {
|
||||
if (result instanceof ObjectName)
|
||||
return toTargetContext((ObjectName) result);
|
||||
return switchContext(result,sourcePrefix,targetPrefix);
|
||||
} catch (ClassNotFoundException x) {
|
||||
throw new IllegalArgumentException("Can't process result: "+x,x);
|
||||
} catch (IOException x) {
|
||||
throw new IllegalArgumentException("Can't process result: "+x,x);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T rewriteInput(T input) {
|
||||
if (identity) return input;
|
||||
return (T) processInput(input);
|
||||
}
|
||||
|
||||
private Object processInput(Object input) {
|
||||
try {
|
||||
if (input instanceof ObjectName)
|
||||
return toSourceContext((ObjectName) input);
|
||||
return switchContext(input,targetPrefix,sourcePrefix);
|
||||
} catch (ClassNotFoundException x) {
|
||||
throw new IllegalArgumentException("Can't process input: "+x,x);
|
||||
} catch (IOException x) {
|
||||
throw new IllegalArgumentException("Can't process input: "+x,x);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>The <code>com.sun.jmx.namespace.serial</code> package</title>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
</head>
|
||||
<body bgcolor="white">
|
||||
<p>The <code>com.sun.jmx.namespace.serial</code> package contains
|
||||
sun specific implementation classes used to switch namespace
|
||||
prefixes in ObjectName during serialization.
|
||||
</p>
|
||||
<p><b>NEVER USE THESE CLASSES DIRECTLY</b></p>
|
||||
<p><b>
|
||||
This API is a Sun internal API and is subject to changes without notice.
|
||||
</b></p>
|
||||
<p>The public API through which these proprietary classes can be invoked is
|
||||
located in <code>javax.management.namespace.JMXNamespaces</code>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@ -86,8 +86,7 @@ public class ServerNotifForwarder {
|
||||
|
||||
// Explicitly check MBeanPermission for addNotificationListener
|
||||
//
|
||||
checkMBeanPermission(getMBeanServerName(),
|
||||
mbeanServer, name, "addNotificationListener");
|
||||
checkMBeanPermission(name, "addNotificationListener");
|
||||
if (notificationAccessController != null) {
|
||||
notificationAccessController.addNotificationListener(
|
||||
connectionId, name, getSubject());
|
||||
@ -157,8 +156,7 @@ public class ServerNotifForwarder {
|
||||
|
||||
// Explicitly check MBeanPermission for removeNotificationListener
|
||||
//
|
||||
checkMBeanPermission(getMBeanServerName(),
|
||||
mbeanServer, name, "removeNotificationListener");
|
||||
checkMBeanPermission(name, "removeNotificationListener");
|
||||
if (notificationAccessController != null) {
|
||||
notificationAccessController.removeNotificationListener(
|
||||
connectionId, name, getSubject());
|
||||
@ -333,8 +331,8 @@ public class ServerNotifForwarder {
|
||||
* Explicitly check the MBeanPermission for
|
||||
* the current access control context.
|
||||
*/
|
||||
public static void checkMBeanPermission(String serverName,
|
||||
final MBeanServer mbs, final ObjectName name, final String actions)
|
||||
public void checkMBeanPermission(
|
||||
final ObjectName name, final String actions)
|
||||
throws InstanceNotFoundException, SecurityException {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
@ -345,7 +343,7 @@ public class ServerNotifForwarder {
|
||||
new PrivilegedExceptionAction<ObjectInstance>() {
|
||||
public ObjectInstance run()
|
||||
throws InstanceNotFoundException {
|
||||
return mbs.getObjectInstance(name);
|
||||
return mbeanServer.getObjectInstance(name);
|
||||
}
|
||||
});
|
||||
} catch (PrivilegedActionException e) {
|
||||
@ -353,7 +351,6 @@ public class ServerNotifForwarder {
|
||||
}
|
||||
String classname = oi.getClassName();
|
||||
MBeanPermission perm = new MBeanPermission(
|
||||
serverName,
|
||||
classname,
|
||||
null,
|
||||
name,
|
||||
@ -369,8 +366,7 @@ public class ServerNotifForwarder {
|
||||
TargetedNotification tn) {
|
||||
try {
|
||||
if (checkNotificationEmission) {
|
||||
checkMBeanPermission(getMBeanServerName(),
|
||||
mbeanServer, name, "addNotificationListener");
|
||||
checkMBeanPermission(name, "addNotificationListener");
|
||||
}
|
||||
if (notificationAccessController != null) {
|
||||
notificationAccessController.fetchNotification(
|
||||
@ -432,27 +428,12 @@ public class ServerNotifForwarder {
|
||||
}
|
||||
}
|
||||
|
||||
private String getMBeanServerName() {
|
||||
if (mbeanServerName != null) return mbeanServerName;
|
||||
else return (mbeanServerName = getMBeanServerName(mbeanServer));
|
||||
}
|
||||
|
||||
private static String getMBeanServerName(final MBeanServer server) {
|
||||
final PrivilegedAction<String> action = new PrivilegedAction<String>() {
|
||||
public String run() {
|
||||
return Util.getMBeanServerSecurityName(server);
|
||||
}
|
||||
};
|
||||
return AccessController.doPrivileged(action);
|
||||
}
|
||||
|
||||
|
||||
//------------------
|
||||
// PRIVATE VARIABLES
|
||||
//------------------
|
||||
|
||||
private MBeanServer mbeanServer;
|
||||
private volatile String mbeanServerName;
|
||||
|
||||
private final String connectionId;
|
||||
|
||||
@ -462,7 +443,7 @@ public class ServerNotifForwarder {
|
||||
private final static int[] listenerCounterLock = new int[0];
|
||||
|
||||
private NotificationBuffer notifBuffer;
|
||||
private Map<ObjectName, Set<IdAndFilter>> listenerMap =
|
||||
private final Map<ObjectName, Set<IdAndFilter>> listenerMap =
|
||||
new HashMap<ObjectName, Set<IdAndFilter>>();
|
||||
|
||||
private boolean terminated = false;
|
||||
|
||||
@ -780,25 +780,6 @@ public class EnvHelp {
|
||||
return new Hashtable<K, V>(m);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the parameter JMXConnector.USE_EVENT_SERVICE is set to a
|
||||
* String equals "true" by ignoring case in the map or in the System.
|
||||
*/
|
||||
public static boolean eventServiceEnabled(Map<String, ?> env) {
|
||||
return computeBooleanFromString(env, JMXConnector.USE_EVENT_SERVICE, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the parameter JMXConnectorServer.DELEGATE_TO_EVENT_SERVICE
|
||||
* is set to a String equals "true" (ignores case).
|
||||
* If the property DELEGATE_TO_EVENT_SERVICE is not set, returns
|
||||
* a default value of "true".
|
||||
*/
|
||||
public static boolean delegateToEventService(Map<String, ?> env) {
|
||||
return computeBooleanFromString(env,
|
||||
JMXConnectorServer.DELEGATE_TO_EVENT_SERVICE, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Name of the attribute that specifies whether a connector server
|
||||
* should not prevent the VM from exiting
|
||||
@ -817,46 +798,6 @@ public class EnvHelp {
|
||||
("true".equalsIgnoreCase((String)env.get(JMX_SERVER_DAEMON)));
|
||||
}
|
||||
|
||||
// /**
|
||||
// * <p>Name of the attribute that specifies an EventRelay object to use.
|
||||
// */
|
||||
// public static final String EVENT_RELAY =
|
||||
// "jmx.remote.x.event.relay";
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * Returns an EventRelay object. The default one is FetchingEventRelay.
|
||||
// * If {@code EVENT_RELAY} is specified in {@code env} as a key,
|
||||
// * its value will be returned as an EventRelay object, if the value is
|
||||
// * not of type {@code EventRelay}, the default {@code FetchingEventRelay}
|
||||
// * will be returned.
|
||||
// * If {@code EVENT_RELAY} is not specified but {@code ENABLE_EVENT_RELAY}
|
||||
// * is specified as a key and its value is <code true>, the default {@code FetchingEventRelay}
|
||||
// * will be returned.
|
||||
// */
|
||||
// public static EventRelay getEventRelay(Map env) {
|
||||
// Map info = env == null ?
|
||||
// Collections.EMPTY_MAP : env;
|
||||
//
|
||||
// Object o = env.get(EVENT_RELAY);
|
||||
// if (o instanceof EventRelay) {
|
||||
// return (EventRelay)o;
|
||||
// } else if (o != null) {
|
||||
// logger.warning("getEventRelay",
|
||||
// "The user specified object is not an EventRelay object, " +
|
||||
// "using the default class FetchingEventRelay.");
|
||||
//
|
||||
// return new FetchingEventRelay();
|
||||
// }
|
||||
//
|
||||
// if (enableEventRelay(env)) {
|
||||
// return new FetchingEventRelay();
|
||||
// }
|
||||
//
|
||||
// return null;
|
||||
// }
|
||||
|
||||
|
||||
private static final class SinkOutputStream extends OutputStream {
|
||||
public void write(byte[] b, int off, int len) {}
|
||||
public void write(int b) {}
|
||||
|
||||
@ -1,469 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-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 com.sun.jmx.remote.util;
|
||||
|
||||
import com.sun.jmx.defaults.JmxProperties;
|
||||
import com.sun.jmx.event.EventClientFactory;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.NotificationFilter;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.event.EventClient;
|
||||
import javax.management.event.EventClientDelegate;
|
||||
import javax.management.namespace.JMXNamespaces;
|
||||
|
||||
/**
|
||||
* Class EventClientConnection - a {@link Proxy} that wraps an
|
||||
* {@link MBeanServerConnection} and an {@link EventClient}.
|
||||
* All methods are routed to the underlying {@code MBeanServerConnection},
|
||||
* except add/remove notification listeners which are routed to the
|
||||
* {@code EventClient}.
|
||||
* The caller only sees an {@code MBeanServerConnection} which uses an
|
||||
* {@code EventClient} behind the scenes.
|
||||
*
|
||||
* @author Sun Microsystems, Inc.
|
||||
*/
|
||||
public class EventClientConnection implements InvocationHandler,
|
||||
EventClientFactory {
|
||||
|
||||
/**
|
||||
* A logger for this class.
|
||||
**/
|
||||
private static final Logger LOG = JmxProperties.NOTIFICATION_LOGGER;
|
||||
|
||||
private static final int NAMESPACE_SEPARATOR_LENGTH =
|
||||
JMXNamespaces.NAMESPACE_SEPARATOR.length();
|
||||
|
||||
/**
|
||||
* Creates a new {@code EventClientConnection}.
|
||||
* @param connection The underlying MBeanServerConnection.
|
||||
*/
|
||||
public EventClientConnection(MBeanServerConnection connection) {
|
||||
this(connection,null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code EventClientConnection}.
|
||||
* @param connection The underlying MBeanServerConnection.
|
||||
* @param eventClientFactory a factory object that will be invoked
|
||||
* to create an {@link EventClient} when needed.
|
||||
* The {@code EventClient} is created lazily, when it is needed
|
||||
* for the first time. If null, a default factory will be used
|
||||
* (see {@link #createEventClient}).
|
||||
*/
|
||||
public EventClientConnection(MBeanServerConnection connection,
|
||||
Callable<EventClient> eventClientFactory) {
|
||||
|
||||
if (connection == null) {
|
||||
throw new IllegalArgumentException("Null connection");
|
||||
}
|
||||
this.connection = connection;
|
||||
if (eventClientFactory == null) {
|
||||
eventClientFactory = new Callable<EventClient>() {
|
||||
public final EventClient call() throws Exception {
|
||||
return createEventClient(EventClientConnection.this.connection);
|
||||
}
|
||||
};
|
||||
}
|
||||
this.eventClientFactory = eventClientFactory;
|
||||
this.lock = new ReentrantLock();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>The MBean server connection through which the methods of
|
||||
* a proxy using this handler are forwarded.</p>
|
||||
*
|
||||
* @return the MBean server connection.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public MBeanServerConnection getMBeanServerConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new EventClientConnection proxy instance.
|
||||
*
|
||||
* @param <T> The underlying {@code MBeanServerConnection} - which should
|
||||
* not be using the Event Service itself.
|
||||
* @param interfaceClass {@code MBeanServerConnection.class}, or a subclass.
|
||||
* @param eventClientFactory a factory used to create the EventClient.
|
||||
* If null, a default factory is used (see {@link
|
||||
* #createEventClient}).
|
||||
* @return the new proxy instance, which will route add/remove notification
|
||||
* listener calls through an {@code EventClient}.
|
||||
*
|
||||
*/
|
||||
private static <T extends MBeanServerConnection> T
|
||||
newProxyInstance(T connection,
|
||||
Class<T> interfaceClass, Callable<EventClient> eventClientFactory) {
|
||||
final InvocationHandler handler =
|
||||
new EventClientConnection(connection,eventClientFactory);
|
||||
final Class<?>[] interfaces =
|
||||
new Class<?>[] {interfaceClass, EventClientFactory.class};
|
||||
|
||||
Object proxy =
|
||||
Proxy.newProxyInstance(interfaceClass.getClassLoader(),
|
||||
interfaces,
|
||||
handler);
|
||||
return interfaceClass.cast(proxy);
|
||||
}
|
||||
|
||||
|
||||
public Object invoke(Object proxy, Method method, Object[] args)
|
||||
throws Throwable {
|
||||
final String methodName = method.getName();
|
||||
|
||||
// add/remove notification listener are routed to the EventClient
|
||||
if (methodName.equals("addNotificationListener")
|
||||
|| methodName.equals("removeNotificationListener")) {
|
||||
final Class<?>[] sig = method.getParameterTypes();
|
||||
if (sig.length>1 &&
|
||||
NotificationListener.class.isAssignableFrom(sig[1])) {
|
||||
return invokeBroadcasterMethod(proxy,method,args);
|
||||
}
|
||||
}
|
||||
|
||||
// subscribe/unsubscribe are also routed to the EventClient.
|
||||
final Class<?> clazz = method.getDeclaringClass();
|
||||
if (clazz.equals(EventClientFactory.class)) {
|
||||
return invokeEventClientSubscriberMethod(proxy,method,args);
|
||||
}
|
||||
|
||||
// local or not: equals, toString, hashCode
|
||||
if (shouldDoLocally(proxy, method))
|
||||
return doLocally(proxy, method, args);
|
||||
|
||||
return call(connection,method,args);
|
||||
}
|
||||
|
||||
// The purpose of this method is to unwrap InvocationTargetException,
|
||||
// in order to avoid throwing UndeclaredThrowableException for
|
||||
// declared exceptions.
|
||||
//
|
||||
// When calling method.invoke(), any exception thrown by the invoked
|
||||
// method will be wrapped in InvocationTargetException. If we don't
|
||||
// unwrap this exception, the proxy will always throw
|
||||
// UndeclaredThrowableException, even for runtime exceptions.
|
||||
//
|
||||
private Object call(final Object obj, final Method m,
|
||||
final Object[] args)
|
||||
throws Throwable {
|
||||
try {
|
||||
return m.invoke(obj,args);
|
||||
} catch (InvocationTargetException x) {
|
||||
final Throwable xx = x.getTargetException();
|
||||
if (xx == null) throw x;
|
||||
else throw xx;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Route add/remove notification listener to the event client.
|
||||
**/
|
||||
private Object invokeBroadcasterMethod(Object proxy, Method method,
|
||||
Object[] args) throws Exception {
|
||||
final String methodName = method.getName();
|
||||
final int nargs = (args == null) ? 0 : args.length;
|
||||
|
||||
if (nargs < 1) {
|
||||
final String msg =
|
||||
"Bad arg count: " + nargs;
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
|
||||
final ObjectName mbean = (ObjectName) args[0];
|
||||
final EventClient evtClient = getEventClient();
|
||||
|
||||
// Fails if evtClient is null AND the MBean we try to listen to is
|
||||
// in a subnamespace. We fail here because we know this will not
|
||||
// work.
|
||||
//
|
||||
// Note that if the wrapped MBeanServerConnection points to a an
|
||||
// earlier agent (JDK 1.6 or earlier), then the EventClient will
|
||||
// be null (we can't use the event service with earlier JDKs).
|
||||
//
|
||||
// In principle a null evtClient indicates that the remote VM is of
|
||||
// an earlier version, in which case it shouldn't contain any namespace.
|
||||
//
|
||||
// So having a null evtClient AND an MBean contained in a namespace is
|
||||
// clearly an error case.
|
||||
//
|
||||
if (evtClient == null) {
|
||||
final String domain = mbean.getDomain();
|
||||
final int index = domain.indexOf(JMXNamespaces.NAMESPACE_SEPARATOR);
|
||||
if (index > -1 && index <
|
||||
(domain.length()-NAMESPACE_SEPARATOR_LENGTH)) {
|
||||
throw new UnsupportedOperationException(method.getName()+
|
||||
" on namespace "+domain.substring(0,index+
|
||||
NAMESPACE_SEPARATOR_LENGTH));
|
||||
}
|
||||
}
|
||||
|
||||
if (methodName.equals("addNotificationListener")) {
|
||||
/* The various throws of IllegalArgumentException here
|
||||
should not happen, since we know what the methods in
|
||||
NotificationBroadcaster and NotificationEmitter
|
||||
are. */
|
||||
if (nargs != 4) {
|
||||
final String msg =
|
||||
"Bad arg count to addNotificationListener: " + nargs;
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
/* Other inconsistencies will produce ClassCastException
|
||||
below. */
|
||||
|
||||
final NotificationListener listener = (NotificationListener) args[1];
|
||||
final NotificationFilter filter = (NotificationFilter) args[2];
|
||||
final Object handback = args[3];
|
||||
|
||||
if (evtClient != null) {
|
||||
// general case
|
||||
evtClient.addNotificationListener(mbean,listener,filter,handback);
|
||||
} else {
|
||||
// deprecated case. Only works for mbean in local namespace.
|
||||
connection.addNotificationListener(mbean,listener,filter,
|
||||
handback);
|
||||
}
|
||||
return null;
|
||||
|
||||
} else if (methodName.equals("removeNotificationListener")) {
|
||||
|
||||
/* NullPointerException if method with no args, but that
|
||||
shouldn't happen because removeNL does have args. */
|
||||
NotificationListener listener = (NotificationListener) args[1];
|
||||
|
||||
switch (nargs) {
|
||||
case 2:
|
||||
if (evtClient != null) {
|
||||
// general case
|
||||
evtClient.removeNotificationListener(mbean,listener);
|
||||
} else {
|
||||
// deprecated case. Only works for mbean in local namespace.
|
||||
connection.removeNotificationListener(mbean, listener);
|
||||
}
|
||||
return null;
|
||||
|
||||
case 4:
|
||||
NotificationFilter filter = (NotificationFilter) args[2];
|
||||
Object handback = args[3];
|
||||
if (evtClient != null) {
|
||||
evtClient.removeNotificationListener(mbean,
|
||||
listener,
|
||||
filter,
|
||||
handback);
|
||||
} else {
|
||||
connection.removeNotificationListener(mbean,
|
||||
listener,
|
||||
filter,
|
||||
handback);
|
||||
}
|
||||
return null;
|
||||
|
||||
default:
|
||||
final String msg =
|
||||
"Bad arg count to removeNotificationListener: " + nargs;
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new IllegalArgumentException("Bad method name: " +
|
||||
methodName);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldDoLocally(Object proxy, Method method) {
|
||||
final String methodName = method.getName();
|
||||
if ((methodName.equals("hashCode") || methodName.equals("toString"))
|
||||
&& method.getParameterTypes().length == 0
|
||||
&& isLocal(proxy, method))
|
||||
return true;
|
||||
if (methodName.equals("equals")
|
||||
&& Arrays.equals(method.getParameterTypes(),
|
||||
new Class<?>[] {Object.class})
|
||||
&& isLocal(proxy, method))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private Object doLocally(Object proxy, Method method, Object[] args) {
|
||||
final String methodName = method.getName();
|
||||
|
||||
if (methodName.equals("equals")) {
|
||||
|
||||
if (this == args[0]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(args[0] instanceof Proxy)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final InvocationHandler ihandler =
|
||||
Proxy.getInvocationHandler(args[0]);
|
||||
|
||||
if (ihandler == null ||
|
||||
!(ihandler instanceof EventClientConnection)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final EventClientConnection handler =
|
||||
(EventClientConnection)ihandler;
|
||||
|
||||
return connection.equals(handler.connection) &&
|
||||
proxy.getClass().equals(args[0].getClass());
|
||||
} else if (methodName.equals("hashCode")) {
|
||||
return connection.hashCode();
|
||||
}
|
||||
|
||||
throw new RuntimeException("Unexpected method name: " + methodName);
|
||||
}
|
||||
|
||||
private static boolean isLocal(Object proxy, Method method) {
|
||||
final Class<?>[] interfaces = proxy.getClass().getInterfaces();
|
||||
if(interfaces == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final String methodName = method.getName();
|
||||
final Class<?>[] params = method.getParameterTypes();
|
||||
for (Class<?> intf : interfaces) {
|
||||
try {
|
||||
intf.getMethod(methodName, params);
|
||||
return false; // found method in one of our interfaces
|
||||
} catch (NoSuchMethodException nsme) {
|
||||
// OK.
|
||||
}
|
||||
}
|
||||
|
||||
return true; // did not find in any interface
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the EventClient used by this object. Can be null if the
|
||||
* remote VM is of an earlier JDK version which doesn't have the
|
||||
* event service.<br>
|
||||
* This method will invoke the event client factory the first time
|
||||
* it is called.
|
||||
**/
|
||||
public final EventClient getEventClient() {
|
||||
if (initialized) return client;
|
||||
try {
|
||||
if (!lock.tryLock(TRYLOCK_TIMEOUT,TimeUnit.SECONDS))
|
||||
throw new IllegalStateException("can't acquire lock");
|
||||
try {
|
||||
client = eventClientFactory.call();
|
||||
initialized = true;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} catch (RuntimeException x) {
|
||||
throw x;
|
||||
} catch (Exception x) {
|
||||
throw new IllegalStateException("Can't create EventClient: "+x,x);
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an event client for the wrapped {@code MBeanServerConnection}.
|
||||
* This is the method invoked by the default event client factory.
|
||||
* @param connection the wrapped {@code MBeanServerConnection}.
|
||||
**/
|
||||
protected EventClient createEventClient(MBeanServerConnection connection)
|
||||
throws Exception {
|
||||
final ObjectName name =
|
||||
EventClientDelegate.OBJECT_NAME;
|
||||
if (connection.isRegistered(name)) {
|
||||
return new EventClient(connection);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link MBeanServerConnection} that goes through an
|
||||
* {@link EventClient} to receive/subscribe to notifications.
|
||||
* @param connection the underlying {@link MBeanServerConnection}.
|
||||
* The given <code>connection</code> shouldn't be already
|
||||
* using an {@code EventClient}.
|
||||
* @param eventClientFactory a factory object that will be invoked
|
||||
* to create an {@link EventClient} when needed.
|
||||
* The {@code EventClient} is created lazily, when it is needed
|
||||
* for the first time. If null, a default factory will be used
|
||||
* (see {@link #createEventClient}).
|
||||
* @return the MBeanServerConnection.
|
||||
**/
|
||||
public static MBeanServerConnection getEventConnectionFor(
|
||||
MBeanServerConnection connection,
|
||||
Callable<EventClient> eventClientFactory) {
|
||||
if (connection instanceof EventClientFactory
|
||||
&& eventClientFactory != null)
|
||||
throw new IllegalArgumentException("connection already uses EventClient");
|
||||
|
||||
if (connection instanceof EventClientFactory)
|
||||
return connection;
|
||||
|
||||
// create a new proxy using an event client.
|
||||
//
|
||||
if (LOG.isLoggable(Level.FINE))
|
||||
LOG.fine("Creating EventClient for: "+connection);
|
||||
return newProxyInstance(connection,
|
||||
MBeanServerConnection.class,
|
||||
eventClientFactory);
|
||||
}
|
||||
|
||||
private Object invokeEventClientSubscriberMethod(Object proxy,
|
||||
Method method, Object[] args) throws Throwable {
|
||||
return call(this,method,args);
|
||||
}
|
||||
|
||||
// Maximum lock timeout in seconds. Obviously arbitrary.
|
||||
//
|
||||
private final static short TRYLOCK_TIMEOUT = 3;
|
||||
|
||||
private final MBeanServerConnection connection;
|
||||
private final Callable<EventClient> eventClientFactory;
|
||||
private final Lock lock;
|
||||
private volatile EventClient client = null;
|
||||
private volatile boolean initialized = false;
|
||||
|
||||
}
|
||||
@ -40,6 +40,7 @@ import com.sun.management.HotSpotDiagnosticMXBean;
|
||||
import com.sun.management.UnixOperatingSystemMXBean;
|
||||
|
||||
import sun.management.ManagementFactoryHelper;
|
||||
import sun.management.Util;
|
||||
|
||||
/**
|
||||
* This enum class defines the list of platform components
|
||||
@ -384,7 +385,7 @@ enum PlatformComponent {
|
||||
// if there are more than 1 key properties (i.e. other than "type")
|
||||
domainAndType += ",*";
|
||||
}
|
||||
ObjectName on = ObjectName.valueOf(domainAndType);
|
||||
ObjectName on = Util.newObjectName(domainAndType);
|
||||
Set<ObjectName> set = mbs.queryNames(on, null);
|
||||
for (PlatformComponent pc : subComponents) {
|
||||
set.addAll(pc.getObjectNames(mbs));
|
||||
|
||||
@ -29,6 +29,7 @@ import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
/**
|
||||
@ -118,6 +119,10 @@ class Logging implements LoggingMXBean {
|
||||
}
|
||||
|
||||
public ObjectName getObjectName() {
|
||||
return ObjectName.valueOf(LogManager.LOGGING_MXBEAN_NAME);
|
||||
try {
|
||||
return ObjectName.getInstance(LogManager.LOGGING_MXBEAN_NAME);
|
||||
} catch (MalformedObjectNameException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,26 +104,4 @@ class AndQueryExp extends QueryEval implements QueryExp {
|
||||
public String toString() {
|
||||
return "(" + exp1 + ") and (" + exp2 + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
String toQueryString() {
|
||||
// Parentheses are only added if needed to disambiguate.
|
||||
return parens(exp1) + " and " + parens(exp2);
|
||||
}
|
||||
|
||||
// Add parens if needed to disambiguate an expression such as
|
||||
// Query.and(Query.or(a, b), c). We need to return
|
||||
// (a or b) and c
|
||||
// in such a case, because
|
||||
// a or b and c
|
||||
// would mean
|
||||
// a or (b and c)
|
||||
private static String parens(QueryExp exp) {
|
||||
String s = Query.toString(exp);
|
||||
if (exp instanceof OrQueryExp)
|
||||
return "(" + s + ")";
|
||||
else
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -137,56 +137,6 @@ public class AttributeList extends ArrayList<Object> {
|
||||
super.addAll(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Constructs an {@code AttributeList} containing the elements of
|
||||
* the {@code Map} specified, in the order in which they appear in the
|
||||
* {@code Map}'s {@link Map#entrySet entrySet}. For each <em>{@code
|
||||
* key}</em> and <em>{@code value}</em> in the {@code Map}, the constructed
|
||||
* {@code AttributeList} will contain {@link Attribute#Attribute
|
||||
* Attribute(<em>key</em>, <em>value</em>)}.</p>
|
||||
*
|
||||
* @param map the {@code Map} defining the elements of the new
|
||||
* {@code AttributeList}.
|
||||
*/
|
||||
public AttributeList(Map<String, ?> map) {
|
||||
for (Map.Entry<String, ?> entry : map.entrySet())
|
||||
add(new Attribute(entry.getKey(), entry.getValue()));
|
||||
typeSafe = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return a {@code Map} that is a snapshot of the values in this
|
||||
* {@code AttributeList}. Each key in the {@code Map} is the {@linkplain
|
||||
* Attribute#getName() name} of an {@code Attribute} in the list, and each
|
||||
* value is the corresponding {@linkplain Attribute#getValue() value} of
|
||||
* that {@code Attribute}. The {@code AttributeList} and the {@code Map}
|
||||
* are unrelated after the call, that is, changes to one do not affect the
|
||||
* other.</p>
|
||||
*
|
||||
* <p>If the {@code AttributeList} contains more than one {@code Attribute}
|
||||
* with the same name, then the {@code Map} will contain an entry
|
||||
* for that name where the value is that of the last of those {@code
|
||||
* Attribute}s.</p>
|
||||
*
|
||||
* @return the new {@code Map}.
|
||||
*
|
||||
* @throws IllegalArgumentException if this {@code AttributeList} contains
|
||||
* an element that is not an {@code Attribute}.
|
||||
*/
|
||||
public Map<String, Object> toMap() {
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
|
||||
// We can't call adding(this) because we're not necessarily typeSafe
|
||||
if (tainted)
|
||||
throw new IllegalArgumentException("AttributeList contains non-Attribute");
|
||||
|
||||
for (Object x : this) {
|
||||
Attribute a = (Attribute) x;
|
||||
map.put(a.getName(), a.getValue());
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a view of this list as a {@code List<Attribute>}.
|
||||
* Changes to the returned value are reflected by changes
|
||||
|
||||
@ -51,8 +51,6 @@ public class AttributeValueExp implements ValueExp {
|
||||
*/
|
||||
private String attr;
|
||||
|
||||
private transient int dotIndex;
|
||||
|
||||
/**
|
||||
* An <code>AttributeValueExp</code> with a null attribute.
|
||||
* @deprecated An instance created with this constructor cannot be
|
||||
@ -71,18 +69,6 @@ public class AttributeValueExp implements ValueExp {
|
||||
*/
|
||||
public AttributeValueExp(String attr) {
|
||||
this.attr = attr;
|
||||
setDotIndex();
|
||||
}
|
||||
|
||||
private void setDotIndex() {
|
||||
if (attr != null)
|
||||
dotIndex = attr.indexOf('.');
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in)
|
||||
throws ClassNotFoundException, IOException {
|
||||
in.defaultReadObject();
|
||||
setDotIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -134,7 +120,7 @@ public class AttributeValueExp implements ValueExp {
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return QueryParser.quoteId(attr);
|
||||
return attr;
|
||||
}
|
||||
|
||||
|
||||
@ -160,18 +146,6 @@ public class AttributeValueExp implements ValueExp {
|
||||
* If the attempt to access the attribute generates an exception,
|
||||
* return null.</p>
|
||||
*
|
||||
* <p>Let <em>n</em> be the {@linkplain #getAttributeName attribute
|
||||
* name}. Then this method proceeds as follows. First it calls
|
||||
* {@link MBeanServer#getAttribute getAttribute(name, <em>n</em>)}. If that
|
||||
* generates an {@link AttributeNotFoundException}, and if <em>n</em>
|
||||
* contains at least one dot ({@code .}), then the method calls {@code
|
||||
* getAttribute(name, }<em>n</em>{@code .substring(0, }<em>n</em>{@code
|
||||
* .indexOf('.')))}; in other words it calls {@code getAttribute}
|
||||
* with the substring of <em>n</em> before the first dot. Then it
|
||||
* extracts a component from the retrieved value, as described in the <a
|
||||
* href="monitor/package-summary.html#complex">documentation for the {@code
|
||||
* monitor} package</a>.</p>
|
||||
*
|
||||
* <p>The MBean Server used is the one returned by {@link
|
||||
* QueryEval#getMBeanServer()}.</p>
|
||||
*
|
||||
@ -186,34 +160,9 @@ public class AttributeValueExp implements ValueExp {
|
||||
|
||||
MBeanServer server = QueryEval.getMBeanServer();
|
||||
|
||||
try {
|
||||
return server.getAttribute(name, attr);
|
||||
} catch (AttributeNotFoundException e) {
|
||||
if (dotIndex < 0)
|
||||
throw e;
|
||||
}
|
||||
|
||||
String toGet = attr.substring(0, dotIndex);
|
||||
|
||||
Object value = server.getAttribute(name, toGet);
|
||||
|
||||
return extractElement(value, attr.substring(dotIndex + 1));
|
||||
} catch (Exception re) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Object extractElement(Object value, String elementWithDots)
|
||||
throws AttributeNotFoundException {
|
||||
while (true) {
|
||||
int dot = elementWithDots.indexOf('.');
|
||||
String element = (dot < 0) ?
|
||||
elementWithDots : elementWithDots.substring(0, dot);
|
||||
value = Introspector.elementFromComplex(value, element);
|
||||
if (dot < 0)
|
||||
return value;
|
||||
elementWithDots = elementWithDots.substring(dot + 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -139,9 +139,4 @@ class BetweenQueryExp extends QueryEval implements QueryExp {
|
||||
public String toString() {
|
||||
return "(" + exp1 + ") between (" + exp2 + ") and (" + exp3 + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
String toQueryString() {
|
||||
return exp1 + " between " + exp2 + " and " + exp3;
|
||||
}
|
||||
}
|
||||
|
||||
@ -253,7 +253,5 @@ class BinaryOpValueExp extends QueryEval implements ValueExp {
|
||||
@Deprecated
|
||||
public void setMBeanServer(MBeanServer s) {
|
||||
super.setMBeanServer(s);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -192,11 +192,6 @@ class BinaryRelQueryExp extends QueryEval implements QueryExp {
|
||||
return "(" + exp1 + ") " + relOpString() + " (" + exp2 + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
String toQueryString() {
|
||||
return exp1 + " " + relOpString() + " " + exp2;
|
||||
}
|
||||
|
||||
private String relOpString() {
|
||||
switch (relOp) {
|
||||
case Query.GT:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,180 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-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 javax.management;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* <p>The textual description of an MBean or part of an MBean. This
|
||||
* description is intended to be displayed to users to help them
|
||||
* understand what the MBean does. Ultimately it will be the value of
|
||||
* the {@code getDescription()} method of an {@link MBeanInfo}, {@link
|
||||
* MBeanAttributeInfo}, or similar.</p>
|
||||
*
|
||||
* <p>This annotation applies to Standard MBean interfaces and to
|
||||
* MXBean interfaces, as well as to MBean classes defined using the
|
||||
* {@link MBean @MBean} or {@link MXBean @MXBean} annotations. For
|
||||
* example, a Standard MBean might be defined like this:</p>
|
||||
*
|
||||
* <pre>
|
||||
* <b>{@code @Description}</b>("Application configuration")
|
||||
* public interface ConfigurationMBean {
|
||||
* <b>{@code @Description}</b>("Cache size in bytes")
|
||||
* public int getCacheSize();
|
||||
* public void setCacheSize(int size);
|
||||
*
|
||||
* <b>{@code @Description}</b>("Last time the configuration was changed, " +
|
||||
* "in milliseconds since 1 Jan 1970")
|
||||
* public long getLastChangedTime();
|
||||
*
|
||||
* <b>{@code @Description}</b>("Save the configuration to a file")
|
||||
* public void save(
|
||||
* <b>{@code @Description}</b>("Optional name of the file, or null for the default name")
|
||||
* String fileName);
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>The {@code MBeanInfo} for this MBean will have a {@link
|
||||
* MBeanInfo#getDescription() getDescription()} that is {@code
|
||||
* "Application configuration"}. It will contain an {@code
|
||||
* MBeanAttributeInfo} for the {@code CacheSize} attribute that is
|
||||
* defined by the methods {@code getCacheSize} and {@code
|
||||
* setCacheSize}, and another {@code MBeanAttributeInfo} for {@code
|
||||
* LastChangedTime}. The {@link MBeanAttributeInfo#getDescription()
|
||||
* getDescription()} for {@code CacheSize} will be {@code "Cache size
|
||||
* in bytes"}. Notice that there is no need to add a
|
||||
* {@code @Description} to both {@code getCacheSize} and {@code
|
||||
* setCacheSize} - either alone will do. But if you do add a
|
||||
* {@code @Description} to both, it must be the same.</p>
|
||||
*
|
||||
* <p>The {@code MBeanInfo} will also contain an {@link
|
||||
* MBeanOperationInfo} where {@link
|
||||
* MBeanOperationInfo#getDescription() getDescription()} is {@code
|
||||
* "Save the configuration to a file"}. This {@code
|
||||
* MBeanOperationInfo} will contain an {@link MBeanParameterInfo}
|
||||
* where {@link MBeanParameterInfo#getDescription() getDescription()}
|
||||
* is {@code "Optional name of the file, or null for the default
|
||||
* name"}.</p>
|
||||
*
|
||||
* <p>The {@code @Description} annotation can also be applied to the
|
||||
* public constructors of the implementation class. Continuing the
|
||||
* above example, the {@code Configuration} class implementing {@code
|
||||
* ConfigurationMBean} might look like this:</p>
|
||||
*
|
||||
* <pre>
|
||||
* public class Configuration implements ConfigurationMBean {
|
||||
* <b>{@code @Description}</b>("A Configuration MBean with the default file name")
|
||||
* public Configuration() {
|
||||
* this(DEFAULT_FILE_NAME);
|
||||
* }
|
||||
*
|
||||
* <b>{@code @Description}</b>("A Configuration MBean with a specified file name")
|
||||
* public Configuration(
|
||||
* <b>{@code @Description}</b>("Name of the file the configuration is stored in")
|
||||
* String fileName) {...}
|
||||
* ...
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>The {@code @Description} annotation also works in MBeans that
|
||||
* are defined using the {@code @MBean} or {@code @MXBean} annotation
|
||||
* on classes. Here is an alternative implementation of {@code
|
||||
* Configuration} that does not use an {@code ConfigurationMBean}
|
||||
* interface.</p>
|
||||
*
|
||||
* <pre>
|
||||
* <b>{@code @MBean}</b>
|
||||
* <b>{@code @Description}</b>("Application configuration")
|
||||
* public class Configuration {
|
||||
* <b>{@code @Description}</b>("A Configuration MBean with the default file name")
|
||||
* public Configuration() {
|
||||
* this(DEFAULT_FILE_NAME);
|
||||
* }
|
||||
*
|
||||
* <b>{@code @Description}</b>("A Configuration MBean with a specified file name")
|
||||
* public Configuration(
|
||||
* <b>{@code @Description}</b>("Name of the file the configuration is stored in")
|
||||
* String fileName) {...}
|
||||
*
|
||||
* <b>{@code @ManagedAttribute}</b>
|
||||
* <b>{@code @Description}</b>("Cache size in bytes")
|
||||
* public int getCacheSize() {...}
|
||||
* <b>{@code @ManagedAttribute}</b>
|
||||
* public void setCacheSize(int size) {...}
|
||||
*
|
||||
* <b>{@code @ManagedOperation}</b>
|
||||
* <b>{@code @Description}</b>("Last time the configuration was changed, " +
|
||||
* "in milliseconds since 1 Jan 1970")
|
||||
* public long getLastChangedTime() {...}
|
||||
*
|
||||
* <b>{@code @ManagedOperation}</b>
|
||||
* <b>{@code @Description}</b>("Save the configuration to a file")
|
||||
* public void save(
|
||||
* <b>{@code @Description}</b>("Optional name of the file, or null for the default name")
|
||||
* String fileName) {...}
|
||||
* ...
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER,
|
||||
ElementType.TYPE})
|
||||
public @interface Description {
|
||||
/**
|
||||
* <p>The description.</p>
|
||||
*/
|
||||
String value();
|
||||
|
||||
/**
|
||||
* <p>The base name for the {@link ResourceBundle} in which the key given in
|
||||
* the {@code descriptionResourceKey} field can be found, for example
|
||||
* {@code "com.example.myapp.MBeanResources"}. If a non-default value
|
||||
* is supplied for this element, it will appear in the
|
||||
* <a href="Descriptor.html#descriptionResourceBundleBaseName"><!--
|
||||
* -->{@code Descriptor}</a> for the annotated item.</p>
|
||||
*/
|
||||
@DescriptorKey(
|
||||
value = "descriptionResourceBundleBaseName", omitIfDefault = true)
|
||||
String bundleBaseName() default "";
|
||||
|
||||
/**
|
||||
* <p>A resource key for the description of this element. In
|
||||
* conjunction with the {@link #bundleBaseName bundleBaseName},
|
||||
* this can be used to find a localized version of the description.
|
||||
* If a non-default value
|
||||
* is supplied for this element, it will appear in the
|
||||
* <a href="Descriptor.html#descriptionResourceKey"><!--
|
||||
* -->{@code Descriptor}</a> for the annotated item.</p>
|
||||
*/
|
||||
@DescriptorKey(value = "descriptionResourceKey", omitIfDefault = true)
|
||||
String key() default "";
|
||||
}
|
||||
@ -38,7 +38,6 @@ import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.ResourceBundle;
|
||||
import javax.management.openmbean.CompositeData;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
|
||||
import javax.management.openmbean.OpenMBeanOperationInfoSupport;
|
||||
import javax.management.openmbean.OpenMBeanParameterInfoSupport;
|
||||
@ -118,22 +117,23 @@ import javax.management.openmbean.OpenType;
|
||||
* deprecation, for example {@code "1.3 Replaced by the Capacity
|
||||
* attribute"}.</td>
|
||||
*
|
||||
* <tr><td id="descriptionResourceBundleBaseName"><i>descriptionResource<br>
|
||||
* BundleBaseName</i></td><td>String</td><td>Any</td>
|
||||
* <tr><td id="descriptionResourceBundleBaseName">descriptionResource<br>
|
||||
* BundleBaseName</td><td>String</td><td>Any</td>
|
||||
*
|
||||
* <td>The base name for the {@link ResourceBundle} in which the key given in
|
||||
* the {@code descriptionResourceKey} field can be found, for example
|
||||
* {@code "com.example.myapp.MBeanResources"}. See
|
||||
* {@link MBeanInfo#localizeDescriptions MBeanInfo.localizeDescriptions}.</td>
|
||||
* {@code "com.example.myapp.MBeanResources"}. The meaning of this
|
||||
* field is defined by this specification but the field is not set or
|
||||
* used by the JMX API itself.</td>
|
||||
*
|
||||
* <tr><td id="descriptionResourceKey"><i>descriptionResourceKey</i></td>
|
||||
* <tr><td id="descriptionResourceKey">descriptionResourceKey</td>
|
||||
* <td>String</td><td>Any</td>
|
||||
*
|
||||
* <td>A resource key for the description of this element. In
|
||||
* conjunction with the {@code descriptionResourceBundleBaseName},
|
||||
* this can be used to find a localized version of the description.
|
||||
* See {@link MBeanInfo#localizeDescriptions MBeanInfo.localizeDescriptions}.
|
||||
* </td>
|
||||
* The meaning of this field is defined by this specification but the
|
||||
* field is not set or used by the JMX API itself.</td>
|
||||
*
|
||||
* <tr><td>enabled</td><td>String</td>
|
||||
* <td>MBeanAttributeInfo<br>MBeanNotificationInfo<br>MBeanOperationInfo</td>
|
||||
@ -147,31 +147,16 @@ import javax.management.openmbean.OpenType;
|
||||
* might be disabled if it cannot currently be emitted but could be in
|
||||
* other circumstances.</td>
|
||||
*
|
||||
* <tr id="exceptions"><td><i>exceptions</i><td>String[]</td>
|
||||
* <tr id="exceptions"><td>exceptions<td>String[]</td>
|
||||
* <td>MBeanAttributeInfo, MBeanConstructorInfo, MBeanOperationInfo</td>
|
||||
*
|
||||
* <td>The class names of the exceptions that can be thrown when invoking a
|
||||
* constructor or operation, or getting an attribute. Exceptions thrown when
|
||||
* constructor or operation, or getting an attribute. The meaning of this field
|
||||
* is defined by this specification but the field is not set or used by the
|
||||
* JMX API itself. Exceptions thrown when
|
||||
* setting an attribute are specified by the field
|
||||
* <a href="#setExceptions">{@code setExceptions}</a>.
|
||||
*
|
||||
* <tr id="exceptionErrorCodes"><td>exceptionErrorCodes</td><td>String[]</td>
|
||||
* <td>MBeanAttributeInfo<br>MBeanConstructorInfo<br>MBeanOperationInfo</td>
|
||||
*
|
||||
* <td>The {@linkplain GenericMBeanException#getErrorCode() error codes}
|
||||
* that can appear in a {@link GenericMBeanException} thrown when getting
|
||||
* this attribute or invoking this operation or constructor. See also
|
||||
* <a href="#setExceptionErrorCodes">{@code setExceptionErrorCodes}</a>.
|
||||
*
|
||||
* <tr id="exceptionUserDataTypes"><td>exceptionUserDataTypes</td>
|
||||
* <td>{@link javax.management.openmbean.CompositeType}[]</td>
|
||||
* <td>MBeanAttributeInfo<br>MBeanConstructorInfo<br>MBeanOperationInfo</td>
|
||||
*
|
||||
* <td>The types of {@linkplain GenericMBeanException#getUserData() userData}
|
||||
* that can appear in a {@link GenericMBeanException} thrown when getting
|
||||
* this attribute or invoking this operation or constructor. See also
|
||||
* <a href="#setExceptionUserDataTypes">{@code setExceptionUserDataTypes}</a>.
|
||||
*
|
||||
* <tr id="immutableInfo"><td><i>immutableInfo</i><td>String</td>
|
||||
* <td>MBeanInfo</td>
|
||||
*
|
||||
@ -213,7 +198,7 @@ import javax.management.openmbean.OpenType;
|
||||
* <td>Legal values for an attribute or parameter. See
|
||||
* {@link javax.management.openmbean}.</td>
|
||||
*
|
||||
* <tr id="locale"><td><i>locale</i></td>
|
||||
* <tr id="locale"><td>locale</td>
|
||||
* <td>String</td><td>Any</td>
|
||||
*
|
||||
* <td>The {@linkplain Locale locale} of the description in this
|
||||
@ -254,21 +239,6 @@ import javax.management.openmbean.OpenType;
|
||||
* StandardMBean} class will have this field in its MBeanInfo
|
||||
* Descriptor.</td>
|
||||
*
|
||||
* <tr><td id="mxbeanMappingFactoryClass"><i>mxbeanMappingFactoryClass</i>
|
||||
* </td><td>String</td>
|
||||
* <td>MBeanInfo</td>
|
||||
*
|
||||
* <td>The name of the {@link MXBeanMappingFactory} class that was used for this
|
||||
* MXBean, if it was not the {@linkplain MXBeanMappingFactory#DEFAULT default}
|
||||
* one.</td>
|
||||
*
|
||||
* <tr><td id="objectNameTemplate"><i>objectNameTemplate</i>
|
||||
* </td><td>String</td>
|
||||
* <td>MBeanInfo</td>
|
||||
*
|
||||
* <td>The template to use to name this MBean. Its value must be compliant with
|
||||
* the specification of the {@link ObjectNameTemplate} annotation.</td>
|
||||
*
|
||||
* <tr id="openType"><td><i>openType</i><td>{@link OpenType}</td>
|
||||
* <td>MBeanAttributeInfo<br>MBeanOperationInfo<br>MBeanParameterInfo</td>
|
||||
*
|
||||
@ -306,26 +276,11 @@ import javax.management.openmbean.OpenType;
|
||||
* <td>MBeanAttributeInfo</td>
|
||||
*
|
||||
* <td>The class names of the exceptions that can be thrown when setting
|
||||
* an attribute. Exceptions thrown when getting an attribute are specified
|
||||
* an attribute. The meaning of this field
|
||||
* is defined by this specification but the field is not set or used by the
|
||||
* JMX API itself. Exceptions thrown when getting an attribute are specified
|
||||
* by the field <a href="#exceptions">{@code exceptions}</a>.
|
||||
*
|
||||
* <tr id="setExceptionErrorCodes"><td>setExceptionErrorCodes</td>
|
||||
* <td>String[]</td><td>MBeanAttributeInfo</td>
|
||||
*
|
||||
* <td>The {@linkplain GenericMBeanException#getErrorCode() error codes}
|
||||
* that can appear in a {@link GenericMBeanException} thrown when setting
|
||||
* this attribute. See also
|
||||
* <a href="#exceptionErrorCodes">{@code exceptionErrorCodes}</a>.
|
||||
*
|
||||
* <tr id="setExceptionUserDataTypes"><td>setExceptionUserDataTypes</td>
|
||||
* <td>{@link javax.management.openmbean.CompositeType}[]</td>
|
||||
* <td>MBeanAttributeInfo</td>
|
||||
*
|
||||
* <td>The types of {@linkplain GenericMBeanException#getUserData() userData}
|
||||
* that can appear in a {@link GenericMBeanException} thrown when setting
|
||||
* this attribute. See also
|
||||
* <a href="#exceptionUserDataTypes">{@code exceptionUserDataTypes}</a>.
|
||||
*
|
||||
* <tr><td>severity</td><td>String<br>Integer</td>
|
||||
* <td>MBeanNotificationInfo</td>
|
||||
*
|
||||
|
||||
@ -1,137 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-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 javax.management;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* <p>Annotation that adds fields to a {@link Descriptor}. This can be the
|
||||
* Descriptor for an MBean, or for an attribute, operation, or constructor
|
||||
* in an MBean, or for a parameter of an operation or constructor.</p>
|
||||
*
|
||||
* <p>Consider this Standard MBean interface, for example:</p>
|
||||
*
|
||||
* <pre>
|
||||
* public interface CacheControlMBean {
|
||||
* <b>@DescriptorFields("units=bytes")</b>
|
||||
* public long getCacheSize();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>When a Standard MBean is made using this interface, the usual rules
|
||||
* mean that it will have an attribute called {@code CacheSize} of type
|
||||
* {@code long}. The {@code DescriptorFields} annotation will ensure
|
||||
* that the {@link MBeanAttributeInfo} for this attribute will have a
|
||||
* {@code Descriptor} that has a field called {@code units} with
|
||||
* corresponding value {@code bytes}.</p>
|
||||
*
|
||||
* <p>Similarly, if the interface looks like this:</p>
|
||||
*
|
||||
* <pre>
|
||||
* public interface CacheControlMBean {
|
||||
* <b>@DescriptorFields({"units=bytes", "since=1.5"})</b>
|
||||
* public long getCacheSize();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>then the resulting {@code Descriptor} will contain the following
|
||||
* fields:</p>
|
||||
*
|
||||
* <table border="2">
|
||||
* <tr><th>Name</th><th>Value</th></tr>
|
||||
* <tr><td>units</td><td>"bytes"</td></tr>
|
||||
* <tr><td>since</td><td>"1.5"</td></tr>
|
||||
* </table>
|
||||
*
|
||||
* <p>The {@code @DescriptorFields} annotation can be applied to:</p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>a Standard MBean or MXBean interface;
|
||||
* <li>a method in such an interface;
|
||||
* <li>a parameter of a method in a Standard MBean or MXBean interface
|
||||
* when that method is an operation (not a getter or setter for an attribute);
|
||||
* <li>a public constructor in the class that implements a Standard MBean
|
||||
* or MXBean;
|
||||
* <li>a parameter in such a constructor.
|
||||
* </ul>
|
||||
*
|
||||
* <p>Other uses of the annotation will either fail to compile or be
|
||||
* ignored.</p>
|
||||
*
|
||||
* <p>Interface annotations are checked only on the exact interface
|
||||
* that defines the management interface of a Standard MBean or an
|
||||
* MXBean, not on its parent interfaces. Method annotations are
|
||||
* checked only in the most specific interface in which the method
|
||||
* appears; in other words, if a child interface overrides a method
|
||||
* from a parent interface, only {@code @DescriptorFields} annotations in
|
||||
* the method in the child interface are considered.
|
||||
*
|
||||
* <p>The Descriptor fields contributed in this way must be consistent
|
||||
* with each other and with any fields contributed by {@link
|
||||
* DescriptorKey @DescriptorKey} annotations. That is, two
|
||||
* different annotations, or two members of the same annotation, must
|
||||
* not define a different value for the same Descriptor field. Fields
|
||||
* from annotations on a getter method must also be consistent with
|
||||
* fields from annotations on the corresponding setter method.</p>
|
||||
*
|
||||
* <p>The Descriptor resulting from these annotations will be merged
|
||||
* with any Descriptor fields provided by the implementation, such as
|
||||
* the <a href="Descriptor.html#immutableInfo">{@code
|
||||
* immutableInfo}</a> field for an MBean. The fields from the annotations
|
||||
* must be consistent with these fields provided by the implementation.</p>
|
||||
*
|
||||
* <h4>{@literal @DescriptorFields and @DescriptorKey}</h4>
|
||||
*
|
||||
* <p>The {@link DescriptorKey @DescriptorKey} annotation provides
|
||||
* another way to use annotations to define Descriptor fields.
|
||||
* <code>@DescriptorKey</code> requires more work but is also more
|
||||
* robust, because there is less risk of mistakes such as misspelling
|
||||
* the name of the field or giving an invalid value.
|
||||
* <code>@DescriptorFields</code> is more convenient but includes
|
||||
* those risks. <code>@DescriptorFields</code> is more
|
||||
* appropriate for occasional use, but for a Descriptor field that you
|
||||
* add in many places, you should consider a purpose-built annotation
|
||||
* using <code>@DescriptorKey</code>.
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
@Documented
|
||||
@Inherited // for @MBean and @MXBean classes
|
||||
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD,
|
||||
ElementType.PARAMETER, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DescriptorFields {
|
||||
/**
|
||||
* <p>The descriptor fields. Each element of the string looks like
|
||||
* {@code "name=value"}.</p>
|
||||
*/
|
||||
public String[] value();
|
||||
}
|
||||
@ -33,11 +33,6 @@ import java.lang.annotation.*;
|
||||
* an MBean, or for an attribute, operation, or constructor in an
|
||||
* MBean, or for a parameter of an operation or constructor.</p>
|
||||
*
|
||||
* <p>(The {@link DescriptorFields @DescriptorFields} annotation
|
||||
* provides another way to add fields to a {@code Descriptor}. See
|
||||
* the documentation for that annotation for a comparison of the
|
||||
* two possibilities.)</p>
|
||||
*
|
||||
* <p>Consider this annotation for example:</p>
|
||||
*
|
||||
* <pre>
|
||||
@ -130,13 +125,12 @@ import java.lang.annotation.*;
|
||||
* the method in the child interface are considered.
|
||||
*
|
||||
* <p>The Descriptor fields contributed in this way by different
|
||||
* annotations on the same program element must be consistent with
|
||||
* each other and with any fields contributed by a {@link
|
||||
* DescriptorFields @DescriptorFields} annotation. That is, two
|
||||
* different annotations, or two members of the same annotation, must
|
||||
* not define a different value for the same Descriptor field. Fields
|
||||
* from annotations on a getter method must also be consistent with
|
||||
* fields from annotations on the corresponding setter method.</p>
|
||||
* annotations on the same program element must be consistent. That
|
||||
* is, two different annotations, or two members of the same
|
||||
* annotation, must not define a different value for the same
|
||||
* Descriptor field. Fields from annotations on a getter method must
|
||||
* also be consistent with fields from annotations on the
|
||||
* corresponding setter method.</p>
|
||||
*
|
||||
* <p>The Descriptor resulting from these annotations will be merged
|
||||
* with any Descriptor fields provided by the implementation, such as
|
||||
@ -175,36 +169,4 @@ import java.lang.annotation.*;
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface DescriptorKey {
|
||||
String value();
|
||||
|
||||
/**
|
||||
* <p>Do not include this field in the Descriptor if the annotation
|
||||
* element has its default value. For example, suppose {@code @Units} is
|
||||
* defined like this:</p>
|
||||
*
|
||||
* <pre>
|
||||
* @Documented
|
||||
* @Target(ElementType.METHOD)
|
||||
* @Retention(RetentionPolicy.RUNTIME)
|
||||
* public @interface Units {
|
||||
* @DescriptorKey("units")
|
||||
* String value();
|
||||
*
|
||||
* <b>@DescriptorKey(value = "descriptionResourceKey",
|
||||
* omitIfDefault = true)</b>
|
||||
* String resourceKey() default "";
|
||||
*
|
||||
* <b>@DescriptorKey(value = "descriptionResourceBundleBaseName",
|
||||
* omitIfDefault = true)</b>
|
||||
* String resourceBundleBaseName() default "";
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>Then consider a usage such as {@code @Units("bytes")} or
|
||||
* {@code @Units(value = "bytes", resourceKey = "")}, where the
|
||||
* {@code resourceKey} and {@code resourceBundleBaseNames} elements
|
||||
* have their default values. In this case the Descriptor resulting
|
||||
* from these annotations will not include a {@code descriptionResourceKey}
|
||||
* or {@code descriptionResourceBundleBaseName} field.</p>
|
||||
*/
|
||||
boolean omitIfDefault() default false;
|
||||
}
|
||||
|
||||
@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright 2005-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 javax.management;
|
||||
|
||||
/**
|
||||
* <p>An MBean can implement this interface to affect how the MBeanServer's
|
||||
* {@link MBeanServer#getClassLoaderFor getClassLoaderFor} and
|
||||
* {@link MBeanServer#isInstanceOf isInstanceOf} methods behave.
|
||||
* If these methods should refer to a wrapped object rather than the
|
||||
* MBean object itself, then the {@link #getWrappedObject} method should
|
||||
* return that wrapped object.</p>
|
||||
*
|
||||
* @see MBeanServer#getClassLoaderFor
|
||||
* @see MBeanServer#isInstanceOf
|
||||
*/
|
||||
public interface DynamicWrapperMBean extends DynamicMBean {
|
||||
/**
|
||||
* <p>The resource corresponding to this MBean. This is the object whose
|
||||
* class name should be reflected by the MBean's
|
||||
* {@link MBeanServer#getMBeanInfo getMBeanInfo()}.<!--
|
||||
* -->{@link MBeanInfo#getClassName getClassName()} for example. For a "plain"
|
||||
* DynamicMBean it will be "this". For an MBean that wraps another
|
||||
* object, in the manner of {@link javax.management.StandardMBean}, it will be the
|
||||
* wrapped object.</p>
|
||||
*
|
||||
* @return The resource corresponding to this MBean.
|
||||
*/
|
||||
public Object getWrappedObject();
|
||||
|
||||
/**
|
||||
* <p>The {@code ClassLoader} for this MBean, which can be used to
|
||||
* retrieve resources associated with the MBean for example. Usually,
|
||||
* it will be
|
||||
* {@link #getWrappedObject()}.{@code getClass().getClassLoader()}.
|
||||
*
|
||||
* @return The {@code ClassLoader} for this MBean.
|
||||
*/
|
||||
public ClassLoader getWrappedClassLoader();
|
||||
}
|
||||
@ -1,276 +0,0 @@
|
||||
/*
|
||||
* 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 javax.management;
|
||||
|
||||
import javax.management.openmbean.CompositeData;
|
||||
|
||||
/**
|
||||
* <p>A customizable exception that has an optional error code string and
|
||||
* payload. By using this exception in an MBean, you can avoid requiring
|
||||
* clients of the MBean to have custom exception classes.</p>
|
||||
*
|
||||
* <p>An instance of this class has an optional {@linkplain #getErrorCode()
|
||||
* error code}, and an optional {@linkplain #getUserData() payload} known as
|
||||
* {@code userData}. This allows you to distinguish between different
|
||||
* sorts of exception while still using this class for all of them.</p>
|
||||
*
|
||||
* <p>To produce a suitable {@code userData}, it is often simplest to use
|
||||
* the MXBean framework. For example, suppose you want to convey a severity
|
||||
* and a subsystem with your exception, which are respectively an int and a
|
||||
* String. You could define a class like this:</p>
|
||||
*
|
||||
* <pre>
|
||||
* public class ExceptionDetails {
|
||||
* private final int severity;
|
||||
* private final String subsystem;
|
||||
*
|
||||
* {@link java.beans.ConstructorProperties @ConstructorProperties}(<!--
|
||||
* -->{"severity", "subsystem"})
|
||||
* public ExceptionDetails(int severity, String subsystem) {
|
||||
* this.severity = severity;
|
||||
* this.subsystem = subsystem;
|
||||
* }
|
||||
*
|
||||
* public int getSeverity() {
|
||||
* return severity;
|
||||
* }
|
||||
*
|
||||
* public String getSubsystem() {
|
||||
* return subsystem;
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>Then you can get the MXBean framework to transform {@code ExceptionDetails}
|
||||
* into {@link CompositeData} like this:</p>
|
||||
*
|
||||
* <pre>
|
||||
* static final <!--
|
||||
* -->{@link javax.management.openmbean.MXBeanMapping MXBeanMapping} <!--
|
||||
* -->exceptionDetailsMapping = <!--
|
||||
* -->{@link javax.management.openmbean.MXBeanMappingFactory#DEFAULT
|
||||
* MXBeanMappingFactory.DEFAULT}.mappingForType(
|
||||
* ExceptionDetails.class, MXBeanMappingFactory.DEFAULT);
|
||||
*
|
||||
* public static GenericMBeanException newGenericMBeanException(
|
||||
* String message, String errorCode, int severity, String subsystem) {
|
||||
* ExceptionDetails details = new ExceptionDetails(severity, subsystem);
|
||||
* CompositeData userData = (CompositeData)
|
||||
* exceptionDetailsMapping.toOpenValue(details);
|
||||
* return new GenericMBeanException(
|
||||
* message, errorCode, userData, (Throwable) null);
|
||||
* }
|
||||
*
|
||||
* ...
|
||||
* throw newGenericMBeanException(message, errorCode, 25, "foosystem");
|
||||
* </pre>
|
||||
*
|
||||
* <p>A client that knows the {@code ExceptionDetails} class can convert
|
||||
* back from the {@code userData} of a {@code GenericMBeanException}
|
||||
* that was generated as above:</p>
|
||||
*
|
||||
* <pre>
|
||||
* ...
|
||||
* try {
|
||||
* mbeanProxy.foo();
|
||||
* } catch (GenericMBeanException e) {
|
||||
* CompositeData userData = e.getUserData();
|
||||
* ExceptionDetails details = (ExceptionDetails)
|
||||
* exceptionDetailsMapping.fromOpenValue(userData);
|
||||
* System.out.println("Exception Severity: " + details.getSeverity());
|
||||
* }
|
||||
* ...
|
||||
* </pre>
|
||||
*
|
||||
* <p>The Descriptor field <a href="Descriptor.html#exceptionErrorCodes"><!--
|
||||
* -->exceptionErrorCodes</a> can be used to specify in the
|
||||
* {@link MBeanOperationInfo} for an operation what the possible
|
||||
* {@linkplain #getErrorCode() error codes} are when that operation throws
|
||||
* {@code GenericMBeanException}. It can also be used in an {@link
|
||||
* MBeanConstructorInfo} or {@link MBeanAttributeInfo} to specify what the
|
||||
* possible error codes are for {@code GenericMBeanException} when invoking
|
||||
* that constructor or getting that attribute, respectively. The field
|
||||
* <a href="Descriptor.html#setExceptionErrorCodes"><!--
|
||||
* -->setExceptionErrorCodes</a> can be used to specify what the possible
|
||||
* error codes are when setting an attribute.</p>
|
||||
*
|
||||
* <p>You may want to use the {@link DescriptorKey @DescriptorKey} facility
|
||||
* to define annotations that allow you to specify the error codes. If you
|
||||
* define...</p>
|
||||
*
|
||||
* <pre>
|
||||
* {@link java.lang.annotation.Documented @Documented}
|
||||
* {@link java.lang.annotation.Target @Target}(ElementType.METHOD)
|
||||
* {@link java.lang.annotation.Retention @Retention}(RetentionPolicy.RUNTIME)
|
||||
* public @interface ErrorCodes {
|
||||
* @DescriptorKey("exceptionErrorCodes")
|
||||
* String[] value();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>...then you can write MBean interfaces like this...</p>
|
||||
*
|
||||
* <pre>
|
||||
* public interface FooMBean { // or FooMXBean
|
||||
* @ErrorCodes({"com.example.bad", "com.example.worse"})
|
||||
* public void foo() throws GenericMBeanException;
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>The Descriptor field <a href="Descriptor.html#exceptionUserDataTypes"><!--
|
||||
* -->exceptionUserDataTypes</a> can be used to specify in the
|
||||
* {@link MBeanOperationInfo} for an operation what the possible types of
|
||||
* {@linkplain #getUserData() userData} are when that operation throws
|
||||
* {@code GenericMBeanException}. It is an array of
|
||||
* {@link javax.management.openmbean.CompositeType CompositeType} values
|
||||
* describing the possible {@link CompositeData} formats. This field can also be used
|
||||
* in an {@link MBeanConstructorInfo} or {@link MBeanAttributeInfo} to specify
|
||||
* the possible types of user data for {@code GenericMBeanException} when
|
||||
* invoking that constructor or getting that attribute, respectively. The
|
||||
* field
|
||||
* <a href="Descriptor.html#setExceptionUserDataTypes">setExceptionUserDataTypes</a>
|
||||
* can be used to specify the possible types of user data for exceptions when
|
||||
* setting an attribute. If a Descriptor has both {@code exceptionErrorCodes}
|
||||
* and {@code exceptionUserDataTypes} then the two arrays should be the
|
||||
* same size; each pair of corresponding elements describes one kind
|
||||
* of exception. Similarly for {@code setExceptionErrorCodes} and {@code
|
||||
* setExceptionUserDataTypes}.
|
||||
*
|
||||
*
|
||||
* <h4>Serialization</h4>
|
||||
*
|
||||
* <p>For compatibility reasons, instances of this class are serialized as
|
||||
* instances of {@link MBeanException}. Special logic in that class converts
|
||||
* them back to instances of this class at deserialization time. If the
|
||||
* serialized object is deserialized in an earlier version of the JMX API
|
||||
* that does not include this class, then it will appear as just an {@code
|
||||
* MBeanException} and the error code or userData will not be available.</p>
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public class GenericMBeanException extends MBeanException {
|
||||
private static final long serialVersionUID = -1560202003985932823L;
|
||||
|
||||
/**
|
||||
* <p>Constructs a new {@code GenericMBeanException} with the given
|
||||
* detail message. This constructor is
|
||||
* equivalent to {@link #GenericMBeanException(String, String,
|
||||
* CompositeData, Throwable) GenericMBeanException(message, "",
|
||||
* null, null)}.</p>
|
||||
*
|
||||
* @param message the exception detail message.
|
||||
*/
|
||||
public GenericMBeanException(String message) {
|
||||
this(message, "", null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Constructs a new {@code GenericMBeanException} with the given
|
||||
* detail message and cause. This constructor is
|
||||
* equivalent to {@link #GenericMBeanException(String, String,
|
||||
* CompositeData, Throwable) GenericMBeanException(message, "",
|
||||
* null, cause)}.</p>
|
||||
*
|
||||
* @param message the exception detail message.
|
||||
* @param cause the cause of this exception. Can be null.
|
||||
*/
|
||||
public GenericMBeanException(String message, Throwable cause) {
|
||||
this(message, "", null, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Constructs a new {@code GenericMBeanException} with the given
|
||||
* detail message, error code, and user data. This constructor is
|
||||
* equivalent to {@link #GenericMBeanException(String, String,
|
||||
* CompositeData, Throwable) GenericMBeanException(message, errorCode,
|
||||
* userData, null)}.</p>
|
||||
*
|
||||
* @param message the exception detail message.
|
||||
* @param errorCode the exception error code. Specifying a null value
|
||||
* is equivalent to specifying an empty string. It is recommended to use
|
||||
* the same reverse domain name convention as package names, for example
|
||||
* "com.example.foo.UnexpectedFailure". There is no requirement that the
|
||||
* error code be a syntactically valid Java identifier.
|
||||
* @param userData extra information about the exception. Can be null.
|
||||
*/
|
||||
public GenericMBeanException(
|
||||
String message, String errorCode, CompositeData userData) {
|
||||
this(message, errorCode, userData, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Constructs a new {@code GenericMBeanException} with the given
|
||||
* detail message, error code, user data, and cause.</p>
|
||||
*
|
||||
* @param message the exception detail message.
|
||||
* @param errorCode the exception error code. Specifying a null value
|
||||
* is equivalent to specifying an empty string. It is recommended to use
|
||||
* the same reverse domain name convention as package names, for example
|
||||
* "com.example.foo.UnexpectedFailure". There is no requirement that the
|
||||
* error code be a syntactically valid Java identifier.
|
||||
* @param userData extra information about the exception. Can be null.
|
||||
* @param cause the cause of this exception. Can be null.
|
||||
*/
|
||||
public GenericMBeanException(
|
||||
String message, String errorCode, CompositeData userData,
|
||||
Throwable cause) {
|
||||
super(message, (errorCode == null) ? "" : errorCode, userData, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the error code of this exception.</p>
|
||||
*
|
||||
* @return the error code. This value is never null.
|
||||
*/
|
||||
public String getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the userData of this exception.</p>
|
||||
*
|
||||
* @return the userData. Can be null.
|
||||
*/
|
||||
public CompositeData getUserData() {
|
||||
return userData;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Instances of this class are serialized as instances of
|
||||
* {@link MBeanException}. {@code MBeanException} has private fields that can
|
||||
* not be set by its public constructors. They can only be set in objects
|
||||
* returned by this method. When an {@code MBeanException} instance is
|
||||
* deserialized, if those fields are present then its {@code readResolve}
|
||||
* method will substitute a {@code GenericMBeanException} equivalent to
|
||||
* this one.</p>
|
||||
*/
|
||||
Object writeReplace() {
|
||||
MBeanException x = new MBeanException(
|
||||
getMessage(), errorCode, userData, getCause());
|
||||
x.setStackTrace(this.getStackTrace());
|
||||
return x;
|
||||
}
|
||||
}
|
||||
@ -1,105 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-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 javax.management;
|
||||
|
||||
/**
|
||||
* <p>Defines the impact of an MBean operation, in particular whether it
|
||||
* has an effect on the MBean or simply returns information. This enum
|
||||
* is used in the {@link ManagedOperation @ManagedOperation} annotation.
|
||||
* Its {@link #getCode()} method can be used to get an {@code int} suitable
|
||||
* for use as the {@code impact} parameter in an {@link MBeanOperationInfo}
|
||||
* constructor.</p>
|
||||
*/
|
||||
public enum Impact {
|
||||
/**
|
||||
* The operation is read-like: it returns information but does not change
|
||||
* any state.
|
||||
* @see MBeanOperationInfo#INFO
|
||||
*/
|
||||
INFO(MBeanOperationInfo.INFO),
|
||||
|
||||
/**
|
||||
* The operation is write-like: it has an effect but does not return
|
||||
* any information from the MBean.
|
||||
* @see MBeanOperationInfo#ACTION
|
||||
*/
|
||||
ACTION(MBeanOperationInfo.ACTION),
|
||||
|
||||
/**
|
||||
* The operation is both read-like and write-like: it has an effect,
|
||||
* and it also returns information from the MBean.
|
||||
* @see MBeanOperationInfo#ACTION_INFO
|
||||
*/
|
||||
ACTION_INFO(MBeanOperationInfo.ACTION_INFO),
|
||||
|
||||
/**
|
||||
* The impact of the operation is unknown or cannot be expressed
|
||||
* using one of the other values.
|
||||
* @see MBeanOperationInfo#UNKNOWN
|
||||
*/
|
||||
UNKNOWN(MBeanOperationInfo.UNKNOWN);
|
||||
|
||||
private final int code;
|
||||
|
||||
/**
|
||||
* An instance of this enumeration, with the corresponding {@code int}
|
||||
* code used by the {@link MBeanOperationInfo} constructors.
|
||||
*
|
||||
* @param code the code used by the {@code MBeanOperationInfo} constructors.
|
||||
*/
|
||||
Impact(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
/**
|
||||
* The equivalent {@code int} code used by the {@link MBeanOperationInfo}
|
||||
* constructors.
|
||||
* @return the {@code int} code.
|
||||
*/
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@code Impact} value corresponding to the given {@code int}
|
||||
* code. The {@code code} is the value that would be used in an
|
||||
* {@code MBeanOperationInfo} constructor.
|
||||
*
|
||||
* @param code the {@code int} code.
|
||||
*
|
||||
* @return an {@code Impact} value {@code x} such that
|
||||
* {@code code == x.}{@link #getCode()}, or {@code Impact.UNKNOWN}
|
||||
* if there is no such value.
|
||||
*/
|
||||
public static Impact forCode(int code) {
|
||||
switch (code) {
|
||||
case MBeanOperationInfo.ACTION: return ACTION;
|
||||
case MBeanOperationInfo.INFO: return INFO;
|
||||
case MBeanOperationInfo.ACTION_INFO: return ACTION_INFO;
|
||||
default: return UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1999-2003 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
|
||||
@ -51,16 +51,4 @@ public class InstanceNotFoundException extends OperationsException {
|
||||
public InstanceNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for the frequent case where the message is the ObjectName
|
||||
* of the missing MBean.
|
||||
*
|
||||
* @param name the ObjectName of the missing MBean.
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public InstanceNotFoundException(ObjectName name) {
|
||||
this(String.valueOf(name));
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,22 +58,6 @@ public class JMRuntimeException extends RuntimeException {
|
||||
* specification. A later version may make it public.
|
||||
*/
|
||||
JMRuntimeException(String message, Throwable cause) {
|
||||
super(message);
|
||||
|
||||
/* Make a best effort to set the cause, but if we don't
|
||||
succeed, too bad, you don't get that useful debugging
|
||||
information. We jump through hoops here so that we can
|
||||
work on platforms prior to J2SE 1.4 where the
|
||||
Throwable.initCause method was introduced. If we change
|
||||
the public interface of JMRuntimeException in a future
|
||||
version we can add getCause() so we don't need to do this. */
|
||||
try {
|
||||
java.lang.reflect.Method initCause =
|
||||
Throwable.class.getMethod("initCause",
|
||||
new Class<?>[] {Throwable.class});
|
||||
initCause.invoke(this, new Object[] {cause});
|
||||
} catch (Exception e) {
|
||||
// OK: just means we won't have debugging info
|
||||
}
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* 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
|
||||
@ -26,20 +26,8 @@
|
||||
package javax.management;
|
||||
|
||||
import com.sun.jmx.mbeanserver.Introspector;
|
||||
import com.sun.jmx.mbeanserver.MBeanInjector;
|
||||
import com.sun.jmx.remote.util.ClassLogger;
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import javax.management.namespace.JMXNamespaces;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
|
||||
/**
|
||||
* Static methods from the JMX API. There are no instances of this class.
|
||||
@ -60,27 +48,6 @@ public class JMX {
|
||||
*/
|
||||
public static final String DEFAULT_VALUE_FIELD = "defaultValue";
|
||||
|
||||
/**
|
||||
* The name of the <a
|
||||
* href="Descriptor.html#descriptionResourceBundleBaseName">{@code
|
||||
* descriptionResourceBundleBaseName}</a> field.
|
||||
*/
|
||||
public static final String DESCRIPTION_RESOURCE_BUNDLE_BASE_NAME_FIELD =
|
||||
"descriptionResourceBundleBaseName";
|
||||
|
||||
/**
|
||||
* The name of the <a href="Descriptor.html#descriptionResourceKey">{@code
|
||||
* descriptionResourceKey}</a> field.
|
||||
*/
|
||||
public static final String DESCRIPTION_RESOURCE_KEY_FIELD =
|
||||
"descriptionResourceKey";
|
||||
|
||||
/**
|
||||
* The name of the <a href="Descriptor.html#exceptions">{@code
|
||||
* exceptions}</a> field.
|
||||
*/
|
||||
public static final String EXCEPTIONS_FIELD = "exceptions";
|
||||
|
||||
/**
|
||||
* The name of the <a href="Descriptor.html#immutableInfo">{@code
|
||||
* immutableInfo}</a> field.
|
||||
@ -99,12 +66,6 @@ public class JMX {
|
||||
*/
|
||||
public static final String LEGAL_VALUES_FIELD = "legalValues";
|
||||
|
||||
/**
|
||||
* The name of the <a href="Descriptor.html#locale">{@code locale}</a>
|
||||
* field.
|
||||
*/
|
||||
public static final String LOCALE_FIELD = "locale";
|
||||
|
||||
/**
|
||||
* The name of the <a href="Descriptor.html#maxValue">{@code
|
||||
* maxValue}</a> field.
|
||||
@ -123,14 +84,6 @@ public class JMX {
|
||||
*/
|
||||
public static final String MXBEAN_FIELD = "mxbean";
|
||||
|
||||
/**
|
||||
* The name of the
|
||||
* <a href="Descriptor.html#mxbeanMappingFactoryClass">{@code
|
||||
* mxbeanMappingFactoryClass}</a> field.
|
||||
*/
|
||||
public static final String MXBEAN_MAPPING_FACTORY_CLASS_FIELD =
|
||||
"mxbeanMappingFactoryClass";
|
||||
|
||||
/**
|
||||
* The name of the <a href="Descriptor.html#openType">{@code
|
||||
* openType}</a> field.
|
||||
@ -143,276 +96,6 @@ public class JMX {
|
||||
*/
|
||||
public static final String ORIGINAL_TYPE_FIELD = "originalType";
|
||||
|
||||
/**
|
||||
* The name of the <a href="Descriptor.html#setExceptions">{@code
|
||||
* setExceptions}</a> field.
|
||||
*/
|
||||
public static final String SET_EXCEPTIONS_FIELD = "setExceptions";
|
||||
|
||||
/**
|
||||
* The name of the <a href="Descriptor.html#objectNameTemplate">{@code
|
||||
* objectNameTemplate}</a> field.
|
||||
*/
|
||||
public static final String OBJECT_NAME_TEMPLATE = "objectNameTemplate";
|
||||
|
||||
/**
|
||||
* <p>Options to apply to an MBean proxy or to an instance of {@link
|
||||
* StandardMBean}.</p>
|
||||
*
|
||||
* <p>For example, to specify the "wrapped object visible" option for a
|
||||
* {@code StandardMBean}, you might write this:</p>
|
||||
*
|
||||
* <pre>
|
||||
* StandardMBean.Options opts = new StandardMBean.Options();
|
||||
* opts.setWrappedObjectVisible(true);
|
||||
* StandardMBean mbean = new StandardMBean(impl, intf, opts);
|
||||
* </pre>
|
||||
*
|
||||
* @see javax.management.JMX.ProxyOptions
|
||||
* @see javax.management.StandardMBean.Options
|
||||
*/
|
||||
public static class MBeanOptions implements Serializable, Cloneable {
|
||||
private static final long serialVersionUID = -6380842449318177843L;
|
||||
|
||||
static final MBeanOptions MXBEAN = new MBeanOptions();
|
||||
static {
|
||||
MXBEAN.setMXBeanMappingFactory(MXBeanMappingFactory.DEFAULT);
|
||||
}
|
||||
|
||||
private MXBeanMappingFactory mappingFactory;
|
||||
|
||||
/**
|
||||
* <p>Construct an {@code MBeanOptions} object where all options have
|
||||
* their default values.</p>
|
||||
*/
|
||||
public MBeanOptions() {}
|
||||
|
||||
@Override
|
||||
public MBeanOptions clone() {
|
||||
try {
|
||||
return (MBeanOptions) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>True if this is an MXBean proxy or a StandardMBean instance
|
||||
* that is an MXBean. The default value is false.</p>
|
||||
*
|
||||
* <p>This method is equivalent to {@link #getMXBeanMappingFactory()
|
||||
* this.getMXBeanMappingFactory()}{@code != null}.</p>
|
||||
*
|
||||
* @return true if this is an MXBean proxy or a StandardMBean instance
|
||||
* that is an MXBean.
|
||||
*/
|
||||
public boolean isMXBean() {
|
||||
return (this.mappingFactory != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>The mappings between Java types and Open Types to be used in
|
||||
* an MXBean proxy or a StandardMBean instance that is an MXBean,
|
||||
* or null if this instance is not for an MXBean.
|
||||
* The default value is null.</p>
|
||||
*
|
||||
* @return the mappings to be used in this proxy or StandardMBean,
|
||||
* or null if this instance is not for an MXBean.
|
||||
*/
|
||||
public MXBeanMappingFactory getMXBeanMappingFactory() {
|
||||
return mappingFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Set the {@link #getMXBeanMappingFactory() MXBeanMappingFactory} to
|
||||
* the given value. The value should be null if this instance is not
|
||||
* for an MXBean. If this instance is for an MXBean, the value should
|
||||
* usually be either a custom mapping factory, or
|
||||
* {@link MXBeanMappingFactory#forInterface
|
||||
* MXBeanMappingFactory.forInterface}{@code (mxbeanInterface)}
|
||||
* which signifies
|
||||
* that the {@linkplain MXBeanMappingFactory#DEFAULT default} mapping
|
||||
* factory should be used unless an {@code @}{@link
|
||||
* javax.management.openmbean.MXBeanMappingFactoryClass
|
||||
* MXBeanMappingFactoryClass} annotation on {@code mxbeanInterface}
|
||||
* specifies otherwise.</p>
|
||||
*
|
||||
* <p>Examples:</p>
|
||||
* <pre>
|
||||
* MBeanOptions opts = new MBeanOptions();
|
||||
* opts.setMXBeanMappingFactory(myMappingFactory);
|
||||
* MyMXBean proxy = JMX.newMBeanProxy(
|
||||
* mbeanServerConnection, objectName, MyMXBean.class, opts);
|
||||
*
|
||||
* // ...or...
|
||||
*
|
||||
* MBeanOptions opts = new MBeanOptions();
|
||||
* MXBeanMappingFactory defaultFactoryForMyMXBean =
|
||||
* MXBeanMappingFactory.forInterface(MyMXBean.class);
|
||||
* opts.setMXBeanMappingFactory(defaultFactoryForMyMXBean);
|
||||
* MyMXBean proxy = JMX.newMBeanProxy(
|
||||
* mbeanServerConnection, objectName, MyMXBean.class, opts);
|
||||
* </pre>
|
||||
*
|
||||
* @param f the new value. If null, this instance is not for an
|
||||
* MXBean.
|
||||
*/
|
||||
public void setMXBeanMappingFactory(MXBeanMappingFactory f) {
|
||||
this.mappingFactory = f;
|
||||
}
|
||||
|
||||
/* To maximise object sharing, classes in this package can replace
|
||||
* a private MBeanOptions with no MXBeanMappingFactory with one
|
||||
* of these shared instances. But they must be EXTREMELY careful
|
||||
* never to give out the shared instances to user code, which could
|
||||
* modify them.
|
||||
*/
|
||||
private static final MBeanOptions[] CANONICALS = {
|
||||
new MBeanOptions(), MXBEAN,
|
||||
};
|
||||
// Overridden in local subclasses:
|
||||
MBeanOptions[] canonicals() {
|
||||
return CANONICALS;
|
||||
}
|
||||
|
||||
// This is only used by the logic for canonical instances.
|
||||
// Overridden in local subclasses:
|
||||
boolean same(MBeanOptions opt) {
|
||||
return (opt.mappingFactory == mappingFactory);
|
||||
}
|
||||
|
||||
final MBeanOptions canonical() {
|
||||
for (MBeanOptions opt : canonicals()) {
|
||||
if (opt.getClass() == this.getClass() && same(opt))
|
||||
return opt;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
final MBeanOptions uncanonical() {
|
||||
for (MBeanOptions opt : canonicals()) {
|
||||
if (this == opt)
|
||||
return clone();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private Map<String, Object> toMap() {
|
||||
Map<String, Object> map = new TreeMap<String, Object>();
|
||||
try {
|
||||
BeanInfo bi = java.beans.Introspector.getBeanInfo(getClass());
|
||||
PropertyDescriptor[] pds = bi.getPropertyDescriptors();
|
||||
for (PropertyDescriptor pd : pds) {
|
||||
String name = pd.getName();
|
||||
if (name.equals("class"))
|
||||
continue;
|
||||
Method get = pd.getReadMethod();
|
||||
if (get != null)
|
||||
map.put(name, get.invoke(this));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Throwable t = e;
|
||||
if (t instanceof InvocationTargetException)
|
||||
t = t.getCause();
|
||||
map.put("Exception", t);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + toMap();
|
||||
// For example "MBeanOptions{MXBean=true, <etc>}".
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Indicates whether some other object is "equal to" this one. The
|
||||
* result is true if and only if the other object is also an instance
|
||||
* of MBeanOptions or a subclass, and has the same properties with
|
||||
* the same values.</p>
|
||||
* @return {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this)
|
||||
return true;
|
||||
if (obj == null || obj.getClass() != this.getClass())
|
||||
return false;
|
||||
return toMap().equals(((MBeanOptions) obj).toMap());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return toMap().hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Options to apply to an MBean proxy.</p>
|
||||
*
|
||||
* @see #newMBeanProxy
|
||||
*/
|
||||
public static class ProxyOptions extends MBeanOptions {
|
||||
private static final long serialVersionUID = 7238804866098386559L;
|
||||
|
||||
private boolean notificationEmitter;
|
||||
|
||||
/**
|
||||
* <p>Construct a {@code ProxyOptions} object where all options have
|
||||
* their default values.</p>
|
||||
*/
|
||||
public ProxyOptions() {}
|
||||
|
||||
@Override
|
||||
public ProxyOptions clone() {
|
||||
return (ProxyOptions) super.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Defines whether the returned proxy should
|
||||
* implement {@link NotificationEmitter}. The default value is false.</p>
|
||||
*
|
||||
* @return true if this proxy will be a NotificationEmitter.
|
||||
*
|
||||
* @see JMX#newMBeanProxy(MBeanServerConnection, ObjectName, Class,
|
||||
* MBeanOptions)
|
||||
*/
|
||||
public boolean isNotificationEmitter() {
|
||||
return this.notificationEmitter;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Set the {@link #isNotificationEmitter NotificationEmitter} option to
|
||||
* the given value.</p>
|
||||
* @param emitter the new value.
|
||||
*/
|
||||
public void setNotificationEmitter(boolean emitter) {
|
||||
this.notificationEmitter = emitter;
|
||||
}
|
||||
|
||||
// Canonical objects for each of (MXBean,!MXBean) x (Emitter,!Emitter)
|
||||
private static final ProxyOptions[] CANONICALS = {
|
||||
new ProxyOptions(), new ProxyOptions(),
|
||||
new ProxyOptions(), new ProxyOptions(),
|
||||
};
|
||||
static {
|
||||
CANONICALS[1].setMXBeanMappingFactory(MXBeanMappingFactory.DEFAULT);
|
||||
CANONICALS[2].setNotificationEmitter(true);
|
||||
CANONICALS[3].setMXBeanMappingFactory(MXBeanMappingFactory.DEFAULT);
|
||||
CANONICALS[3].setNotificationEmitter(true);
|
||||
}
|
||||
@Override
|
||||
MBeanOptions[] canonicals() {
|
||||
return CANONICALS;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean same(MBeanOptions opt) {
|
||||
return (super.same(opt) && opt instanceof ProxyOptions &&
|
||||
((ProxyOptions) opt).notificationEmitter == notificationEmitter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Make a proxy for a Standard MBean in a local or remote
|
||||
* MBean Server.</p>
|
||||
@ -501,12 +184,6 @@ public class JMX {
|
||||
* likewise for the other methods of {@link
|
||||
* NotificationBroadcaster} and {@link NotificationEmitter}.</p>
|
||||
*
|
||||
* <p>This method is equivalent to {@link
|
||||
* #newMBeanProxy(MBeanServerConnection, ObjectName, Class, JMX.MBeanOptions)
|
||||
* newMBeanProxy(connection, objectName, interfaceClass, opts)}, where
|
||||
* {@code opts} is a {@link JMX.ProxyOptions} representing the
|
||||
* {@code notificationEmitter} parameter.</p>
|
||||
*
|
||||
* @param connection the MBean server to forward to.
|
||||
* @param objectName the name of the MBean within
|
||||
* {@code connection} to forward to.
|
||||
@ -515,18 +192,22 @@ public class JMX {
|
||||
* @param notificationEmitter make the returned proxy
|
||||
* implement {@link NotificationEmitter} by forwarding its methods
|
||||
* via {@code connection}.
|
||||
*
|
||||
* @param <T> allows the compiler to know that if the {@code
|
||||
* interfaceClass} parameter is {@code MyMBean.class}, for
|
||||
* example, then the return type is {@code MyMBean}.
|
||||
*
|
||||
* @return the new proxy instance.
|
||||
*/
|
||||
public static <T> T newMBeanProxy(MBeanServerConnection connection,
|
||||
ObjectName objectName,
|
||||
Class<T> interfaceClass,
|
||||
boolean notificationEmitter) {
|
||||
ProxyOptions opts = new ProxyOptions();
|
||||
opts.setNotificationEmitter(notificationEmitter);
|
||||
return newMBeanProxy(connection, objectName, interfaceClass, opts);
|
||||
return MBeanServerInvocationHandler.newProxyInstance(
|
||||
connection,
|
||||
objectName,
|
||||
interfaceClass,
|
||||
notificationEmitter);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -599,6 +280,10 @@ public class JMX {
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <p>The object returned by this method is a
|
||||
* {@link Proxy} whose {@code InvocationHandler} is an
|
||||
* {@link MBeanServerInvocationHandler}.</p>
|
||||
*
|
||||
* <p>This method is equivalent to {@link
|
||||
* #newMXBeanProxy(MBeanServerConnection, ObjectName, Class,
|
||||
* boolean) newMXBeanProxy(connection, objectName, interfaceClass,
|
||||
@ -641,17 +326,6 @@ public class JMX {
|
||||
* likewise for the other methods of {@link
|
||||
* NotificationBroadcaster} and {@link NotificationEmitter}.</p>
|
||||
*
|
||||
* <p>This method is equivalent to {@link
|
||||
* #newMBeanProxy(MBeanServerConnection, ObjectName, Class, JMX.MBeanOptions)
|
||||
* newMBeanProxy(connection, objectName, interfaceClass, opts)}, where
|
||||
* {@code opts} is a {@link JMX.ProxyOptions} where the {@link
|
||||
* JMX.ProxyOptions#getMXBeanMappingFactory() MXBeanMappingFactory}
|
||||
* property is
|
||||
* {@link MXBeanMappingFactory#forInterface(Class)
|
||||
* MXBeanMappingFactory.forInterface(interfaceClass)} and the {@link
|
||||
* JMX.ProxyOptions#isNotificationEmitter() notificationEmitter} property
|
||||
* is equal to the {@code notificationEmitter} parameter.</p>
|
||||
*
|
||||
* @param connection the MBean server to forward to.
|
||||
* @param objectName the name of the MBean within
|
||||
* {@code connection} to forward to.
|
||||
@ -660,130 +334,26 @@ public class JMX {
|
||||
* @param notificationEmitter make the returned proxy
|
||||
* implement {@link NotificationEmitter} by forwarding its methods
|
||||
* via {@code connection}.
|
||||
*
|
||||
* @param <T> allows the compiler to know that if the {@code
|
||||
* interfaceClass} parameter is {@code MyMXBean.class}, for
|
||||
* example, then the return type is {@code MyMXBean}.
|
||||
*
|
||||
* @return the new proxy instance.
|
||||
*/
|
||||
public static <T> T newMXBeanProxy(MBeanServerConnection connection,
|
||||
ObjectName objectName,
|
||||
Class<T> interfaceClass,
|
||||
boolean notificationEmitter) {
|
||||
ProxyOptions opts = new ProxyOptions();
|
||||
MXBeanMappingFactory f = MXBeanMappingFactory.forInterface(interfaceClass);
|
||||
opts.setMXBeanMappingFactory(f);
|
||||
opts.setNotificationEmitter(notificationEmitter);
|
||||
return newMBeanProxy(connection, objectName, interfaceClass, opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Make a proxy for a Standard MBean or MXBean in a local or remote MBean
|
||||
* Server that may also support the methods of {@link
|
||||
* NotificationEmitter} and (for an MXBean) that may define custom MXBean
|
||||
* type mappings.</p>
|
||||
*
|
||||
* <p>This method behaves the same as
|
||||
* {@link #newMBeanProxy(MBeanServerConnection, ObjectName, Class)} or
|
||||
* {@link #newMXBeanProxy(MBeanServerConnection, ObjectName, Class)},
|
||||
* according as {@code opts.isMXBean()} is respectively false or true; but
|
||||
* with the following changes based on {@code opts}.</p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>If {@code opts.isNotificationEmitter()} is {@code
|
||||
* true}, then the MBean is assumed to be a {@link
|
||||
* NotificationBroadcaster} or {@link NotificationEmitter} and the
|
||||
* returned proxy will implement {@link NotificationEmitter} as
|
||||
* well as {@code interfaceClass}. A call to {@link
|
||||
* NotificationBroadcaster#addNotificationListener} on the proxy
|
||||
* will result in a call to {@link
|
||||
* MBeanServerConnection#addNotificationListener(ObjectName,
|
||||
* NotificationListener, NotificationFilter, Object)}, and
|
||||
* likewise for the other methods of {@link
|
||||
* NotificationBroadcaster} and {@link NotificationEmitter}.</li>
|
||||
*
|
||||
* <li>If {@code opts.getMXBeanMappingFactory()} is not null,
|
||||
* then the mappings it defines will be applied to convert between
|
||||
* arbitrary Java types and Open Types.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>The object returned by this method is a
|
||||
* {@link Proxy} whose {@code InvocationHandler} is an
|
||||
* {@link MBeanServerInvocationHandler}. This means that it is possible
|
||||
* to retrieve the parameters that were used to produce the proxy. If the
|
||||
* proxy was produced as follows...</p>
|
||||
*
|
||||
* <pre>
|
||||
* FooMBean proxy =
|
||||
* JMX.newMBeanProxy(connection, objectName, FooMBean.class, opts);
|
||||
* </pre>
|
||||
*
|
||||
* <p>...then you can get the {@code MBeanServerInvocationHandler} like
|
||||
* this...</p>
|
||||
*
|
||||
* <pre>
|
||||
* MBeanServerInvocationHandler mbsih = (MBeanServerInvocationHandler)
|
||||
* {@link Proxy#getInvocationHandler(Object)
|
||||
* Proxy.getInvocationHandler}(proxy);
|
||||
* </pre>
|
||||
*
|
||||
* <p>...and you can retrieve {@code connection}, {@code
|
||||
* objectName}, and {@code opts} using the {@link
|
||||
* MBeanServerInvocationHandler#getMBeanServerConnection()
|
||||
* getMBeanServerConnection()}, {@link
|
||||
* MBeanServerInvocationHandler#getObjectName() getObjectName()}, and
|
||||
* {@link MBeanServerInvocationHandler#getMBeanOptions() getMBeanOptions()}
|
||||
* methods on {@code mbsih}. You can retrieve {@code FooMBean.class}
|
||||
* using {@code proxy.getClass().}{@link
|
||||
* Class#getInterfaces() getInterfaces()}.</p>
|
||||
*
|
||||
* @param connection the MBean server to forward to.
|
||||
* @param objectName the name of the MBean within
|
||||
* {@code connection} to forward to.
|
||||
* @param interfaceClass the Standard MBean or MXBean interface,
|
||||
* which will also be implemented by the returned proxy.
|
||||
* @param opts the options to apply for this proxy. Can be null,
|
||||
* in which case default options are applied.
|
||||
* @param <T> allows the compiler to know that if the {@code
|
||||
* interfaceClass} parameter is {@code MyMXBean.class}, for
|
||||
* example, then the return type is {@code MyMXBean}.
|
||||
* @return the new proxy instance.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code interfaceClass} is not a
|
||||
* valid MXBean interface.
|
||||
*/
|
||||
public static <T> T newMBeanProxy(MBeanServerConnection connection,
|
||||
ObjectName objectName,
|
||||
Class<T> interfaceClass,
|
||||
MBeanOptions opts) {
|
||||
// Check interface for MXBean compliance
|
||||
//
|
||||
try {
|
||||
return newMBeanProxy2(connection, objectName, interfaceClass, opts);
|
||||
Introspector.testComplianceMXBeanInterface(interfaceClass);
|
||||
} catch (NotCompliantMBeanException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> T newMBeanProxy2(MBeanServerConnection connection,
|
||||
ObjectName objectName,
|
||||
Class<T> interfaceClass,
|
||||
MBeanOptions opts)
|
||||
throws NotCompliantMBeanException {
|
||||
|
||||
if (opts == null)
|
||||
opts = new MBeanOptions();
|
||||
|
||||
boolean notificationEmitter = opts instanceof ProxyOptions &&
|
||||
((ProxyOptions) opts).isNotificationEmitter();
|
||||
|
||||
MXBeanMappingFactory mappingFactory = opts.getMXBeanMappingFactory();
|
||||
|
||||
if (mappingFactory != null) {
|
||||
// Check interface for MXBean compliance
|
||||
Introspector.testComplianceMXBeanInterface(interfaceClass,
|
||||
mappingFactory);
|
||||
}
|
||||
|
||||
InvocationHandler handler = new MBeanServerInvocationHandler(
|
||||
connection, objectName, opts);
|
||||
connection, objectName, true);
|
||||
final Class<?>[] interfaces;
|
||||
if (notificationEmitter) {
|
||||
interfaces =
|
||||
@ -822,109 +392,4 @@ public class JMX {
|
||||
// exactly the string "MXBean" since that would mean there
|
||||
// was no package name, which is pretty unlikely in practice.
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Test if an MBean can emit notifications. An MBean can emit
|
||||
* notifications if either it implements {@link NotificationBroadcaster}
|
||||
* (perhaps through its child interface {@link NotificationEmitter}), or
|
||||
* it uses <a href="MBeanRegistration.html#injection">resource
|
||||
* injection</a> to obtain an instance of {@link SendNotification}
|
||||
* through which it can send notifications.</p>
|
||||
*
|
||||
* @param mbean an MBean object.
|
||||
* @return true if the given object is a valid MBean that can emit
|
||||
* notifications; false if the object is a valid MBean but that
|
||||
* cannot emit notifications.
|
||||
* @throws NotCompliantMBeanException if the given object is not
|
||||
* a valid MBean.
|
||||
*/
|
||||
public static boolean isNotificationSource(Object mbean)
|
||||
throws NotCompliantMBeanException {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (mbean instanceof NotificationBroadcaster ||
|
||||
MBeanInjector.injectsSendNotification(mbean))
|
||||
return true;
|
||||
if (mbean instanceof DynamicWrapperMBean)
|
||||
mbean = ((DynamicWrapperMBean) mbean).getWrappedObject();
|
||||
else
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the version of the JMX specification that a (possibly remote)
|
||||
* MBean Server is using. The JMX specification described in this
|
||||
* documentation is version 2.0. The earlier versions that might be
|
||||
* reported by this method are 1.0, 1.1, 1.2, and 1.4. (There is no 1.3.)
|
||||
* All of these versions and all future versions can be compared using
|
||||
* {@link String#compareTo(String)}. So, for example, to tell if
|
||||
* {@code mbsc} is running at least version 2.0 you can write:</p>
|
||||
*
|
||||
* <pre>
|
||||
* String version = JMX.getSpecificationVersion(mbsc, null);
|
||||
* boolean atLeast2dot0 = (version.compareTo("2.0") >= 0);
|
||||
* </pre>
|
||||
*
|
||||
* <p>A remote MBean Server might be running an earlier version of the
|
||||
* JMX API, and in that case <a href="package-summary.html#interop">certain
|
||||
* features</a> might not be available in it.</p>
|
||||
*
|
||||
* <p>The version of the MBean Server {@code mbsc} is not necessarily
|
||||
* the version of all namespaces within that MBean Server, for example
|
||||
* if some of them use {@link javax.management.namespace.JMXRemoteNamespace
|
||||
* JMXRemoteNamespace}. To determine the version of the namespace
|
||||
* that a particular MBean is in, give its name as the {@code mbeanName}
|
||||
* parameter.</p>
|
||||
*
|
||||
* @param mbsc a connection to an MBean Server.
|
||||
*
|
||||
* @param mbeanName the name of an MBean within that MBean Server, or null.
|
||||
* If non-null, the namespace of this name, as determined by
|
||||
* {@link JMXNamespaces#getContainingNamespace
|
||||
* JMXNamespaces.getContainingNamespace}, is the one whose specification
|
||||
* version will be returned.
|
||||
*
|
||||
* @return the JMX specification version reported by that MBean Server.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code mbsc} is null, or if
|
||||
* {@code mbeanName} includes a wildcard character ({@code *} or {@code ?})
|
||||
* in its namespace.
|
||||
*
|
||||
* @throws IOException if the version cannot be obtained, either because
|
||||
* there is a communication problem or because the remote MBean Server
|
||||
* does not have the appropriate {@linkplain
|
||||
* MBeanServerDelegateMBean#getSpecificationVersion() attribute}.
|
||||
*
|
||||
* @see <a href="package-summary.html#interop">Interoperability between
|
||||
* versions of the JMX specification</a>
|
||||
* @see MBeanServerDelegateMBean#getSpecificationVersion
|
||||
*/
|
||||
public static String getSpecificationVersion(
|
||||
MBeanServerConnection mbsc, ObjectName mbeanName)
|
||||
throws IOException {
|
||||
if (mbsc == null)
|
||||
throw new IllegalArgumentException("Null MBeanServerConnection");
|
||||
|
||||
String namespace;
|
||||
if (mbeanName == null)
|
||||
namespace = "";
|
||||
else
|
||||
namespace = JMXNamespaces.getContainingNamespace(mbeanName);
|
||||
if (namespace.contains("*") || namespace.contains("?")) {
|
||||
throw new IllegalArgumentException(
|
||||
"ObjectName contains namespace wildcard: " + mbeanName);
|
||||
}
|
||||
|
||||
try {
|
||||
if (namespace.length() > 0)
|
||||
mbsc = JMXNamespaces.narrowToNamespace(mbsc, namespace);
|
||||
return (String) mbsc.getAttribute(
|
||||
MBeanServerDelegate.DELEGATE_NAME, "SpecificationVersion");
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-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 javax.management;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* <p>Indicates that the annotated class is a Standard MBean. A Standard
|
||||
* MBean class can be defined as in this example:</p>
|
||||
*
|
||||
* <pre>
|
||||
* {@code @MBean}
|
||||
* public class Configuration {
|
||||
* {@link ManagedAttribute @ManagedAttribute}
|
||||
* public int getCacheSize() {...}
|
||||
* {@code @ManagedAttribute}
|
||||
* public void setCacheSize(int size);
|
||||
*
|
||||
* {@code @ManagedAttribute}
|
||||
* public long getLastChangedTime();
|
||||
*
|
||||
* {@link ManagedOperation @ManagedOperation}
|
||||
* public void save();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>The class must be public. Public methods within the class can be
|
||||
* annotated with {@code @ManagedOperation} to indicate that they are
|
||||
* MBean operations. Public getter and setter methods within the class
|
||||
* can be annotated with {@code @ManagedAttribute} to indicate that they define
|
||||
* MBean attributes.</p>
|
||||
*
|
||||
* <p>If the MBean is to be an MXBean rather than a Standard MBean, then
|
||||
* the {@link MXBean @MXBean} annotation must be used instead of
|
||||
* {@code @MBean}.</p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Inherited
|
||||
public @interface MBean {
|
||||
}
|
||||
@ -186,10 +186,8 @@ public class MBeanAttributeInfo extends MBeanFeatureInfo implements Cloneable {
|
||||
(getter != null),
|
||||
(setter != null),
|
||||
isIs(getter),
|
||||
ImmutableDescriptor.union(Introspector.
|
||||
descriptorForElement(getter, false),
|
||||
Introspector.descriptorForElement(setter,
|
||||
true)));
|
||||
ImmutableDescriptor.union(Introspector.descriptorForElement(getter),
|
||||
Introspector.descriptorForElement(setter)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -67,7 +67,7 @@ public class MBeanConstructorInfo extends MBeanFeatureInfo implements Cloneable
|
||||
public MBeanConstructorInfo(String description, Constructor<?> constructor) {
|
||||
this(constructor.getName(), description,
|
||||
constructorSignature(constructor),
|
||||
Introspector.descriptorForElement(constructor, false));
|
||||
Introspector.descriptorForElement(constructor));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -25,8 +25,6 @@
|
||||
|
||||
package javax.management;
|
||||
|
||||
import javax.management.openmbean.CompositeData;
|
||||
|
||||
|
||||
/**
|
||||
* Represents "user defined" exceptions thrown by MBean methods
|
||||
@ -42,26 +40,6 @@ public class MBeanException extends JMException {
|
||||
/* Serial version */
|
||||
private static final long serialVersionUID = 4066342430588744142L;
|
||||
|
||||
/**
|
||||
* @serial This field is null for instances of this class that were
|
||||
* produced by its public constructors. It is non-null for instances
|
||||
* of this class that represent serialized instances of {@link
|
||||
* GenericMBeanException}.
|
||||
*
|
||||
* @see GenericMBeanException#getErrorCode()
|
||||
*/
|
||||
final String errorCode;
|
||||
|
||||
/**
|
||||
* @serial This field is null for instances of this class that were
|
||||
* produced by its public constructors. It may be non-null for instances
|
||||
* of this class that represent serialized instances of {@link
|
||||
* GenericMBeanException}.
|
||||
*
|
||||
* @see GenericMBeanException#getUserData()
|
||||
*/
|
||||
final CompositeData userData;
|
||||
|
||||
/**
|
||||
* @serial Encapsulated {@link Exception}
|
||||
*/
|
||||
@ -73,8 +51,9 @@ public class MBeanException extends JMException {
|
||||
*
|
||||
* @param e the wrapped exception.
|
||||
*/
|
||||
public MBeanException(Exception e) {
|
||||
this(null, null, null, e);
|
||||
public MBeanException(java.lang.Exception e) {
|
||||
super() ;
|
||||
exception = e ;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -84,19 +63,11 @@ public class MBeanException extends JMException {
|
||||
* @param e the wrapped exception.
|
||||
* @param message the detail message.
|
||||
*/
|
||||
public MBeanException(Exception e, String message) {
|
||||
this(message, null, null, e);
|
||||
public MBeanException(java.lang.Exception e, String message) {
|
||||
super(message) ;
|
||||
exception = e ;
|
||||
}
|
||||
|
||||
MBeanException(
|
||||
String message, String errorCode, CompositeData userData, Throwable cause) {
|
||||
super(message);
|
||||
initCause(cause);
|
||||
if (cause instanceof Exception)
|
||||
this.exception = (Exception) cause;
|
||||
this.errorCode = errorCode;
|
||||
this.userData = userData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the actual {@link Exception} thrown.
|
||||
@ -108,24 +79,11 @@ public class MBeanException extends JMException {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is invoked when deserializing instances of this class.
|
||||
* If the {@code errorCode} field of the deserialized instance is not
|
||||
* null, this method returns an instance of {@link GenericMBeanException}
|
||||
* instead. Otherwise it returns {@code this}.
|
||||
* @return {@code this}, or a {@code GenericMBeanException}.
|
||||
* Return the actual {@link Exception} thrown.
|
||||
*
|
||||
* @return the wrapped exception.
|
||||
*/
|
||||
Object readResolve() {
|
||||
if (errorCode == null) {
|
||||
// serial compatibility: earlier versions did not set
|
||||
// Throwable.cause because they overrode getCause().
|
||||
if (getCause() == null && exception != null)
|
||||
initCause(exception);
|
||||
return this;
|
||||
} else {
|
||||
Throwable t = new GenericMBeanException(
|
||||
getMessage(), errorCode, userData, getCause());
|
||||
t.setStackTrace(this.getStackTrace());
|
||||
return t;
|
||||
}
|
||||
public Throwable getCause() {
|
||||
return exception;
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +25,6 @@
|
||||
|
||||
package javax.management;
|
||||
|
||||
import com.sun.jmx.mbeanserver.Util;
|
||||
import java.io.IOException;
|
||||
import java.io.StreamCorruptedException;
|
||||
import java.io.Serializable;
|
||||
@ -38,12 +37,6 @@ import java.util.WeakHashMap;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import static javax.management.ImmutableDescriptor.nonNullDescriptor;
|
||||
|
||||
/**
|
||||
@ -80,50 +73,27 @@ import static javax.management.ImmutableDescriptor.nonNullDescriptor;
|
||||
* constructors in that object;
|
||||
*
|
||||
* <li>{@link #getAttributes()} returns the list of all attributes
|
||||
* whose existence is deduced as follows:
|
||||
* <ul>
|
||||
* <li>if the Standard MBean is defined with an MBean interface,
|
||||
* from <code>get<i>Name</i></code>, <code>is<i>Name</i></code>, or
|
||||
* <code>set<i>Name</i></code> methods that conform to the conventions
|
||||
* whose existence is deduced from the presence in the MBean interface
|
||||
* of a <code>get<i>Name</i></code>, <code>is<i>Name</i></code>, or
|
||||
* <code>set<i>Name</i></code> method that conforms to the conventions
|
||||
* for Standard MBeans;
|
||||
* <li>if the Standard MBean is defined with the {@link MBean @MBean} or
|
||||
* {@link MXBean @MXBean} annotation on a class, from methods with the
|
||||
* {@link ManagedAttribute @ManagedAttribute} annotation;
|
||||
* </ul>
|
||||
*
|
||||
* <li>{@link #getOperations()} returns the list of all operations whose
|
||||
* existence is deduced as follows:
|
||||
* <ul>
|
||||
* <li>if the Standard MBean is defined with an MBean interface, from methods in
|
||||
* <li>{@link #getOperations()} returns the list of all methods in
|
||||
* the MBean interface that do not represent attributes;
|
||||
* <li>if the Standard MBean is defined with the {@link MBean @MBean} or
|
||||
* {@link MXBean @MXBean} annotation on a class, from methods with the
|
||||
* {@link ManagedOperation @ManagedOperation} annotation;
|
||||
* </ul>
|
||||
*
|
||||
* <li>{@link #getNotifications()} returns:
|
||||
* <ul>
|
||||
* <li>if the MBean implements the {@link NotificationBroadcaster} interface,
|
||||
* the result of calling {@link
|
||||
* <li>{@link #getNotifications()} returns an empty array if the MBean
|
||||
* does not implement the {@link NotificationBroadcaster} interface,
|
||||
* otherwise the result of calling {@link
|
||||
* NotificationBroadcaster#getNotificationInfo()} on it;
|
||||
* <li>otherwise, if there is a {@link NotificationInfo @NotificationInfo}
|
||||
* or {@link NotificationInfos @NotificationInfos} annotation on the
|
||||
* MBean interface or <code>@MBean</code> or <code>@MXBean</code>
|
||||
* class, the array implied by those annotations;
|
||||
* <li>otherwise an empty array;
|
||||
* </ul>
|
||||
*
|
||||
* <li>{@link #getDescriptor()} returns a descriptor containing the contents
|
||||
* of any descriptor annotations in the MBean interface (see
|
||||
* {@link DescriptorFields @DescriptorFields} and
|
||||
* {@link DescriptorKey @DescriptorKey}).
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <p>The description returned by {@link #getDescription()} and the
|
||||
* descriptions of the contained attributes and operations are determined
|
||||
* by the corresponding {@link Description} annotations if any;
|
||||
* otherwise their contents are not specified.</p>
|
||||
* descriptions of the contained attributes and operations are not specified.</p>
|
||||
*
|
||||
* <p>The remaining details of the <code>MBeanInfo</code> for a
|
||||
* Standard MBean are not specified. This includes the description of
|
||||
@ -758,377 +728,4 @@ public class MBeanInfo implements Cloneable, Serializable, DescriptorRead {
|
||||
throw new StreamCorruptedException("Got unexpected byte.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return an {@code MBeanInfo} object that is the same as this one
|
||||
* except that its descriptions are localized in the given locale.
|
||||
* This means the text returned by {@link MBeanInfo#getDescription}
|
||||
* (the description of the MBean itself), and the text returned by the
|
||||
* {@link MBeanFeatureInfo#getDescription getDescription()} method
|
||||
* for every {@linkplain MBeanAttributeInfo attribute}, {@linkplain
|
||||
* MBeanOperationInfo operation}, {@linkplain MBeanConstructorInfo
|
||||
* constructor}, and {@linkplain MBeanNotificationInfo notification}
|
||||
* contained in the {@code MBeanInfo}.</p>
|
||||
*
|
||||
* <p>Here is how the description {@code this.getDescription()} is
|
||||
* localized.</p>
|
||||
*
|
||||
* <p>First, if the {@linkplain #getDescriptor() descriptor}
|
||||
* of this {@code MBeanInfo} contains a field <code><a
|
||||
* href="Descriptor.html#locale">"locale"</a></code>, and the value of
|
||||
* the field is the same as {@code locale.toString()}, then this {@code
|
||||
* MBeanInfo} is returned. Otherwise, localization proceeds as follows,
|
||||
* and the {@code "locale"} field in the returned {@code MBeanInfo} will
|
||||
* be {@code locale.toString()}.
|
||||
*
|
||||
* <p>A <em>{@code className}</em> is determined. If this
|
||||
* {@code MBeanInfo} contains a descriptor with the field
|
||||
* <a href="Descriptor.html#interfaceClassName">{@code
|
||||
* "interfaceClassName"}</a>, then the value of that field is the
|
||||
* {@code className}. Otherwise, it is {@link #getClassName()}.
|
||||
* Everything before the last period (.) in the {@code className} is
|
||||
* the <em>{@code package}</em>, and everything after is the <em>{@code
|
||||
* simpleClassName}</em>. (If there is no period, then the {@code package}
|
||||
* is empty and the {@code simpleClassName} is the same as the {@code
|
||||
* className}.)</p>
|
||||
*
|
||||
* <p>A <em>{@code resourceKey}</em> is determined. If this {@code
|
||||
* MBeanInfo} contains a {@linkplain MBeanInfo#getDescriptor() descriptor}
|
||||
* with a field {@link JMX#DESCRIPTION_RESOURCE_KEY_FIELD
|
||||
* "descriptionResourceKey"}, the value of the field is
|
||||
* the {@code resourceKey}. Otherwise, the {@code resourceKey} is {@code
|
||||
* simpleClassName + ".mbean"}.</p>
|
||||
*
|
||||
* <p>A <em>{@code resourceBundleBaseName}</em> is determined. If
|
||||
* this {@code MBeanInfo} contains a descriptor with a field {@link
|
||||
* JMX#DESCRIPTION_RESOURCE_BUNDLE_BASE_NAME_FIELD
|
||||
* "descriptionResourceBundleBaseName"}, the value of the field
|
||||
* is the {@code resourceBundleBaseName}. Otherwise, the {@code
|
||||
* resourceBundleBaseName} is {@code package + ".MBeanDescriptions"}.
|
||||
*
|
||||
* <p>Then, a {@link java.util.ResourceBundle ResourceBundle} is
|
||||
* determined, using<br> {@link java.util.ResourceBundle#getBundle(String,
|
||||
* Locale, ClassLoader) ResourceBundle.getBundle(resourceBundleBaseName,
|
||||
* locale, loader)}. If this succeeds, and if {@link
|
||||
* java.util.ResourceBundle#getString(String) getString(resourceKey)}
|
||||
* returns a string, then that string is the localized description.
|
||||
* Otherwise, the original description is unchanged.</p>
|
||||
*
|
||||
* <p>A localized description for an {@code MBeanAttributeInfo} is
|
||||
* obtained similarly. The default {@code resourceBundleBaseName}
|
||||
* is the same as above. The default description and the
|
||||
* descriptor fields {@code "descriptionResourceKey"} and {@code
|
||||
* "descriptionResourceBundleBaseName"} come from the {@code
|
||||
* MBeanAttributeInfo} rather than the {@code MBeanInfo}. If the
|
||||
* attribute's {@linkplain MBeanFeatureInfo#getName() name} is {@code
|
||||
* Foo} then its default {@code resourceKey} is {@code simpleClassName +
|
||||
* ".attribute.Foo"}.</p>
|
||||
*
|
||||
* <p>Similar rules apply for operations, constructors, and notifications.
|
||||
* If the name of the operation, constructor, or notification is {@code
|
||||
* Foo} then the default {@code resourceKey} is respectively {@code
|
||||
* simpleClassName + ".operation.Foo"}, {@code simpleClassName +
|
||||
* ".constructor.Foo"}, or {@code simpleClassName + ".notification.Foo"}.
|
||||
* If two operations or constructors have the same name (overloading) then
|
||||
* they have the same default {@code resourceKey}; if different localized
|
||||
* descriptions are needed then a non-default key must be supplied using
|
||||
* {@code "descriptionResourceKey"}.</p>
|
||||
*
|
||||
* <p>Similar rules also apply for descriptions of parameters ({@link
|
||||
* MBeanParameterInfo}). The default {@code resourceKey} for a parameter
|
||||
* whose {@linkplain MBeanFeatureInfo#getName() name} is {@code
|
||||
* Bar} in an operation or constructor called {@code Foo} is {@code
|
||||
* simpleClassName + ".operation.Foo.Bar"} or {@code simpleClassName +
|
||||
* ".constructor.Foo.Bar"} respectively.</p>
|
||||
*
|
||||
* <h4>Example</h4>
|
||||
*
|
||||
* <p>Suppose you have an MBean defined by these two Java source files:</p>
|
||||
*
|
||||
* <pre>
|
||||
* // ConfigurationMBean.java
|
||||
* package com.example;
|
||||
* public interface ConfigurationMBean {
|
||||
* public String getName();
|
||||
* public void save(String fileName);
|
||||
* }
|
||||
*
|
||||
* // Configuration.java
|
||||
* package com.example;
|
||||
* public class Configuration implements ConfigurationMBean {
|
||||
* public Configuration(String defaultName) {
|
||||
* ...
|
||||
* }
|
||||
* ...
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>Then you could define the default descriptions for the MBean, by
|
||||
* including a resource bundle called {@code com/example/MBeanDescriptions}
|
||||
* with the compiled classes. Most often this is done by creating a file
|
||||
* {@code MBeanDescriptions.properties} in the same directory as {@code
|
||||
* ConfigurationMBean.java}. Make sure that this file is copied into the
|
||||
* same place as the compiled classes; in typical build environments that
|
||||
* will be true by default.</p>
|
||||
*
|
||||
* <p>The file {@code com/example/MBeanDescriptions.properties} might
|
||||
* look like this:</p>
|
||||
*
|
||||
* <pre>
|
||||
* # Description of the MBean
|
||||
* ConfigurationMBean.mbean = Configuration manager
|
||||
*
|
||||
* # Description of the Name attribute
|
||||
* ConfigurationMBean.attribute.Name = The name of the configuration
|
||||
*
|
||||
* # Description of the save operation
|
||||
* ConfigurationMBean.operation.save = Save the configuration to a file
|
||||
*
|
||||
* # Description of the parameter to the save operation.
|
||||
* # Parameter names from the original Java source are not available,
|
||||
* # so the default names are p1, p2, etc. If the names were available,
|
||||
* # this would be ConfigurationMBean.operation.save.fileName
|
||||
* ConfigurationMBean.operation.save.p1 = The name of the file
|
||||
*
|
||||
* # Description of the constructor. The default name of a constructor is
|
||||
* # its fully-qualified class name.
|
||||
* ConfigurationMBean.constructor.com.example.Configuration = <!--
|
||||
* -->Constructor with name of default file
|
||||
* # Description of the constructor parameter.
|
||||
* ConfigurationMBean.constructor.com.example.Configuration.p1 = <!--
|
||||
* -->Name of the default file
|
||||
* </pre>
|
||||
*
|
||||
* <p>Starting with this file, you could create descriptions for the French
|
||||
* locale by creating {@code com/example/MBeanDescriptions_fr.properties}.
|
||||
* The keys in this file are the same as before but the text has been
|
||||
* translated:
|
||||
*
|
||||
* <pre>
|
||||
* ConfigurationMBean.mbean = Gestionnaire de configuration
|
||||
*
|
||||
* ConfigurationMBean.attribute.Name = Le nom de la configuration
|
||||
*
|
||||
* ConfigurationMBean.operation.save = Sauvegarder la configuration <!--
|
||||
* -->dans un fichier
|
||||
*
|
||||
* ConfigurationMBean.operation.save.p1 = Le nom du fichier
|
||||
*
|
||||
* ConfigurationMBean.constructor.com.example.Configuration = <!--
|
||||
* -->Constructeur avec nom du fichier par défaut
|
||||
* ConfigurationMBean.constructor.com.example.Configuration.p1 = <!--
|
||||
* -->Nom du fichier par défaut
|
||||
* </pre>
|
||||
*
|
||||
* <p>The descriptions in {@code MBeanDescriptions.properties} and
|
||||
* {@code MBeanDescriptions_fr.properties} will only be consulted if
|
||||
* {@code localizeDescriptions} is called, perhaps because the
|
||||
* MBean Server has been wrapped by {@link
|
||||
* ClientContext#newLocalizeMBeanInfoForwarder} or because the
|
||||
* connector server has been created with the {@link
|
||||
* javax.management.remote.JMXConnectorServer#LOCALIZE_MBEAN_INFO_FORWARDER
|
||||
* LOCALIZE_MBEAN_INFO_FORWARDER} option. If you want descriptions
|
||||
* even when there is no localization step, then you should consider
|
||||
* using {@link Description @Description} annotations. Annotations
|
||||
* provide descriptions by default but are overridden if {@code
|
||||
* localizeDescriptions} is called.</p>
|
||||
*
|
||||
* @param locale the target locale for descriptions. Cannot be null.
|
||||
*
|
||||
* @param loader the {@code ClassLoader} to use for looking up resource
|
||||
* bundles.
|
||||
*
|
||||
* @return an {@code MBeanInfo} with descriptions appropriately localized.
|
||||
*
|
||||
* @throws NullPointerException if {@code locale} is null.
|
||||
*/
|
||||
public MBeanInfo localizeDescriptions(Locale locale, ClassLoader loader) {
|
||||
if (locale == null)
|
||||
throw new NullPointerException("locale");
|
||||
Descriptor d = getDescriptor();
|
||||
String mbiLocaleString = (String) d.getFieldValue(JMX.LOCALE_FIELD);
|
||||
if (locale.toString().equals(mbiLocaleString))
|
||||
return this;
|
||||
return new Rewriter(this, locale, loader).getMBeanInfo();
|
||||
}
|
||||
|
||||
private static class Rewriter {
|
||||
private final MBeanInfo mbi;
|
||||
private final ClassLoader loader;
|
||||
private final Locale locale;
|
||||
private final String packageName;
|
||||
private final String simpleClassNamePlusDot;
|
||||
private ResourceBundle defaultBundle;
|
||||
private boolean defaultBundleLoaded;
|
||||
|
||||
// ResourceBundle.getBundle throws NullPointerException
|
||||
// if the loader is null, even though that is perfectly
|
||||
// valid and means the bootstrap loader. So we work
|
||||
// around with a ClassLoader that is equivalent to the
|
||||
// bootstrap loader but is not null.
|
||||
private static final ClassLoader bootstrapLoader =
|
||||
new ClassLoader(null) {};
|
||||
|
||||
Rewriter(MBeanInfo mbi, Locale locale, ClassLoader loader) {
|
||||
this.mbi = mbi;
|
||||
this.locale = locale;
|
||||
if (loader == null)
|
||||
loader = bootstrapLoader;
|
||||
this.loader = loader;
|
||||
|
||||
String intfName = (String)
|
||||
mbi.getDescriptor().getFieldValue("interfaceClassName");
|
||||
if (intfName == null)
|
||||
intfName = mbi.getClassName();
|
||||
int lastDot = intfName.lastIndexOf('.');
|
||||
this.packageName = intfName.substring(0, lastDot + 1);
|
||||
this.simpleClassNamePlusDot = intfName.substring(lastDot + 1) + ".";
|
||||
// Inner classes show up as Outer$Inner so won't match the dot.
|
||||
// When there is no dot, lastDot is -1,
|
||||
// packageName is empty, and simpleClassNamePlusDot is intfName.
|
||||
}
|
||||
|
||||
MBeanInfo getMBeanInfo() {
|
||||
MBeanAttributeInfo[] mbais =
|
||||
rewrite(mbi.getAttributes(), "attribute.");
|
||||
MBeanOperationInfo[] mbois =
|
||||
rewrite(mbi.getOperations(), "operation.");
|
||||
MBeanConstructorInfo[] mbcis =
|
||||
rewrite(mbi.getConstructors(), "constructor.");
|
||||
MBeanNotificationInfo[] mbnis =
|
||||
rewrite(mbi.getNotifications(), "notification.");
|
||||
Descriptor d = mbi.getDescriptor();
|
||||
d = changeLocale(d);
|
||||
String description = getDescription(d, "mbean", "");
|
||||
if (description == null)
|
||||
description = mbi.getDescription();
|
||||
return new MBeanInfo(
|
||||
mbi.getClassName(), description,
|
||||
mbais, mbcis, mbois, mbnis, d);
|
||||
}
|
||||
|
||||
private Descriptor changeLocale(Descriptor d) {
|
||||
if (d.getFieldValue(JMX.LOCALE_FIELD) != null) {
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
for (String field : d.getFieldNames())
|
||||
map.put(field, d.getFieldValue(field));
|
||||
map.remove(JMX.LOCALE_FIELD);
|
||||
d = new ImmutableDescriptor(map);
|
||||
}
|
||||
return ImmutableDescriptor.union(
|
||||
d, new ImmutableDescriptor(JMX.LOCALE_FIELD + "=" + locale));
|
||||
}
|
||||
|
||||
private String getDescription(
|
||||
Descriptor d, String defaultPrefix, String defaultSuffix) {
|
||||
ResourceBundle bundle = bundleFromDescriptor(d);
|
||||
if (bundle == null)
|
||||
return null;
|
||||
String key =
|
||||
(String) d.getFieldValue(JMX.DESCRIPTION_RESOURCE_KEY_FIELD);
|
||||
if (key == null)
|
||||
key = simpleClassNamePlusDot + defaultPrefix + defaultSuffix;
|
||||
return descriptionFromResource(bundle, key);
|
||||
}
|
||||
|
||||
private <T extends MBeanFeatureInfo> T[] rewrite(
|
||||
T[] features, String resourcePrefix) {
|
||||
for (int i = 0; i < features.length; i++) {
|
||||
T feature = features[i];
|
||||
Descriptor d = feature.getDescriptor();
|
||||
String description =
|
||||
getDescription(d, resourcePrefix, feature.getName());
|
||||
if (description != null &&
|
||||
!description.equals(feature.getDescription())) {
|
||||
features[i] = setDescription(feature, description);
|
||||
}
|
||||
}
|
||||
return features;
|
||||
}
|
||||
|
||||
private <T extends MBeanFeatureInfo> T setDescription(
|
||||
T feature, String description) {
|
||||
|
||||
Object newf;
|
||||
String name = feature.getName();
|
||||
Descriptor d = feature.getDescriptor();
|
||||
|
||||
if (feature instanceof MBeanAttributeInfo) {
|
||||
MBeanAttributeInfo mbai = (MBeanAttributeInfo) feature;
|
||||
newf = new MBeanAttributeInfo(
|
||||
name, mbai.getType(), description,
|
||||
mbai.isReadable(), mbai.isWritable(), mbai.isIs(),
|
||||
d);
|
||||
} else if (feature instanceof MBeanOperationInfo) {
|
||||
MBeanOperationInfo mboi = (MBeanOperationInfo) feature;
|
||||
MBeanParameterInfo[] sig = rewrite(
|
||||
mboi.getSignature(), "operation." + name + ".");
|
||||
newf = new MBeanOperationInfo(
|
||||
name, description, sig,
|
||||
mboi.getReturnType(), mboi.getImpact(), d);
|
||||
} else if (feature instanceof MBeanConstructorInfo) {
|
||||
MBeanConstructorInfo mbci = (MBeanConstructorInfo) feature;
|
||||
MBeanParameterInfo[] sig = rewrite(
|
||||
mbci.getSignature(), "constructor." + name + ".");
|
||||
newf = new MBeanConstructorInfo(
|
||||
name, description, sig, d);
|
||||
} else if (feature instanceof MBeanNotificationInfo) {
|
||||
MBeanNotificationInfo mbni = (MBeanNotificationInfo) feature;
|
||||
newf = new MBeanNotificationInfo(
|
||||
mbni.getNotifTypes(), name, description, d);
|
||||
} else if (feature instanceof MBeanParameterInfo) {
|
||||
MBeanParameterInfo mbpi = (MBeanParameterInfo) feature;
|
||||
newf = new MBeanParameterInfo(
|
||||
name, mbpi.getType(), description, d);
|
||||
} else {
|
||||
logger().log(Level.FINE, "Unknown feature type: " +
|
||||
feature.getClass());
|
||||
newf = feature;
|
||||
}
|
||||
|
||||
return Util.<T>cast(newf);
|
||||
}
|
||||
|
||||
private ResourceBundle bundleFromDescriptor(Descriptor d) {
|
||||
String bundleName = (String) d.getFieldValue(
|
||||
JMX.DESCRIPTION_RESOURCE_BUNDLE_BASE_NAME_FIELD);
|
||||
|
||||
if (bundleName != null)
|
||||
return getBundle(bundleName);
|
||||
|
||||
if (defaultBundleLoaded)
|
||||
return defaultBundle;
|
||||
|
||||
bundleName = packageName + "MBeanDescriptions";
|
||||
defaultBundle = getBundle(bundleName);
|
||||
defaultBundleLoaded = true;
|
||||
return defaultBundle;
|
||||
}
|
||||
|
||||
private String descriptionFromResource(
|
||||
ResourceBundle bundle, String key) {
|
||||
try {
|
||||
return bundle.getString(key);
|
||||
} catch (MissingResourceException e) {
|
||||
logger().log(Level.FINEST, "No resource for " + key, e);
|
||||
} catch (Exception e) {
|
||||
logger().log(Level.FINE, "Bad resource for " + key, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private ResourceBundle getBundle(String name) {
|
||||
try {
|
||||
return ResourceBundle.getBundle(name, locale, loader);
|
||||
} catch (Exception e) {
|
||||
logger().log(Level.FINE,
|
||||
"Could not load ResourceBundle " + name, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Logger logger() {
|
||||
return Logger.getLogger("javax.management.locale");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,28 +48,24 @@ public class MBeanOperationInfo extends MBeanFeatureInfo implements Cloneable {
|
||||
/**
|
||||
* Indicates that the operation is read-like:
|
||||
* it returns information but does not change any state.
|
||||
* @see Impact#INFO
|
||||
*/
|
||||
public static final int INFO = 0;
|
||||
|
||||
/**
|
||||
* Indicates that the operation is write-like: it has an effect but does
|
||||
* not return any information from the MBean.
|
||||
* @see Impact#ACTION
|
||||
*/
|
||||
public static final int ACTION = 1;
|
||||
|
||||
/**
|
||||
* Indicates that the operation is both read-like and write-like:
|
||||
* it has an effect, and it also returns information from the MBean.
|
||||
* @see Impact#ACTION_INFO
|
||||
*/
|
||||
public static final int ACTION_INFO = 2;
|
||||
|
||||
/**
|
||||
* Indicates that the impact of the operation is unknown or cannot be
|
||||
* expressed using one of the other values.
|
||||
* @see Impact#UNKNOWN
|
||||
*/
|
||||
public static final int UNKNOWN = 3;
|
||||
|
||||
@ -113,7 +109,7 @@ public class MBeanOperationInfo extends MBeanFeatureInfo implements Cloneable {
|
||||
methodSignature(method),
|
||||
method.getReturnType().getName(),
|
||||
UNKNOWN,
|
||||
Introspector.descriptorForElement(method, false));
|
||||
Introspector.descriptorForElement(method));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -185,6 +181,7 @@ public class MBeanOperationInfo extends MBeanFeatureInfo implements Cloneable {
|
||||
* <p>Since this class is immutable, cloning is chiefly of interest
|
||||
* to subclasses.</p>
|
||||
*/
|
||||
@Override
|
||||
public Object clone () {
|
||||
try {
|
||||
return super.clone() ;
|
||||
@ -257,6 +254,7 @@ public class MBeanOperationInfo extends MBeanFeatureInfo implements Cloneable {
|
||||
return impact;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String impactString;
|
||||
switch (getImpact()) {
|
||||
@ -288,6 +286,7 @@ public class MBeanOperationInfo extends MBeanFeatureInfo implements Cloneable {
|
||||
* to those of this MBeanConstructorInfo. Two signature arrays
|
||||
* are equal if their elements are pairwise equal.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this)
|
||||
return true;
|
||||
@ -327,14 +326,9 @@ public class MBeanOperationInfo extends MBeanFeatureInfo implements Cloneable {
|
||||
|
||||
for (int i = 0; i < classes.length; i++) {
|
||||
Descriptor d = Introspector.descriptorForAnnotations(annots[i]);
|
||||
String description = Introspector.descriptionForParameter(annots[i]);
|
||||
if (description == null)
|
||||
description = "";
|
||||
String name = Introspector.nameForParameter(annots[i]);
|
||||
if (name == null)
|
||||
name = "p" + (i + 1);
|
||||
params[i] = new MBeanParameterInfo(
|
||||
name, classes[i].getName(), description, d);
|
||||
final String pn = "p" + (i + 1);
|
||||
params[i] =
|
||||
new MBeanParameterInfo(pn, classes[i].getName(), "", d);
|
||||
}
|
||||
|
||||
return params;
|
||||
|
||||
@ -25,7 +25,6 @@
|
||||
|
||||
package javax.management;
|
||||
|
||||
import com.sun.jmx.mbeanserver.Util;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.security.Permission;
|
||||
@ -46,7 +45,7 @@ import java.security.Permission;
|
||||
* allowed if the permissions you have {@linkplain #implies imply} the
|
||||
* permission you need.</p>
|
||||
*
|
||||
* <p>An MBeanPermission contains five items of information:</p>
|
||||
* <p>An MBeanPermission contains four items of information:</p>
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
@ -58,23 +57,6 @@ import java.security.Permission;
|
||||
*
|
||||
* <p>The action is returned by {@link #getActions()}.</p>
|
||||
*
|
||||
* <li id="MBeanServerName"><p>The <em>MBean Server name</em>.</p>
|
||||
*
|
||||
* <p>For a permission you need, this is the {@linkplain
|
||||
* javax.management.MBeanServerFactory#getMBeanServerName
|
||||
* name of the MBeanServer}
|
||||
* containing the <a href="#MBeanName">MBean</a> for which the MBean
|
||||
* permission is checked.</p>
|
||||
*
|
||||
* <p>For a permission you have, this is either the {@linkplain
|
||||
* javax.management.MBeanServerFactory#getMBeanServerName
|
||||
* name of the MBeanServer} in which the <a href="#MBeanName">MBean</a>
|
||||
* you have this permission for must be registered,
|
||||
* or a pattern against which that MBean Server name will be matched.<br>
|
||||
* An {@code mbeanServerName} pattern can also be empty or the single
|
||||
* character {@code "*"}, both of which will match any {@code MBeanServer} name.
|
||||
* </p>
|
||||
*
|
||||
* <li><p>The <em>class name</em>.</p>
|
||||
*
|
||||
* <p>For a permission you need, this is the class name of an MBean
|
||||
@ -121,15 +103,15 @@ import java.security.Permission;
|
||||
* </ul>
|
||||
*
|
||||
* <p>If you have an MBeanPermission, it allows operations only if all
|
||||
* five of the items match.</p>
|
||||
* four of the items match.</p>
|
||||
*
|
||||
* <p>The MBean Server name, class name, member, and object name can be written
|
||||
* together as a single string, which is the <em>name</em> of this permission.
|
||||
* <p>The class name, member, and object name can be written together
|
||||
* as a single string, which is the <em>name</em> of this permission.
|
||||
* The name of the permission is the string returned by {@link
|
||||
* Permission#getName() getName()}. The format of the string is:</p>
|
||||
*
|
||||
* <blockquote>
|
||||
* <code>mbeanServerName::className#member[objectName]</code>
|
||||
* <code>className#member[objectName]</code>
|
||||
* </blockquote>
|
||||
*
|
||||
* <p>The object name is written using the usual syntax for {@link
|
||||
@ -137,18 +119,15 @@ import java.security.Permission;
|
||||
* <code>]</code>. It is terminated by a <code>]</code> character
|
||||
* that is the last character in the string.</p>
|
||||
*
|
||||
* <p>One or more of the <code>mbeanServerName</code>, <code>className</code>,
|
||||
* <code>member</code>, or <code>objectName</code> may be omitted. If the
|
||||
* <code>mbeanServerName</code> is omitted, the <code>::</code> may be too (but
|
||||
* does not have to be).
|
||||
* If the <code>member</code> is omitted, the <code>#</code> may be too (but
|
||||
* <p>One or more of the <code>className</code>, <code>member</code>,
|
||||
* or <code>objectName</code> may be omitted. If the
|
||||
* <code>member</code> is omitted, the <code>#</code> may be too (but
|
||||
* does not have to be). If the <code>objectName</code> is omitted,
|
||||
* the <code>[]</code> may be too (but does not have to be). It is
|
||||
* not legal to omit all four items, that is to have a <em>name</em>
|
||||
* not legal to omit all three items, that is to have a <em>name</em>
|
||||
* that is the empty string.</p>
|
||||
*
|
||||
* <p>One or more of the <code>mbeanServerName</code>, <code>className</code>,
|
||||
* <code>member</code>,
|
||||
* <p>One or more of the <code>className</code>, <code>member</code>,
|
||||
* or <code>objectName</code> may be the character "<code>-</code>",
|
||||
* which is equivalent to a null value. A null value is implied by
|
||||
* any value (including another null value) but does not imply any
|
||||
@ -267,13 +246,6 @@ public class MBeanPermission extends Permission {
|
||||
*/
|
||||
private transient ObjectName objectName;
|
||||
|
||||
/**
|
||||
* The name of the MBeanServer in which this permission is checked, or
|
||||
* granted. If null, is implied by any MBean Server name
|
||||
* but does not imply any non-null MBean Server name.
|
||||
*/
|
||||
private transient String mbeanServerName;
|
||||
|
||||
/**
|
||||
* Parse <code>actions</code> parameter.
|
||||
*/
|
||||
@ -311,13 +283,6 @@ public class MBeanPermission extends Permission {
|
||||
throw new IllegalArgumentException("MBeanPermission name " +
|
||||
"cannot be empty");
|
||||
|
||||
final int sepIndex = name.indexOf("::");
|
||||
if (sepIndex < 0) {
|
||||
setMBeanServerName("*");
|
||||
} else {
|
||||
setMBeanServerName(name.substring(0,sepIndex));
|
||||
}
|
||||
|
||||
/* The name looks like "class#member[objectname]". We subtract
|
||||
elements from the right as we parse, so after parsing the
|
||||
objectname we have "class#member" and after parsing the
|
||||
@ -325,14 +290,11 @@ public class MBeanPermission extends Permission {
|
||||
|
||||
// Parse ObjectName
|
||||
|
||||
|
||||
final int start = (sepIndex<0)?0:sepIndex+2;
|
||||
int openingBracket = name.indexOf("[",start);
|
||||
int openingBracket = name.indexOf("[");
|
||||
if (openingBracket == -1) {
|
||||
// If "[on]" missing then ObjectName("*:*")
|
||||
//
|
||||
objectName = ObjectName.WILDCARD;
|
||||
name = name.substring(start);
|
||||
} else {
|
||||
if (!name.endsWith("]")) {
|
||||
throw new IllegalArgumentException("MBeanPermission: " +
|
||||
@ -343,11 +305,11 @@ public class MBeanPermission extends Permission {
|
||||
} else {
|
||||
// Create ObjectName
|
||||
//
|
||||
String on = name.substring(openingBracket + 1,
|
||||
name.length() - 1);
|
||||
try {
|
||||
// If "[]" then ObjectName("*:*")
|
||||
//
|
||||
String on = name.substring(openingBracket + 1,
|
||||
name.length() - 1);
|
||||
if (on.equals(""))
|
||||
objectName = ObjectName.WILDCARD;
|
||||
else if (on.equals("-"))
|
||||
@ -362,7 +324,7 @@ public class MBeanPermission extends Permission {
|
||||
}
|
||||
}
|
||||
|
||||
name = name.substring(start, openingBracket);
|
||||
name = name.substring(0, openingBracket);
|
||||
}
|
||||
|
||||
// Parse member
|
||||
@ -386,9 +348,8 @@ public class MBeanPermission extends Permission {
|
||||
* Assign fields based on className, member, and objectName
|
||||
* parameters.
|
||||
*/
|
||||
private void initName(String mbeanServerName, String className,
|
||||
String member, ObjectName objectName) {
|
||||
setMBeanServerName(mbeanServerName);
|
||||
private void initName(String className, String member,
|
||||
ObjectName objectName) {
|
||||
setClassName(className);
|
||||
setMember(member);
|
||||
this.objectName = objectName;
|
||||
@ -420,30 +381,19 @@ public class MBeanPermission extends Permission {
|
||||
this.member = member;
|
||||
}
|
||||
|
||||
private void setMBeanServerName(String mbeanServerName) {
|
||||
if (mbeanServerName == null || mbeanServerName.equals("-")) {
|
||||
this.mbeanServerName = null;
|
||||
} else if (mbeanServerName.equals("")) {
|
||||
this.mbeanServerName = "*";
|
||||
} else {
|
||||
this.mbeanServerName = mbeanServerName;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>Create a new MBeanPermission object with the specified target name
|
||||
* and actions.</p>
|
||||
*
|
||||
* <p>The target name is of the form
|
||||
* "<code>mbeanServerName::className#member[objectName]</code>" where
|
||||
* each part is optional. It must not be empty or null.</p>
|
||||
* "<code>className#member[objectName]</code>" where each part is
|
||||
* optional. It must not be empty or null.</p>
|
||||
*
|
||||
* <p>The actions parameter contains a comma-separated list of the
|
||||
* desired actions granted on the target name. It must not be
|
||||
* empty or null.</p>
|
||||
*
|
||||
* @param name the quadruplet "mbeanServerName::className#member[objectName]".
|
||||
* @param name the triplet "className#member[objectName]".
|
||||
* @param actions the action string.
|
||||
*
|
||||
* @exception IllegalArgumentException if the <code>name</code> or
|
||||
@ -468,12 +418,6 @@ public class MBeanPermission extends Permission {
|
||||
* optional. This will be the result of {@link #getName()} on the
|
||||
* resultant MBeanPermission.</p>
|
||||
*
|
||||
* <p>This corresponds to a permission granted for all
|
||||
* MBean servers present in the JVM and is equivalent to
|
||||
* {@link #MBeanPermission(String,String,String,ObjectName,String)
|
||||
* MBeanPermission("*",className,member,objectName,actions)}.
|
||||
* </p>
|
||||
*
|
||||
* <p>The actions parameter contains a comma-separated list of the
|
||||
* desired actions granted on the target name. It must not be
|
||||
* empty or null.</p>
|
||||
@ -495,67 +439,17 @@ public class MBeanPermission extends Permission {
|
||||
String member,
|
||||
ObjectName objectName,
|
||||
String actions) {
|
||||
this("*",className,member,objectName,actions);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Create a new MBeanPermission object with the specified target name
|
||||
* (MBean Server name, class name, member, object name) and actions.</p>
|
||||
*
|
||||
* <p>The MBean Server name, class name, member and object name
|
||||
* parameters define a target name of the form
|
||||
* "<code>mbeanServerName::className#member[objectName]</code>" where each
|
||||
* part is optional. This will be the result of {@link #getName()} on the
|
||||
* resultant MBeanPermission.
|
||||
* If the <code>mbeanServerName</code> is empty or exactly {@code "*"}, then
|
||||
* "{@code mbeanServerName::}" is omitted in that result.
|
||||
* </p>
|
||||
*
|
||||
* <p>The actions parameter contains a comma-separated list of the
|
||||
* desired actions granted on the target name. It must not be
|
||||
* empty or null.</p>
|
||||
*
|
||||
* @param mbeanServerName the name of the {@code MBeanServer} to which this
|
||||
* permission applies.
|
||||
* May be null or <code>"-"</code>, which represents an MBeanServer name
|
||||
* that is implied by any MBeanServer name but does not imply any other
|
||||
* MBeanServer name.
|
||||
* @param className the class name to which this permission applies.
|
||||
* May be null or <code>"-"</code>, which represents a class name
|
||||
* that is implied by any class name but does not imply any other
|
||||
* class name.
|
||||
* @param member the member to which this permission applies. May
|
||||
* be null or <code>"-"</code>, which represents a member that is
|
||||
* implied by any member but does not imply any other member.
|
||||
* @param objectName the object name to which this permission
|
||||
* applies. May be null, which represents an object name that is
|
||||
* implied by any object name but does not imply any other object
|
||||
* name.
|
||||
* @param actions the action string.
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public MBeanPermission(String mbeanServerName,
|
||||
String className,
|
||||
String member,
|
||||
ObjectName objectName,
|
||||
String actions) {
|
||||
|
||||
super(makeName(mbeanServerName,className, member, objectName));
|
||||
initName(mbeanServerName,className, member, objectName);
|
||||
super(makeName(className, member, objectName));
|
||||
initName(className, member, objectName);
|
||||
|
||||
this.actions = actions;
|
||||
parseActions();
|
||||
}
|
||||
|
||||
private static String makeName(String mbeanServerName, String className,
|
||||
String member,
|
||||
private static String makeName(String className, String member,
|
||||
ObjectName objectName) {
|
||||
final StringBuilder name = new StringBuilder();
|
||||
if (mbeanServerName == null)
|
||||
mbeanServerName = "-";
|
||||
if (!mbeanServerName.equals("") && !mbeanServerName.equals("*"))
|
||||
name.append(mbeanServerName).append("::");
|
||||
if (className == null)
|
||||
className = "-";
|
||||
name.append(className);
|
||||
@ -1097,9 +991,6 @@ public class MBeanPermission extends Permission {
|
||||
*
|
||||
* <li> <i>p</i> is an instance of MBeanPermission; and</li>
|
||||
*
|
||||
* <li> <i>p</i> has a null mbeanServerName or <i>p</i>'s mbeanServerName
|
||||
* matches this object's mbeanServerName; and</li>
|
||||
*
|
||||
* <li> <i>p</i> has a null className or <i>p</i>'s className
|
||||
* matches this object's className; and</li>
|
||||
*
|
||||
@ -1113,13 +1004,6 @@ public class MBeanPermission extends Permission {
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <p>If this object's mbeanServerName is a pattern, then <i>p</i>'s
|
||||
* mbeanServerName is matched against that pattern. An empty
|
||||
* mbeanServerName is equivalent to "{@code *}". A null
|
||||
* mbeanServerName is equivalent to "{@code -}".</p>
|
||||
* <p>If this object's mbeanServerName is "<code>*</code>" or is
|
||||
* empty, <i>p</i>'s mbeanServerName always matches it.</p>
|
||||
*
|
||||
* <p>If this object's className is "<code>*</code>", <i>p</i>'s
|
||||
* className always matches it. If it is "<code>a.*</code>", <i>p</i>'s
|
||||
* className matches it if it begins with "<code>a.</code>".</p>
|
||||
@ -1166,12 +1050,6 @@ public class MBeanPermission extends Permission {
|
||||
|
||||
// Target name
|
||||
//
|
||||
// The 'mbeanServerName' check is true iff:
|
||||
// 1) the mbeanServerName in 'this' permission is omitted or "*", or
|
||||
// 2) the mbeanServerName in 'that' permission is omitted or "*", or
|
||||
// 3) the mbeanServerName in 'this' permission does pattern
|
||||
// matching with the mbeanServerName in 'that' permission.
|
||||
//
|
||||
// The 'className' check is true iff:
|
||||
// 1) the className in 'this' permission is omitted or "*", or
|
||||
// 2) the className in 'that' permission is omitted or "*", or
|
||||
@ -1198,17 +1076,6 @@ public class MBeanPermission extends Permission {
|
||||
expect that "that" contains a wildcard, since it is a
|
||||
needed permission. So we assume that.classNameExactMatch. */
|
||||
|
||||
if (that.mbeanServerName == null) {
|
||||
// bottom is implied
|
||||
} else if (this.mbeanServerName == null) {
|
||||
// bottom implies nothing but itself
|
||||
return false;
|
||||
} else if (that.mbeanServerName.equals(this.mbeanServerName)) {
|
||||
// exact match
|
||||
} else if (!Util.wildmatch(that.mbeanServerName,this.mbeanServerName)) {
|
||||
return false; // no match
|
||||
}
|
||||
|
||||
if (that.classNamePrefix == null) {
|
||||
// bottom is implied
|
||||
} else if (this.classNamePrefix == null) {
|
||||
|
||||
@ -33,99 +33,6 @@ package javax.management;
|
||||
* to get a reference to the MBean Server and/or its name within that
|
||||
* MBean Server.</p>
|
||||
*
|
||||
* <h4 id="injection">Resource injection</h4>
|
||||
*
|
||||
* <p>As an alternative to implementing {@code MBeanRegistration}, if all that
|
||||
* is needed is the MBean Server or ObjectName then an MBean can use
|
||||
* <em>resource injection</em>.</p>
|
||||
*
|
||||
* <p>If a field in the MBean object has type {@link ObjectName} and has
|
||||
* the {@link javax.annotation.Resource @Resource} annotation,
|
||||
* then the {@code ObjectName} under which the MBean is registered is
|
||||
* assigned to that field during registration. Likewise, if a field has type
|
||||
* {@link MBeanServer} and the <code>@Resource</code> annotation, then it will
|
||||
* be set to the {@code MBeanServer} in which the MBean is registered.</p>
|
||||
*
|
||||
* <p>For example:</p>
|
||||
*
|
||||
* <pre>
|
||||
* public Configuration implements ConfigurationMBean {
|
||||
* @Resource
|
||||
* private volatile MBeanServer mbeanServer;
|
||||
* @Resource
|
||||
* private volatile ObjectName objectName;
|
||||
* ...
|
||||
* void unregisterSelf() throws Exception {
|
||||
* mbeanServer.unregisterMBean(objectName);
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>Resource injection can also be used on fields of type
|
||||
* {@link SendNotification} to simplify notification sending. Such a field
|
||||
* will get a reference to an object of type {@code SendNotification} when
|
||||
* the MBean is registered, and it can use this reference to send notifications.
|
||||
* For example:</p>
|
||||
*
|
||||
* <pre>
|
||||
* public Configuration implements ConfigurationMBean {
|
||||
* @Resource
|
||||
* private volatile SendNotification sender;
|
||||
* ...
|
||||
* private void updated() {
|
||||
* Notification n = new Notification(...);
|
||||
* sender.sendNotification(n);
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>(Listeners may be invoked in the same thread as the caller of
|
||||
* {@code sender.sendNotification}.)</p>
|
||||
*
|
||||
* <p>A field to be injected must not be static. It is recommended that
|
||||
* such fields be declared {@code volatile}.</p>
|
||||
*
|
||||
* <p>It is also possible to use the <code>@Resource</code> annotation on
|
||||
* methods. Such a method must have a {@code void} return type and a single
|
||||
* argument of the appropriate type, for example {@code ObjectName}.</p>
|
||||
*
|
||||
* <p>Any number of fields and methods may have the <code>@Resource</code>
|
||||
* annotation. All fields and methods with type {@code ObjectName}
|
||||
* (for example) will receive the same {@code ObjectName} value.</p>
|
||||
*
|
||||
* <p>Resource injection is available for all types of MBeans, not just
|
||||
* Standard MBeans.</p>
|
||||
*
|
||||
* <p>If an MBean implements the {@link DynamicWrapperMBean} interface then
|
||||
* resource injection happens on the object returned by that interface's
|
||||
* {@link DynamicWrapperMBean#getWrappedObject() getWrappedObject()} method
|
||||
* rather than on the MBean object itself.
|
||||
*
|
||||
* <p>Resource injection happens after the {@link #preRegister preRegister}
|
||||
* method is called (if any), and before the MBean is actually registered
|
||||
* in the MBean Server. If a <code>@Resource</code> method throws
|
||||
* an exception, the effect is the same as if {@code preRegister} had
|
||||
* thrown the exception. In particular it will prevent the MBean from being
|
||||
* registered.</p>
|
||||
*
|
||||
* <p>Resource injection can be used on a field or method where the type
|
||||
* is a parent of the injected type, if the injected type is explicitly
|
||||
* specified in the <code>@Resource</code> annotation. For example:</p>
|
||||
*
|
||||
* <pre>
|
||||
* @Resource(type = MBeanServer.class)
|
||||
* private volatile MBeanServerConnection mbsc;
|
||||
* </pre>
|
||||
*
|
||||
* <p>Formally, suppose <em>R</em> is the type in the <code>@Resource</code>
|
||||
* annotation and <em>T</em> is the type of the method parameter or field.
|
||||
* Then one of <em>R</em> and <em>T</em> must be a subtype of the other
|
||||
* (or they must be the same type). Injection happens if this subtype
|
||||
* is {@code MBeanServer}, {@code ObjectName}, or {@code SendNotification}.
|
||||
* Otherwise the <code>@Resource</code> annotation is ignored.</p>
|
||||
*
|
||||
* <p>Resource injection in MBeans is new in version 2.0 of the JMX API.</p>
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
public interface MBeanRegistration {
|
||||
@ -196,7 +103,7 @@ public interface MBeanRegistration {
|
||||
* <p>If the implementation of this method throws a {@link RuntimeException}
|
||||
* or an {@link Error}, the MBean Server will rethrow those inside
|
||||
* a {@link RuntimeMBeanException} or {@link RuntimeErrorException},
|
||||
* respectively. However, throwing an excepption in {@code postDeregister}
|
||||
* respectively. However, throwing an exception in {@code postDeregister}
|
||||
* will not change the state of the MBean:
|
||||
* the MBean was already successfully deregistered and will remain so. </p>
|
||||
* <p>This might be confusing for the code calling
|
||||
|
||||
@ -61,13 +61,9 @@ import javax.management.loading.ClassLoaderRepository;
|
||||
* <CODE>ObjectName</CODE> is: <BR>
|
||||
* <CODE>JMImplementation:type=MBeanServerDelegate</CODE>.</p>
|
||||
*
|
||||
* <p id="security">An object obtained from the {@link
|
||||
* MBeanServerFactory#createMBeanServer(String) createMBeanServer}, {@link
|
||||
* MBeanServerFactory#createNamedMBeanServer(String,String) createNamedMBeanServer},
|
||||
* {@link
|
||||
* MBeanServerFactory#newMBeanServer(String) newMBeanServer}, or
|
||||
* {@link
|
||||
* MBeanServerFactory#newNamedMBeanServer(String,String) newNamedMBeanServer}
|
||||
* <p>An object obtained from the {@link
|
||||
* MBeanServerFactory#createMBeanServer(String) createMBeanServer} or
|
||||
* {@link MBeanServerFactory#newMBeanServer(String) newMBeanServer}
|
||||
* methods of the {@link MBeanServerFactory} class applies security
|
||||
* checks to its methods, as follows.</p>
|
||||
*
|
||||
@ -77,26 +73,10 @@ import javax.management.loading.ClassLoaderRepository;
|
||||
*
|
||||
* <p>Assuming that there is a security manager, or that the
|
||||
* implementation chooses to make checks anyway, the checks are made
|
||||
* as detailed below.
|
||||
* In what follows, and unless otherwise specified:
|
||||
* </p>
|
||||
* <ul><li><code>className</code> is the
|
||||
* as detailed below. In what follows, and unless otherwise specified,
|
||||
* {@code className} is the
|
||||
* string returned by {@link MBeanInfo#getClassName()} for the target
|
||||
* MBean,</li>
|
||||
* <li>{@code mbeanServerName} is the
|
||||
* {@linkplain MBeanServerFactory#getMBeanServerName name of the
|
||||
* MBean Server} in which the target MBean is registered. This is the
|
||||
* value returned by {@link MBeanServerFactory#getMBeanServerName
|
||||
* MBeanServerFactory.getMBeanServerName(MBeanServer)}, and
|
||||
* is usually the {@code mbeanServerName} parameter that was supplied
|
||||
* to the {@link
|
||||
* MBeanServerFactory#createNamedMBeanServer(String,String)
|
||||
* createNamedMBeanServer} or {@link
|
||||
* MBeanServerFactory#newNamedMBeanServer(String,String) newNamedMBeanServer}
|
||||
* methods of the {@link MBeanServerFactory} when the MBeanServer was created,
|
||||
* or {@value javax.management.MBeanServerFactory#DEFAULT_MBEANSERVER_NAME} if
|
||||
* no name was supplied.
|
||||
* </li></ul>
|
||||
* MBean.</p>
|
||||
*
|
||||
* <p>If a security check fails, the method throws {@link
|
||||
* SecurityException}.</p>
|
||||
@ -110,87 +90,79 @@ import javax.management.loading.ClassLoaderRepository;
|
||||
*
|
||||
* <li><p>For the {@link #invoke invoke} method, the caller's
|
||||
* permissions must imply {@link
|
||||
* MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
|
||||
* MBeanPermission(mbeanServerName, className, operationName, name, "invoke")}.
|
||||
* </p>
|
||||
* MBeanPermission#MBeanPermission(String,String,ObjectName,String)
|
||||
* MBeanPermission(className, operationName, name, "invoke")}.</p>
|
||||
*
|
||||
* <li><p>For the {@link #getAttribute getAttribute} method, the
|
||||
* caller's permissions must imply {@link
|
||||
* MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
|
||||
* MBeanPermission(mbeanServerName, className, attribute, name,
|
||||
* "getAttribute")}.</p>
|
||||
* MBeanPermission#MBeanPermission(String,String,ObjectName,String)
|
||||
* MBeanPermission(className, attribute, name, "getAttribute")}.</p>
|
||||
*
|
||||
* <li><p>For the {@link #getAttributes getAttributes} method, the
|
||||
* caller's permissions must imply {@link
|
||||
* MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
|
||||
* MBeanPermission(mbeanServerName,className, null, name, "getAttribute")}.
|
||||
* MBeanPermission#MBeanPermission(String,String,ObjectName,String)
|
||||
* MBeanPermission(className, null, name, "getAttribute")}.
|
||||
* Additionally, for each attribute <em>a</em> in the {@link
|
||||
* AttributeList}, if the caller's permissions do not imply {@link
|
||||
* MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
|
||||
* MBeanPermission(mbeanServerName, className, <em>a</em>, name,
|
||||
* "getAttribute")}, the
|
||||
* MBeanPermission#MBeanPermission(String,String,ObjectName,String)
|
||||
* MBeanPermission(className, <em>a</em>, name, "getAttribute")}, the
|
||||
* MBean server will behave as if that attribute had not been in the
|
||||
* supplied list.</p>
|
||||
*
|
||||
* <li><p>For the {@link #setAttribute setAttribute} method, the
|
||||
* caller's permissions must imply {@link
|
||||
* MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
|
||||
* MBeanPermission(mbeanServerName, className, attrName, name,
|
||||
* "setAttribute")}, where
|
||||
* MBeanPermission#MBeanPermission(String,String,ObjectName,String)
|
||||
* MBeanPermission(className, attrName, name, "setAttribute")}, where
|
||||
* <code>attrName</code> is {@link Attribute#getName()
|
||||
* attribute.getName()}.</p>
|
||||
*
|
||||
* <li><p>For the {@link #setAttributes setAttributes} method, the
|
||||
* caller's permissions must imply {@link
|
||||
* MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
|
||||
* MBeanPermission(mbeanServerName, className, null, name, "setAttribute")}.
|
||||
* MBeanPermission#MBeanPermission(String,String,ObjectName,String)
|
||||
* MBeanPermission(className, null, name, "setAttribute")}.
|
||||
* Additionally, for each attribute <em>a</em> in the {@link
|
||||
* AttributeList}, if the caller's permissions do not imply {@link
|
||||
* MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
|
||||
* MBeanPermission(mbeanServerName, className, <em>a</em>, name,
|
||||
* "setAttribute")}, the
|
||||
* MBeanPermission#MBeanPermission(String,String,ObjectName,String)
|
||||
* MBeanPermission(className, <em>a</em>, name, "setAttribute")}, the
|
||||
* MBean server will behave as if that attribute had not been in the
|
||||
* supplied list.</p>
|
||||
*
|
||||
* <li><p>For the <code>addNotificationListener</code> methods,
|
||||
* the caller's permissions must imply {@link
|
||||
* MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
|
||||
* MBeanPermission(mbeanServerName, className, null, name,
|
||||
* MBeanPermission#MBeanPermission(String,String,ObjectName,String)
|
||||
* MBeanPermission(className, null, name,
|
||||
* "addNotificationListener")}.</p>
|
||||
*
|
||||
* <li><p>For the <code>removeNotificationListener</code> methods,
|
||||
* the caller's permissions must imply {@link
|
||||
* MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
|
||||
* MBeanPermission(mbeanServerName, className, null, name,
|
||||
* MBeanPermission#MBeanPermission(String,String,ObjectName,String)
|
||||
* MBeanPermission(className, null, name,
|
||||
* "removeNotificationListener")}.</p>
|
||||
*
|
||||
* <li><p>For the {@link #getMBeanInfo getMBeanInfo} method, the
|
||||
* caller's permissions must imply {@link
|
||||
* MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
|
||||
* MBeanPermission(mbeanServerName, className, null, name, "getMBeanInfo")}.
|
||||
* </p>
|
||||
* MBeanPermission#MBeanPermission(String,String,ObjectName,String)
|
||||
* MBeanPermission(className, null, name, "getMBeanInfo")}.</p>
|
||||
*
|
||||
* <li><p>For the {@link #getObjectInstance getObjectInstance} method,
|
||||
* the caller's permissions must imply {@link
|
||||
* MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
|
||||
* MBeanPermission(mbeanServerName, className, null, name,
|
||||
* "getObjectInstance")}.</p>
|
||||
* MBeanPermission#MBeanPermission(String,String,ObjectName,String)
|
||||
* MBeanPermission(className, null, name, "getObjectInstance")}.</p>
|
||||
*
|
||||
* <li><p>For the {@link #isInstanceOf isInstanceOf} method, the
|
||||
* caller's permissions must imply {@link
|
||||
* MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
|
||||
* MBeanPermission(mbeanServerName, className, null, name, "isInstanceOf")}.
|
||||
* </p>
|
||||
* MBeanPermission#MBeanPermission(String,String,ObjectName,String)
|
||||
* MBeanPermission(className, null, name, "isInstanceOf")}.</p>
|
||||
*
|
||||
* <li><p>For the {@link #queryMBeans queryMBeans} method, the
|
||||
* caller's permissions must imply {@link
|
||||
* MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
|
||||
* MBeanPermission(mbeanServerName, null, null, null, "queryMBeans")}.
|
||||
* MBeanPermission#MBeanPermission(String,String,ObjectName,String)
|
||||
* MBeanPermission(null, null, null, "queryMBeans")}.
|
||||
* Additionally, for each MBean <em>n</em> that matches <code>name</code>,
|
||||
* if the caller's permissions do not imply {@link
|
||||
* MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
|
||||
* MBeanPermission(mbeanServerName, className, null, <em>n</em>, "queryMBeans")},
|
||||
* the MBean server will behave as if that MBean did not exist.</p>
|
||||
* MBeanPermission#MBeanPermission(String,String,ObjectName,String)
|
||||
* MBeanPermission(className, null, <em>n</em>, "queryMBeans")}, the
|
||||
* MBean server will behave as if that MBean did not exist.</p>
|
||||
*
|
||||
* <p>Certain query elements perform operations on the MBean server.
|
||||
* If the caller does not have the required permissions for a given
|
||||
@ -208,10 +180,10 @@ import javax.management.loading.ClassLoaderRepository;
|
||||
*
|
||||
* <li><p>For the {@link #getDomains getDomains} method, the caller's
|
||||
* permissions must imply {@link
|
||||
* MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
|
||||
* MBeanPermission(mbeanServerName, null, null, null, "getDomains")}.
|
||||
* Additionally, for each domain <var>d</var> in the returned array, if the
|
||||
* caller's permissions do not imply {@link
|
||||
* MBeanPermission#MBeanPermission(String,String,ObjectName,String)
|
||||
* MBeanPermission(null, null, null, "getDomains")}. Additionally,
|
||||
* for each domain <var>d</var> in the returned array, if the caller's
|
||||
* permissions do not imply {@link
|
||||
* MBeanPermission#MBeanPermission(String,String,ObjectName,String)
|
||||
* MBeanPermission(null, null, new ObjectName("<var>d</var>:x=x"),
|
||||
* "getDomains")}, the domain is eliminated from the array. Here,
|
||||
@ -220,22 +192,21 @@ import javax.management.loading.ClassLoaderRepository;
|
||||
*
|
||||
* <li><p>For the {@link #getClassLoader getClassLoader} method, the
|
||||
* caller's permissions must imply {@link
|
||||
* MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
|
||||
* MBeanPermission(mbeanServerName, className, null, loaderName,
|
||||
* MBeanPermission#MBeanPermission(String,String,ObjectName,String)
|
||||
* MBeanPermission(className, null, loaderName,
|
||||
* "getClassLoader")}.</p>
|
||||
*
|
||||
* <li><p>For the {@link #getClassLoaderFor getClassLoaderFor} method,
|
||||
* the caller's permissions must imply {@link
|
||||
* MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
|
||||
* MBeanPermission(mbeanServerName, className, null, mbeanName,
|
||||
* MBeanPermission#MBeanPermission(String,String,ObjectName,String)
|
||||
* MBeanPermission(className, null, mbeanName,
|
||||
* "getClassLoaderFor")}.</p>
|
||||
*
|
||||
* <li><p>For the {@link #getClassLoaderRepository
|
||||
* getClassLoaderRepository} method, the caller's permissions must
|
||||
* imply {@link
|
||||
* MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
|
||||
* MBeanPermission(mbeanServerName, null, null, null,
|
||||
* "getClassLoaderRepository")}.</p>
|
||||
* MBeanPermission#MBeanPermission(String,String,ObjectName,String)
|
||||
* MBeanPermission(null, null, null, "getClassLoaderRepository")}.</p>
|
||||
*
|
||||
* <li><p>For the deprecated <code>deserialize</code> methods, the
|
||||
* required permissions are the same as for the methods that replace
|
||||
@ -243,15 +214,15 @@ import javax.management.loading.ClassLoaderRepository;
|
||||
*
|
||||
* <li><p>For the <code>instantiate</code> methods, the caller's
|
||||
* permissions must imply {@link
|
||||
* MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
|
||||
* MBeanPermission(mbeanServerName, className, null, null, "instantiate")},
|
||||
* MBeanPermission#MBeanPermission(String,String,ObjectName,String)
|
||||
* MBeanPermission(className, null, null, "instantiate")},
|
||||
* where {@code className} is the name of the class which is to
|
||||
* be instantiated.</p>
|
||||
*
|
||||
* <li><p>For the {@link #registerMBean registerMBean} method, the
|
||||
* caller's permissions must imply {@link
|
||||
* MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
|
||||
* MBeanPermission(mbeanServerName, className, null, name, "registerMBean")}.
|
||||
* MBeanPermission#MBeanPermission(String,String,ObjectName,String)
|
||||
* MBeanPermission(className, null, name, "registerMBean")}.
|
||||
*
|
||||
* <p>If the <code>MBeanPermission</code> check succeeds, the MBean's
|
||||
* class is validated by checking that its {@link
|
||||
@ -271,8 +242,8 @@ import javax.management.loading.ClassLoaderRepository;
|
||||
*
|
||||
* <li><p>For the {@link #unregisterMBean unregisterMBean} method,
|
||||
* the caller's permissions must imply {@link
|
||||
* MBeanPermission#MBeanPermission(String,String,String,ObjectName,String)
|
||||
* MBeanPermission(mbeanServerName, className, null, name, "unregisterMBean")}.
|
||||
* MBeanPermission#MBeanPermission(String,String,ObjectName,String)
|
||||
* MBeanPermission(className, null, name, "unregisterMBean")}.</p>
|
||||
* </p>
|
||||
*
|
||||
* </ul>
|
||||
@ -351,14 +322,11 @@ public interface MBeanServer extends MBeanServerConnection {
|
||||
|
||||
/**
|
||||
* <p>Registers a pre-existing object as an MBean with the MBean
|
||||
* server. If the object name given is null, the
|
||||
* MBean must provide its own name in one or both of two ways: by implementing the {@link
|
||||
* server. If the object name given is null, the MBean must
|
||||
* provide its own name by implementing the {@link
|
||||
* javax.management.MBeanRegistration MBeanRegistration} interface
|
||||
* and returning the name from the {@link
|
||||
* MBeanRegistration#preRegister preRegister} method; or by defining
|
||||
* an {@code objectNameTemplate} field in its {@link Descriptor},
|
||||
* typically using the {@link ObjectNameTemplate @ObjectNameTemplate}
|
||||
* annotation.</p>
|
||||
* MBeanRegistration#preRegister preRegister} method.
|
||||
*
|
||||
* <p>If this method successfully registers an MBean, a notification
|
||||
* is sent as described <a href="#notif">above</a>.</p>
|
||||
@ -764,16 +732,13 @@ public interface MBeanServer extends MBeanServerConnection {
|
||||
ReflectionException;
|
||||
|
||||
/**
|
||||
* <p>Return the {@link java.lang.ClassLoader} that was used for loading
|
||||
* the class of the named MBean. If the MBean implements the {@link
|
||||
* DynamicWrapperMBean} interface, then the returned value is the
|
||||
* result of the {@link DynamicWrapperMBean#getWrappedClassLoader()}
|
||||
* method.</p>
|
||||
* <p>Return the {@link java.lang.ClassLoader} that was used for
|
||||
* loading the class of the named MBean.</p>
|
||||
*
|
||||
* @param mbeanName The ObjectName of the MBean.
|
||||
*
|
||||
* @return The ClassLoader used for that MBean. If <var>l</var>
|
||||
* is the value specified by the rules above, and <var>r</var> is the
|
||||
* is the MBean's actual ClassLoader, and <var>r</var> is the
|
||||
* returned value, then either:
|
||||
*
|
||||
* <ul>
|
||||
|
||||
@ -29,7 +29,6 @@ package javax.management;
|
||||
// java import
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import javax.management.event.NotificationManager;
|
||||
|
||||
|
||||
/**
|
||||
@ -40,20 +39,17 @@ import javax.management.event.NotificationManager;
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
public interface MBeanServerConnection extends NotificationManager {
|
||||
public interface MBeanServerConnection {
|
||||
/**
|
||||
* <p>Instantiates and registers an MBean in the MBean server. The
|
||||
* MBean server will use its {@link
|
||||
* javax.management.loading.ClassLoaderRepository Default Loader
|
||||
* Repository} to load the class of the MBean. An object name is
|
||||
* associated with the MBean. If the object name given is null, the
|
||||
* MBean must provide its own name in one or both of two ways: by implementing the {@link
|
||||
* MBean must provide its own name by implementing the {@link
|
||||
* javax.management.MBeanRegistration MBeanRegistration} interface
|
||||
* and returning the name from the {@link
|
||||
* MBeanRegistration#preRegister preRegister} method; or by defining
|
||||
* an {@code objectNameTemplate} field in its {@link Descriptor},
|
||||
* typically using the {@link ObjectNameTemplate @ObjectNameTemplate}
|
||||
* annotation.</p>
|
||||
* MBeanRegistration#preRegister preRegister} method.</p>
|
||||
*
|
||||
* <p>This method is equivalent to {@link
|
||||
* #createMBean(String,ObjectName,Object[],String[])
|
||||
@ -122,14 +118,11 @@ public interface MBeanServerConnection extends NotificationManager {
|
||||
* class loader to be used is identified by its object name. An
|
||||
* object name is associated with the MBean. If the object name of
|
||||
* the loader is null, the ClassLoader that loaded the MBean
|
||||
* server will be used. If the object name given is null, the
|
||||
* MBean must provide its own name in one or both of two ways: by implementing the {@link
|
||||
* server will be used. If the MBean's object name given is null,
|
||||
* the MBean must provide its own name by implementing the {@link
|
||||
* javax.management.MBeanRegistration MBeanRegistration} interface
|
||||
* and returning the name from the {@link
|
||||
* MBeanRegistration#preRegister preRegister} method; or by defining
|
||||
* an {@code objectNameTemplate} field in its {@link Descriptor},
|
||||
* typically using the {@link ObjectNameTemplate @ObjectNameTemplate}
|
||||
* annotation.</p>
|
||||
* MBeanRegistration#preRegister preRegister} method.</p>
|
||||
*
|
||||
* <p>This method is equivalent to {@link
|
||||
* #createMBean(String,ObjectName,ObjectName,Object[],String[])
|
||||
@ -205,13 +198,10 @@ public interface MBeanServerConnection extends NotificationManager {
|
||||
* javax.management.loading.ClassLoaderRepository Default Loader
|
||||
* Repository} to load the class of the MBean. An object name is
|
||||
* associated with the MBean. If the object name given is null, the
|
||||
* MBean must provide its own name in one or both of two ways: by implementing the {@link
|
||||
* MBean must provide its own name by implementing the {@link
|
||||
* javax.management.MBeanRegistration MBeanRegistration} interface
|
||||
* and returning the name from the {@link
|
||||
* MBeanRegistration#preRegister preRegister} method; or by defining
|
||||
* an {@code objectNameTemplate} field in its {@link Descriptor},
|
||||
* typically using the {@link ObjectNameTemplate @ObjectNameTemplate}
|
||||
* annotation.</p>
|
||||
* MBeanRegistration#preRegister preRegister} method.
|
||||
*
|
||||
* @param className The class name of the MBean to be instantiated.
|
||||
* @param name The object name of the MBean. May be null.
|
||||
@ -280,14 +270,11 @@ public interface MBeanServerConnection extends NotificationManager {
|
||||
* class loader to be used is identified by its object name. An
|
||||
* object name is associated with the MBean. If the object name of
|
||||
* the loader is not specified, the ClassLoader that loaded the
|
||||
* MBean server will be used. If the object name given is null, the
|
||||
* MBean must provide its own name in one or both of two ways: by implementing the {@link
|
||||
* javax.management.MBeanRegistration MBeanRegistration} interface
|
||||
* and returning the name from the {@link
|
||||
* MBeanRegistration#preRegister preRegister} method; or by defining
|
||||
* an {@code objectNameTemplate} field in its {@link Descriptor},
|
||||
* typically using the {@link ObjectNameTemplate @ObjectNameTemplate}
|
||||
* annotation.</p>
|
||||
* MBean server will be used. If the MBean object name given is
|
||||
* null, the MBean must provide its own name by implementing the
|
||||
* {@link javax.management.MBeanRegistration MBeanRegistration}
|
||||
* interface and returning the name from the {@link
|
||||
* MBeanRegistration#preRegister preRegister} method.
|
||||
*
|
||||
* @param className The class name of the MBean to be instantiated.
|
||||
* @param name The object name of the MBean. May be null.
|
||||
@ -436,17 +423,7 @@ public interface MBeanServerConnection extends NotificationManager {
|
||||
* specified, all the MBeans registered will be retrieved.
|
||||
* @param query The query expression to be applied for selecting
|
||||
* MBeans. If null no query expression will be applied for
|
||||
* selecting MBeans. ObjectName patterns that may be contained in the
|
||||
* query expression will be
|
||||
* <a href="namespace/package-summary.html#NamespaceAndQueries"><!--
|
||||
* -->evaluated</a> in the context of the
|
||||
* {@link javax.management.namespace namespace}
|
||||
* in which the MBeans selected by {@code name} are registered.
|
||||
* Thus, in the {@code query} parameter, no ObjectName pattern containing a
|
||||
* namespace path can match any of the MBean names selected by {@code name}.
|
||||
* See the
|
||||
* <a href="namespace/package-summary.html#RejectedNamespacePatterns"><!--
|
||||
* -->namespaces documentation</a> for more details.
|
||||
* selecting MBeans.
|
||||
*
|
||||
* @return A set containing the <CODE>ObjectInstance</CODE>
|
||||
* objects for the selected MBeans. If no MBean satisfies the
|
||||
@ -454,11 +431,6 @@ public interface MBeanServerConnection extends NotificationManager {
|
||||
*
|
||||
* @exception IOException A communication problem occurred when
|
||||
* talking to the MBean server.
|
||||
* @exception RuntimeOperationsException Wraps a
|
||||
* <CODE>java.lang.IllegalArgumentException</CODE>: The <em>name</em>
|
||||
* parameter contains an invalid pattern. See the
|
||||
* <a href="namespace/package-summary.html#RejectedNamespacePatterns"><!--
|
||||
* -->namespaces documentation</a> for more details.
|
||||
*/
|
||||
public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query)
|
||||
throws IOException;
|
||||
@ -479,17 +451,7 @@ public interface MBeanServerConnection extends NotificationManager {
|
||||
* specified, the name of all registered MBeans will be retrieved.
|
||||
* @param query The query expression to be applied for selecting
|
||||
* MBeans. If null no query expression will be applied for
|
||||
* selecting MBeans. ObjectName patterns that may be contained in the
|
||||
* query expression will be
|
||||
* <a href="namespace/package-summary.html#NamespaceAndQueries"><!--
|
||||
* -->evaluated</a> in the context of the
|
||||
* {@link javax.management.namespace namespace}
|
||||
* in which the MBeans slected by {@code name} are registered.
|
||||
* Thus, in the {@code query} parameter, no ObjectName pattern containing a
|
||||
* namespace path can match any of the MBean names selected by {@code name}.
|
||||
* See the
|
||||
* <a href="namespace/package-summary.html#RejectedNamespacePatterns"><!--
|
||||
* -->namespaces documentation</a> for more details.
|
||||
* selecting MBeans.
|
||||
*
|
||||
* @return A set containing the ObjectNames for the MBeans
|
||||
* selected. If no MBean satisfies the query, an empty list is
|
||||
@ -497,11 +459,6 @@ public interface MBeanServerConnection extends NotificationManager {
|
||||
*
|
||||
* @exception IOException A communication problem occurred when
|
||||
* talking to the MBean server.
|
||||
* @exception RuntimeOperationsException Wraps a
|
||||
* <CODE>java.lang.IllegalArgumentException</CODE>: The <em>name</em>
|
||||
* parameter contains an invalid pattern. See the
|
||||
* <a href="namespace/package-summary.html#RejectedNamespacePatterns"><!--
|
||||
* -->namespaces documentation</a> for more details.
|
||||
*/
|
||||
public Set<ObjectName> queryNames(ObjectName name, QueryExp query)
|
||||
throws IOException;
|
||||
@ -594,7 +551,8 @@ public interface MBeanServerConnection extends NotificationManager {
|
||||
* else {
|
||||
* {@code List<String>} missing = new {@code ArrayList<String>}(<!--
|
||||
* -->{@link java.util.Arrays#asList Arrays.asList}(attrNames));
|
||||
* missing.removeAll(list.toMap().keySet());
|
||||
* for (Attribute a : list.asList())
|
||||
* missing.remove(a.getName());
|
||||
* System.out.println("Did not retrieve: " + missing);
|
||||
* }
|
||||
* </pre>
|
||||
@ -681,9 +639,11 @@ public interface MBeanServerConnection extends NotificationManager {
|
||||
* if (inputAttrs.size() == outputAttrs.size())
|
||||
* System.out.println("All attributes were set successfully");
|
||||
* else {
|
||||
* {@code List<String>} missing = new {@code ArrayList<String>}(<!--
|
||||
* -->inputAttrs.toMap().keySet());
|
||||
* missing.removeAll(outputAttrs.toMap().keySet());
|
||||
* {@code List<String>} missing = new {@code ArrayList<String>}();
|
||||
* for (Attribute a : inputAttrs.asList())
|
||||
* missing.add(a.getName());
|
||||
* for (Attribute a : outputAttrs.asList())
|
||||
* missing.remove(a.getName());
|
||||
* System.out.println("Did not set: " + missing);
|
||||
* }
|
||||
* </pre>
|
||||
@ -809,7 +769,28 @@ public interface MBeanServerConnection extends NotificationManager {
|
||||
public String[] getDomains()
|
||||
throws IOException;
|
||||
|
||||
// doc inherited from NotificationManager
|
||||
/**
|
||||
* <p>Adds a listener to a registered MBean.
|
||||
* Notifications emitted by the MBean will be forwarded to the listener.</p>
|
||||
*
|
||||
* @param name The name of the MBean on which the listener should
|
||||
* be added.
|
||||
* @param listener The listener object which will handle the
|
||||
* notifications emitted by the registered MBean.
|
||||
* @param filter The filter object. If filter is null, no
|
||||
* filtering will be performed before handling notifications.
|
||||
* @param handback The context to be sent to the listener when a
|
||||
* notification is emitted.
|
||||
*
|
||||
* @exception InstanceNotFoundException The MBean name provided
|
||||
* does not match any of the registered MBeans.
|
||||
* @exception IOException A communication problem occurred when
|
||||
* talking to the MBean server.
|
||||
*
|
||||
* @see #removeNotificationListener(ObjectName, NotificationListener)
|
||||
* @see #removeNotificationListener(ObjectName, NotificationListener,
|
||||
* NotificationFilter, Object)
|
||||
*/
|
||||
public void addNotificationListener(ObjectName name,
|
||||
NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
@ -926,13 +907,65 @@ public interface MBeanServerConnection extends NotificationManager {
|
||||
throws InstanceNotFoundException, ListenerNotFoundException,
|
||||
IOException;
|
||||
|
||||
// doc inherited from NotificationManager
|
||||
|
||||
/**
|
||||
* <p>Removes a listener from a registered MBean.</p>
|
||||
*
|
||||
* <P> If the listener is registered more than once, perhaps with
|
||||
* different filters or callbacks, this method will remove all
|
||||
* those registrations.
|
||||
*
|
||||
* @param name The name of the MBean on which the listener should
|
||||
* be removed.
|
||||
* @param listener The listener to be removed.
|
||||
*
|
||||
* @exception InstanceNotFoundException The MBean name provided
|
||||
* does not match any of the registered MBeans.
|
||||
* @exception ListenerNotFoundException The listener is not
|
||||
* registered in the MBean.
|
||||
* @exception IOException A communication problem occurred when
|
||||
* talking to the MBean server.
|
||||
*
|
||||
* @see #addNotificationListener(ObjectName, NotificationListener,
|
||||
* NotificationFilter, Object)
|
||||
*/
|
||||
public void removeNotificationListener(ObjectName name,
|
||||
NotificationListener listener)
|
||||
throws InstanceNotFoundException, ListenerNotFoundException,
|
||||
IOException;
|
||||
|
||||
// doc inherited from NotificationManager
|
||||
/**
|
||||
* <p>Removes a listener from a registered MBean.</p>
|
||||
*
|
||||
* <p>The MBean must have a listener that exactly matches the
|
||||
* given <code>listener</code>, <code>filter</code>, and
|
||||
* <code>handback</code> parameters. If there is more than one
|
||||
* such listener, only one is removed.</p>
|
||||
*
|
||||
* <p>The <code>filter</code> and <code>handback</code> parameters
|
||||
* may be null if and only if they are null in a listener to be
|
||||
* removed.</p>
|
||||
*
|
||||
* @param name The name of the MBean on which the listener should
|
||||
* be removed.
|
||||
* @param listener The listener to be removed.
|
||||
* @param filter The filter that was specified when the listener
|
||||
* was added.
|
||||
* @param handback The handback that was specified when the
|
||||
* listener was added.
|
||||
*
|
||||
* @exception InstanceNotFoundException The MBean name provided
|
||||
* does not match any of the registered MBeans.
|
||||
* @exception ListenerNotFoundException The listener is not
|
||||
* registered in the MBean, or it is not registered with the given
|
||||
* filter and handback.
|
||||
* @exception IOException A communication problem occurred when
|
||||
* talking to the MBean server.
|
||||
*
|
||||
* @see #addNotificationListener(ObjectName, NotificationListener,
|
||||
* NotificationFilter, Object)
|
||||
*
|
||||
*/
|
||||
public void removeNotificationListener(ObjectName name,
|
||||
NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
@ -986,12 +1019,6 @@ public interface MBeanServerConnection extends NotificationManager {
|
||||
*
|
||||
* <p>Otherwise, the result is false.</p>
|
||||
*
|
||||
* <p>If the MBean implements the {@link DynamicWrapperMBean}
|
||||
* interface, then in the above rules X is the result of the MBean's {@link
|
||||
* DynamicWrapperMBean#getWrappedObject() getWrappedObject()} method and L
|
||||
* is the result of its {@link DynamicWrapperMBean#getWrappedClassLoader()
|
||||
* getWrappedClassLoader()} method.
|
||||
*
|
||||
* @param name The <CODE>ObjectName</CODE> of the MBean.
|
||||
* @param className The name of the class.
|
||||
*
|
||||
|
||||
@ -41,7 +41,6 @@ public class MBeanServerDelegate implements MBeanServerDelegateMBean,
|
||||
|
||||
/** The MBean server agent identification.*/
|
||||
private String mbeanServerId ;
|
||||
private String mbeanServerName;
|
||||
|
||||
/** The NotificationBroadcasterSupport object that sends the
|
||||
notifications */
|
||||
@ -71,7 +70,6 @@ public class MBeanServerDelegate implements MBeanServerDelegateMBean,
|
||||
public MBeanServerDelegate () {
|
||||
stamp = getStamp();
|
||||
broadcaster = new NotificationBroadcasterSupport() ;
|
||||
mbeanServerName=null;
|
||||
}
|
||||
|
||||
|
||||
@ -90,98 +88,11 @@ public class MBeanServerDelegate implements MBeanServerDelegateMBean,
|
||||
"using \"localhost\" instead. Cause is: "+e);
|
||||
localHost = "localhost";
|
||||
}
|
||||
mbeanServerId =
|
||||
Util.insertMBeanServerName(localHost + "_" + stamp,
|
||||
mbeanServerName);
|
||||
mbeanServerId = localHost + "_" + stamp;
|
||||
}
|
||||
return mbeanServerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the MBeanServer.
|
||||
* @return The name of the MBeanServer, or {@value
|
||||
* javax.management.MBeanServerFactory#DEFAULT_MBEANSERVER_NAME} if no
|
||||
* name was specified.
|
||||
*
|
||||
* @since 1.7
|
||||
* @see #setMBeanServerName
|
||||
*/
|
||||
public synchronized String getMBeanServerName() {
|
||||
if (Util.isMBeanServerNameUndefined(mbeanServerName))
|
||||
return MBeanServerFactory.DEFAULT_MBEANSERVER_NAME;
|
||||
return mbeanServerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the MBeanServer. The name will be embedded into the
|
||||
* {@link #getMBeanServerId MBeanServerId} using the following format:<br>
|
||||
* {@code mbeanServerId: <mbeanServerId>;mbeanServerName=<mbeanServerName>}
|
||||
* <p>The characters {@code ':'} (colon), {@code ';'} (semicolon ),
|
||||
* {@code '*'} (star) and {@code '?'} (question mark) are not legal in an
|
||||
* MBean Server name.</p>
|
||||
* <p>For instance, if the {@code mbeanServerName} provided is
|
||||
* {@code "com.mycompany.myapp.server1"}, and the original
|
||||
* {@code MBeanServerId} was {@code "myhost_1213353064145"},
|
||||
* then {@code mbeanServerName} will be
|
||||
* embedded in the {@code MBeanServerId} - and the new value of the
|
||||
* {@code MBeanServerId} will be:
|
||||
* </p>
|
||||
* <pre>
|
||||
* "myhost_1213353064145;mbeanServerName=com.mycompany.myapp.server1"
|
||||
* </pre>
|
||||
* <p>Note: The {@code mbeanServerName} is usually set by the
|
||||
* {@code MBeanServerFactory}. It is set only once, before the
|
||||
* MBean Server is returned by the factory. Once the MBean Server name is
|
||||
* set, it is not possible to change it.
|
||||
* </p>
|
||||
* @param mbeanServerName The MBeanServer name.
|
||||
* @throws IllegalArgumentException if the MBeanServerName is already set
|
||||
* to a different value, or if the provided name contains
|
||||
* illegal characters, or if the provided name is {@code ""}
|
||||
* (the empty string) or "-" (dash).
|
||||
* @throws UnsupportedOperationException if this object is of a legacy
|
||||
* subclass of MBeanServerDelegate which overrides {@link
|
||||
* #getMBeanServerId()}
|
||||
* in a way that doesn't support setting an MBeanServer name.
|
||||
* @see MBeanServerFactory#getMBeanServerName
|
||||
* @since 1.7
|
||||
*/
|
||||
public synchronized void setMBeanServerName(String mbeanServerName) {
|
||||
// Sets the name on the delegate. For complex backward
|
||||
// compatibility reasons it is not possible to give the
|
||||
// name to the MBeanServerDelegate constructor.
|
||||
//
|
||||
// The method setMBeanServerName() will call getMBeanServerId()
|
||||
// to check that the name is accurately set in the MBeanServerId.
|
||||
// If not (which could happen if a custom MBeanServerDelegate
|
||||
// implementation overrides getMBeanServerId() and was not updated
|
||||
// with respect to JMX 2.0 spec), this method will throw an
|
||||
// IllegalStateException...
|
||||
|
||||
// will fail if mbeanServerName is illegal
|
||||
final String name = Util.checkServerName(mbeanServerName);
|
||||
|
||||
// can only set mbeanServerDelegate once.
|
||||
if (this.mbeanServerName != null && !this.mbeanServerName.equals(name))
|
||||
throw new IllegalArgumentException(
|
||||
"MBeanServerName already set to a different value");
|
||||
|
||||
this.mbeanServerName = name;
|
||||
|
||||
// will fail if mbeanServerId already has a different mbeanServerName
|
||||
mbeanServerId =
|
||||
Util.insertMBeanServerName(getMBeanServerId(),name);
|
||||
|
||||
// check that we don't have a subclass which overrides
|
||||
// getMBeanServerId() without setting mbeanServerName
|
||||
if (!name.equals(
|
||||
Util.extractMBeanServerName(getMBeanServerId())))
|
||||
throw new UnsupportedOperationException(
|
||||
"Can't set MBeanServerName in MBeanServerId - " +
|
||||
"unsupported by "+this.getClass().getName()+"?");
|
||||
// OK: at this point we know that we have correctly set mbeanServerName.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full name of the JMX specification implemented
|
||||
* by this product.
|
||||
@ -304,7 +215,7 @@ public class MBeanServerDelegate implements MBeanServerDelegateMBean,
|
||||
* @since 1.6
|
||||
*/
|
||||
public static final ObjectName DELEGATE_NAME =
|
||||
ObjectName.valueOf("JMImplementation:type=MBeanServerDelegate");
|
||||
Util.newObjectName("JMImplementation:type=MBeanServerDelegate");
|
||||
|
||||
/* Return a timestamp that is monotonically increasing even if
|
||||
System.currentTimeMillis() isn't (for example, if you call this
|
||||
|
||||
@ -29,11 +29,9 @@ import com.sun.jmx.defaults.JmxProperties;
|
||||
import static com.sun.jmx.defaults.JmxProperties.JMX_INITIAL_BUILDER;
|
||||
import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
|
||||
import com.sun.jmx.mbeanserver.GetPropertyAction;
|
||||
import com.sun.jmx.mbeanserver.Util;
|
||||
import java.security.AccessController;
|
||||
import java.security.Permission;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import javax.management.loading.ClassLoaderRepository;
|
||||
|
||||
@ -83,53 +81,10 @@ import javax.management.loading.ClassLoaderRepository;
|
||||
* returned by the default MBeanServerBuilder implementation, for the purpose
|
||||
* of e.g. adding an additional security layer.</p>
|
||||
*
|
||||
* <p id="MBeanServerName">Since version 2.0 of the JMX API, when creating
|
||||
* an MBeanServer,
|
||||
* it is possible to specify an {@linkplain #getMBeanServerName
|
||||
* MBean Server name}.
|
||||
* To create an MBean Server with a name, the MBeanServerFactory provides two
|
||||
* new methods:</p>
|
||||
* <ul><li>{@link #createNamedMBeanServer
|
||||
* createNamedMBeanServer(mbeanServerName, defaultDomain)}: creates a named
|
||||
* MBeanServer and keeps an internal reference to the created object. The
|
||||
* MBeanServer can be later retrieved using {@link #findMBeanServer
|
||||
* findMBeanServer(mbeanServerId)} or
|
||||
* {@link #findMBeanServerByName findMBeanServerByName(mbeanServerName)}, and
|
||||
* can be released through {@link
|
||||
* #releaseMBeanServer releaseMBeanServer(mbeanServer)}.</li>
|
||||
* <li>{@link #newNamedMBeanServer
|
||||
* newNamedMBeanServer(mbeanServerName, defaultDomain)}:
|
||||
* creates a named MBeanServer without keeping any internal reference to the
|
||||
* named server.</li>
|
||||
* </ul>
|
||||
* <p>The name of the MBeanServer is stored in the
|
||||
* {@linkplain MBeanServerDelegate MBean Server delegate MBean}
|
||||
* and is embedded in its {@link MBeanServerDelegate#getMBeanServerId
|
||||
* MBeanServerId} attribute.</p>
|
||||
* <p>The name of the MBeanServer is particularly useful when
|
||||
* <a href="MBeanServer.html#security">MBean permissions</a> are checked:
|
||||
* it makes it
|
||||
* possible to distinguish between an MBean named "X" in MBeanServer named
|
||||
* "M1", and another MBean of the same name "X" in another MBeanServer named
|
||||
* "M2".</p>
|
||||
* <p>When naming MBean servers it is recommended to use a name that starts
|
||||
* with a Java package name. It is also recommended that the default domain and
|
||||
* the MBeanServer name be the same.</p>
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
public class MBeanServerFactory {
|
||||
|
||||
/**
|
||||
* The <a href="#MBeanServerName">MBean Server name</a> that will be
|
||||
* checked by a <a href="MBeanServer.html#security">permission you need</a>
|
||||
* when checking access to an MBean registered in an MBeanServer for
|
||||
* which no MBeanServer name was specified.
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public final static String DEFAULT_MBEANSERVER_NAME = "default";
|
||||
|
||||
/*
|
||||
* There are no instances of this class so don't generate the
|
||||
* default public constructor.
|
||||
@ -268,78 +223,13 @@ public class MBeanServerFactory {
|
||||
* <code>javax.management.builder.initial</code> exists and can be
|
||||
* instantiated but is not assignment compatible with {@link
|
||||
* MBeanServerBuilder}.
|
||||
*
|
||||
* @see #createNamedMBeanServer
|
||||
*/
|
||||
public static MBeanServer createMBeanServer(String domain) {
|
||||
return createMBeanServer(null,domain);
|
||||
}
|
||||
checkPermission("createMBeanServer");
|
||||
|
||||
/**
|
||||
* <p>Return a new object implementing the {@link MBeanServer}
|
||||
* interface with the specified
|
||||
* <a href="#MBeanServerName">MBean Server name</a>
|
||||
* and default domain name. The given MBean server name
|
||||
* is used in <a href="MBeanServer.html#security">security checks</a>, and
|
||||
* can also be used to {@linkplain #findMBeanServerByName(java.lang.String)
|
||||
* find an MBeanServer by name}. The given
|
||||
* domain name is used as the domain part in the ObjectName of
|
||||
* MBeans when the domain is specified by the user is null.</p>
|
||||
*
|
||||
* <p>The MBeanServer reference is internally kept. This will
|
||||
* allow <CODE>findMBeanServer</CODE> to return a reference to
|
||||
* this MBeanServer object.</p>
|
||||
*
|
||||
* @param mbeanServerName the name for the created
|
||||
* MBeanServer. This is the name that will be included in the
|
||||
* {@linkplain MBeanPermission permission you need} when checking
|
||||
* <a href="MBeanServer.html#security">MBean Permissions</a> for accessing
|
||||
* an MBean registered in the returned MBeanServer. The characters
|
||||
* {@code ':'} (colon), {@code ';'} (semicolon), {@code '*'} (star)
|
||||
* and {@code '?'} are not legal.
|
||||
* It is recommended that the {@code mbeanServerName}
|
||||
* be unique in the context of a JVM, and in the form of a java package
|
||||
* identifier. If {@code mbeanServerName} is {@code null} then the created
|
||||
* MBean Server has no name - and {@value #DEFAULT_MBEANSERVER_NAME} is used.
|
||||
* Calling {@code createNamedMBeanServer(null,domain)} is equivalent
|
||||
* to calling {@link #createMBeanServer(String) createMBeanServer(domain)}.
|
||||
*
|
||||
* @param domain the default domain name for the created
|
||||
* MBeanServer. This is the value that will be returned by {@link
|
||||
* MBeanServer#getDefaultDomain}. If a non null mbeanServerName is given,
|
||||
* it is recommended to pass the same value as default domain.
|
||||
*
|
||||
* @return the newly created MBeanServer.
|
||||
*
|
||||
* @exception SecurityException if there is a SecurityManager and
|
||||
* the caller's permissions do not include or imply <code>{@link
|
||||
* MBeanServerPermission}("createMBeanServer")</code>.
|
||||
*
|
||||
* @exception JMRuntimeException if the property
|
||||
* <code>javax.management.builder.initial</code> exists but the
|
||||
* class it names cannot be instantiated through a public
|
||||
* no-argument constructor; or if the instantiated builder returns
|
||||
* null from its {@link MBeanServerBuilder#newMBeanServerDelegate
|
||||
* newMBeanServerDelegate} or {@link
|
||||
* MBeanServerBuilder#newMBeanServer newMBeanServer} methods.
|
||||
*
|
||||
* @exception ClassCastException if the property
|
||||
* <code>javax.management.builder.initial</code> exists and can be
|
||||
* instantiated but is not assignment compatible with {@link
|
||||
* MBeanServerBuilder}.
|
||||
*
|
||||
* @exception IllegalArgumentException if the specified
|
||||
* {@code mbeanServerName} is empty, or is {@code "-"}, or contains a
|
||||
* character which is not legal.
|
||||
*
|
||||
* @exception UnsupportedOperationException if the specified
|
||||
* {@code mbeanServerName} cannot be set.
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public static MBeanServer createNamedMBeanServer(String mbeanServerName,
|
||||
String domain) {
|
||||
return createMBeanServer(mbeanServerName, domain);
|
||||
final MBeanServer mBeanServer = newMBeanServer(domain);
|
||||
addMBeanServer(mBeanServer);
|
||||
return mBeanServer;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -418,88 +308,6 @@ public class MBeanServerFactory {
|
||||
* MBeanServerBuilder}.
|
||||
*/
|
||||
public static MBeanServer newMBeanServer(String domain) {
|
||||
return newMBeanServer(null,domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return a new object implementing the MBeanServer interface
|
||||
* with the specified <a href="#MBeanServerName">MBean server name</a>
|
||||
* and default domain name, without keeping an
|
||||
* internal reference to this new object. The given MBean server name
|
||||
* is used in <a href="MBeanServer.html#security">security checks</a>.
|
||||
* The given domain name
|
||||
* is used as the domain part in the ObjectName of MBeans when the
|
||||
* domain is specified by the user is null.</p>
|
||||
*
|
||||
* <p>No reference is kept. <CODE>findMBeanServer</CODE> and
|
||||
* <CODE>findMBeanServerByName</CODE> will not
|
||||
* be able to return a reference to this MBeanServer object, but
|
||||
* the garbage collector will be able to remove the MBeanServer
|
||||
* object when it is no longer referenced.</p>
|
||||
*
|
||||
* @param mbeanServerName the name for the created
|
||||
* MBeanServer. This is the name that will be included in the
|
||||
* {@linkplain MBeanPermission permission you need} when checking
|
||||
* <a href="MBeanServer.html#security">MBean Permissions</a> for accessing
|
||||
* an MBean registered in the returned MBeanServer. The characters
|
||||
* {@code ':'} (colon), {@code ';'} (semicolon), {@code '*'} (star)
|
||||
* and {@code '?'} are not legal.
|
||||
* It is recommended that the mbeanServerName
|
||||
* be unique in the context of a JVM, and in the form of a java package
|
||||
* identifier. If {@code mbeanServerName} is {@code null} then the created
|
||||
* MBean Server has no name - and {@value #DEFAULT_MBEANSERVER_NAME} is used.
|
||||
* Calling {@code newNamedMBeanServer(null,domain)} is equivalent
|
||||
* to calling {@link #newMBeanServer(String) newMBeanServer(domain)}.
|
||||
*
|
||||
* @param domain the default domain name for the created
|
||||
* MBeanServer. This is the value that will be returned by {@link
|
||||
* MBeanServer#getDefaultDomain}.
|
||||
*
|
||||
* @return the newly created MBeanServer.
|
||||
*
|
||||
* @exception SecurityException if there is a SecurityManager and the
|
||||
* caller's permissions do not include or imply <code>{@link
|
||||
* MBeanServerPermission}("newMBeanServer")</code>.
|
||||
*
|
||||
* @exception JMRuntimeException if the property
|
||||
* <code>javax.management.builder.initial</code> exists but the
|
||||
* class it names cannot be instantiated through a public
|
||||
* no-argument constructor; or if the instantiated builder returns
|
||||
* null from its {@link MBeanServerBuilder#newMBeanServerDelegate
|
||||
* newMBeanServerDelegate} or {@link
|
||||
* MBeanServerBuilder#newMBeanServer newMBeanServer} methods.
|
||||
*
|
||||
* @exception ClassCastException if the property
|
||||
* <code>javax.management.builder.initial</code> exists and can be
|
||||
* instantiated but is not assignment compatible with {@link
|
||||
* MBeanServerBuilder}.
|
||||
*
|
||||
* @exception IllegalArgumentException if the specified
|
||||
* {@code mbeanServerName} is empty, or is {@code "-"},
|
||||
* or contains a character which is not legal.
|
||||
*
|
||||
* @exception UnsupportedOperationException if the specified
|
||||
* {@code mbeanServerName} cannot be set.
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public static MBeanServer newNamedMBeanServer(String mbeanServerName,
|
||||
String domain) {
|
||||
return newMBeanServer(mbeanServerName, domain);
|
||||
}
|
||||
|
||||
private static MBeanServer createMBeanServer(String mbeanServerName,
|
||||
String domain) {
|
||||
checkPermission("createMBeanServer");
|
||||
|
||||
final MBeanServer mBeanServer =
|
||||
newMBeanServer(mbeanServerName,domain);
|
||||
addMBeanServer(mBeanServer);
|
||||
return mBeanServer;
|
||||
}
|
||||
|
||||
private static MBeanServer newMBeanServer(String mbeanServerName,
|
||||
String domain) {
|
||||
checkPermission("newMBeanServer");
|
||||
|
||||
// Get the builder. Creates a new one if necessary.
|
||||
@ -516,22 +324,6 @@ public class MBeanServerFactory {
|
||||
"returned null";
|
||||
throw new JMRuntimeException(msg);
|
||||
}
|
||||
|
||||
// Sets the name on the delegate. For complex backward
|
||||
// compatibility reasons it is not possible to give the
|
||||
// name to the MBeanServerDelegate constructor.
|
||||
//
|
||||
// The method setMBeanServerName() will call getMBeanServerId()
|
||||
// to check that the name is accurately set in the MBeanServerId.
|
||||
// If not (which could happen if a custom MBeanServerDelegate
|
||||
// implementation overrides getMBeanServerId() and was not updated
|
||||
// with respect to JMX 2.0 spec, this method will throw an
|
||||
// IllegalStateException...
|
||||
//
|
||||
if (!Util.isMBeanServerNameUndefined(mbeanServerName)) {
|
||||
delegate.setMBeanServerName(mbeanServerName);
|
||||
}
|
||||
|
||||
final MBeanServer mbeanServer =
|
||||
mbsBuilder.newMBeanServer(domain,null,delegate);
|
||||
if (mbeanServer == null) {
|
||||
@ -539,20 +331,6 @@ public class MBeanServerFactory {
|
||||
"MBeanServerBuilder.newMBeanServer() returned null";
|
||||
throw new JMRuntimeException(msg);
|
||||
}
|
||||
|
||||
// double check that the MBeanServer name is correctly set.
|
||||
// "*" might mean that the caller doesn't have the permission
|
||||
// to see the MBeanServer name.
|
||||
//
|
||||
final String mbsName = Util.getMBeanServerSecurityName(mbeanServer);
|
||||
if (!mbsName.equals(Util.checkServerName(mbeanServerName))
|
||||
&& !mbsName.equals("*")) {
|
||||
throw new UnsupportedOperationException(
|
||||
"can't create MBeanServer with name \""+
|
||||
mbeanServerName+"\" using "+
|
||||
builder.getClass().getName());
|
||||
}
|
||||
|
||||
return mbeanServer;
|
||||
}
|
||||
}
|
||||
@ -593,96 +371,6 @@ public class MBeanServerFactory {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns a list of registered MBeanServer objects with the given name. A
|
||||
* registered MBeanServer object is one that was created by one of
|
||||
* the <code>createMBeanServer</code> or <code>createNamedMBeanServer</code>
|
||||
* methods and not subsequently released with <code>releaseMBeanServer</code>.</p>
|
||||
* <p>See the section about <a href="#MBeanServerName">MBean Server names</a>
|
||||
* above.</p>
|
||||
*
|
||||
* @param mbeanServerName The name of the MBeanServer to
|
||||
* retrieve. If this parameter is null, all registered MBeanServers
|
||||
* in this JVM are returned.
|
||||
* Otherwise, only those MBeanServers that have a name
|
||||
* matching <code>mbeanServerName</code> are returned: this
|
||||
* parameter can be a pattern, where {@code '*'} matches any
|
||||
* sequence of characters and {@code '?'} matches any character.<br>
|
||||
* The name of an MBeanServer, if specified, is embedded in the
|
||||
* <code>MBeanServerId</code> attribute of its delegate MBean:
|
||||
* this method will parse the <code>MBeanServerId</code> to get the
|
||||
* MBeanServer name. If this parameter is equal to {@code "*"} then
|
||||
* all registered MBeanServers in this JVM are returned, whether they have
|
||||
* a name or not: {@code findMBeanServerByName(null)},
|
||||
* {@code findMBeanServerByName("*")} and {@code findMBeanServer(null)},
|
||||
* are equivalent. It is also possible to get all MBeanServers for which
|
||||
* no name was specified by calling <code>findMBeanServerByName({@value
|
||||
* #DEFAULT_MBEANSERVER_NAME})</code>.
|
||||
*
|
||||
* @return A list of MBeanServer objects.
|
||||
*
|
||||
* @exception SecurityException if there is a SecurityManager and the
|
||||
* caller's permissions do not include or imply <code>{@link
|
||||
* MBeanServerPermission}("findMBeanServer")</code>.
|
||||
*
|
||||
* @see #getMBeanServerName(MBeanServer)
|
||||
* @since 1.7
|
||||
*/
|
||||
public synchronized static
|
||||
List<MBeanServer> findMBeanServerByName(String mbeanServerName) {
|
||||
|
||||
checkPermission("findMBeanServer");
|
||||
|
||||
if (mbeanServerName==null || "*".equals(mbeanServerName))
|
||||
return new ArrayList<MBeanServer>(mBeanServerList);
|
||||
|
||||
// noname=true iff we are looking for MBeanServers for which no name
|
||||
// were specified.
|
||||
ArrayList<MBeanServer> result = new ArrayList<MBeanServer>();
|
||||
for (MBeanServer mbs : mBeanServerList) {
|
||||
final String name = Util.getMBeanServerSecurityName(mbs);
|
||||
if (Util.wildmatch(name, mbeanServerName)) result.add(mbs);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the MBeanServer embedded in the MBeanServerId of
|
||||
* the given {@code server}. If the given MBeanServerId doesn't contain
|
||||
* any name, {@value #DEFAULT_MBEANSERVER_NAME} is returned.
|
||||
* The MBeanServerId is expected to be of the form:
|
||||
* {@code *[;mbeanServerName=<mbeanServerName>[;*]]}
|
||||
* <br>where {@code *} denotes any sequence of characters, and {@code [ ]}
|
||||
* indicate optional parts.
|
||||
* </p>
|
||||
* <p>For instance, if an MBeanServer is created using {@link
|
||||
* #createNamedMBeanServer(java.lang.String, java.lang.String)
|
||||
* server =
|
||||
* MBeanServerFactory.createNamedMBeanServer("com.mycompany.myapp.server1",
|
||||
* null)} then {@code MBeanServerFactory.getMBeanServerName(server)}
|
||||
* will return {@code "com.mycompany.myapp.server1"} and
|
||||
* <code>server.getAttribute({@link
|
||||
* javax.management.MBeanServerDelegate#DELEGATE_NAME
|
||||
* MBeanServerDelegate.DELEGATE_NAME}, "MBeanServerId")</code> will return
|
||||
* something like
|
||||
* {@code "myhost_1213353064145;mbeanServerName=com.mycompany.myapp.server1"}.
|
||||
* </p>
|
||||
* <p>See the section about <a href="#MBeanServerName">MBean Server names</a>
|
||||
* above.</p>
|
||||
* @param server A named (or unnamed) MBeanServer.
|
||||
* @return the name of the MBeanServer if found, or
|
||||
* {@value #DEFAULT_MBEANSERVER_NAME} if no name is
|
||||
* present in its MBeanServerId, or "*" if its
|
||||
* MBeanServerId couldn't be obtained. Returning "*" means that
|
||||
* only {@link MBeanPermission}s that allow all MBean Server names
|
||||
* will apply to this MBean Server.
|
||||
* @see MBeanServerDelegate
|
||||
* @since 1.7
|
||||
*/
|
||||
public static String getMBeanServerName(MBeanServer server) {
|
||||
return Util.getMBeanServerSecurityName(server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ClassLoaderRepository used by the given MBeanServer.
|
||||
* This method is equivalent to {@link
|
||||
|
||||
@ -33,9 +33,6 @@ import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Arrays;
|
||||
import java.util.WeakHashMap;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
|
||||
import static javax.management.JMX.MBeanOptions;
|
||||
|
||||
/**
|
||||
* <p>{@link InvocationHandler} that forwards methods in an MBean's
|
||||
@ -114,7 +111,7 @@ public class MBeanServerInvocationHandler implements InvocationHandler {
|
||||
public MBeanServerInvocationHandler(MBeanServerConnection connection,
|
||||
ObjectName objectName) {
|
||||
|
||||
this(connection, objectName, null);
|
||||
this(connection, objectName, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -141,14 +138,6 @@ public class MBeanServerInvocationHandler implements InvocationHandler {
|
||||
public MBeanServerInvocationHandler(MBeanServerConnection connection,
|
||||
ObjectName objectName,
|
||||
boolean isMXBean) {
|
||||
this(connection, objectName, isMXBean ? MBeanOptions.MXBEAN : null);
|
||||
}
|
||||
|
||||
public MBeanServerInvocationHandler(MBeanServerConnection connection,
|
||||
ObjectName objectName,
|
||||
MBeanOptions options) {
|
||||
if (options == null)
|
||||
options = new MBeanOptions();
|
||||
if (connection == null) {
|
||||
throw new IllegalArgumentException("Null connection");
|
||||
}
|
||||
@ -157,7 +146,7 @@ public class MBeanServerInvocationHandler implements InvocationHandler {
|
||||
}
|
||||
this.connection = connection;
|
||||
this.objectName = objectName;
|
||||
this.options = options.canonical();
|
||||
this.isMXBean = isMXBean;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -193,16 +182,7 @@ public class MBeanServerInvocationHandler implements InvocationHandler {
|
||||
* @since 1.6
|
||||
*/
|
||||
public boolean isMXBean() {
|
||||
return options.isMXBean();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return the {@link MBeanOptions} used for this proxy.</p>
|
||||
*
|
||||
* @return the MBeanOptions.
|
||||
*/
|
||||
public MBeanOptions getMBeanOptions() {
|
||||
return options.uncanonical();
|
||||
return isMXBean;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -346,40 +326,30 @@ public class MBeanServerInvocationHandler implements InvocationHandler {
|
||||
*/
|
||||
}
|
||||
|
||||
private MXBeanProxy findMXBeanProxy(Class<?> mxbeanInterface) {
|
||||
MXBeanMappingFactory mappingFactory = options.getMXBeanMappingFactory();
|
||||
private static MXBeanProxy findMXBeanProxy(Class<?> mxbeanInterface) {
|
||||
synchronized (mxbeanProxies) {
|
||||
ClassToProxy classToProxy = mxbeanProxies.get(mappingFactory);
|
||||
if (classToProxy == null) {
|
||||
classToProxy = new ClassToProxy();
|
||||
mxbeanProxies.put(mappingFactory, classToProxy);
|
||||
WeakReference<MXBeanProxy> proxyRef =
|
||||
mxbeanProxies.get(mxbeanInterface);
|
||||
MXBeanProxy p = (proxyRef == null) ? null : proxyRef.get();
|
||||
if (p == null) {
|
||||
try {
|
||||
p = new MXBeanProxy(mxbeanInterface);
|
||||
} catch (IllegalArgumentException e) {
|
||||
String msg = "Cannot make MXBean proxy for " +
|
||||
mxbeanInterface.getName() + ": " + e.getMessage();
|
||||
IllegalArgumentException iae =
|
||||
new IllegalArgumentException(msg, e.getCause());
|
||||
iae.setStackTrace(e.getStackTrace());
|
||||
throw iae;
|
||||
}
|
||||
mxbeanProxies.put(mxbeanInterface,
|
||||
new WeakReference<MXBeanProxy>(p));
|
||||
}
|
||||
WeakReference<MXBeanProxy> wr = classToProxy.get(mxbeanInterface);
|
||||
MXBeanProxy p;
|
||||
if (wr != null) {
|
||||
p = wr.get();
|
||||
if (p != null)
|
||||
return p;
|
||||
}
|
||||
try {
|
||||
p = new MXBeanProxy(mxbeanInterface, mappingFactory);
|
||||
} catch (IllegalArgumentException e) {
|
||||
String msg = "Cannot make MXBean proxy for " +
|
||||
mxbeanInterface.getName() + ": " + e.getMessage();
|
||||
throw new IllegalArgumentException(msg, e.getCause());
|
||||
}
|
||||
classToProxy.put(mxbeanInterface, new WeakReference<MXBeanProxy>(p));
|
||||
return p;
|
||||
}
|
||||
}
|
||||
private static final WeakHashMap<MXBeanMappingFactory, ClassToProxy>
|
||||
mxbeanProxies = newWeakHashMap();
|
||||
private static class ClassToProxy
|
||||
extends WeakHashMap<Class<?>, WeakReference<MXBeanProxy>> {}
|
||||
|
||||
private static <K, V> WeakHashMap<K, V> newWeakHashMap() {
|
||||
return new WeakHashMap<K, V>();
|
||||
}
|
||||
private static final WeakHashMap<Class<?>, WeakReference<MXBeanProxy>>
|
||||
mxbeanProxies = new WeakHashMap<Class<?>, WeakReference<MXBeanProxy>>();
|
||||
|
||||
private Object invokeBroadcasterMethod(Object proxy, Method method,
|
||||
Object[] args) throws Exception {
|
||||
@ -523,5 +493,5 @@ public class MBeanServerInvocationHandler implements InvocationHandler {
|
||||
|
||||
private final MBeanServerConnection connection;
|
||||
private final ObjectName objectName;
|
||||
private final MBeanOptions options;
|
||||
private final boolean isMXBean;
|
||||
}
|
||||
|
||||
@ -64,13 +64,13 @@ package javax.management;
|
||||
* mbeanServer.addNotificationListener(
|
||||
* MBeanServerDelegate.DELEGATE_NAME, printListener, null, null);
|
||||
* </pre>
|
||||
*
|
||||
* <p id="group">
|
||||
* An MBean which is not an {@link MBeanServerDelegate} may also emit
|
||||
* MBeanServerNotifications. In particular, a custom subclass of the
|
||||
* {@link javax.management.namespace.JMXDomain JMXDomain} MBean or a custom
|
||||
* subclass of the {@link javax.management.namespace.JMXNamespace JMXNamespace}
|
||||
* MBean may emit an MBeanServerNotification for a group of MBeans.<br>
|
||||
* An MBeanServerNotification emitted to denote the registration or
|
||||
* MBeanServerNotifications. In particular, there is a convention for
|
||||
* MBeans to emit an MBeanServerNotification for a group of MBeans.</p>
|
||||
*
|
||||
* <p>An MBeanServerNotification emitted to denote the registration or
|
||||
* unregistration of a group of MBeans has the following characteristics:
|
||||
* <ul><li>Its {@linkplain Notification#getType() notification type} is
|
||||
* {@code "JMX.mbean.registered.group"} or
|
||||
@ -92,58 +92,6 @@ package javax.management;
|
||||
* declare them in their {@link MBeanInfo#getNotifications()
|
||||
* MBeanNotificationInfo}.
|
||||
* </p>
|
||||
* <P>
|
||||
* To receive a group MBeanServerNotification, you need to register a listener
|
||||
* with the MBean that emits it. For instance, assuming that the {@link
|
||||
* javax.management.namespace.JMXNamespace JMXNamespace} MBean handling
|
||||
* namespace {@code "foo"} has declared that it emits such a notification,
|
||||
* you will need to register your notification listener with that MBean, which
|
||||
* will be named {@link
|
||||
* javax.management.namespace.JMXNamespaces#getNamespaceObjectName(java.lang.String)
|
||||
* foo//:type=JMXNamespace}.
|
||||
* </p>
|
||||
* <p>The following code prints a message every time a group of MBean is
|
||||
* registered or unregistered in the namespace {@code "foo"}, assumimg its
|
||||
* {@link javax.management.namespace.JMXNamespace handler} supports
|
||||
* group MBeanServerNotifications:</p>
|
||||
*
|
||||
* <pre>
|
||||
* private static final NotificationListener printListener = new NotificationListener() {
|
||||
* public void handleNotification(Notification n, Object handback) {
|
||||
* if (!(n instanceof MBeanServerNotification)) {
|
||||
* System.out.println("Ignored notification of class " + n.getClass().getName());
|
||||
* return;
|
||||
* }
|
||||
* MBeanServerNotification mbsn = (MBeanServerNotification) n;
|
||||
* String what;
|
||||
* ObjectName[] names = null;
|
||||
* if (n.getType().equals(MBeanServerNotification.REGISTRATION_NOTIFICATION)) {
|
||||
* what = "MBean registered";
|
||||
* } else if (n.getType().equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION)) {
|
||||
* what = "MBean unregistered";
|
||||
* } else if (n.getType().equals(MBeanServerNotification.REGISTRATION_NOTIFICATION+".group")) {
|
||||
* what = "Group of MBeans registered matching";
|
||||
* if (mbsn.getUserData() instanceof ObjectName[])
|
||||
* names = (ObjectName[]) mbsn.getUserData();
|
||||
* } else if (n.getType().equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION+".group")) {
|
||||
* what = "Group of MBeans unregistered matching";
|
||||
* if (mbsn.getUserData() instanceof ObjectName[])
|
||||
* names = (ObjectName[]) mbsn.getUserData();
|
||||
* } else
|
||||
* what = "Unknown type " + n.getType();
|
||||
* System.out.println("Received MBean Server notification: " + what + ": " +
|
||||
* mbsn.getMBeanName());
|
||||
* if (names != null) {
|
||||
* for (ObjectName mb : names)
|
||||
* System.out.println("\t"+mb);
|
||||
* }
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* ...
|
||||
* mbeanServer.addNotificationListener(
|
||||
* JMXNamespaces.getNamespaceObjectName("foo"), printListener, null, null);
|
||||
* </pre>
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
|
||||
@ -27,7 +27,6 @@ package javax.management;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
@ -44,10 +43,6 @@ import javax.management.openmbean.CompositeDataInvocationHandler;
|
||||
import javax.management.openmbean.CompositeDataSupport;
|
||||
import javax.management.openmbean.CompositeDataView;
|
||||
import javax.management.openmbean.CompositeType;
|
||||
import javax.management.openmbean.MXBeanMapping;
|
||||
import javax.management.openmbean.MXBeanMappingClass;
|
||||
import javax.management.openmbean.MXBeanMappingFactory;
|
||||
import javax.management.openmbean.MXBeanMappingFactoryClass;
|
||||
import javax.management.openmbean.OpenDataException;
|
||||
import javax.management.openmbean.OpenMBeanInfo;
|
||||
import javax.management.openmbean.OpenType;
|
||||
@ -57,13 +52,11 @@ import javax.management.openmbean.TabularDataSupport;
|
||||
import javax.management.openmbean.TabularType;
|
||||
|
||||
/**
|
||||
<p>Annotation to mark a class or interface explicitly as being an MXBean,
|
||||
or as not being an MXBean. By default, an
|
||||
<p>Annotation to mark an interface explicitly as being an MXBean
|
||||
interface, or as not being an MXBean interface. By default, an
|
||||
interface is an MXBean interface if its name ends with {@code
|
||||
MXBean}, as in {@code SomethingMXBean}. A class is never an MXBean by
|
||||
default.</p>
|
||||
|
||||
<p>The following interfaces are MXBean interfaces:</p>
|
||||
MXBean}, as in {@code SomethingMXBean}. The following interfaces
|
||||
are MXBean interfaces:</p>
|
||||
|
||||
<pre>
|
||||
public interface WhatsitMXBean {}
|
||||
@ -84,12 +77,7 @@ import javax.management.openmbean.TabularType;
|
||||
public interface MisleadingMXBean {}
|
||||
</pre>
|
||||
|
||||
<p>A class can be annotated with {@code @MXBean} to indicate that it
|
||||
is an MXBean. In this case, its methods should have <code>@{@link
|
||||
ManagedAttribute}</code> or <code>@{@link ManagedOperation}</code>
|
||||
annotations, as described for <code>@{@link MBean}</code>.</p>
|
||||
|
||||
<h3 id="MXBean-spec">MXBean specification</h3>
|
||||
<h3 id="MXBean-spec">MXBean specification</a></h3>
|
||||
|
||||
<p>The MXBean concept provides a simple way to code an MBean
|
||||
that only references a predefined set of types, the ones defined
|
||||
@ -486,11 +474,7 @@ public class MemoryPool
|
||||
from type <em>opendata(J)</em> to type <em>J</em>, a null value is
|
||||
mapped to a null value.</p>
|
||||
|
||||
<p>In addition to the default type mapping rules, you can specify
|
||||
custom type mappings, as described <a
|
||||
href="#custom">below</a>.</p>
|
||||
|
||||
<p>The following table summarizes the default type mapping rules.</p>
|
||||
<p>The following table summarizes the type mapping rules.</p>
|
||||
|
||||
<table border="1" cellpadding="5">
|
||||
<tr>
|
||||
@ -1051,77 +1035,6 @@ public interface Node {
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>Alternatively, you can define a custom mapping for your recursive
|
||||
type; see the next section.</p>
|
||||
|
||||
<h3 id="custom">Custom MXBean type mappings</h3>
|
||||
|
||||
<p>You can augment or replace the default type mappings described
|
||||
above with custom mappings. An example appears in the
|
||||
documentation for {@link MXBeanMapping}.</p>
|
||||
|
||||
<p>If an MXBean uses custom mappings, then an MXBean proxy for
|
||||
that MXBean must use the same mappings for correct behavior.
|
||||
This requires more careful synchronization between client and
|
||||
server than is necessary with the default mappings. For example
|
||||
it typically requires the client to have the same implementation
|
||||
of any {@link MXBeanMapping} subclasses as the server. For this
|
||||
reason, custom mappings should be avoided if possible.</p>
|
||||
|
||||
<p>Every MXBean has an associated {@link MXBeanMappingFactory}.
|
||||
Call this <code><em>f</em></code>. Then every type that appears
|
||||
in that MXBean has an associated {@link MXBeanMapping}
|
||||
determined by <code><em>f</em></code>. If the type is
|
||||
<code><em>J</em></code>, say, then the mapping is {@link
|
||||
MXBeanMappingFactory#mappingForType
|
||||
<em>f</em>.mappingForType}<code>(<em>J</em>,
|
||||
<em>f</em>)</code>.</p>
|
||||
|
||||
<p>The {@code MXBeanMappingFactory} <code><em>f</em></code> for an
|
||||
MXBean is determined as follows.</p>
|
||||
|
||||
<ul>
|
||||
<li><p>If a {@link JMX.MBeanOptions} argument is supplied to
|
||||
the {@link StandardMBean} constructor that makes an MXBean,
|
||||
or to the {@link JMX#newMBeanProxy(MBeanServerConnection,
|
||||
ObjectName, Class, JMX.MBeanOptions) JMX.newMBeanProxy}
|
||||
method, and the {@code MBeanOptions} object defines a non-null
|
||||
{@code MXBeanMappingFactory}, then that is the value of
|
||||
<code><em>f</em></code>.</p></li>
|
||||
|
||||
<li><p>Otherwise, if the MXBean interface has an {@link
|
||||
MXBeanMappingFactoryClass} annotation, then that annotation
|
||||
must identify a subclass of {@code MXBeanMappingFactory}
|
||||
with a no-argument constructor. Then
|
||||
<code><em>f</em></code> is the result of calling this
|
||||
constructor. If the class does not have a no-argument
|
||||
constructor, or if calling the constructor produces an
|
||||
exception, then the MXBean is invalid and an attempt to
|
||||
register it in the MBean Server will produce a {@link
|
||||
NotCompliantMBeanException}.</p>
|
||||
|
||||
<p>This annotation is not inherited from any parent
|
||||
interfaces. If an MXBean interface has this annotation,
|
||||
then usually any MXBean subinterfaces must repeat the same
|
||||
annotation for correct behavior.</p></li>
|
||||
|
||||
<li><p>Otherwise, if the package in which the MXBean interface
|
||||
appears has an {@code MXBeanMappingFactoryClass} annotation,
|
||||
then <code><em>f</em></code> is determined as if that
|
||||
annotation appeared on the MXBean interface.</p></li>
|
||||
|
||||
<li><p>Otherwise, <code><em>f</em></code> is the default mapping
|
||||
factory, {@link MXBeanMappingFactory#DEFAULT}.</p></li>
|
||||
</ul>
|
||||
|
||||
<p>The default mapping factory recognizes the {@link
|
||||
MXBeanMappingClass} annotation on a class or interface. If
|
||||
<code><em>J</em></code> is a class or interface that has such an
|
||||
annotation, then the {@code MXBeanMapping} for
|
||||
<code><em>J</em></code> produced by the default mapping factory
|
||||
will be determined by the value of the annotation as described
|
||||
in its {@linkplain MXBeanMappingClass documentation}.</p>
|
||||
|
||||
<h3>MBeanInfo contents for an MXBean</h3>
|
||||
|
||||
<p>An MXBean is a type of Open MBean. However, for compatibility
|
||||
@ -1250,29 +1163,12 @@ public interface Node {
|
||||
appropriate), or <em>C</em> is true of <em>e</em>.{@link
|
||||
Throwable#getCause() getCause()}".</p>
|
||||
|
||||
@see MXBeanMapping
|
||||
|
||||
@since 1.6
|
||||
*/
|
||||
|
||||
/*
|
||||
* This annotation is @Inherited because if an MXBean is defined as a
|
||||
* class using annotations, then its subclasses are also MXBeans.
|
||||
* For example:
|
||||
* @MXBean
|
||||
* public class Super {
|
||||
* @ManagedAttribute
|
||||
* public String getName() {...}
|
||||
* }
|
||||
* public class Sub extends Super {}
|
||||
* Here Sub is an MXBean.
|
||||
*
|
||||
* The @Inherited annotation has no effect when applied to an interface.
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Inherited
|
||||
public @interface MXBean {
|
||||
/**
|
||||
True if the annotated interface is an MXBean interface.
|
||||
|
||||
@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-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 javax.management;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* <p>Indicates that a method in an MBean class defines an MBean attribute.
|
||||
* This annotation must be applied to a public method of a public class
|
||||
* that is itself annotated with an {@link MBean @MBean} or
|
||||
* {@link MXBean @MXBean} annotation, or inherits such an annotation from
|
||||
* a superclass.</p>
|
||||
*
|
||||
* <p>The annotated method must be a getter or setter. In other words,
|
||||
* it must look like one of the following...</p>
|
||||
*
|
||||
* <pre>
|
||||
* <i>T</i> get<i>Foo</i>()
|
||||
* void set<i>Foo</i>(<i>T</i> param)
|
||||
* </pre>
|
||||
*
|
||||
* <p>...where <i>{@code T}</i> is any type and <i>{@code Foo}</i> is the
|
||||
* name of the attribute. For any attribute <i>{@code Foo}</i>, if only
|
||||
* a {@code get}<i>{@code Foo}</i> method has a {@code ManagedAttribute}
|
||||
* annotation, then <i>{@code Foo}</i> is a read-only attribute. If only
|
||||
* a {@code set}<i>{@code Foo}</i> method has a {@code ManagedAttribute}
|
||||
* annotation, then <i>{@code Foo}</i> is a write-only attribute. If
|
||||
* both {@code get}<i>{@code Foo}</i> and {@code set}<i>{@code Foo}</i>
|
||||
* methods have the annotation, then <i>{@code Foo}</i> is a read-write
|
||||
* attribute. In this last case, the type <i>{@code T}</i> must be the
|
||||
* same in both methods.</p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@Documented
|
||||
public @interface ManagedAttribute {
|
||||
}
|
||||
@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright 2007-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 javax.management;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* <p>Indicates that a method in an MBean class defines an MBean operation.
|
||||
* This annotation can be applied to:</p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>A public method of a public class
|
||||
* that is itself annotated with an {@link MBean @MBean} or
|
||||
* {@link MXBean @MXBean} annotation, or inherits such an annotation from
|
||||
* a superclass.</li>
|
||||
* <li>A method of an MBean or MXBean interface.
|
||||
* </ul>
|
||||
*
|
||||
* <p>Every method in an MBean or MXBean interface defines an MBean
|
||||
* operation even without this annotation, but the annotation allows
|
||||
* you to specify the impact of the operation:</p>
|
||||
*
|
||||
* <pre>
|
||||
* public interface ConfigurationMBean {
|
||||
* {@code @ManagedOperation}(impact = {@link Impact#ACTION Impact.ACTION})
|
||||
* public void save();
|
||||
* ...
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@Documented
|
||||
public @interface ManagedOperation {
|
||||
/**
|
||||
* <p>The impact of this operation, as shown by
|
||||
* {@link MBeanOperationInfo#getImpact()}.
|
||||
*/
|
||||
Impact impact() default Impact.UNKNOWN;
|
||||
}
|
||||
@ -90,10 +90,4 @@ class NotQueryExp extends QueryEval implements QueryExp {
|
||||
public String toString() {
|
||||
return "not (" + exp + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
String toQueryString() {
|
||||
return "not (" + Query.toString(exp) + ")";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@ import com.sun.jmx.mbeanserver.GetPropertyAction;
|
||||
* @since 1.5
|
||||
*/
|
||||
@SuppressWarnings("serial") // serialVersionUID is not constant
|
||||
public class Notification extends EventObject implements Cloneable {
|
||||
public class Notification extends EventObject {
|
||||
|
||||
// Serialization compatibility stuff:
|
||||
// Two serial forms are supported in this class. The selected form depends
|
||||
@ -243,26 +243,6 @@ public class Notification extends EventObject implements Cloneable {
|
||||
this.message = message ;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Creates and returns a copy of this object. The copy is created as
|
||||
* described for {@link Object#clone()}. This means, first, that the
|
||||
* class of the object will be the same as the class of this object, and,
|
||||
* second, that the copy is a "shallow copy". Fields of this notification
|
||||
* are not themselves copied. In particular, the {@linkplain
|
||||
* #getUserData user data} of the copy is the same object as the
|
||||
* original.</p>
|
||||
*
|
||||
* @return a copy of this object.
|
||||
*/
|
||||
@Override
|
||||
public Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the source.
|
||||
*
|
||||
@ -341,23 +321,11 @@ public class Notification extends EventObject implements Cloneable {
|
||||
*
|
||||
* @return The message string of this notification object.
|
||||
*
|
||||
* @see #setMessage
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the notification message.
|
||||
*
|
||||
* @param message the new notification message.
|
||||
*
|
||||
* @see #getMessage
|
||||
*/
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user data.
|
||||
*
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1999-2007 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
|
||||
@ -58,8 +58,7 @@ import com.sun.jmx.remote.util.ClassLogger;
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
public class NotificationBroadcasterSupport
|
||||
implements NotificationEmitter, SendNotification {
|
||||
public class NotificationBroadcasterSupport implements NotificationEmitter {
|
||||
/**
|
||||
* Constructs a NotificationBroadcasterSupport where each listener is invoked by the
|
||||
* thread sending the notification. This constructor is equivalent to
|
||||
@ -249,26 +248,6 @@ public class NotificationBroadcasterSupport
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns true if there are any listeners.
|
||||
*
|
||||
* @return true if there is at least one listener that has been added with
|
||||
* {@code addNotificationListener} and not subsequently removed with
|
||||
* {@code removeNotificationListener} or {@code removeAllNotificationListeners}.
|
||||
* @since 1.7
|
||||
*/
|
||||
public boolean isListenedTo() {
|
||||
return listenerList.size() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all listeners.
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public void removeAllNotificationListeners() {
|
||||
listenerList.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>This method is called by {@link #sendNotification
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user