All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.remotingjmx.protocol.v2.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).

There is a newer version: 34.0.0.Final
Show newest version
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2023 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jboss.remotingjmx.protocol.v2;

import static org.jboss.remotingjmx.protocol.v2.Constants.ADD_NOTIFICATION_LISTENER;
import static org.jboss.remotingjmx.protocol.v2.Constants.ATTRIBUTE;
import static org.jboss.remotingjmx.protocol.v2.Constants.ATTRIBUTE_LIST;
import static org.jboss.remotingjmx.protocol.v2.Constants.BOOLEAN;
import static org.jboss.remotingjmx.protocol.v2.Constants.CREATE_MBEAN;
import static org.jboss.remotingjmx.protocol.v2.Constants.GET_ATTRIBUTE;
import static org.jboss.remotingjmx.protocol.v2.Constants.GET_ATTRIBUTES;
import static org.jboss.remotingjmx.protocol.v2.Constants.GET_DEFAULT_DOMAIN;
import static org.jboss.remotingjmx.protocol.v2.Constants.GET_DOMAINS;
import static org.jboss.remotingjmx.protocol.v2.Constants.GET_MBEAN_COUNT;
import static org.jboss.remotingjmx.protocol.v2.Constants.GET_MBEAN_INFO;
import static org.jboss.remotingjmx.protocol.v2.Constants.GET_OBJECT_INSTANCE;
import static org.jboss.remotingjmx.protocol.v2.Constants.INSTANCE_OF;
import static org.jboss.remotingjmx.protocol.v2.Constants.INTEGER;
import static org.jboss.remotingjmx.protocol.v2.Constants.INTEGER_ARRAY;
import static org.jboss.remotingjmx.protocol.v2.Constants.INVOKE;
import static org.jboss.remotingjmx.protocol.v2.Constants.IS_REGISTERED;
import static org.jboss.remotingjmx.protocol.v2.Constants.MBEAN_INFO;
import static org.jboss.remotingjmx.protocol.v2.Constants.NOTIFICATION;
import static org.jboss.remotingjmx.protocol.v2.Constants.NOTIFICATION_FILTER;
import static org.jboss.remotingjmx.protocol.v2.Constants.OBJECT;
import static org.jboss.remotingjmx.protocol.v2.Constants.OBJECT_ARRAY;
import static org.jboss.remotingjmx.protocol.v2.Constants.OBJECT_INSTANCE;
import static org.jboss.remotingjmx.protocol.v2.Constants.OBJECT_NAME;
import static org.jboss.remotingjmx.protocol.v2.Constants.QUERY_EXP;
import static org.jboss.remotingjmx.protocol.v2.Constants.QUERY_MBEANS;
import static org.jboss.remotingjmx.protocol.v2.Constants.QUERY_NAMES;
import static org.jboss.remotingjmx.protocol.v2.Constants.REMOVE_NOTIFICATION_LISTENER;
import static org.jboss.remotingjmx.protocol.v2.Constants.RESPONSE_MASK;
import static org.jboss.remotingjmx.protocol.v2.Constants.SEND_NOTIFICATION;
import static org.jboss.remotingjmx.protocol.v2.Constants.SET_ATTRIBUTE;
import static org.jboss.remotingjmx.protocol.v2.Constants.SET_ATTRIBUTES;
import static org.jboss.remotingjmx.protocol.v2.Constants.SET_OBJECT_INSTANCE;
import static org.jboss.remotingjmx.protocol.v2.Constants.SET_OBJECT_NAME;
import static org.jboss.remotingjmx.protocol.v2.Constants.STRING;
import static org.jboss.remotingjmx.protocol.v2.Constants.STRING_ARRAY;
import static org.jboss.remotingjmx.protocol.v2.Constants.SUCCESS;
import static org.jboss.remotingjmx.protocol.v2.Constants.UNREGISTER_MBEAN;

import java.io.DataInput;
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.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.remotingjmx.ServerMessageInterceptor;
import org.jboss.remotingjmx.VersionedProxy;
import org.jboss.remotingjmx.WrappedMBeanServerConnection;

/**
 * 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 ServerCommon 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;
    // 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, executor, serverMessageInterceptor);
        this.channel = channel;
        this.server = server;
        handlerRegistry = createHandlerRegistry();
        this.remoteNotificationManager = new RemoteNotificationManager();
        this.executor = executor;
    }

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

    @Override
    Map getHandlerRegistry() {
        return handlerRegistry;
    }

    @Override
    void end() {
        remoteNotificationManager.removeNotificationListener();
        server.connectionClosed(this);
    }

    void start() throws IOException {
        // Create a connection ID
        connectionId = UUID.randomUUID();
        log.debugf("Created connectionID %s", connectionId.toString());
        // Inform server the connection is now open
        server.connectionOpened(this);
        channel.receiveMessage(new MessageReciever());
    }

    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();
            server.connectionClosed(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 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_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;
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy