This commit is contained in:
Chris Hegarty 2009-10-21 16:50:44 +01:00
commit c3d3d4780a
294 changed files with 1230 additions and 57288 deletions

View file

@ -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 \

View file

@ -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.
*/

View file

@ -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.

View file

@ -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");
}

View file

@ -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");
}

View file

@ -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();
}

View file

@ -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);
}
}
}

View file

@ -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");
}

View file

@ -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");
}

View file

@ -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");
}

View file

@ -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");
}

View file

@ -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");
}

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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.");
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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();

View file

@ -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));

View file

@ -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().

View file

@ -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

View file

@ -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);

View file

@ -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);

View file

@ -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>>();
}

View file

@ -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.

View file

@ -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;

View file

@ -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();
}

View file

@ -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();
}

View file

@ -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();
}

View file

@ -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);
}
}

View file

@ -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

View file

@ -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();
}

View file

@ -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;
}

View file

@ -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();
}

View file

@ -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;
}
}

View file

@ -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) {

View file

@ -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;
}
}

View file

@ -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());

View file

@ -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

View file

@ -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());
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}
}

View file

@ -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();
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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>

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}
}

View file

@ -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>

View file

@ -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;

View file

@ -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) {}

View file

@ -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;
}

View file

@ -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));

View file

@ -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);
}
}
}

View file

@ -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;
}
}

View file

@ -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

View file

@ -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);
}
}
}

View file

@ -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;
}
}

View file

@ -253,7 +253,5 @@ class BinaryOpValueExp extends QueryEval implements ValueExp {
@Deprecated
public void setMBeanServer(MBeanServer s) {
super.setMBeanServer(s);
}
}
}

View file

@ -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

View file

@ -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 "";
}

View file

@ -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>
*

View file

@ -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>&#64;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>&#64;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 &#64;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>&#64;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>&#64;DescriptorFields</code> is more convenient but includes
* those risks. <code>&#64;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>&#64;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();
}

View file

@ -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 &#64;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>
* &#64;Documented
* &#64;Target(ElementType.METHOD)
* &#64;Retention(RetentionPolicy.RUNTIME)
* public &#64;interface Units {
* &#64;DescriptorKey("units")
* String value();
*
* <b>&#64;DescriptorKey(value = "descriptionResourceKey",
* omitIfDefault = true)</b>
* String resourceKey() default "";
*
* <b>&#64;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;
}

View file

@ -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();
}

View file

@ -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 &#64;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 &#64;DescriptorKey} facility
* to define annotations that allow you to specify the error codes. If you
* define...</p>
*
* <pre>
* {@link java.lang.annotation.Documented &#64;Documented}
* {@link java.lang.annotation.Target &#64;Target}(ElementType.METHOD)
* {@link java.lang.annotation.Retention &#64;Retention}(RetentionPolicy.RUNTIME)
* public &#64;interface ErrorCodes {
* &#64;DescriptorKey("exceptionErrorCodes")
* String[] value();
* }
* </pre>
*
* <p>...then you can write MBean interfaces like this...</p>
*
* <pre>
* public interface FooMBean { // or FooMXBean
* &#64;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;
}
}

View file

@ -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;
}
}
}

View file

@ -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));
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}
}

View file

@ -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 {
}

View file

@ -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)));
}
/**

View file

@ -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));
}
/**

View file

@ -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;
}
}

View file

@ -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 &#64;MBean} or
* {@link MXBean &#64;MXBean} annotation on a class, from methods with the
* {@link ManagedAttribute &#64;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 &#64;MBean} or
* {@link MXBean &#64;MXBean} annotation on a class, from methods with the
* {@link ManagedOperation &#64;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 &#64;NotificationInfo}
* or {@link NotificationInfos &#64;NotificationInfos} annotation on the
* MBean interface or <code>&#64;MBean</code> or <code>&#64;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 &#64;DescriptorFields} and
* {@link DescriptorKey &#64;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&eacute;faut
* ConfigurationMBean.constructor.com.example.Configuration.p1 = <!--
* -->Nom du fichier par d&eacute;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 &#64;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");
}
}
}

View file

@ -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;

View file

@ -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) {

View file

@ -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 &#64;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>&#64;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 {
* &#64;Resource
* private volatile MBeanServer mbeanServer;
* &#64;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 {
* &#64;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>&#64;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>&#64;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>&#64;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>&#64;Resource</code> annotation. For example:</p>
*
* <pre>
* &#64;Resource(type = MBeanServer.class)
* private volatile MBeanServerConnection mbsc;
* </pre>
*
* <p>Formally, suppose <em>R</em> is the type in the <code>&#64;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>&#64;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

View file

@ -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 &#64;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>

View file

@ -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 &#64;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 &#64;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 &#64;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 &#64;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.
*

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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
*/

View file

@ -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>&#64;{@link
ManagedAttribute}</code> or <code>&#64;{@link ManagedOperation}</code>
annotations, as described for <code>&#64;{@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.

View file

@ -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 {
}

View file

@ -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;
}

View file

@ -90,10 +90,4 @@ class NotQueryExp extends QueryEval implements QueryExp {
public String toString() {
return "not (" + exp + ")";
}
@Override
String toQueryString() {
return "not (" + Query.toString(exp) + ")";
}
}

View file

@ -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.
*

View file

@ -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