提交 c6b1acc7 编写于 作者: S sjiang

5108776: Add reliable event handling to the JMX API

6218920: API bug - impossible to delete last MBeanServerForwarder on a connector
Reviewed-by: emcmanus
上级 152f3ab7
/*
* 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");
}
/*
* 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. ...@@ -29,5 +29,8 @@ have any questions.
</head> </head>
<body bgcolor="white"> <body bgcolor="white">
Provides specific classes to <B>Sun JMX Reference Implementation</B>. 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> </BODY>
</HTML> </HTML>
...@@ -172,7 +172,7 @@ public class MBeanInjector { ...@@ -172,7 +172,7 @@ public class MBeanInjector {
* reference. * reference.
* *
* So we accept a Field if it has a @Resource annotation and either * 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 * compatible with ObjectName (e.g. it is Object); or
* (b) its type is compatible with ObjectName and its @Resource type * (b) its type is compatible with ObjectName and its @Resource type
* is exactly ObjectName. Fields that meet these criteria will not * is exactly ObjectName. Fields that meet these criteria will not
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
package com.sun.jmx.mbeanserver; package com.sun.jmx.mbeanserver;
import static com.sun.jmx.mbeanserver.Util.*;
import javax.management.Attribute; import javax.management.Attribute;
import javax.management.AttributeList; 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; ...@@ -38,10 +38,13 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.SortedMap; import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.TreeSet;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import javax.management.MalformedObjectNameException; import javax.management.MalformedObjectNameException;
import javax.management.ObjectName; import javax.management.ObjectName;
import javax.management.loading.ClassLoaderRepository;
public class Util { public class Util {
static <K, V> Map<K, V> newMap() { static <K, V> Map<K, V> newMap() {
...@@ -142,4 +145,97 @@ public class Util { ...@@ -142,4 +145,97 @@ public class Util {
return hash; 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 { ...@@ -576,6 +576,7 @@ public abstract class ClientNotifForwarder {
int notFoundCount = 0; int notFoundCount = 0;
NotificationResult result = null; NotificationResult result = null;
long firstEarliest = -1;
while (result == null && !shouldStop()) { while (result == null && !shouldStop()) {
NotificationResult nr; NotificationResult nr;
...@@ -598,6 +599,8 @@ public abstract class ClientNotifForwarder { ...@@ -598,6 +599,8 @@ public abstract class ClientNotifForwarder {
return null; return null;
startSequenceNumber = nr.getNextSequenceNumber(); startSequenceNumber = nr.getNextSequenceNumber();
if (firstEarliest < 0)
firstEarliest = nr.getEarliestSequenceNumber();
try { try {
// 1 notif to skip possible missing class // 1 notif to skip possible missing class
...@@ -628,6 +631,17 @@ public abstract class ClientNotifForwarder { ...@@ -628,6 +631,17 @@ public abstract class ClientNotifForwarder {
(notFoundCount == 1 ? "" : "s") + (notFoundCount == 1 ? "" : "s") +
" because classes were missing locally"; " because classes were missing locally";
lostNotifs(msg, notFoundCount); 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; return result;
......
...@@ -33,10 +33,8 @@ import org.omg.CORBA.Any; ...@@ -33,10 +33,8 @@ import org.omg.CORBA.Any;
import org.omg.CORBA.Context; import org.omg.CORBA.Context;
import org.omg.CORBA.NO_IMPLEMENT; import org.omg.CORBA.NO_IMPLEMENT;
import org.omg.CORBA.ORB; import org.omg.CORBA.ORB;
import org.omg.CORBA.Principal;
import org.omg.CORBA.TypeCode; import org.omg.CORBA.TypeCode;
import org.omg.CORBA.portable.BoxedValueHelper; import org.omg.CORBA.portable.BoxedValueHelper;
import org.omg.CORBA_2_3.portable.InputStream;
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public class ProxyInputStream extends org.omg.CORBA_2_3.portable.InputStream { 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 { ...@@ -160,54 +158,71 @@ public class ProxyInputStream extends org.omg.CORBA_2_3.portable.InputStream {
return in.read_any(); return in.read_any();
} }
public Principal read_Principal() { /**
* @deprecated
*/
@Override
@Deprecated
public org.omg.CORBA.Principal read_Principal() {
return in.read_Principal(); return in.read_Principal();
} }
@Override
public int read() throws IOException { public int read() throws IOException {
return in.read(); return in.read();
} }
@Override
public BigDecimal read_fixed() { public BigDecimal read_fixed() {
return in.read_fixed(); return in.read_fixed();
} }
@Override
public Context read_Context() { public Context read_Context() {
return in.read_Context(); return in.read_Context();
} }
@Override
public org.omg.CORBA.Object read_Object(java.lang.Class clz) { public org.omg.CORBA.Object read_Object(java.lang.Class clz) {
return in.read_Object(clz); return in.read_Object(clz);
} }
@Override
public ORB orb() { public ORB orb() {
return in.orb(); return in.orb();
} }
@Override
public Serializable read_value() { public Serializable read_value() {
return narrow().read_value(); return narrow().read_value();
} }
@Override
public Serializable read_value(Class clz) { public Serializable read_value(Class clz) {
return narrow().read_value(clz); return narrow().read_value(clz);
} }
@Override
public Serializable read_value(BoxedValueHelper factory) { public Serializable read_value(BoxedValueHelper factory) {
return narrow().read_value(factory); return narrow().read_value(factory);
} }
@Override
public Serializable read_value(String rep_id) { public Serializable read_value(String rep_id) {
return narrow().read_value(rep_id); return narrow().read_value(rep_id);
} }
@Override
public Serializable read_value(Serializable value) { public Serializable read_value(Serializable value) {
return narrow().read_value(value); return narrow().read_value(value);
} }
@Override
public Object read_abstract_interface() { public Object read_abstract_interface() {
return narrow().read_abstract_interface(); return narrow().read_abstract_interface();
} }
@Override
public Object read_abstract_interface(Class clz) { public Object read_abstract_interface(Class clz) {
return narrow().read_abstract_interface(clz); return narrow().read_abstract_interface(clz);
} }
......
...@@ -31,8 +31,6 @@ import java.io.ObjectOutput; ...@@ -31,8 +31,6 @@ import java.io.ObjectOutput;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.rmi.Remote; import java.rmi.Remote;
import java.rmi.RemoteException; import java.rmi.RemoteException;
import java.rmi.server.Operation;
import java.rmi.server.RemoteCall;
import java.rmi.server.RemoteObject; import java.rmi.server.RemoteObject;
import java.rmi.server.RemoteRef; import java.rmi.server.RemoteRef;
...@@ -54,7 +52,11 @@ public class ProxyRef implements RemoteRef { ...@@ -54,7 +52,11 @@ public class ProxyRef implements RemoteRef {
ref.writeExternal(out); 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); ref.invoke(call);
} }
...@@ -63,7 +65,11 @@ public class ProxyRef implements RemoteRef { ...@@ -63,7 +65,11 @@ public class ProxyRef implements RemoteRef {
return ref.invoke(obj, method, params, opnum); 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); ref.done(call);
} }
...@@ -71,7 +77,12 @@ public class ProxyRef implements RemoteRef { ...@@ -71,7 +77,12 @@ public class ProxyRef implements RemoteRef {
return ref.getRefClass(out); 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 { long hash) throws RemoteException {
return ref.newCall(obj, op, opnum, hash); return ref.newCall(obj, op, opnum, hash);
} }
......
...@@ -25,16 +25,16 @@ ...@@ -25,16 +25,16 @@
package com.sun.jmx.remote.internal; package com.sun.jmx.remote.internal;
import com.sun.jmx.mbeanserver.Util;
import com.sun.jmx.remote.security.NotificationAccessController; import com.sun.jmx.remote.security.NotificationAccessController;
import com.sun.jmx.remote.util.ClassLogger; import com.sun.jmx.remote.util.ClassLogger;
import com.sun.jmx.remote.util.EnvHelp; import com.sun.jmx.remote.util.EnvHelp;
import java.io.IOException; import java.io.IOException;
import java.security.AccessControlContext; import java.security.AccessControlContext;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException; import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction; import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
...@@ -67,9 +67,9 @@ public class ServerNotifForwarder { ...@@ -67,9 +67,9 @@ public class ServerNotifForwarder {
connectionTimeout = EnvHelp.getServerConnectionTimeout(env); connectionTimeout = EnvHelp.getServerConnectionTimeout(env);
checkNotificationEmission = EnvHelp.computeBooleanFromString( checkNotificationEmission = EnvHelp.computeBooleanFromString(
env, env,
"jmx.remote.x.check.notification.emission"); "jmx.remote.x.check.notification.emission",false);
notificationAccessController = (NotificationAccessController) notificationAccessController =
env.get("com.sun.jmx.remote.notification.access.controller"); EnvHelp.getNotificationAccessController(env);
} }
public Integer addNotificationListener(final ObjectName name, public Integer addNotificationListener(final ObjectName name,
...@@ -88,9 +88,7 @@ public class ServerNotifForwarder { ...@@ -88,9 +88,7 @@ public class ServerNotifForwarder {
checkMBeanPermission(name, "addNotificationListener"); checkMBeanPermission(name, "addNotificationListener");
if (notificationAccessController != null) { if (notificationAccessController != null) {
notificationAccessController.addNotificationListener( notificationAccessController.addNotificationListener(
connectionId, connectionId, name, getSubject());
name,
Subject.getSubject(AccessController.getContext()));
} }
try { try {
boolean instanceOf = boolean instanceOf =
...@@ -160,9 +158,7 @@ public class ServerNotifForwarder { ...@@ -160,9 +158,7 @@ public class ServerNotifForwarder {
checkMBeanPermission(name, "removeNotificationListener"); checkMBeanPermission(name, "removeNotificationListener");
if (notificationAccessController != null) { if (notificationAccessController != null) {
notificationAccessController.removeNotificationListener( notificationAccessController.removeNotificationListener(
connectionId, connectionId, name, getSubject());
name,
Subject.getSubject(AccessController.getContext()));
} }
Exception re = null; Exception re = null;
...@@ -312,6 +308,10 @@ public class ServerNotifForwarder { ...@@ -312,6 +308,10 @@ public class ServerNotifForwarder {
// PRIVATE METHODS // PRIVATE METHODS
//---------------- //----------------
private Subject getSubject() {
return Subject.getSubject(AccessController.getContext());
}
private void checkState() throws IOException { private void checkState() throws IOException {
synchronized(terminationLock) { synchronized(terminationLock) {
if (terminated) { if (terminated) {
...@@ -332,7 +332,13 @@ public class ServerNotifForwarder { ...@@ -332,7 +332,13 @@ public class ServerNotifForwarder {
*/ */
private void checkMBeanPermission(final ObjectName name, private void checkMBeanPermission(final ObjectName name,
final String actions) 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(); SecurityManager sm = System.getSecurityManager();
if (sm != null) { if (sm != null) {
AccessControlContext acc = AccessController.getContext(); AccessControlContext acc = AccessController.getContext();
...@@ -342,7 +348,7 @@ public class ServerNotifForwarder { ...@@ -342,7 +348,7 @@ public class ServerNotifForwarder {
new PrivilegedExceptionAction<ObjectInstance>() { new PrivilegedExceptionAction<ObjectInstance>() {
public ObjectInstance run() public ObjectInstance run()
throws InstanceNotFoundException { throws InstanceNotFoundException {
return mbeanServer.getObjectInstance(name); return mbs.getObjectInstance(name);
} }
}); });
} catch (PrivilegedActionException e) { } catch (PrivilegedActionException e) {
...@@ -364,14 +370,12 @@ public class ServerNotifForwarder { ...@@ -364,14 +370,12 @@ public class ServerNotifForwarder {
TargetedNotification tn) { TargetedNotification tn) {
try { try {
if (checkNotificationEmission) { if (checkNotificationEmission) {
checkMBeanPermission(name, "addNotificationListener"); checkMBeanPermission(
name, "addNotificationListener");
} }
if (notificationAccessController != null) { if (notificationAccessController != null) {
notificationAccessController.fetchNotification( notificationAccessController.fetchNotification(
connectionId, connectionId, name, tn.getNotification(), getSubject());
name,
tn.getNotification(),
Subject.getSubject(AccessController.getContext()));
} }
return true; return true;
} catch (SecurityException e) { } catch (SecurityException e) {
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
package com.sun.jmx.remote.security; package com.sun.jmx.remote.security;
import com.sun.jmx.mbeanserver.GetPropertyAction;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
...@@ -47,8 +48,6 @@ import com.sun.jmx.remote.util.ClassLogger; ...@@ -47,8 +48,6 @@ import com.sun.jmx.remote.util.ClassLogger;
import com.sun.jmx.remote.util.EnvHelp; import com.sun.jmx.remote.util.EnvHelp;
import sun.management.jmxremote.ConnectorBootstrap; import sun.management.jmxremote.ConnectorBootstrap;
import sun.security.action.GetPropertyAction;
/** /**
* This {@link LoginModule} performs file-based authentication. * This {@link LoginModule} performs file-based authentication.
* *
...@@ -479,7 +478,7 @@ public class FileLoginModule implements LoginModule { ...@@ -479,7 +478,7 @@ public class FileLoginModule implements LoginModule {
if (userSuppliedPasswordFile || hasJavaHomePermission) { if (userSuppliedPasswordFile || hasJavaHomePermission) {
throw e; throw e;
} else { } else {
FilePermission fp = final FilePermission fp =
new FilePermission(passwordFileDisplayName, "read"); new FilePermission(passwordFileDisplayName, "read");
AccessControlException ace = new AccessControlException( AccessControlException ace = new AccessControlException(
"access denied " + fp.toString()); "access denied " + fp.toString());
...@@ -488,10 +487,13 @@ public class FileLoginModule implements LoginModule { ...@@ -488,10 +487,13 @@ public class FileLoginModule implements LoginModule {
} }
} }
try { try {
BufferedInputStream bis = new BufferedInputStream(fis); final BufferedInputStream bis = new BufferedInputStream(fis);
userCredentials = new Properties(); try {
userCredentials.load(bis); userCredentials = new Properties();
bis.close(); userCredentials.load(bis);
} finally {
bis.close();
}
} finally { } finally {
fis.close(); fis.close();
} }
......
...@@ -40,9 +40,6 @@ import java.util.TreeMap; ...@@ -40,9 +40,6 @@ import java.util.TreeMap;
import java.util.TreeSet; import java.util.TreeSet;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import javax.management.ObjectName; import javax.management.ObjectName;
import javax.management.MBeanServer; import javax.management.MBeanServer;
...@@ -50,6 +47,9 @@ import javax.management.InstanceNotFoundException; ...@@ -50,6 +47,9 @@ import javax.management.InstanceNotFoundException;
import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXConnectorServerFactory; import javax.management.remote.JMXConnectorServerFactory;
import com.sun.jmx.mbeanserver.GetPropertyAction; 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 { public class EnvHelp {
...@@ -346,7 +346,24 @@ public class EnvHelp { ...@@ -346,7 +346,24 @@ public class EnvHelp {
*/ */
public static long getFetchTimeout(Map env) { public static long getFetchTimeout(Map env) {
return getIntegerAttribute(env, FETCH_TIMEOUT, 60000L, 0, 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 { ...@@ -470,24 +487,24 @@ public class EnvHelp {
} }
/** /**
The value of this attribute, if present, is a string specifying * The value of this attribute, if present, is a string specifying
what other attributes should not appear in * what other attributes should not appear in
JMXConnectorServer.getAttributes(). It is a space-separated * JMXConnectorServer.getAttributes(). It is a space-separated
list of attribute patterns, where each pattern is either an * list of attribute patterns, where each pattern is either an
attribute name, or an attribute prefix followed by a "*" * attribute name, or an attribute prefix followed by a "*"
character. The "*" has no special significance anywhere except * character. The "*" has no special significance anywhere except
at the end of a pattern. By default, this list is added to the * at the end of a pattern. By default, this list is added to the
list defined by {@link #DEFAULT_HIDDEN_ATTRIBUTES} (which * list defined by {@link #DEFAULT_HIDDEN_ATTRIBUTES} (which
uses the same format). If the value of this attribute begins * uses the same format). If the value of this attribute begins
with an "=", then the remainder of the string defines the * with an "=", then the remainder of the string defines the
complete list of attribute patterns. * complete list of attribute patterns.
*/ */
public static final String HIDDEN_ATTRIBUTES = public static final String HIDDEN_ATTRIBUTES =
"jmx.remote.x.hidden.attributes"; "jmx.remote.x.hidden.attributes";
/** /**
Default list of attributes not to show. * Default list of attributes not to show.
@see #HIDDEN_ATTRIBUTES * @see #HIDDEN_ATTRIBUTES
*/ */
/* This list is copied directly from the spec, plus /* This list is copied directly from the spec, plus
java.naming.security.*. Most of the attributes here would have java.naming.security.*. Most of the attributes here would have
...@@ -651,6 +668,8 @@ public class EnvHelp { ...@@ -651,6 +668,8 @@ public class EnvHelp {
* @param env the environment map. * @param env the environment map.
* @param prop the name of the property in the environment map whose * @param prop the name of the property in the environment map whose
* returned string value must be converted into a boolean value. * 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 * @return
* <ul> * <ul>
...@@ -671,16 +690,73 @@ public class EnvHelp { ...@@ -671,16 +690,73 @@ public class EnvHelp {
* @throws ClassCastException if {@code env.get(prop)} cannot be cast * @throws ClassCastException if {@code env.get(prop)} cannot be cast
* to {@code String}. * to {@code String}.
*/ */
public static boolean computeBooleanFromString(Map env, String prop) public static boolean computeBooleanFromString(
throws IllegalArgumentException, ClassCastException { 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) if (env == null)
throw new IllegalArgumentException("env map cannot be null"); throw new IllegalArgumentException("env map cannot be null");
String stringBoolean = (String) env.get(prop); String stringBoolean = (String) env.get(prop);
if (stringBoolean == null && systemProperty) {
stringBoolean =
AccessController.doPrivileged(new GetPropertyAction(prop));
}
if (stringBoolean == null) if (stringBoolean == null)
return false; return defaultValue;
else if (stringBoolean.equalsIgnoreCase("true")) else if (stringBoolean.equalsIgnoreCase("true"))
return true; return true;
else if (stringBoolean.equalsIgnoreCase("false")) else if (stringBoolean.equalsIgnoreCase("false"))
...@@ -703,6 +779,65 @@ public class EnvHelp { ...@@ -703,6 +779,65 @@ public class EnvHelp {
return new Hashtable<K, V>(m); 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 { private static final class SinkOutputStream extends OutputStream {
public void write(byte[] b, int off, int len) {} public void write(byte[] b, int off, int len) {}
public void write(int b) {} 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 { ...@@ -45,15 +45,9 @@ public class ThreadService implements TaskServer {
minThreads = threadNumber; minThreads = threadNumber;
threadList = new ExecutorThread[threadNumber]; threadList = new ExecutorThread[threadNumber];
// for (int i=0; i<threadNumber; i++) {
// threadList[i] = new ExecutorThread();
// threadList[i].start();
// }
priority = Thread.currentThread().getPriority(); priority = Thread.currentThread().getPriority();
cloader = Thread.currentThread().getContextClassLoader(); cloader = Thread.currentThread().getContextClassLoader();
//System.out.println("---jsl: ThreadService: running threads = "+threadNumber);
} }
// public methods // public methods
...@@ -89,7 +83,6 @@ public class ThreadService implements TaskServer { ...@@ -89,7 +83,6 @@ public class ThreadService implements TaskServer {
synchronized(jobList) { synchronized(jobList) {
jobList.add(jobList.size(), task); jobList.add(jobList.size(), task);
//System.out.println("jsl-ThreadService: added job "+addedJobs++);
jobList.notify(); jobList.notify();
} }
...@@ -196,8 +189,6 @@ public class ThreadService implements TaskServer { ...@@ -196,8 +189,6 @@ public class ThreadService implements TaskServer {
try { try {
idle--; idle--;
job.run(); job.run();
//System.out.println("jsl-ThreadService: done job "+doneJobs++);
} catch (Exception e) { } catch (Exception e) {
// TODO // TODO
e.printStackTrace(); e.printStackTrace();
...@@ -228,7 +219,6 @@ public class ThreadService implements TaskServer { ...@@ -228,7 +219,6 @@ public class ThreadService implements TaskServer {
ExecutorThread et = new ExecutorThread(); ExecutorThread et = new ExecutorThread();
et.start(); et.start();
threadList[currThreds++] = et; threadList[currThreds++] = et;
//System.out.println("jsl-ThreadService: create new thread: "+currThreds);
} }
} }
} }
......
...@@ -128,13 +128,13 @@ public class ImmutableDescriptor implements Descriptor { ...@@ -128,13 +128,13 @@ public class ImmutableDescriptor implements Descriptor {
* @throws InvalidObjectException if the read object has invalid fields. * @throws InvalidObjectException if the read object has invalid fields.
*/ */
private Object readResolve() throws InvalidObjectException { private Object readResolve() throws InvalidObjectException {
if (names.length == 0 && getClass() == ImmutableDescriptor.class)
return EMPTY_DESCRIPTOR;
boolean bad = false; boolean bad = false;
if (names == null || values == null || names.length != values.length) if (names == null || values == null || names.length != values.length)
bad = true; bad = true;
if (!bad) { if (!bad) {
if (names.length == 0 && getClass() == ImmutableDescriptor.class)
return EMPTY_DESCRIPTOR;
final Comparator<String> compare = String.CASE_INSENSITIVE_ORDER; final Comparator<String> compare = String.CASE_INSENSITIVE_ORDER;
String lastName = ""; // also catches illegal null name String lastName = ""; // also catches illegal null name
for (int i = 0; i < names.length; i++) { for (int i = 0; i < names.length; i++) {
......
...@@ -420,7 +420,13 @@ public interface MBeanServer extends MBeanServerConnection { ...@@ -420,7 +420,13 @@ public interface MBeanServer extends MBeanServerConnection {
// doc comment inherited from MBeanServerConnection // doc comment inherited from MBeanServerConnection
public String[] getDomains(); 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, public void addNotificationListener(ObjectName name,
NotificationListener listener, NotificationListener listener,
NotificationFilter filter, NotificationFilter filter,
......
...@@ -29,6 +29,7 @@ package javax.management; ...@@ -29,6 +29,7 @@ package javax.management;
// java import // java import
import java.io.IOException; import java.io.IOException;
import java.util.Set; import java.util.Set;
import javax.management.event.NotificationManager;
/** /**
...@@ -39,7 +40,7 @@ import java.util.Set; ...@@ -39,7 +40,7 @@ import java.util.Set;
* *
* @since 1.5 * @since 1.5
*/ */
public interface MBeanServerConnection { public interface MBeanServerConnection extends NotificationManager {
/** /**
* <p>Instantiates and registers an MBean in the MBean server. The * <p>Instantiates and registers an MBean in the MBean server. The
* MBean server will use its {@link * MBean server will use its {@link
...@@ -676,32 +677,7 @@ public interface MBeanServerConnection { ...@@ -676,32 +677,7 @@ public interface MBeanServerConnection {
public String[] getDomains() public String[] getDomains()
throws IOException; throws IOException;
/** // doc inherited from NotificationManager
* <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)
*/
public void addNotificationListener(ObjectName name, public void addNotificationListener(ObjectName name,
NotificationListener listener, NotificationListener listener,
NotificationFilter filter, NotificationFilter filter,
...@@ -818,65 +794,13 @@ public interface MBeanServerConnection { ...@@ -818,65 +794,13 @@ public interface MBeanServerConnection {
throws InstanceNotFoundException, ListenerNotFoundException, throws InstanceNotFoundException, ListenerNotFoundException,
IOException; IOException;
// doc inherited from NotificationManager
/**
* <p>Removes a listener from a registered MBean.</p>
*
* <P> If the listener is registered more than once, perhaps with
* different filters or callbacks, this method will remove all
* those registrations.
*
* @param name The name of the MBean on which the listener should
* be removed.
* @param listener The listener to be removed.
*
* @exception InstanceNotFoundException The MBean name provided
* does not match any of the registered MBeans.
* @exception ListenerNotFoundException The listener is not
* registered in the MBean.
* @exception IOException A communication problem occurred when
* talking to the MBean server.
*
* @see #addNotificationListener(ObjectName, NotificationListener,
* NotificationFilter, Object)
*/
public void removeNotificationListener(ObjectName name, public void removeNotificationListener(ObjectName name,
NotificationListener listener) NotificationListener listener)
throws InstanceNotFoundException, ListenerNotFoundException, throws InstanceNotFoundException, ListenerNotFoundException,
IOException; IOException;
/** // doc inherited from NotificationManager
* <p>Removes a listener from a registered MBean.</p>
*
* <p>The MBean must have a listener that exactly matches the
* given <code>listener</code>, <code>filter</code>, and
* <code>handback</code> parameters. If there is more than one
* such listener, only one is removed.</p>
*
* <p>The <code>filter</code> and <code>handback</code> parameters
* may be null if and only if they are null in a listener to be
* removed.</p>
*
* @param name The name of the MBean on which the listener should
* be removed.
* @param listener The listener to be removed.
* @param filter The filter that was specified when the listener
* was added.
* @param handback The handback that was specified when the
* listener was added.
*
* @exception InstanceNotFoundException The MBean name provided
* does not match any of the registered MBeans.
* @exception ListenerNotFoundException The listener is not
* registered in the MBean, or it is not registered with the given
* filter and handback.
* @exception IOException A communication problem occurred when
* talking to the MBean server.
*
* @see #addNotificationListener(ObjectName, NotificationListener,
* NotificationFilter, Object)
*
*/
public void removeNotificationListener(ObjectName name, public void removeNotificationListener(ObjectName name,
NotificationListener listener, NotificationListener listener,
NotificationFilter filter, NotificationFilter filter,
......
...@@ -33,7 +33,6 @@ import java.lang.annotation.RetentionPolicy; ...@@ -33,7 +33,6 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
// remaining imports are for Javadoc // remaining imports are for Javadoc
import java.beans.ConstructorProperties;
import java.io.InvalidObjectException; import java.io.InvalidObjectException;
import java.lang.management.MemoryUsage; import java.lang.management.MemoryUsage;
import java.lang.reflect.UndeclaredThrowableException; import java.lang.reflect.UndeclaredThrowableException;
...@@ -865,7 +864,8 @@ public interface ModuleMXBean { ...@@ -865,7 +864,8 @@ public interface ModuleMXBean {
<em>J</em>.</p></li> <em>J</em>.</p></li>
<li><p>Otherwise, if <em>J</em> has at least one public <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) of those constructors (not necessarily always the same one)
will be called to reconstruct an instance of <em>J</em>. will be called to reconstruct an instance of <em>J</em>.
Every such annotation must list as many strings as the Every such annotation must list as many strings as the
......
...@@ -312,7 +312,7 @@ class QueryParser { ...@@ -312,7 +312,7 @@ class QueryParser {
if (e > 0) if (e > 0)
ss = s.substring(0, e); ss = s.substring(0, e);
ss = ss.replace("0", "").replace(".", ""); ss = ss.replace("0", "").replace(".", "");
if (!ss.isEmpty()) if (!ss.equals(""))
throw new NumberFormatException("Underflow: " + s); throw new NumberFormatException("Underflow: " + s);
} }
return d; return d;
......
...@@ -85,6 +85,7 @@ public class StringValueExp implements ValueExp { ...@@ -85,6 +85,7 @@ public class StringValueExp implements ValueExp {
/* There is no need for this method, because if a query is being /* There is no need for this method, because if a query is being
evaluated a StringValueExp can only appear inside a QueryExp, evaluated a StringValueExp can only appear inside a QueryExp,
and that QueryExp will itself have done setMBeanServer. */ and that QueryExp will itself have done setMBeanServer. */
@Deprecated
public void setMBeanServer(MBeanServer s) { } public void setMBeanServer(MBeanServer s) { }
/** /**
......
...@@ -373,7 +373,7 @@ public class ModelMBeanInfoSupport extends MBeanInfo implements ModelMBeanInfo { ...@@ -373,7 +373,7 @@ public class ModelMBeanInfoSupport extends MBeanInfo implements ModelMBeanInfo {
"getDescriptors(String)", "Entry"); "getDescriptors(String)", "Entry");
} }
if ((inDescriptorType == null) || (inDescriptorType.isEmpty())) { if ((inDescriptorType == null) || (inDescriptorType.equals(""))) {
inDescriptorType = "all"; inDescriptorType = "all";
} }
...@@ -616,7 +616,7 @@ public class ModelMBeanInfoSupport extends MBeanInfo implements ModelMBeanInfo { ...@@ -616,7 +616,7 @@ public class ModelMBeanInfoSupport extends MBeanInfo implements ModelMBeanInfo {
inDescriptor = new DescriptorSupport(); inDescriptor = new DescriptorSupport();
} }
if ((inDescriptorType == null) || (inDescriptorType.isEmpty())) { if ((inDescriptorType == null) || (inDescriptorType.equals(""))) {
inDescriptorType = inDescriptorType =
(String) inDescriptor.getFieldValue("descriptorType"); (String) inDescriptor.getFieldValue("descriptorType");
......
...@@ -1123,7 +1123,7 @@ public class RequiredModelMBean ...@@ -1123,7 +1123,7 @@ public class RequiredModelMBean
if (tracing) { if (tracing) {
MODELMBEAN_LOGGER.logp(Level.FINER, MODELMBEAN_LOGGER.logp(Level.FINER,
RequiredModelMBean.class.getName(),"resolveMethod", RequiredModelMBean.class.getName(),"resolveMethod",
"resolving " + targetClass + "." + opMethodName); "resolving " + targetClass.getName() + "." + opMethodName);
} }
final Class[] argClasses; final Class[] argClasses;
......
...@@ -108,7 +108,7 @@ public class RelationService extends NotificationBroadcasterSupport ...@@ -108,7 +108,7 @@ public class RelationService extends NotificationBroadcasterSupport
// the value HashMap mapping: // the value HashMap mapping:
// <relation id> -> ArrayList of <role name> // <relation id> -> ArrayList of <role name>
// to track where a given MBean is referenced. // to track where a given MBean is referenced.
private Map<ObjectName,Map<String,List<String>>> private final Map<ObjectName,Map<String,List<String>>>
myRefedMBeanObjName2RelIdsMap = myRefedMBeanObjName2RelIdsMap =
new HashMap<ObjectName,Map<String,List<String>>>(); new HashMap<ObjectName,Map<String,List<String>>>();
...@@ -1492,7 +1492,7 @@ public class RelationService extends NotificationBroadcasterSupport ...@@ -1492,7 +1492,7 @@ public class RelationService extends NotificationBroadcasterSupport
// Clones the list of notifications to be able to still receive new // Clones the list of notifications to be able to still receive new
// notifications while proceeding those ones // notifications while proceeding those ones
List<MBeanServerNotification> localUnregNtfList; List<MBeanServerNotification> localUnregNtfList;
synchronized(myUnregNtfList) { synchronized(myRefedMBeanObjName2RelIdsMap) {
localUnregNtfList = localUnregNtfList =
new ArrayList<MBeanServerNotification>(myUnregNtfList); new ArrayList<MBeanServerNotification>(myUnregNtfList);
// Resets list // Resets list
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册