org.jboss.remotingjmx.protocol.v1.ServerProxy Maven / Gradle / Ivy
Go to download
This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including
all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and
JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up
with different versions on classes on the class path).
/*
* JBoss, Home of Professional Open Source.
* Copyright 2012, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.remotingjmx.protocol.v1;
import static org.jboss.remotingjmx.protocol.v1.Constants.ADD_NOTIFICATION_LISTENER;
import static org.jboss.remotingjmx.protocol.v1.Constants.ATTRIBUTE;
import static org.jboss.remotingjmx.protocol.v1.Constants.ATTRIBUTE_LIST;
import static org.jboss.remotingjmx.protocol.v1.Constants.BOOLEAN;
import static org.jboss.remotingjmx.protocol.v1.Constants.CREATE_MBEAN;
import static org.jboss.remotingjmx.protocol.v1.Constants.EXCEPTION;
import static org.jboss.remotingjmx.protocol.v1.Constants.FAILURE;
import static org.jboss.remotingjmx.protocol.v1.Constants.GET_ATTRIBUTE;
import static org.jboss.remotingjmx.protocol.v1.Constants.GET_ATTRIBUTES;
import static org.jboss.remotingjmx.protocol.v1.Constants.GET_DEFAULT_DOMAIN;
import static org.jboss.remotingjmx.protocol.v1.Constants.GET_DOMAINS;
import static org.jboss.remotingjmx.protocol.v1.Constants.GET_MBEAN_COUNT;
import static org.jboss.remotingjmx.protocol.v1.Constants.GET_MBEAN_INFO;
import static org.jboss.remotingjmx.protocol.v1.Constants.GET_OBJECT_INSTANCE;
import static org.jboss.remotingjmx.protocol.v1.Constants.INSTANCE_OF;
import static org.jboss.remotingjmx.protocol.v1.Constants.INTEGER;
import static org.jboss.remotingjmx.protocol.v1.Constants.INTEGER_ARRAY;
import static org.jboss.remotingjmx.protocol.v1.Constants.INVOKE;
import static org.jboss.remotingjmx.protocol.v1.Constants.IS_REGISTERED;
import static org.jboss.remotingjmx.protocol.v1.Constants.MBEAN_INFO;
import static org.jboss.remotingjmx.protocol.v1.Constants.NOTIFICATION;
import static org.jboss.remotingjmx.protocol.v1.Constants.NOTIFICATION_FILTER;
import static org.jboss.remotingjmx.protocol.v1.Constants.OBJECT;
import static org.jboss.remotingjmx.protocol.v1.Constants.OBJECT_ARRAY;
import static org.jboss.remotingjmx.protocol.v1.Constants.OBJECT_INSTANCE;
import static org.jboss.remotingjmx.protocol.v1.Constants.OBJECT_NAME;
import static org.jboss.remotingjmx.protocol.v1.Constants.QUERY_EXP;
import static org.jboss.remotingjmx.protocol.v1.Constants.QUERY_MBEANS;
import static org.jboss.remotingjmx.protocol.v1.Constants.QUERY_NAMES;
import static org.jboss.remotingjmx.protocol.v1.Constants.REMOVE_NOTIFICATION_LISTENER;
import static org.jboss.remotingjmx.protocol.v1.Constants.RESPONSE_MASK;
import static org.jboss.remotingjmx.protocol.v1.Constants.SEND_NOTIFICATION;
import static org.jboss.remotingjmx.protocol.v1.Constants.SET_ATTRIBUTE;
import static org.jboss.remotingjmx.protocol.v1.Constants.SET_ATTRIBUTES;
import static org.jboss.remotingjmx.protocol.v1.Constants.SET_OBJECT_INSTANCE;
import static org.jboss.remotingjmx.protocol.v1.Constants.SET_OBJECT_NAME;
import static org.jboss.remotingjmx.protocol.v1.Constants.STRING;
import static org.jboss.remotingjmx.protocol.v1.Constants.STRING_ARRAY;
import static org.jboss.remotingjmx.protocol.v1.Constants.SUCCESS;
import static org.jboss.remotingjmx.protocol.v1.Constants.UNREGISTER_MBEAN;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.IOException;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Executor;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.InvalidAttributeValueException;
import javax.management.JMRuntimeException;
import javax.management.ListenerNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MBeanServerConnection;
import javax.management.NotCompliantMBeanException;
import javax.management.Notification;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.QueryExp;
import javax.management.ReflectionException;
import org.jboss.logging.Logger;
import org.jboss.marshalling.AbstractClassResolver;
import org.jboss.marshalling.Marshaller;
import org.jboss.marshalling.Unmarshaller;
import org.jboss.remoting3.Channel;
import org.jboss.remoting3.MessageInputStream;
import org.jboss.remotingjmx.ServerMessageInterceptor;
import org.jboss.remotingjmx.ServerMessageInterceptor.Event;
import org.jboss.remotingjmx.VersionedProxy;
import org.jboss.remotingjmx.WrappedMBeanServerConnection;
import org.xnio.IoUtils;
/**
* The VersionOne server proxy.
*
* The ServerProxy is a proxy for a single client connection, any state tracked by a proxy is client connection specific.
*
* @author Darran Lofthouse
*/
class ServerProxy extends Common implements VersionedProxy {
private static final Logger log = Logger.getLogger(ServerProxy.class);
private final Channel channel;
private final WrappedMBeanServerConnection server;
private UUID connectionId;
private final Executor executor;
private final ServerMessageInterceptor serverMessageInterceptor;
// Registry of handlers for the incoming messages.
private final Map handlerRegistry;
private final RemoteNotificationManager remoteNotificationManager;
ServerProxy(final Channel channel, final WrappedMBeanServerConnection server, final Executor executor,
final ServerMessageInterceptor serverMessageInterceptor) {
super(channel);
this.channel = channel;
this.server = server;
this.handlerRegistry = createHandlerRegistry();
this.remoteNotificationManager = new RemoteNotificationManager();
this.executor = executor;
this.serverMessageInterceptor = serverMessageInterceptor;
}
private Map createHandlerRegistry() {
Map registry = new HashMap();
registry.put(ADD_NOTIFICATION_LISTENER, new AddNotificationListenerHandler());
registry.put(CREATE_MBEAN, new CreateMBeanHandler());
registry.put(GET_ATTRIBUTE, new GetAttributeHandler());
registry.put(GET_ATTRIBUTES, new GetAttributesHandler());
registry.put(GET_DEFAULT_DOMAIN, new GetDefaultDomainHandler());
registry.put(GET_DOMAINS, new GetDomainsHandler());
registry.put(GET_MBEAN_COUNT, new GetMBeanCountHandler());
registry.put(GET_MBEAN_INFO, new GetMBeanInfoHandler());
registry.put(GET_OBJECT_INSTANCE, new GetObjectInstanceHandler());
registry.put(INSTANCE_OF, new InstanceofHandler());
registry.put(INVOKE, new InvokeHandler());
registry.put(IS_REGISTERED, new IsRegisteredHandler());
registry.put(QUERY_MBEANS, new QueryMBeansHandler());
registry.put(QUERY_NAMES, new QueryNamesHandler());
registry.put(REMOVE_NOTIFICATION_LISTENER, new RemoveNotificationListenerHandler());
registry.put(SET_ATTRIBUTE, new SetAttributeHandler());
registry.put(SET_ATTRIBUTES, new SetAttributesHandler());
registry.put(UNREGISTER_MBEAN, new UnregisterMBeanHandler());
return Collections.unmodifiableMap(registry);
}
void start() throws IOException {
// Create a connection ID
connectionId = UUID.randomUUID();
log.debugf("Created connectionID %s", connectionId.toString());
// Send ID to client
sendConnectionId();
// Inform server the connection is now open
server.connectionOpened(this);
channel.receiveMessage(new MessageReciever());
}
private void sendConnectionId() throws IOException {
write(new MessageWriter() {
@Override
public void write(DataOutput output) throws IOException {
output.writeBytes("JMX");
output.writeUTF(connectionId.toString());
}
});
log.tracef("Written connectionId %s", connectionId.toString());
}
public String getConnectionId() {
return connectionId.toString();
}
public void close() {
try {
channel.writeShutdown();
channel.close();
} catch (IOException e) {
log.warn("Unable to close channel");
// Can't rely on the Receiver to have called this if we can't close down.
remoteNotificationManager.removeNotificationListener();
}
}
private class MessageReciever implements Channel.Receiver {
@Override
public void handleMessage(final Channel channel, MessageInputStream message) {
final DataInputStream dis = new DataInputStream(message);
try {
final byte messageId = dis.readByte();
final int correlationId = dis.readInt();
log.tracef("Message Received id(%h), correlationId(%d)", messageId, correlationId);
final Common.MessageHandler mh = handlerRegistry.get(messageId);
if (mh != null) {
executor.execute(new Runnable() {
@Override
public void run() {
try {
serverMessageInterceptor.handleEvent(new Event() {
@Override
public void run() throws IOException {
mh.handle(dis, correlationId);
}
});
} catch (Throwable t) {
if (correlationId != 0x00) {
Exception response;
if (t instanceof IOException) {
response = (Exception) t;
} else if (t instanceof JMRuntimeException) {
response = (Exception) t;
} else {
response = new IOException("Internal server error.");
log.warn("Unexpected internal error", t);
}
sendIOException(response);
} else {
log.error("null correlationId so error not sent to client", t);
}
} finally {
IoUtils.safeClose(dis);
}
}
private void sendIOException(final Exception e) {
try {
writeResponse(e, messageId, correlationId);
log.tracef("[%d] %h - Success Response Sent", correlationId, messageId);
} catch (IOException ioe) {
// Here there is nothing left we can do, we know we can not sent to the client though.
log.error(ioe);
}
}
});
} else {
throw new IOException("Unrecognised Message ID");
}
} catch (IOException e) {
log.error(e);
IoUtils.safeClose(dis);
} finally {
// On shut down we expect one of the following pair to be called
// so that will end the receive loop.
channel.receiveMessage(this);
}
}
public void handleError(Channel channel, IOException error) {
log.warn("Channel closing due to error", error);
remoteNotificationManager.removeNotificationListener();
server.connectionClosed(ServerProxy.this);
}
@Override
public void handleEnd(Channel channel) {
remoteNotificationManager.removeNotificationListener();
server.connectionClosed(ServerProxy.this);
}
}
/**
* Manager to maintain the list of remote notifications and to pass these notifications back to the clients.
*/
private class RemoteNotificationManager {
private Map listeners = new HashMap();
private synchronized void addNotificationListener(ObjectName name, int listenerId, NotificationFilter filter,
Object handback) throws InstanceNotFoundException, IOException {
NotificationProxy proxy = new NotificationProxy(listenerId);
server.getMBeanServerConnection().addNotificationListener(name, proxy, filter, handback);
Association association = new Association();
association.name = name;
association.listener = proxy;
association.filter = filter;
association.handback = handback;
listeners.put(listenerId, association);
}
private synchronized void removeNotificationListener() {
Iterator keys = listeners.keySet().iterator();
int[] all = new int[listeners.size()];
for (int i = 0; i < all.length; i++) {
all[i] = keys.next();
}
removeNotificationListeners(all);
}
private synchronized void removeNotificationListener(int listenerId) throws ListenerNotFoundException,
InstanceNotFoundException, IOException {
Association association = listeners.remove(listenerId);
if (association != null) {
server.getMBeanServerConnection().removeNotificationListener(association.name, association.listener,
association.filter, association.handback);
} else {
log.warnf("Request to removeNotificationListener, listener with ID %d not found.", listenerId);
}
}
private void removeNotificationListeners(int[] listenerIds) {
for (int current : listenerIds) {
try {
removeNotificationListener(current);
} catch (ListenerNotFoundException e) {
log.warn("Failure removing notification listener", e);
} catch (InstanceNotFoundException e) {
log.warn("Failure removing notification listener", e);
} catch (IOException e) {
log.warn("Failure removing notification listener", e);
}
}
}
private class NotificationProxy implements NotificationListener {
private final int listenerId;
private NotificationProxy(final int listenerId) {
this.listenerId = listenerId;
}
public void handleNotification(final Notification notification, final Object handback) {
// Just send the notification to the client and let the client deal with it.
// By using the executor we can return the thread back to the NotificationBroadcaster quickly.
executor.execute(new Runnable() {
@Override
public void run() {
try {
writeNotification(listenerId, notification, handback);
} catch (IOException e) {
log.warnf("Unable to send notification to listener %d", listenerId);
}
}
});
}
}
private class Association {
private ObjectName name;
private NotificationListener listener;
private NotificationFilter filter;
private Object handback;
}
}
private void writeResponse(final byte inResponseTo, final int correlationId) throws IOException {
write(new MessageWriter() {
@Override
public void write(DataOutput output) throws IOException {
output.writeByte(inResponseTo ^ RESPONSE_MASK);
output.writeInt(correlationId);
output.writeByte(SUCCESS);
}
});
}
private void writeResponse(final Exception e, final byte inResponseTo, final int correlationId) throws IOException {
write(new MessageWriter() {
@Override
public void write(DataOutput output) throws IOException {
output.writeByte(inResponseTo ^ RESPONSE_MASK);
output.writeInt(correlationId);
output.writeByte(FAILURE);
output.writeByte(EXCEPTION);
Marshaller marshaller = prepareForMarshalling(output);
marshaller.writeObject(e);
marshaller.finish();
}
});
}
private void writeResponse(final boolean response, final byte inResponseTo, final int correlationId) throws IOException {
write(new MessageWriter() {
@Override
public void write(DataOutput output) throws IOException {
output.writeByte(inResponseTo ^ RESPONSE_MASK);
output.writeInt(correlationId);
output.writeByte(SUCCESS);
output.writeByte(BOOLEAN);
output.writeBoolean(response);
}
});
}
private void writeResponse(final Integer response, final byte inResponseTo, final int correlationId) throws IOException {
write(new MessageWriter() {
@Override
public void write(DataOutput output) throws IOException {
output.writeByte(inResponseTo ^ RESPONSE_MASK);
output.writeInt(correlationId);
output.writeByte(SUCCESS);
output.writeByte(INTEGER);
output.writeInt(response);
}
});
}
private void writeResponse(final Object response, final byte type, final byte inResponseTo, final int correlationId)
throws IOException {
write(new MessageWriter() {
@Override
public void write(DataOutput output) throws IOException {
output.writeByte(inResponseTo ^ RESPONSE_MASK);
output.writeInt(correlationId);
output.writeByte(SUCCESS);
output.writeByte(type);
Marshaller marshaller = prepareForMarshalling(output);
marshaller.writeObject(response);
marshaller.finish();
}
});
}
private void writeResponse(final String response, final byte inResponseTo, final int correlationId) throws IOException {
write(new MessageWriter() {
@Override
public void write(DataOutput output) throws IOException {
output.writeByte(inResponseTo ^ RESPONSE_MASK);
output.writeInt(correlationId);
output.writeByte(SUCCESS);
output.writeByte(STRING);
output.writeUTF(response);
}
});
}
private void writeResponse(final String[] response, final byte inResponseTo, final int correlationId) throws IOException {
write(new MessageWriter() {
@Override
public void write(DataOutput output) throws IOException {
output.writeByte(inResponseTo ^ RESPONSE_MASK);
output.writeInt(correlationId);
output.writeByte(SUCCESS);
output.writeByte(STRING_ARRAY);
output.writeInt(response.length);
for (String currentDomain : response) {
output.writeUTF(currentDomain);
}
}
});
}
private void writeNotification(final int listenerId, final Notification notification, final Object handback)
throws IOException {
write(new MessageWriter() {
@Override
public void write(DataOutput output) throws IOException {
output.writeByte(SEND_NOTIFICATION);
output.writeInt(0x00);
output.writeByte(INTEGER);
output.writeInt(listenerId);
output.writeByte(NOTIFICATION);
Marshaller marshaller = prepareForMarshalling(output);
marshaller.writeObject(notification);
marshaller.writeByte(OBJECT);
marshaller.writeObject(handback);
marshaller.finish();
}
});
}
private class AddNotificationListenerHandler implements Common.MessageHandler {
@Override
public void handle(DataInput input, int correlationId) throws IOException {
log.trace("AddNotificationListener");
byte paramType = input.readByte();
if (paramType != OBJECT_NAME) {
throw new IOException("Unexpected paramType");
}
Unmarshaller unmarshaller = prepareForUnMarshalling(input);
ObjectName name;
boolean remoteNotification;
int listenerId = -1;
ObjectName listener = null;
NotificationFilter filter;
Object handback;
try {
name = unmarshaller.readObject(ObjectName.class);
paramType = unmarshaller.readByte();
if (paramType == INTEGER) {
remoteNotification = true;
listenerId = unmarshaller.readInt();
} else if (paramType == OBJECT_NAME) {
remoteNotification = false;
listener = unmarshaller.readObject(ObjectName.class);
} else {
throw new IOException("Unexpected paramType");
}
paramType = unmarshaller.readByte();
if (paramType != NOTIFICATION_FILTER) {
throw new IOException("Unexpected paramType");
}
filter = unmarshaller.readObject(NotificationFilter.class);
paramType = unmarshaller.readByte();
if (paramType != OBJECT) {
throw new IOException("Unexpected paramType");
}
handback = unmarshaller.readObject();
} catch (ClassNotFoundException cnfe) {
throw new IOException(cnfe);
}
try {
if (remoteNotification) {
remoteNotificationManager.addNotificationListener(name, listenerId, filter, handback);
} else {
server.getMBeanServerConnection().addNotificationListener(name, listener, filter, handback);
}
writeResponse(ADD_NOTIFICATION_LISTENER, correlationId);
log.tracef("[%d] AddNotificationListener - Success Response Sent", correlationId);
} catch (InstanceNotFoundException e) {
writeResponse(e, ADD_NOTIFICATION_LISTENER, correlationId);
log.tracef("[%d] AddNotificationListener - Failure Response Sent", correlationId);
}
}
}
private class CreateMBeanHandler implements Common.MessageHandler {
@Override
public void handle(DataInput input, final int correlationId) throws IOException {
log.trace("CreateMBean");
byte paramType = input.readByte();
if (paramType != INTEGER) {
throw new IOException("Unexpected paramType");
}
int paramCount = input.readInt();
String className = null;
ObjectName name = null;
ObjectName loader = null;
Object[] params = null;
String[] signature = null;
final ClassLoaderSwitchingClassResolver resolver = new ClassLoaderSwitchingClassResolver(
ServerProxy.class.getClassLoader());
Unmarshaller unmarshaller = prepareForUnMarshalling(input, resolver);
for (int i = 0; i < paramCount; i++) {
byte param = unmarshaller.readByte();
switch (param) {
case STRING:
if (className == null) {
className = unmarshaller.readUTF();
} else {
throw new IOException("Unexpected paramter");
}
break;
case OBJECT_NAME:
try {
if (name == null) {
name = unmarshaller.readObject(ObjectName.class);
} else if (loader == null) {
loader = unmarshaller.readObject(ObjectName.class);
switchClassLoaderForLoader(loader, resolver);
} else {
throw new IOException("Unexpected paramter");
}
} catch (ClassNotFoundException e) {
throw new IOException(e);
}
break;
case OBJECT_ARRAY:
if (params == null) {
int count = unmarshaller.readInt();
params = new Object[count];
for (int j = 0; j < count; j++) {
try {
params[j] = unmarshaller.readObject();
} catch (ClassNotFoundException e) {
throw new IOException(e);
}
}
} else {
throw new IOException("Unexpected paramter");
}
break;
case STRING_ARRAY:
if (signature == null) {
int count = unmarshaller.readInt();
signature = new String[count];
for (int j = 0; j < count; j++) {
signature[j] = unmarshaller.readUTF();
}
} else {
throw new IOException("Unexpected paramter");
}
break;
default:
throw new IOException("Unexpected paramter");
}
}
try {
final ObjectInstance instance;
switch (paramCount) {
case 2:
instance = server.getMBeanServerConnection().createMBean(className, name);
break;
case 3:
instance = server.getMBeanServerConnection().createMBean(className, name, loader);
break;
case 4:
instance = server.getMBeanServerConnection().createMBean(className, name, params, signature);
break;
case 5:
instance = server.getMBeanServerConnection().createMBean(className, name, loader, params, signature);
break;
default:
throw new IOException("Unable to identify correct create method to call.");
}
writeResponse(instance, OBJECT_INSTANCE, CREATE_MBEAN, correlationId);
log.tracef("[%d] CreateMBean - Success Response Sent", correlationId);
} catch (InstanceAlreadyExistsException e) {
writeResponse(e, CREATE_MBEAN, correlationId);
log.tracef("[%d] CreateMBean - Failure Response Sent", correlationId);
} catch (NotCompliantMBeanException e) {
writeResponse(e, CREATE_MBEAN, correlationId);
log.tracef("[%d] CreateMBean - Failure Response Sent", correlationId);
} catch (MBeanException e) {
writeResponse(e, CREATE_MBEAN, correlationId);
log.tracef("[%d] CreateMBean - Failure Response Sent", correlationId);
} catch (ReflectionException e) {
writeResponse(e, CREATE_MBEAN, correlationId);
log.tracef("[%d] CreateMBean - Failure Response Sent", correlationId);
} catch (InstanceNotFoundException e) {
writeResponse(e, CREATE_MBEAN, correlationId);
log.tracef("[%d] CreateMBean - Failure Response Sent", correlationId);
}
log.tracef("[%d] CreateMBean - Failure Response Sent", correlationId);
}
}
private void switchClassLoaderForMBean(final ObjectName name, final ClassLoaderSwitchingClassResolver resolver) {
try {
MBeanServerConnection connection = server.getMBeanServerConnection();
if (connection instanceof MBeanServer) {
final MBeanServer server = (MBeanServer) connection;
//This privileged block is needed!
//This classloader switch is an internal call to do other things.
//When running WildFly with RBAC, normally, if there is a subject, only superuser
//or administrator can call this method on the MBeanServer, meaning that the 'other things' will fail.
//Tbe privileged block clears the subject so the internal call will work
ClassLoader loader = AccessController.doPrivileged(new PrivilegedExceptionAction() {
@Override
public ClassLoader run() throws Exception {
ClassLoader loader = server.getClassLoaderFor(name);
//if the loader was null, chances are it was the bootstrap classloader so try that
if (loader == null){
loader = ClassLoader.getSystemClassLoader();
}
return loader;
}
});
resolver.switchClassLoader(loader);
}
} catch (Exception e) {
log.debugf(e, "Could not get class loader for %s", name);
}
}
private void switchClassLoaderForLoader(final ObjectName name, final ClassLoaderSwitchingClassResolver resolver) {
try {
MBeanServerConnection connection = server.getMBeanServerConnection();
if (connection instanceof MBeanServer) {
final MBeanServer server = (MBeanServer) connection;
//This privileged block is needed!
//This classloader switch is an internal call to do other things.
//When running WildFly with RBAC, normally, if there is a subject, only superuser
//or administrator can call this method on the MBeanServer, meaning that the 'other things' will fail.
//Tbe privileged block clears the subject so the internal call will work
ClassLoader loader = AccessController.doPrivileged(new PrivilegedExceptionAction() {
@Override
public ClassLoader run() throws Exception {
ClassLoader loader = server.getClassLoader(name);
//if the loader was null, chances are it was the bootstrap classloader so try that
if (loader == null){
loader = ClassLoader.getSystemClassLoader();
}
return loader;
}
});
resolver.switchClassLoader(loader);
}
} catch (Exception e) {
log.debugf(e, "Could not get class loader for %s", name);
}
}
private class GetDefaultDomainHandler implements Common.MessageHandler {
@Override
public void handle(DataInput input, final int correlationId) throws IOException {
log.trace("GetDefaultDomain");
final String defaultDomain = server.getMBeanServerConnection().getDefaultDomain();
writeResponse(defaultDomain, GET_DEFAULT_DOMAIN, correlationId);
log.tracef("[%d] CreateMBean - Success Response Sent", correlationId);
}
}
private class GetDomainsHandler implements Common.MessageHandler {
@Override
public void handle(DataInput input, final int correlationId) throws IOException {
log.trace("GetDomains");
final String[] domains = server.getMBeanServerConnection().getDomains();
writeResponse(domains, GET_DOMAINS, correlationId);
log.tracef("[%d] GetDomains - Success Response Sent", correlationId);
}
}
private class GetMBeanCountHandler implements Common.MessageHandler {
@Override
public void handle(DataInput input, final int correlationId) throws IOException {
log.trace("GetMBeanCount");
final Integer count = server.getMBeanServerConnection().getMBeanCount();
writeResponse(count, GET_MBEAN_COUNT, correlationId);
log.tracef("[%d] GetMBeanCount - Success Response Sent", correlationId);
}
}
private class GetAttributeHandler implements Common.MessageHandler {
@Override
public void handle(DataInput input, final int correlationId) throws IOException {
log.trace("GetAttribute");
byte paramType = input.readByte();
if (paramType != OBJECT_NAME) {
throw new IOException("Unexpected paramType");
}
Unmarshaller unmarshaller = prepareForUnMarshalling(input);
ObjectName objectName;
try {
objectName = unmarshaller.readObject(ObjectName.class);
} catch (ClassNotFoundException cnfe) {
throw new IOException(cnfe);
}
paramType = unmarshaller.readByte();
if (paramType != STRING) {
throw new IOException("Unexpected paramType");
}
String attribute = unmarshaller.readUTF();
try {
final Object attributeValue = server.getMBeanServerConnection().getAttribute(objectName, attribute);
writeResponse(attributeValue, OBJECT, GET_ATTRIBUTE, correlationId);
log.tracef("[%d] GetAttribute - Success Response Sent", correlationId);
} catch (AttributeNotFoundException e) {
writeResponse(e, GET_ATTRIBUTE, correlationId);
log.tracef("[%d] GetAttribute - Failure Response Sent", correlationId);
} catch (InstanceNotFoundException e) {
writeResponse(e, GET_ATTRIBUTE, correlationId);
log.tracef("[%d] GetAttribute - Failure Response Sent", correlationId);
} catch (MBeanException e) {
writeResponse(e, GET_ATTRIBUTE, correlationId);
log.tracef("[%d] GetAttribute - Failure Response Sent", correlationId);
} catch (ReflectionException e) {
writeResponse(e, GET_ATTRIBUTE, correlationId);
log.tracef("[%d] GetAttribute - Failure Response Sent", correlationId);
}
}
}
private class GetAttributesHandler implements Common.MessageHandler {
@Override
public void handle(DataInput input, int correlationId) throws IOException {
log.trace("GetAttributes");
byte paramType = input.readByte();
if (paramType != OBJECT_NAME) {
throw new IOException("Unexpected paramType");
}
Unmarshaller unmarshaller = prepareForUnMarshalling(input);
ObjectName objectName;
try {
objectName = unmarshaller.readObject(ObjectName.class);
} catch (ClassNotFoundException cnfe) {
throw new IOException(cnfe);
}
paramType = unmarshaller.readByte();
if (paramType != STRING_ARRAY) {
throw new IOException("Unexpected paramType");
}
int count = unmarshaller.readInt();
String[] attributes = new String[count];
for (int i = 0; i < count; i++) {
attributes[i] = unmarshaller.readUTF();
}
try {
AttributeList attributeValues = server.getMBeanServerConnection().getAttributes(objectName, attributes);
writeResponse(attributeValues, ATTRIBUTE_LIST, GET_ATTRIBUTES, correlationId);
log.tracef("[%d] GetAttributes - Success Response Sent", correlationId);
} catch (InstanceNotFoundException e) {
writeResponse(e, GET_ATTRIBUTES, correlationId);
log.tracef("[%d] GetAttributes - Failure Response Sent", correlationId);
} catch (ReflectionException e) {
writeResponse(e, GET_ATTRIBUTES, correlationId);
log.tracef("[%d] GetAttributes - Failure Response Sent", correlationId);
}
}
}
private class GetMBeanInfoHandler implements Common.MessageHandler {
@Override
public void handle(DataInput input, int correlationId) throws IOException {
log.trace("GetMBeanInfo");
byte paramType = input.readByte();
if (paramType != OBJECT_NAME) {
throw new IOException("Unexpected paramType");
}
Unmarshaller unmarshaller = prepareForUnMarshalling(input);
ObjectName objectName;
try {
objectName = unmarshaller.readObject(ObjectName.class);
} catch (ClassNotFoundException cnfe) {
throw new IOException(cnfe);
}
try {
MBeanInfo info = server.getMBeanServerConnection().getMBeanInfo(objectName);
writeResponse(info, MBEAN_INFO, GET_MBEAN_INFO, correlationId);
log.tracef("[%d] GetMBeanInfo - Success Response Sent", correlationId);
} catch (IntrospectionException e) {
writeResponse(e, MBEAN_INFO, correlationId);
log.tracef("[%d] GetMBeanInfo - Failure Response Sent", correlationId);
} catch (InstanceNotFoundException e) {
writeResponse(e, MBEAN_INFO, correlationId);
log.tracef("[%d] GetMBeanInfo - Failure Response Sent", correlationId);
} catch (ReflectionException e) {
writeResponse(e, MBEAN_INFO, correlationId);
log.tracef("[%d] GetMBeanInfo - Failure Response Sent", correlationId);
}
}
}
private class GetObjectInstanceHandler implements Common.MessageHandler {
@Override
public void handle(DataInput input, int correlationId) throws IOException {
log.trace("GetObjectInstance");
byte paramType = input.readByte();
if (paramType != OBJECT_NAME) {
throw new IOException("Unexpected paramType");
}
Unmarshaller unmarshaller = prepareForUnMarshalling(input);
ObjectName objectName;
try {
objectName = unmarshaller.readObject(ObjectName.class);
} catch (ClassNotFoundException cnfe) {
throw new IOException(cnfe);
}
try {
ObjectInstance objectInstance = server.getMBeanServerConnection().getObjectInstance(objectName);
writeResponse(objectInstance, OBJECT_INSTANCE, GET_OBJECT_INSTANCE, correlationId);
log.tracef("[%d] GetObjectInstance - Success Response Sent", correlationId);
} catch (InstanceNotFoundException e) {
writeResponse(e, GET_OBJECT_INSTANCE, correlationId);
log.tracef("[%d] GetObjectInstance - Failure Response Sent", correlationId);
}
}
}
private class InstanceofHandler implements Common.MessageHandler {
@Override
public void handle(DataInput input, int correlationId) throws IOException {
log.trace("IsInstanceOf");
byte paramType = input.readByte();
if (paramType != OBJECT_NAME) {
throw new IOException("Unexpected paramType");
}
Unmarshaller unmarshaller = prepareForUnMarshalling(input);
ObjectName objectName;
try {
objectName = unmarshaller.readObject(ObjectName.class);
} catch (ClassNotFoundException cnfe) {
throw new IOException(cnfe);
}
paramType = unmarshaller.readByte();
if (paramType != STRING) {
throw new IOException("Unexpected paramType");
}
String className = unmarshaller.readUTF();
try {
boolean instanceOf = server.getMBeanServerConnection().isInstanceOf(objectName, className);
writeResponse(instanceOf, INSTANCE_OF, correlationId);
log.tracef("[%d] IsInstanceOf - Success Response Sent", correlationId);
} catch (InstanceNotFoundException e) {
writeResponse(e, INSTANCE_OF, correlationId);
log.tracef("[%d] IsInstanceOf - Failure Response Sent", correlationId);
}
}
}
private class IsRegisteredHandler implements Common.MessageHandler {
@Override
public void handle(DataInput input, int correlationId) throws IOException {
log.trace("IsRegistered");
byte paramType = input.readByte();
if (paramType != OBJECT_NAME) {
throw new IOException("Unexpected paramType");
}
Unmarshaller unmarshaller = prepareForUnMarshalling(input);
ObjectName objectName;
try {
objectName = unmarshaller.readObject(ObjectName.class);
} catch (ClassNotFoundException cnfe) {
throw new IOException(cnfe);
}
boolean registered = server.getMBeanServerConnection().isRegistered(objectName);
writeResponse(registered, IS_REGISTERED, correlationId);
log.tracef("[%d] IsRegistered - Success Response Sent", correlationId);
}
}
private class InvokeHandler implements Common.MessageHandler {
@Override
public void handle(DataInput input, int correlationId) throws IOException {
log.trace("Invoke");
byte paramType = input.readByte();
if (paramType != OBJECT_NAME) {
throw new IOException("Unexpected paramType");
}
final ClassLoaderSwitchingClassResolver resolver = new ClassLoaderSwitchingClassResolver(
ServerProxy.class.getClassLoader());
Unmarshaller unmarshaller = prepareForUnMarshalling(input, resolver);
ObjectName objectName;
String operationName;
Object[] params;
String[] signature;
try {
objectName = unmarshaller.readObject(ObjectName.class);
switchClassLoaderForMBean(objectName, resolver);
paramType = unmarshaller.readByte();
if (paramType != STRING) {
throw new IOException("Unexpected paramType");
}
operationName = unmarshaller.readUTF();
paramType = unmarshaller.readByte();
if (paramType != OBJECT_ARRAY) {
throw new IOException("Unexpected paramType");
}
int count = unmarshaller.readInt();
params = new Object[count];
for (int i = 0; i < count; i++) {
params[i] = unmarshaller.readObject();
}
paramType = unmarshaller.readByte();
if (paramType != STRING_ARRAY) {
throw new IOException("Unexpected paramType");
}
count = unmarshaller.readInt();
signature = new String[count];
for (int i = 0; i < count; i++) {
signature[i] = unmarshaller.readUTF();
}
} catch (ClassNotFoundException cnfe) {
throw new IOException(cnfe);
}
try {
Object result = server.getMBeanServerConnection().invoke(objectName, operationName, params, signature);
writeResponse(result, OBJECT, INVOKE, correlationId);
log.tracef("[%d] Invoke - Success Response Sent", correlationId);
} catch (InstanceNotFoundException e) {
writeResponse(e, INVOKE, correlationId);
log.tracef("[%d] Invoke - Failure Response Sent", correlationId);
} catch (ReflectionException e) {
writeResponse(e, INVOKE, correlationId);
log.tracef("[%d] Invoke - Failure Response Sent", correlationId);
} catch (MBeanException e) {
writeResponse(e, INVOKE, correlationId);
log.tracef("[%d] Invoke - Failure Response Sent", correlationId);
}
}
}
private class RemoveNotificationListenerHandler implements Common.MessageHandler {
@Override
public void handle(DataInput input, int correlationId) throws IOException {
log.trace("RemoveNotificationListener");
byte paramType = input.readByte();
if (paramType != INTEGER) {
throw new IOException("Unexpected paramType");
}
final int count = input.readInt();
if (count != 1 && count != 2 && count != 4) {
throw new IOException("Invalid count received.");
}
int[] toRemove = null;
ObjectName name = null;
ObjectName listener = null;
NotificationFilter filter = null;
Object handback = null;
if (count == 1) {
paramType = input.readByte();
if (paramType != INTEGER_ARRAY) {
throw new IOException("Unexpected paramType");
}
int itemCount = input.readInt();
toRemove = new int[itemCount];
for (int i = 0; i < itemCount; i++) {
toRemove[i] = input.readInt();
}
} else {
paramType = input.readByte();
if (paramType != OBJECT_NAME) {
throw new IOException("Unexpected paramType");
}
Unmarshaller unmarshaller = prepareForUnMarshalling(input);
try {
name = unmarshaller.readObject(ObjectName.class);
paramType = unmarshaller.readByte();
if (paramType != OBJECT_NAME) {
throw new IOException("Unexpected paramType");
}
listener = unmarshaller.readObject(ObjectName.class);
if (count == 4) {
paramType = unmarshaller.readByte();
if (paramType != NOTIFICATION_FILTER) {
throw new IOException("Unexpected paramType");
}
filter = unmarshaller.readObject(NotificationFilter.class);
paramType = unmarshaller.readByte();
if (paramType != OBJECT) {
throw new IOException("Unexpected paramType");
}
handback = unmarshaller.readObject();
}
} catch (ClassNotFoundException cnfe) {
throw new IOException(cnfe);
}
}
try {
if (count == 1) {
remoteNotificationManager.removeNotificationListeners(toRemove);
} else if (count == 2) {
server.getMBeanServerConnection().removeNotificationListener(name, listener);
} else {
server.getMBeanServerConnection().removeNotificationListener(name, listener, filter, handback);
}
writeResponse(REMOVE_NOTIFICATION_LISTENER, correlationId);
log.tracef("[%d] RemoveNotificationListener - Success Response Sent", correlationId);
} catch (InstanceNotFoundException e) {
writeResponse(e, REMOVE_NOTIFICATION_LISTENER, correlationId);
log.tracef("[%d] RemoveNotificationListener - Failure Response Sent", correlationId);
} catch (ListenerNotFoundException e) {
writeResponse(e, REMOVE_NOTIFICATION_LISTENER, correlationId);
log.tracef("[%d] RemoveNotificationListener - Failure Response Sent", correlationId);
}
}
}
private class QueryMBeansHandler implements Common.MessageHandler {
@Override
public void handle(DataInput input, int correlationId) throws IOException {
log.trace("QueryMBeans");
byte paramType = input.readByte();
if (paramType != OBJECT_NAME) {
throw new IOException("Unexpected paramType");
}
ObjectName objectName;
QueryExp query;
try {
Unmarshaller unmarshaller = prepareForUnMarshalling(input);
objectName = unmarshaller.readObject(ObjectName.class);
paramType = unmarshaller.readByte();
if (paramType != QUERY_EXP) {
throw new IOException("Unexpected paramType");
}
query = unmarshaller.readObject(QueryExp.class);
} catch (ClassNotFoundException cnfe) {
throw new IOException(cnfe);
}
Set instances = server.getMBeanServerConnection().queryMBeans(objectName, query);
writeResponse(instances, SET_OBJECT_INSTANCE, QUERY_MBEANS, correlationId);
log.tracef("[%d] QueryMBeans - Success Response Sent", correlationId);
}
}
private class QueryNamesHandler implements Common.MessageHandler {
@Override
public void handle(DataInput input, int correlationId) throws IOException {
log.trace("QueryNames");
byte paramType = input.readByte();
if (paramType != OBJECT_NAME) {
throw new IOException("Unexpected paramType");
}
ObjectName objectName;
QueryExp query;
try {
Unmarshaller unmarshaller = prepareForUnMarshalling(input);
objectName = unmarshaller.readObject(ObjectName.class);
paramType = unmarshaller.readByte();
if (paramType != QUERY_EXP) {
throw new IOException("Unexpected paramType");
}
query = unmarshaller.readObject(QueryExp.class);
} catch (ClassNotFoundException cnfe) {
throw new IOException(cnfe);
}
Set instances = server.getMBeanServerConnection().queryNames(objectName, query);
writeResponse(instances, SET_OBJECT_NAME, QUERY_NAMES, correlationId);
log.tracef("[%d] QueryNames - Success Response Sent", correlationId);
}
}
private class SetAttributeHandler implements Common.MessageHandler {
@Override
public void handle(DataInput input, int correlationId) throws IOException {
log.trace("SetAttribute");
byte paramType = input.readByte();
if (paramType != OBJECT_NAME) {
throw new IOException("Unexpected paramType");
}
final ClassLoaderSwitchingClassResolver resolver = new ClassLoaderSwitchingClassResolver(
ServerProxy.class.getClassLoader());
Unmarshaller unmarshaller = prepareForUnMarshalling(input, resolver);
ObjectName objectName;
Attribute attr;
try {
objectName = unmarshaller.readObject(ObjectName.class);
switchClassLoaderForMBean(objectName, resolver);
paramType = unmarshaller.readByte();
if (paramType != ATTRIBUTE) {
throw new IOException("Unexpected paramType");
}
attr = unmarshaller.readObject(Attribute.class);
} catch (ClassNotFoundException cnfe) {
throw new IOException(cnfe);
}
try {
server.getMBeanServerConnection().setAttribute(objectName, attr);
writeResponse(SET_ATTRIBUTE, correlationId);
log.tracef("[%d] SetAttribute - Success Response Sent", correlationId);
} catch (InstanceNotFoundException e) {
writeResponse(e, SET_ATTRIBUTE, correlationId);
log.tracef("[%d] SetAttribute - Failure Response Sent", correlationId);
} catch (InvalidAttributeValueException e) {
writeResponse(e, SET_ATTRIBUTE, correlationId);
log.tracef("[%d] SetAttribute - Failure Response Sent", correlationId);
} catch (AttributeNotFoundException e) {
writeResponse(e, SET_ATTRIBUTE, correlationId);
log.tracef("[%d] SetAttribute - Failure Response Sent", correlationId);
} catch (ReflectionException e) {
writeResponse(e, SET_ATTRIBUTE, correlationId);
log.tracef("[%d] SetAttribute - Failure Response Sent", correlationId);
} catch (MBeanException e) {
writeResponse(e, SET_ATTRIBUTE, correlationId);
log.tracef("[%d] SetAttribute - Failure Response Sent", correlationId);
}
}
}
private class SetAttributesHandler implements Common.MessageHandler {
@Override
public void handle(DataInput input, int correlationId) throws IOException {
log.trace("SetAttributes");
byte paramType = input.readByte();
if (paramType != OBJECT_NAME) {
throw new IOException("Unexpected paramType");
}
final ClassLoaderSwitchingClassResolver resolver = new ClassLoaderSwitchingClassResolver(
ServerProxy.class.getClassLoader());
final Unmarshaller unmarshaller = prepareForUnMarshalling(input, resolver);
ObjectName objectName;
AttributeList attributes;
try {
objectName = unmarshaller.readObject(ObjectName.class);
switchClassLoaderForMBean(objectName, resolver);
paramType = unmarshaller.readByte();
if (paramType != ATTRIBUTE_LIST) {
throw new IOException("Unexpected paramType");
}
attributes = unmarshaller.readObject(AttributeList.class);
} catch (ClassNotFoundException cnfe) {
throw new IOException(cnfe);
}
try {
AttributeList attributeValues = server.getMBeanServerConnection().setAttributes(objectName, attributes);
writeResponse(attributeValues, ATTRIBUTE_LIST, SET_ATTRIBUTES, correlationId);
log.tracef("[%d] SetAttributes - Success Response Sent", correlationId);
} catch (InstanceNotFoundException e) {
writeResponse(e, SET_ATTRIBUTES, correlationId);
log.tracef("[%d] SetAttributes - Failure Response Sent", correlationId);
} catch (ReflectionException e) {
writeResponse(e, SET_ATTRIBUTES, correlationId);
log.tracef("[%d] SetAttributes - Failure Response Sent", correlationId);
}
}
}
private class UnregisterMBeanHandler implements Common.MessageHandler {
@Override
public void handle(DataInput input, int correlationId) throws IOException {
log.trace("UnregisterMBean");
byte paramType = input.readByte();
if (paramType != OBJECT_NAME) {
throw new IOException("Unexpected paramType");
}
Unmarshaller unmarshaller = prepareForUnMarshalling(input);
ObjectName objectName;
try {
objectName = unmarshaller.readObject(ObjectName.class);
} catch (ClassNotFoundException cnfe) {
throw new IOException(cnfe);
}
try {
server.getMBeanServerConnection().unregisterMBean(objectName);
writeResponse(UNREGISTER_MBEAN, correlationId);
log.tracef("[%d] UnregisterMBean - Success Response Sent", correlationId);
} catch (MBeanRegistrationException e) {
writeResponse(e, UNREGISTER_MBEAN, correlationId);
log.tracef("[%d] UnregisterMBean - Failure Response Sent", correlationId);
} catch (InstanceNotFoundException e) {
writeResponse(e, UNREGISTER_MBEAN, correlationId);
log.tracef("[%d] UnregisterMBean - Failure Response Sent", correlationId);
}
}
}
/**
* A mutable {@link org.jboss.marshalling.ClassResolver}
*/
private class ClassLoaderSwitchingClassResolver extends AbstractClassResolver {
private ClassLoader currentClassLoader;
ClassLoaderSwitchingClassResolver(final ClassLoader classLoader) {
this.currentClassLoader = classLoader;
}
/**
* Sets the passed newCL
as the classloader which will be returned on subsequent calls to
* {@link #getClassLoader()}
*
* @param newCL
*/
void switchClassLoader(final ClassLoader newCL) {
this.currentClassLoader = newCL;
}
@Override
protected ClassLoader getClassLoader() {
return this.currentClassLoader;
}
}
}