提交 34494f81 编写于 作者: T tbell

Merge

......@@ -155,6 +155,7 @@ CORE_PKGS = \
javax.lang.model.type \
javax.lang.model.util \
javax.management \
javax.management.event \
javax.management.loading \
javax.management.monitor \
javax.management.relation \
......
/*
* Copyright 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
* 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");
}
/*
* Copyright 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
* 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");
}
/*
* Copyright 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
* 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();
}
/*
* Copyright 2002-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
* 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);
}
}
}
/*
* Copyright 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
* 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_LEASE_TIMEOUT;
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");
}
/*
* Copyright 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
* 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.FutureTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
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();
}
}
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;
}
private final Runnable callback;
private ScheduledFuture scheduled; // If null, the lease has expired.
private final ScheduledExecutorService executor
= Executors.newScheduledThreadPool(1,
new DaemonThreadFactory("LeaseManager"));
private static final ClassLogger logger =
new ClassLogger("javax.management.event", "LeaseManager");
}
/*
* Copyright 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
* 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");
}
/*
* Copyright 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
* 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");
}
/*
* Copyright 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
* 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(
"setEventReceiver", "Executor threw exception", 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");
}
......@@ -453,11 +453,12 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
final ResourceContext context =
unregisterFromRepository(resource, instance, name);
if (instance instanceof MBeanRegistration)
postDeregisterInvoke((MBeanRegistration) instance);
context.done();
try {
if (instance instanceof MBeanRegistration)
postDeregisterInvoke(name,(MBeanRegistration) instance);
} finally {
context.done();
}
}
public ObjectInstance getObjectInstance(ObjectName name)
......@@ -989,10 +990,12 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
registerFailed = false;
registered = true;
} finally {
postRegister(mbean, registered, registerFailed);
try {
postRegister(logicalName, mbean, registered, registerFailed);
} finally {
if (registered) context.done();
}
}
context.done();
return new ObjectInstance(logicalName, classname);
}
......@@ -1051,7 +1054,8 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
}
private static void postRegister(
DynamicMBean mbean, boolean registrationDone, boolean registerFailed) {
ObjectName logicalName, DynamicMBean mbean,
boolean registrationDone, boolean registerFailed) {
if (registerFailed && mbean instanceof DynamicMBean2)
((DynamicMBean2) mbean).registerFailed();
......@@ -1059,11 +1063,19 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
if (mbean instanceof MBeanRegistration)
((MBeanRegistration) mbean).postRegister(registrationDone);
} catch (RuntimeException e) {
MBEANSERVER_LOGGER.fine("While registering MBean ["+logicalName+
"]: " + "Exception thrown by postRegister: " +
"rethrowing <"+e+">, but keeping the MBean registered");
throw new RuntimeMBeanException(e,
"RuntimeException thrown in postRegister method");
"RuntimeException thrown in postRegister method: "+
"rethrowing <"+e+">, but keeping the MBean registered");
} catch (Error er) {
MBEANSERVER_LOGGER.fine("While registering MBean ["+logicalName+
"]: " + "Error thrown by postRegister: " +
"rethrowing <"+er+">, but keeping the MBean registered");
throw new RuntimeErrorException(er,
"Error thrown in postRegister method");
"Error thrown in postRegister method: "+
"rethrowing <"+er+">, but keeping the MBean registered");
}
}
......@@ -1076,15 +1088,28 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
}
}
private static void postDeregisterInvoke(MBeanRegistration moi) {
private static void postDeregisterInvoke(ObjectName mbean,
MBeanRegistration moi) {
try {
moi.postDeregister();
} catch (RuntimeException e) {
MBEANSERVER_LOGGER.fine("While unregistering MBean ["+mbean+
"]: " + "Exception thrown by postDeregister: " +
"rethrowing <"+e+">, although the MBean is succesfully " +
"unregistered");
throw new RuntimeMBeanException(e,
"RuntimeException thrown in postDeregister method");
"RuntimeException thrown in postDeregister method: "+
"rethrowing <"+e+
">, although the MBean is sucessfully unregistered");
} catch (Error er) {
MBEANSERVER_LOGGER.fine("While unregistering MBean ["+mbean+
"]: " + "Error thrown by postDeregister: " +
"rethrowing <"+er+">, although the MBean is succesfully " +
"unregistered");
throw new RuntimeErrorException(er,
"Error thrown in postDeregister method");
"Error thrown in postDeregister method: "+
"rethrowing <"+er+
">, although the MBean is sucessfully unregistered");
}
}
......
/*
* 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.remote.IdentityMBeanServerForwarder;
public class SingleMBeanForwarder extends IdentityMBeanServerForwarder {
private final ObjectName mbeanName;
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;
}
};
public SingleMBeanForwarder(ObjectName mbeanName, DynamicMBean mbean) {
this.mbeanName = mbeanName;
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() {
TreeSet<String> domainSet =
new TreeSet<String>(Arrays.asList(super.getDomains()));
domainSet.add(mbeanName.getDomain());
return domainSet.toArray(new String[domainSet.size()]);
}
@Override
public Integer getMBeanCount() {
Integer count = super.getMBeanCount();
if (!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 (!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 (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 (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);
}
}
......@@ -29,5 +29,8 @@ have any questions.
</head>
<body bgcolor="white">
Provides specific classes to <B>Sun JMX Reference Implementation</B>.
<p><b>
This API is a Sun internal API and is subject to changes without notice.
</b></p>
</BODY>
</HTML>
......@@ -172,7 +172,7 @@ public class MBeanInjector {
* reference.
*
* So we accept a Field if it has a @Resource annotation and either
* (a) its type is ObjectName or a subclass and its @Resource type is
* (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
......
......@@ -25,7 +25,6 @@
package com.sun.jmx.mbeanserver;
import static com.sun.jmx.mbeanserver.Util.*;
import javax.management.Attribute;
import javax.management.AttributeList;
......
/*
* 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
* 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;
}
}
......@@ -38,10 +38,13 @@ 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 javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.loading.ClassLoaderRepository;
public class Util {
static <K, V> Map<K, V> newMap() {
......@@ -142,4 +145,97 @@ public class Util {
return hash;
}
/**
* 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;
}
/**
* 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);
}
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 if (set != null) {
set = new HashSet<T>(set.size());
} else
set = new HashSet<T>();
return set;
}
}
......@@ -576,6 +576,7 @@ public abstract class ClientNotifForwarder {
int notFoundCount = 0;
NotificationResult result = null;
long firstEarliest = -1;
while (result == null && !shouldStop()) {
NotificationResult nr;
......@@ -598,6 +599,8 @@ public abstract class ClientNotifForwarder {
return null;
startSequenceNumber = nr.getNextSequenceNumber();
if (firstEarliest < 0)
firstEarliest = nr.getEarliestSequenceNumber();
try {
// 1 notif to skip possible missing class
......@@ -628,6 +631,17 @@ public abstract class ClientNotifForwarder {
(notFoundCount == 1 ? "" : "s") +
" because classes were missing locally";
lostNotifs(msg, notFoundCount);
// Even if result.getEarliestSequenceNumber() is now greater than
// it was initially, meaning some notifs have been dropped
// from the buffer, we don't want the caller to see that
// because it is then likely to renotify about the lost notifs.
// So we put back the first value of earliestSequenceNumber
// that we saw.
if (result != null) {
result = new NotificationResult(
firstEarliest, result.getNextSequenceNumber(),
result.getTargetedNotifications());
}
}
return result;
......
......@@ -33,10 +33,8 @@ import org.omg.CORBA.Any;
import org.omg.CORBA.Context;
import org.omg.CORBA.NO_IMPLEMENT;
import org.omg.CORBA.ORB;
import org.omg.CORBA.Principal;
import org.omg.CORBA.TypeCode;
import org.omg.CORBA.portable.BoxedValueHelper;
import org.omg.CORBA_2_3.portable.InputStream;
@SuppressWarnings("deprecation")
public class ProxyInputStream extends org.omg.CORBA_2_3.portable.InputStream {
......@@ -160,54 +158,71 @@ public class ProxyInputStream extends org.omg.CORBA_2_3.portable.InputStream {
return in.read_any();
}
public Principal read_Principal() {
/**
* @deprecated
*/
@Override
@Deprecated
public org.omg.CORBA.Principal read_Principal() {
return in.read_Principal();
}
@Override
public int read() throws IOException {
return in.read();
}
@Override
public BigDecimal read_fixed() {
return in.read_fixed();
}
@Override
public Context read_Context() {
return in.read_Context();
}
@Override
public org.omg.CORBA.Object read_Object(java.lang.Class clz) {
return in.read_Object(clz);
}
@Override
public ORB orb() {
return in.orb();
}
@Override
public Serializable read_value() {
return narrow().read_value();
}
@Override
public Serializable read_value(Class clz) {
return narrow().read_value(clz);
}
@Override
public Serializable read_value(BoxedValueHelper factory) {
return narrow().read_value(factory);
}
@Override
public Serializable read_value(String rep_id) {
return narrow().read_value(rep_id);
}
@Override
public Serializable read_value(Serializable value) {
return narrow().read_value(value);
}
@Override
public Object read_abstract_interface() {
return narrow().read_abstract_interface();
}
@Override
public Object read_abstract_interface(Class clz) {
return narrow().read_abstract_interface(clz);
}
......
......@@ -31,8 +31,6 @@ import java.io.ObjectOutput;
import java.lang.reflect.Method;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.server.Operation;
import java.rmi.server.RemoteCall;
import java.rmi.server.RemoteObject;
import java.rmi.server.RemoteRef;
......@@ -54,7 +52,11 @@ public class ProxyRef implements RemoteRef {
ref.writeExternal(out);
}
public void invoke(RemoteCall call) throws Exception {
/**
* @deprecated
*/
@Deprecated
public void invoke(java.rmi.server.RemoteCall call) throws Exception {
ref.invoke(call);
}
......@@ -63,7 +65,11 @@ public class ProxyRef implements RemoteRef {
return ref.invoke(obj, method, params, opnum);
}
public void done(RemoteCall call) throws RemoteException {
/**
* @deprecated
*/
@Deprecated
public void done(java.rmi.server.RemoteCall call) throws RemoteException {
ref.done(call);
}
......@@ -71,7 +77,12 @@ public class ProxyRef implements RemoteRef {
return ref.getRefClass(out);
}
public RemoteCall newCall(RemoteObject obj, Operation[] op, int opnum,
/**
* @deprecated
*/
@Deprecated
public java.rmi.server.RemoteCall newCall(RemoteObject obj,
java.rmi.server.Operation[] op, int opnum,
long hash) throws RemoteException {
return ref.newCall(obj, op, opnum, hash);
}
......
......@@ -25,16 +25,16 @@
package com.sun.jmx.remote.internal;
import com.sun.jmx.mbeanserver.Util;
import com.sun.jmx.remote.security.NotificationAccessController;
import com.sun.jmx.remote.util.ClassLogger;
import com.sun.jmx.remote.util.EnvHelp;
import java.io.IOException;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
......@@ -67,9 +67,9 @@ public class ServerNotifForwarder {
connectionTimeout = EnvHelp.getServerConnectionTimeout(env);
checkNotificationEmission = EnvHelp.computeBooleanFromString(
env,
"jmx.remote.x.check.notification.emission");
notificationAccessController = (NotificationAccessController)
env.get("com.sun.jmx.remote.notification.access.controller");
"jmx.remote.x.check.notification.emission",false);
notificationAccessController =
EnvHelp.getNotificationAccessController(env);
}
public Integer addNotificationListener(final ObjectName name,
......@@ -88,9 +88,7 @@ public class ServerNotifForwarder {
checkMBeanPermission(name, "addNotificationListener");
if (notificationAccessController != null) {
notificationAccessController.addNotificationListener(
connectionId,
name,
Subject.getSubject(AccessController.getContext()));
connectionId, name, getSubject());
}
try {
boolean instanceOf =
......@@ -160,9 +158,7 @@ public class ServerNotifForwarder {
checkMBeanPermission(name, "removeNotificationListener");
if (notificationAccessController != null) {
notificationAccessController.removeNotificationListener(
connectionId,
name,
Subject.getSubject(AccessController.getContext()));
connectionId, name, getSubject());
}
Exception re = null;
......@@ -312,6 +308,10 @@ public class ServerNotifForwarder {
// PRIVATE METHODS
//----------------
private Subject getSubject() {
return Subject.getSubject(AccessController.getContext());
}
private void checkState() throws IOException {
synchronized(terminationLock) {
if (terminated) {
......@@ -332,7 +332,13 @@ public class ServerNotifForwarder {
*/
private void checkMBeanPermission(final ObjectName name,
final String actions)
throws InstanceNotFoundException, SecurityException {
throws InstanceNotFoundException, SecurityException {
checkMBeanPermission(mbeanServer, name, actions);
}
public static void checkMBeanPermission(
final MBeanServer mbs, final ObjectName name, final String actions)
throws InstanceNotFoundException, SecurityException {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
AccessControlContext acc = AccessController.getContext();
......@@ -342,7 +348,7 @@ public class ServerNotifForwarder {
new PrivilegedExceptionAction<ObjectInstance>() {
public ObjectInstance run()
throws InstanceNotFoundException {
return mbeanServer.getObjectInstance(name);
return mbs.getObjectInstance(name);
}
});
} catch (PrivilegedActionException e) {
......@@ -364,14 +370,12 @@ public class ServerNotifForwarder {
TargetedNotification tn) {
try {
if (checkNotificationEmission) {
checkMBeanPermission(name, "addNotificationListener");
checkMBeanPermission(
name, "addNotificationListener");
}
if (notificationAccessController != null) {
notificationAccessController.fetchNotification(
connectionId,
name,
tn.getNotification(),
Subject.getSubject(AccessController.getContext()));
connectionId, name, tn.getNotification(), getSubject());
}
return true;
} catch (SecurityException e) {
......
......@@ -25,6 +25,7 @@
package com.sun.jmx.remote.security;
import com.sun.jmx.mbeanserver.GetPropertyAction;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
......@@ -47,8 +48,6 @@ import com.sun.jmx.remote.util.ClassLogger;
import com.sun.jmx.remote.util.EnvHelp;
import sun.management.jmxremote.ConnectorBootstrap;
import sun.security.action.GetPropertyAction;
/**
* This {@link LoginModule} performs file-based authentication.
*
......@@ -479,7 +478,7 @@ public class FileLoginModule implements LoginModule {
if (userSuppliedPasswordFile || hasJavaHomePermission) {
throw e;
} else {
FilePermission fp =
final FilePermission fp =
new FilePermission(passwordFileDisplayName, "read");
AccessControlException ace = new AccessControlException(
"access denied " + fp.toString());
......@@ -488,10 +487,13 @@ public class FileLoginModule implements LoginModule {
}
}
try {
BufferedInputStream bis = new BufferedInputStream(fis);
userCredentials = new Properties();
userCredentials.load(bis);
bis.close();
final BufferedInputStream bis = new BufferedInputStream(fis);
try {
userCredentials = new Properties();
userCredentials.load(bis);
} finally {
bis.close();
}
} finally {
fis.close();
}
......
......@@ -40,9 +40,6 @@ import java.util.TreeMap;
import java.util.TreeSet;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import javax.management.ObjectName;
import javax.management.MBeanServer;
......@@ -50,6 +47,9 @@ import javax.management.InstanceNotFoundException;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXConnectorServerFactory;
import com.sun.jmx.mbeanserver.GetPropertyAction;
import com.sun.jmx.remote.security.NotificationAccessController;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorServer;
public class EnvHelp {
......@@ -346,7 +346,24 @@ public class EnvHelp {
*/
public static long getFetchTimeout(Map env) {
return getIntegerAttribute(env, FETCH_TIMEOUT, 60000L, 0,
Long.MAX_VALUE);
Long.MAX_VALUE);
}
/**
* <p>Name of the attribute that specifies an object that will check
* accesses to add/removeNotificationListener and also attempts to
* receive notifications. The value associated with this attribute
* should be a <code>NotificationAccessController</code> object.
* The default value is null.</p>
* This field is not public because of its com.sun dependency.
*/
public static final String NOTIF_ACCESS_CONTROLLER =
"com.sun.jmx.remote.notification.access.controller";
public static NotificationAccessController getNotificationAccessController(
Map env) {
return (env == null) ? null :
(NotificationAccessController) env.get(NOTIF_ACCESS_CONTROLLER);
}
/**
......@@ -470,24 +487,24 @@ public class EnvHelp {
}
/**
The value of this attribute, if present, is a string specifying
what other attributes should not appear in
JMXConnectorServer.getAttributes(). It is a space-separated
list of attribute patterns, where each pattern is either an
attribute name, or an attribute prefix followed by a "*"
character. The "*" has no special significance anywhere except
at the end of a pattern. By default, this list is added to the
list defined by {@link #DEFAULT_HIDDEN_ATTRIBUTES} (which
uses the same format). If the value of this attribute begins
with an "=", then the remainder of the string defines the
complete list of attribute patterns.
* The value of this attribute, if present, is a string specifying
* what other attributes should not appear in
* JMXConnectorServer.getAttributes(). It is a space-separated
* list of attribute patterns, where each pattern is either an
* attribute name, or an attribute prefix followed by a "*"
* character. The "*" has no special significance anywhere except
* at the end of a pattern. By default, this list is added to the
* list defined by {@link #DEFAULT_HIDDEN_ATTRIBUTES} (which
* uses the same format). If the value of this attribute begins
* with an "=", then the remainder of the string defines the
* complete list of attribute patterns.
*/
public static final String HIDDEN_ATTRIBUTES =
"jmx.remote.x.hidden.attributes";
/**
Default list of attributes not to show.
@see #HIDDEN_ATTRIBUTES
* Default list of attributes not to show.
* @see #HIDDEN_ATTRIBUTES
*/
/* This list is copied directly from the spec, plus
java.naming.security.*. Most of the attributes here would have
......@@ -651,6 +668,8 @@ public class EnvHelp {
* @param env the environment map.
* @param prop the name of the property in the environment map whose
* returned string value must be converted into a boolean value.
* @param systemProperty if true, consult a system property of the
* same name if there is no entry in the environment map.
*
* @return
* <ul>
......@@ -671,16 +690,73 @@ public class EnvHelp {
* @throws ClassCastException if {@code env.get(prop)} cannot be cast
* to {@code String}.
*/
public static boolean computeBooleanFromString(Map env, String prop)
throws IllegalArgumentException, ClassCastException {
public static boolean computeBooleanFromString(
Map env, String prop, boolean systemProperty) {
if (env == null)
throw new IllegalArgumentException("env map cannot be null");
// returns a default value of 'false' if no property is found...
return computeBooleanFromString(env,prop,systemProperty,false);
}
/**
* Computes a boolean value from a string value retrieved from a
* property in the given map.
*
* @param env the environment map.
* @param prop the name of the property in the environment map whose
* returned string value must be converted into a boolean value.
* @param systemProperty if true, consult a system property of the
* same name if there is no entry in the environment map.
* @param defaultValue a default value to return in case no property
* was defined.
*
* @return
* <ul>
* <li>{@code defaultValue} if {@code env.get(prop)} is {@code null}
* and {@code systemProperty} is {@code false}</li>
* <li>{@code defaultValue} if {@code env.get(prop)} is {@code null}
* and {@code systemProperty} is {@code true} and
* {@code System.getProperty(prop)} is {@code null}</li>
* <li>{@code false} if {@code env.get(prop)} is {@code null}
* and {@code systemProperty} is {@code true} and
* {@code System.getProperty(prop).equalsIgnoreCase("false")}
* is {@code true}</li>
* <li>{@code true} if {@code env.get(prop)} is {@code null}
* and {@code systemProperty} is {@code true} and
* {@code System.getProperty(prop).equalsIgnoreCase("true")}
* is {@code true}</li>
* <li>{@code false} if
* {@code ((String)env.get(prop)).equalsIgnoreCase("false")}
* is {@code true}</li>
* <li>{@code true} if
* {@code ((String)env.get(prop)).equalsIgnoreCase("true")}
* is {@code true}</li>
* </ul>
*
* @throws IllegalArgumentException if {@code env} is {@code null} or
* {@code env.get(prop)} is not {@code null} and
* {@code ((String)env.get(prop)).equalsIgnoreCase("false")} and
* {@code ((String)env.get(prop)).equalsIgnoreCase("true")} are
* {@code false}.
* @throws ClassCastException if {@code env.get(prop)} cannot be cast
* to {@code String}.
*/
public static boolean computeBooleanFromString(
Map env, String prop, boolean systemProperty, boolean defaultValue) {
if (env == null)
throw new IllegalArgumentException("env map cannot be null");
String stringBoolean = (String) env.get(prop);
if (stringBoolean == null && systemProperty) {
stringBoolean =
AccessController.doPrivileged(new GetPropertyAction(prop));
}
if (stringBoolean == null)
return false;
return defaultValue;
else if (stringBoolean.equalsIgnoreCase("true"))
return true;
else if (stringBoolean.equalsIgnoreCase("false"))
......@@ -703,6 +779,65 @@ 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 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 env) {
return computeBooleanFromString(env,
JMXConnectorServer.DELEGATE_TO_EVENT_SERVICE, true, true);
}
// /**
// * <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) {}
......
/*
* Copyright 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
* 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.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;
/**
* 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 =
Logger.getLogger(EventClientConnection.class.getName());
private static final String NAMESPACE_SEPARATOR = "//";
private static final int NAMESPACE_SEPARATOR_LENGTH =
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 client = getEventClient();
// Fails if client 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 client indicates that the remote VM is of
// an earlier version, in which case it shouldn't contain any namespace.
//
// So having a null client AND an MBean contained in a namespace is
// clearly an error case.
//
if (client == null) {
final String domain = mbean.getDomain();
final int index = domain.indexOf(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 (client != null) {
// general case
client.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 (client != null) {
// general case
client.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 (client != null) {
client.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
**/
public static MBeanServerConnection getEventConnectionFor(
MBeanServerConnection connection,
Callable<EventClient> eventClientFactory) {
// if c already uses an EventClient no need to create a new one.
//
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;
}
......@@ -45,15 +45,9 @@ public class ThreadService implements TaskServer {
minThreads = threadNumber;
threadList = new ExecutorThread[threadNumber];
// for (int i=0; i<threadNumber; i++) {
// threadList[i] = new ExecutorThread();
// threadList[i].start();
// }
priority = Thread.currentThread().getPriority();
cloader = Thread.currentThread().getContextClassLoader();
//System.out.println("---jsl: ThreadService: running threads = "+threadNumber);
}
// public methods
......@@ -89,7 +83,6 @@ public class ThreadService implements TaskServer {
synchronized(jobList) {
jobList.add(jobList.size(), task);
//System.out.println("jsl-ThreadService: added job "+addedJobs++);
jobList.notify();
}
......@@ -196,8 +189,6 @@ public class ThreadService implements TaskServer {
try {
idle--;
job.run();
//System.out.println("jsl-ThreadService: done job "+doneJobs++);
} catch (Exception e) {
// TODO
e.printStackTrace();
......@@ -228,7 +219,6 @@ public class ThreadService implements TaskServer {
ExecutorThread et = new ExecutorThread();
et.start();
threadList[currThreds++] = et;
//System.out.println("jsl-ThreadService: create new thread: "+currThreds);
}
}
}
......
......@@ -25,6 +25,7 @@
package java.util;
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;
/**
* A facility for threads to schedule tasks for future execution in a
......@@ -92,12 +93,12 @@ public class Timer {
* and the timer thread consumes, executing timer tasks as appropriate,
* and removing them from the queue when they're obsolete.
*/
private TaskQueue queue = new TaskQueue();
private final TaskQueue queue = new TaskQueue();
/**
* The timer thread.
*/
private TimerThread thread = new TimerThread(queue);
private final TimerThread thread = new TimerThread(queue);
/**
* This object causes the timer's task execution thread to exit
......@@ -106,7 +107,7 @@ public class Timer {
* Timer as such a finalizer would be susceptible to a subclass's
* finalizer forgetting to call it.
*/
private Object threadReaper = new Object() {
private final Object threadReaper = new Object() {
protected void finalize() throws Throwable {
synchronized(queue) {
thread.newTasksMayBeScheduled = false;
......@@ -116,12 +117,11 @@ public class Timer {
};
/**
* This ID is used to generate thread names. (It could be replaced
* by an AtomicInteger as soon as they become available.)
* This ID is used to generate thread names.
*/
private static int nextSerialNumber = 0;
private static synchronized int serialNumber() {
return nextSerialNumber++;
private final static AtomicInteger nextSerialNumber = new AtomicInteger(0);
private static int serialNumber() {
return nextSerialNumber.getAndIncrement();
}
/**
......@@ -387,6 +387,11 @@ public class Timer {
if (time < 0)
throw new IllegalArgumentException("Illegal execution time.");
// Constrain value of period sufficiently to prevent numeric
// overflow while still being effectively infinitely large.
if (Math.abs(period) > (Long.MAX_VALUE >> 1))
period >>= 1;
synchronized(queue) {
if (!thread.newTasksMayBeScheduled)
throw new IllegalStateException("Timer already cancelled.");
......
......@@ -223,8 +223,7 @@ public class ScheduledThreadPoolExecutor
}
public long getDelay(TimeUnit unit) {
long d = unit.convert(time - now(), TimeUnit.NANOSECONDS);
return d;
return unit.convert(time - now(), TimeUnit.NANOSECONDS);
}
public int compareTo(Delayed other) {
......@@ -264,7 +263,7 @@ public class ScheduledThreadPoolExecutor
if (p > 0)
time += p;
else
time = now() - p;
time = triggerTime(-p);
}
public boolean cancel(boolean mayInterruptIfRunning) {
......@@ -472,6 +471,38 @@ public class ScheduledThreadPoolExecutor
new DelayedWorkQueue(), threadFactory, handler);
}
/**
* Returns the trigger time of a delayed action.
*/
private long triggerTime(long delay, TimeUnit unit) {
return triggerTime(unit.toNanos((delay < 0) ? 0 : delay));
}
/**
* Returns the trigger time of a delayed action.
*/
long triggerTime(long delay) {
return now() +
((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
}
/**
* Constrains the values of all delays in the queue to be within
* Long.MAX_VALUE of each other, to avoid overflow in compareTo.
* This may occur if a task is eligible to be dequeued, but has
* not yet been, while some other task is added with a delay of
* Long.MAX_VALUE.
*/
private long overflowFree(long delay) {
Delayed head = (Delayed) super.getQueue().peek();
if (head != null) {
long headDelay = head.getDelay(TimeUnit.NANOSECONDS);
if (headDelay < 0 && (delay - headDelay < 0))
delay = Long.MAX_VALUE + headDelay;
}
return delay;
}
/**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
......@@ -481,10 +512,9 @@ public class ScheduledThreadPoolExecutor
TimeUnit unit) {
if (command == null || unit == null)
throw new NullPointerException();
if (delay < 0) delay = 0;
long triggerTime = now() + unit.toNanos(delay);
RunnableScheduledFuture<?> t = decorateTask(command,
new ScheduledFutureTask<Void>(command, null, triggerTime));
new ScheduledFutureTask<Void>(command, null,
triggerTime(delay, unit)));
delayedExecute(t);
return t;
}
......@@ -498,10 +528,9 @@ public class ScheduledThreadPoolExecutor
TimeUnit unit) {
if (callable == null || unit == null)
throw new NullPointerException();
if (delay < 0) delay = 0;
long triggerTime = now() + unit.toNanos(delay);
RunnableScheduledFuture<V> t = decorateTask(callable,
new ScheduledFutureTask<V>(callable, triggerTime));
new ScheduledFutureTask<V>(callable,
triggerTime(delay, unit)));
delayedExecute(t);
return t;
}
......@@ -519,12 +548,10 @@ public class ScheduledThreadPoolExecutor
throw new NullPointerException();
if (period <= 0)
throw new IllegalArgumentException();
if (initialDelay < 0) initialDelay = 0;
long triggerTime = now() + unit.toNanos(initialDelay);
ScheduledFutureTask<Void> sft =
new ScheduledFutureTask<Void>(command,
null,
triggerTime,
triggerTime(initialDelay, unit),
unit.toNanos(period));
RunnableScheduledFuture<Void> t = decorateTask(command, sft);
sft.outerTask = t;
......@@ -545,12 +572,10 @@ public class ScheduledThreadPoolExecutor
throw new NullPointerException();
if (delay <= 0)
throw new IllegalArgumentException();
if (initialDelay < 0) initialDelay = 0;
long triggerTime = now() + unit.toNanos(initialDelay);
ScheduledFutureTask<Void> sft =
new ScheduledFutureTask<Void>(command,
null,
triggerTime,
triggerTime(initialDelay, unit),
unit.toNanos(-delay));
RunnableScheduledFuture<Void> t = decorateTask(command, sft);
sft.outerTask = t;
......
......@@ -128,13 +128,13 @@ public class ImmutableDescriptor implements Descriptor {
* @throws InvalidObjectException if the read object has invalid fields.
*/
private Object readResolve() throws InvalidObjectException {
if (names.length == 0 && getClass() == ImmutableDescriptor.class)
return EMPTY_DESCRIPTOR;
boolean bad = false;
if (names == null || values == null || names.length != values.length)
bad = true;
if (!bad) {
if (names.length == 0 && getClass() == ImmutableDescriptor.class)
return EMPTY_DESCRIPTOR;
final Comparator<String> compare = String.CASE_INSENSITIVE_ORDER;
String lastName = ""; // also catches illegal null name
for (int i = 0; i < names.length; i++) {
......
......@@ -158,7 +158,19 @@ public interface MBeanRegistration {
/**
* Allows the MBean to perform any operations needed after having been
* registered in the MBean server or after the registration has failed.
*
* <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 exception in {@code postRegister}
* will not change the state of the MBean:
* if the MBean was already registered ({@code registrationDone} is
* {@code true}), the MBean will remain registered. </p>
* <p>This might be confusing for the code calling {@code createMBean()}
* or {@code registerMBean()}, as such code might assume that MBean
* registration has failed when such an exception is raised.
* Therefore it is recommended that implementations of
* {@code postRegister} do not throw Runtime Exceptions or Errors if it
* can be avoided.</p>
* @param registrationDone Indicates whether or not the MBean has
* been successfully registered in the MBean server. The value
* false means that the registration phase has failed.
......@@ -178,6 +190,17 @@ public interface MBeanRegistration {
/**
* Allows the MBean to perform any operations needed after having been
* unregistered in the MBean server.
* <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}
* 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
* {@code unregisterMBean()}, as it might assume that MBean deregistration
* has failed. Therefore it is recommended that implementations of
* {@code postDeregister} do not throw Runtime Exceptions or Errors if it
* can be avoided.</p>
*/
public void postDeregister();
......
......@@ -50,8 +50,8 @@ import javax.management.loading.ClassLoaderRepository;
* server. A Java object cannot be registered in the MBean server
* unless it is a JMX compliant MBean.</p>
*
* <p id="notif">When an MBean is registered or unregistered in the MBean server
* a {@link javax.management.MBeanServerNotification
* <p id="notif">When an MBean is registered or unregistered in the
* MBean server a {@link javax.management.MBeanServerNotification
* MBeanServerNotification} Notification is emitted. To register an
* object as listener to MBeanServerNotifications you should call the
* MBean server method {@link #addNotificationListener
......@@ -262,6 +262,8 @@ public interface MBeanServer extends MBeanServerConnection {
* {@inheritDoc}
* <p>If this method successfully creates an MBean, a notification
* is sent as described <a href="#notif">above</a>.</p>
*
* @throws RuntimeOperationsException {@inheritDoc}
*/
public ObjectInstance createMBean(String className, ObjectName name)
throws ReflectionException, InstanceAlreadyExistsException,
......@@ -272,6 +274,8 @@ public interface MBeanServer extends MBeanServerConnection {
* {@inheritDoc}
* <p>If this method successfully creates an MBean, a notification
* is sent as described <a href="#notif">above</a>.</p>
*
* @throws RuntimeOperationsException {@inheritDoc}
*/
public ObjectInstance createMBean(String className, ObjectName name,
ObjectName loaderName)
......@@ -283,6 +287,8 @@ public interface MBeanServer extends MBeanServerConnection {
* {@inheritDoc}
* <p>If this method successfully creates an MBean, a notification
* is sent as described <a href="#notif">above</a>.</p>
*
* @throws RuntimeOperationsException {@inheritDoc}
*/
public ObjectInstance createMBean(String className, ObjectName name,
Object params[], String signature[])
......@@ -294,6 +300,8 @@ public interface MBeanServer extends MBeanServerConnection {
* {@inheritDoc}
* <p>If this method successfully creates an MBean, a notification
* is sent as described <a href="#notif">above</a>.</p>
*
* @throws RuntimeOperationsException {@inheritDoc}
*/
public ObjectInstance createMBean(String className, ObjectName name,
ObjectName loaderName, Object params[],
......@@ -328,11 +336,30 @@ public interface MBeanServer extends MBeanServerConnection {
* <CODE>preRegister</CODE> (<CODE>MBeanRegistration</CODE>
* interface) method of the MBean has thrown an exception. The
* MBean will not be registered.
* @exception RuntimeMBeanException If the <CODE>postRegister</CODE>
* (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws a
* <CODE>RuntimeException</CODE>, the <CODE>registerMBean<CODE> method will
* throw a <CODE>RuntimeMBeanException</CODE>, although the MBean
* registration succeeded. In such a case, the MBean will be actually
* registered even though the <CODE>registerMBean<CODE> method
* threw an exception. Note that <CODE>RuntimeMBeanException</CODE> can
* also be thrown by <CODE>preRegister</CODE>, in which case the MBean
* will not be registered.
* @exception RuntimeErrorException If the <CODE>postRegister</CODE>
* (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws an
* <CODE>Error</CODE>, the <CODE>registerMBean<CODE> method will
* throw a <CODE>RuntimeErrorException</CODE>, although the MBean
* registration succeeded. In such a case, the MBean will be actually
* registered even though the <CODE>registerMBean<CODE> method
* threw an exception. Note that <CODE>RuntimeErrorException</CODE> can
* also be thrown by <CODE>preRegister</CODE>, in which case the MBean
* will not be registered.
* @exception NotCompliantMBeanException This object is not a JMX
* compliant MBean
* @exception RuntimeOperationsException Wraps a
* <CODE>java.lang.IllegalArgumentException</CODE>: The object
* passed in parameter is null or no object name is specified.
* @see javax.management.MBeanRegistration
*/
public ObjectInstance registerMBean(Object object, ObjectName name)
throws InstanceAlreadyExistsException, MBeanRegistrationException,
......@@ -343,6 +370,8 @@ public interface MBeanServer extends MBeanServerConnection {
*
* <p>If this method successfully unregisters an MBean, a notification
* is sent as described <a href="#notif">above</a>.</p>
*
* @throws RuntimeOperationsException {@inheritDoc}
*/
public void unregisterMBean(ObjectName name)
throws InstanceNotFoundException, MBeanRegistrationException;
......@@ -358,6 +387,9 @@ public interface MBeanServer extends MBeanServerConnection {
public Set<ObjectName> queryNames(ObjectName name, QueryExp query);
// doc comment inherited from MBeanServerConnection
/**
* @throws RuntimeOperationsException {@inheritDoc}
*/
public boolean isRegistered(ObjectName name);
/**
......@@ -370,21 +402,33 @@ public interface MBeanServer extends MBeanServerConnection {
public Integer getMBeanCount();
// doc comment inherited from MBeanServerConnection
/**
* @throws RuntimeOperationsException {@inheritDoc}
*/
public Object getAttribute(ObjectName name, String attribute)
throws MBeanException, AttributeNotFoundException,
InstanceNotFoundException, ReflectionException;
// doc comment inherited from MBeanServerConnection
/**
* @throws RuntimeOperationsException {@inheritDoc}
*/
public AttributeList getAttributes(ObjectName name, String[] attributes)
throws InstanceNotFoundException, ReflectionException;
// doc comment inherited from MBeanServerConnection
/**
* @throws RuntimeOperationsException {@inheritDoc}
*/
public void setAttribute(ObjectName name, Attribute attribute)
throws InstanceNotFoundException, AttributeNotFoundException,
InvalidAttributeValueException, MBeanException,
ReflectionException;
// doc comment inherited from MBeanServerConnection
/**
* @throws RuntimeOperationsException {@inheritDoc}
*/
public AttributeList setAttributes(ObjectName name,
AttributeList attributes)
throws InstanceNotFoundException, ReflectionException;
......@@ -401,14 +445,23 @@ public interface MBeanServer extends MBeanServerConnection {
// doc comment inherited from MBeanServerConnection
public String[] getDomains();
// doc comment inherited from MBeanServerConnection
// doc comment inherited from MBeanServerConnection, plus:
/**
* {@inheritDoc}
* If the source of the notification
* is a reference to an MBean object, the MBean server will replace it
* by that MBean's ObjectName. Otherwise the source is unchanged.
*/
public void addNotificationListener(ObjectName name,
NotificationListener listener,
NotificationFilter filter,
Object handback)
throws InstanceNotFoundException;
// doc comment inherited from MBeanServerConnection
/**
* {@inheritDoc}
* @throws RuntimeOperationsException {@inheritDoc}
*/
public void addNotificationListener(ObjectName name,
ObjectName listener,
NotificationFilter filter,
......
......@@ -29,6 +29,7 @@ package javax.management;
// java import
import java.io.IOException;
import java.util.Set;
import javax.management.event.NotificationManager;
/**
......@@ -39,7 +40,7 @@ import java.util.Set;
*
* @since 1.5
*/
public interface MBeanServerConnection {
public interface MBeanServerConnection extends NotificationManager {
/**
* <p>Instantiates and registers an MBean in the MBean server. The
* MBean server will use its {@link
......@@ -75,6 +76,24 @@ public interface MBeanServerConnection {
* <CODE>preRegister</CODE> (<CODE>MBeanRegistration</CODE>
* interface) method of the MBean has thrown an exception. The
* MBean will not be registered.
* @exception RuntimeMBeanException If the <CODE>postRegister</CODE>
* (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws a
* <CODE>RuntimeException</CODE>, the <CODE>createMBean<CODE> method will
* throw a <CODE>RuntimeMBeanException</CODE>, although the MBean creation
* and registration succeeded. In such a case, the MBean will be actually
* registered even though the <CODE>createMBean<CODE> method
* threw an exception. Note that <CODE>RuntimeMBeanException</CODE> can
* also be thrown by <CODE>preRegister</CODE>, in which case the MBean
* will not be registered.
* @exception RuntimeErrorException If the <CODE>postRegister</CODE>
* (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws an
* <CODE>Error</CODE>, the <CODE>createMBean<CODE> method will
* throw a <CODE>RuntimeErrorException</CODE>, although the MBean creation
* and registration succeeded. In such a case, the MBean will be actually
* registered even though the <CODE>createMBean<CODE> method
* threw an exception. Note that <CODE>RuntimeErrorException</CODE> can
* also be thrown by <CODE>preRegister</CODE>, in which case the MBean
* will not be registered.
* @exception MBeanException The constructor of the MBean has
* thrown an exception
* @exception NotCompliantMBeanException This class is not a JMX
......@@ -86,7 +105,7 @@ public interface MBeanServerConnection {
* is specified for the MBean.
* @exception IOException A communication problem occurred when
* talking to the MBean server.
*
* @see javax.management.MBeanRegistration
*/
public ObjectInstance createMBean(String className, ObjectName name)
throws ReflectionException, InstanceAlreadyExistsException,
......@@ -129,6 +148,24 @@ public interface MBeanServerConnection {
* <CODE>preRegister</CODE> (<CODE>MBeanRegistration</CODE>
* interface) method of the MBean has thrown an exception. The
* MBean will not be registered.
* @exception RuntimeMBeanException If the <CODE>postRegister</CODE>
* (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws a
* <CODE>RuntimeException</CODE>, the <CODE>createMBean<CODE> method will
* throw a <CODE>RuntimeMBeanException</CODE>, although the MBean creation
* and registration succeeded. In such a case, the MBean will be actually
* registered even though the <CODE>createMBean<CODE> method
* threw an exception. Note that <CODE>RuntimeMBeanException</CODE> can
* also be thrown by <CODE>preRegister</CODE>, in which case the MBean
* will not be registered.
* @exception RuntimeErrorException If the <CODE>postRegister</CODE>
* (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws an
* <CODE>Error</CODE>, the <CODE>createMBean<CODE> method will
* throw a <CODE>RuntimeErrorException</CODE>, although the MBean creation
* and registration succeeded. In such a case, the MBean will be actually
* registered even though the <CODE>createMBean<CODE> method
* threw an exception. Note that <CODE>RuntimeErrorException</CODE> can
* also be thrown by <CODE>preRegister</CODE>, in which case the MBean
* will not be registered.
* @exception MBeanException The constructor of the MBean has
* thrown an exception
* @exception NotCompliantMBeanException This class is not a JMX
......@@ -142,6 +179,7 @@ public interface MBeanServerConnection {
* is specified for the MBean.
* @exception IOException A communication problem occurred when
* talking to the MBean server.
* @see javax.management.MBeanRegistration
*/
public ObjectInstance createMBean(String className, ObjectName name,
ObjectName loaderName)
......@@ -185,6 +223,24 @@ public interface MBeanServerConnection {
* <CODE>preRegister</CODE> (<CODE>MBeanRegistration</CODE>
* interface) method of the MBean has thrown an exception. The
* MBean will not be registered.
* @exception RuntimeMBeanException If the <CODE>postRegister</CODE>
* (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws a
* <CODE>RuntimeException</CODE>, the <CODE>createMBean<CODE> method will
* throw a <CODE>RuntimeMBeanException</CODE>, although the MBean creation
* and registration succeeded. In such a case, the MBean will be actually
* registered even though the <CODE>createMBean<CODE> method
* threw an exception. Note that <CODE>RuntimeMBeanException</CODE> can
* also be thrown by <CODE>preRegister</CODE>, in which case the MBean
* will not be registered.
* @exception RuntimeErrorException If the <CODE>postRegister</CODE>
* (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws an
* <CODE>Error</CODE>, the <CODE>createMBean<CODE> method will
* throw a <CODE>RuntimeErrorException</CODE>, although the MBean creation
* and registration succeeded. In such a case, the MBean will be actually
* registered even though the <CODE>createMBean<CODE> method
* threw an exception. Note that <CODE>RuntimeErrorException</CODE> can
* also be thrown by <CODE>preRegister</CODE>, in which case the MBean
* will not be registered.
* @exception MBeanException The constructor of the MBean has
* thrown an exception
* @exception NotCompliantMBeanException This class is not a JMX
......@@ -196,7 +252,7 @@ public interface MBeanServerConnection {
* is specified for the MBean.
* @exception IOException A communication problem occurred when
* talking to the MBean server.
*
* @see javax.management.MBeanRegistration
*/
public ObjectInstance createMBean(String className, ObjectName name,
Object params[], String signature[])
......@@ -239,6 +295,24 @@ public interface MBeanServerConnection {
* <CODE>preRegister</CODE> (<CODE>MBeanRegistration</CODE>
* interface) method of the MBean has thrown an exception. The
* MBean will not be registered.
* @exception RuntimeMBeanException If the <CODE>postRegister</CODE>
* (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws a
* <CODE>RuntimeException</CODE>, the <CODE>createMBean<CODE> method will
* throw a <CODE>RuntimeMBeanException</CODE>, although the MBean creation
* and registration succeeded. In such a case, the MBean will be actually
* registered even though the <CODE>createMBean<CODE> method
* threw an exception. Note that <CODE>RuntimeMBeanException</CODE> can
* also be thrown by <CODE>preRegister</CODE>, in which case the MBean
* will not be registered.
* @exception RuntimeErrorException If the <CODE>postRegister</CODE> method
* (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws an
* <CODE>Error</CODE>, the <CODE>createMBean<CODE> method will
* throw a <CODE>RuntimeErrorException</CODE>, although the MBean creation
* and registration succeeded. In such a case, the MBean will be actually
* registered even though the <CODE>createMBean<CODE> method
* threw an exception. Note that <CODE>RuntimeErrorException</CODE> can
* also be thrown by <CODE>preRegister</CODE>, in which case the MBean
* will not be registered.
* @exception MBeanException The constructor of the MBean has
* thrown an exception
* @exception NotCompliantMBeanException This class is not a JMX
......@@ -252,7 +326,7 @@ public interface MBeanServerConnection {
* is specified for the MBean.
* @exception IOException A communication problem occurred when
* talking to the MBean server.
*
* @see javax.management.MBeanRegistration
*/
public ObjectInstance createMBean(String className, ObjectName name,
ObjectName loaderName, Object params[],
......@@ -275,6 +349,24 @@ public interface MBeanServerConnection {
* @exception MBeanRegistrationException The preDeregister
* ((<CODE>MBeanRegistration</CODE> interface) method of the MBean
* has thrown an exception.
* @exception RuntimeMBeanException If the <CODE>postDeregister</CODE>
* (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws a
* <CODE>RuntimeException</CODE>, the <CODE>unregisterMBean<CODE> method
* will throw a <CODE>RuntimeMBeanException</CODE>, although the MBean
* unregistration succeeded. In such a case, the MBean will be actually
* unregistered even though the <CODE>unregisterMBean<CODE> method
* threw an exception. Note that <CODE>RuntimeMBeanException</CODE> can
* also be thrown by <CODE>preDeregister</CODE>, in which case the MBean
* will remain registered.
* @exception RuntimeErrorException If the <CODE>postDeregister</CODE>
* (<CODE>MBeanRegistration</CODE> interface) method of the MBean throws an
* <CODE>Error</CODE>, the <CODE>unregisterMBean<CODE> method will
* throw a <CODE>RuntimeErrorException</CODE>, although the MBean
* unregistration succeeded. In such a case, the MBean will be actually
* unregistered even though the <CODE>unregisterMBean<CODE> method
* threw an exception. Note that <CODE>RuntimeMBeanException</CODE> can
* also be thrown by <CODE>preDeregister</CODE>, in which case the MBean
* will remain registered.
* @exception RuntimeOperationsException Wraps a
* <CODE>java.lang.IllegalArgumentException</CODE>: The object
* name in parameter is null or the MBean you are when trying to
......@@ -282,7 +374,7 @@ public interface MBeanServerConnection {
* MBeanServerDelegate} MBean.
* @exception IOException A communication problem occurred when
* talking to the MBean server.
*
* @see javax.management.MBeanRegistration
*/
public void unregisterMBean(ObjectName name)
throws InstanceNotFoundException, MBeanRegistrationException,
......@@ -585,32 +677,7 @@ public interface MBeanServerConnection {
public String[] getDomains()
throws IOException;
/**
* <p>Adds a listener to a registered MBean.</p>
*
* <P> A notification emitted by an MBean will be forwarded by the
* MBeanServer to the listener. If the source of the notification
* is a reference to an MBean object, the MBean server will replace it
* by that MBean's ObjectName. Otherwise the source is unchanged.
*
* @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)
*/
// doc inherited from NotificationManager
public void addNotificationListener(ObjectName name,
NotificationListener listener,
NotificationFilter filter,
......@@ -727,65 +794,13 @@ public interface MBeanServerConnection {
throws InstanceNotFoundException, ListenerNotFoundException,
IOException;
/**
* <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)
*/
// doc inherited from NotificationManager
public void removeNotificationListener(ObjectName name,
NotificationListener listener)
throws InstanceNotFoundException, ListenerNotFoundException,
IOException;
/**
* <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)
*
*/
// doc inherited from NotificationManager
public void removeNotificationListener(ObjectName name,
NotificationListener listener,
NotificationFilter filter,
......
......@@ -38,56 +38,64 @@ package javax.management;
*
* @since 1.5
*/
public class MBeanServerNotification extends Notification {
public class MBeanServerNotification extends Notification {
/* Serial version */
private static final long serialVersionUID = 2876477500475969677L;
/* Serial version */
private static final long serialVersionUID = 2876477500475969677L;
/**
* Notification type denoting that an MBean has been registered.
* Value is "JMX.mbean.registered".
*/
public static final String REGISTRATION_NOTIFICATION =
"JMX.mbean.registered";
/**
* Notification type denoting that an MBean has been unregistered.
* Value is "JMX.mbean.unregistered".
*/
public static final String UNREGISTRATION_NOTIFICATION =
"JMX.mbean.unregistered";
/**
* @serial The object names of the MBeans concerned by this notification
*/
private final ObjectName objectName;
/**
* Notification type denoting that an MBean has been registered. Value is "JMX.mbean.registered".
*/
public static final String REGISTRATION_NOTIFICATION = "JMX.mbean.registered" ;
/**
* Creates an MBeanServerNotification object specifying object names of
* the MBeans that caused the notification and the specified notification
* type.
*
* @param type A string denoting the type of the
* notification. Set it to one these values: {@link
* #REGISTRATION_NOTIFICATION}, {@link
* #UNREGISTRATION_NOTIFICATION}.
* @param source The MBeanServerNotification object responsible
* for forwarding MBean server notification.
* @param sequenceNumber A sequence number that can be used to order
* received notifications.
* @param objectName The object name of the MBean that caused the
* notification.
*
*/
public MBeanServerNotification(String type, Object source,
long sequenceNumber, ObjectName objectName) {
super(type, source, sequenceNumber);
this.objectName = objectName;
}
/**
* Notification type denoting that an MBean has been unregistered. Value is "JMX.mbean.unregistered".
*/
public static final String UNREGISTRATION_NOTIFICATION = "JMX.mbean.unregistered" ;
/**
* Returns the object name of the MBean that caused the notification.
*
* @return the object name of the MBean that caused the notification.
*/
public ObjectName getMBeanName() {
return objectName;
}
@Override
public String toString() {
return super.toString() + "[mbeanName=" + objectName + "]";
/**
* @serial The object names of the MBeans concerned by this notification
*/
private final ObjectName objectName;
/**
* Creates an MBeanServerNotification object specifying object names of
* the MBeans that caused the notification and the specified notification type.
*
* @param type A string denoting the type of the
* notification. Set it to one these values: {@link
* #REGISTRATION_NOTIFICATION}, {@link
* #UNREGISTRATION_NOTIFICATION}.
* @param source The MBeanServerNotification object responsible
* for forwarding MBean server notification.
* @param sequenceNumber A sequence number that can be used to order
* received notifications.
* @param objectName The object name of the MBean that caused the notification.
*
*/
public MBeanServerNotification(String type, Object source, long sequenceNumber, ObjectName objectName ) {
super (type,source,sequenceNumber) ;
this.objectName = objectName ;
}
/**
* Returns the object name of the MBean that caused the notification.
*
* @return the object name of the MBean that caused the notification.
*/
public ObjectName getMBeanName() {
return objectName ;
}
}
}
......@@ -33,7 +33,6 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// remaining imports are for Javadoc
import java.beans.ConstructorProperties;
import java.io.InvalidObjectException;
import java.lang.management.MemoryUsage;
import java.lang.reflect.UndeclaredThrowableException;
......@@ -865,7 +864,8 @@ public interface ModuleMXBean {
<em>J</em>.</p></li>
<li><p>Otherwise, if <em>J</em> has at least one public
constructor with a {@link ConstructorProperties} annotation, then one
constructor with a {@link java.beans.ConstructorProperties
ConstructorProperties} annotation, then one
of those constructors (not necessarily always the same one)
will be called to reconstruct an instance of <em>J</em>.
Every such annotation must list as many strings as the
......@@ -1081,9 +1081,10 @@ public interface Node {
MXBean is determined as follows.</p>
<ul>
<li><p>If an {@link JMX.MBeanOptions} argument is supplied to
<li><p>If a {@link JMX.MBeanOptions} argument is supplied to
the {@link StandardMBean} constructor that makes an MXBean,
or to the {@link JMX#newMXBeanProxy JMX.newMXBeanProxy}
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>
......
......@@ -38,9 +38,6 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.QueryExp;
/**
* <p>Represents the object name of an MBean, or a pattern that can
......@@ -1160,9 +1157,19 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp {
//
//in.defaultReadObject();
final ObjectInputStream.GetField fields = in.readFields();
String propListString =
(String)fields.get("propertyListString", "");
// 6616825: take care of property patterns
final boolean propPattern =
fields.get("propertyPattern" , false);
if (propPattern) {
propListString =
(propListString.length()==0?"*":(propListString+",*"));
}
cn = (String)fields.get("domain", "default")+
":"+
(String)fields.get("propertyListString", "");
":"+ propListString;
} else {
// Read an object serialized in the new serial form
//
......@@ -1796,6 +1803,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp {
* @return True if <code>object</code> is an ObjectName whose
* canonical form is equal to that of this ObjectName.
*/
@Override
public boolean equals(Object object) {
// same object case
......@@ -1819,6 +1827,7 @@ public class ObjectName implements Comparable<ObjectName>, QueryExp {
* Returns a hash code for this object name.
*
*/
@Override
public int hashCode() {
return _canonicalName.hashCode();
}
......
......@@ -312,7 +312,7 @@ class QueryParser {
if (e > 0)
ss = s.substring(0, e);
ss = ss.replace("0", "").replace(".", "");
if (!ss.isEmpty())
if (!ss.equals(""))
throw new NumberFormatException("Underflow: " + s);
}
return d;
......
......@@ -85,6 +85,7 @@ public class StringValueExp implements ValueExp {
/* There is no need for this method, because if a query is being
evaluated a StringValueExp can only appear inside a QueryExp,
and that QueryExp will itself have done setMBeanServer. */
@Deprecated
public void setMBeanServer(MBeanServer s) { }
/**
......
/*
* Copyright 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
* 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.event;
import java.rmi.Remote;
import java.rmi.RemoteException;
import javax.management.remote.NotificationResult;
/**
* The {@link RMIPushEventRelay} exports an RMI object of this class and
* sends a client stub for that object to the associated
* {@link RMIPushEventForwarder} in a remote MBean server. The
* {@code RMIPushEventForwarder} then sends notifications to the
* RMI object.
*/
public interface RMIPushServer extends Remote {
/**
* <p>Dispatch the notifications in {@code nr} to the {@link RMIPushEventRelay}
* associated with this object.</p>
* @param nr the notification result to dispatch.
* @throws java.rmi.RemoteException if the remote invocation of this method
* failed.
*/
public void receive(NotificationResult nr) throws RemoteException;
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册