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

org.jolokia.service.jmx.handler.WriteHandler Maven / Gradle / Ivy

There is a newer version: 2.1.1
Show newest version
package org.jolokia.service.jmx.handler;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.List;

import javax.management.*;
import javax.management.openmbean.OpenMBeanAttributeInfo;
import javax.management.openmbean.OpenType;

import org.jolokia.server.core.request.JolokiaWriteRequest;
import org.jolokia.server.core.service.serializer.Serializer;
import org.jolokia.server.core.util.RequestType;

/*
 * Copyright 2009-2013 Roland Huss
 *
 * 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.
 */


/**
 * Handler for dealing with write request.
 *
 * @author roland
 * @since Jun 12, 2009
 */
public class WriteHandler extends AbstractCommandHandler {

    /** {@inheritDoc} */
    public RequestType getType() {
        return RequestType.WRITE;
    }

    /** {@inheritDoc} */
    @Override
    protected void checkForRestriction(JolokiaWriteRequest pRequest) {
        if (!context.isAttributeWriteAllowed(pRequest.getObjectName(),pRequest.getAttributeName())) {
            throw new SecurityException("Writing attribute " + pRequest.getAttributeName() +
                    " forbidden for MBean " + pRequest.getObjectNameAsString());
        }
    }

    /** {@inheritDoc} */
    @Override
    public Object doHandleSingleServerRequest(MBeanServerConnection server, JolokiaWriteRequest request)
            throws InstanceNotFoundException, AttributeNotFoundException, ReflectionException, MBeanException, IOException {

        try {
            return setAttribute(request, server);
        } catch (IntrospectionException exp) {
            throw new IllegalArgumentException("Cannot get info for MBean " + request.getObjectName() + ": " +exp,exp);
        } catch (InvalidAttributeValueException e) {
            throw new IllegalArgumentException("Invalid value " + request.getValue() + " for attribute " +
                    request.getAttributeName() + ", MBean " + request.getObjectNameAsString(),e);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new IllegalArgumentException("Cannot set value " + request.getValue() + " for attribute " +
                    request.getAttributeName() + ", MBean " + request.getObjectNameAsString(),e);
        }
    }

    private Object setAttribute(JolokiaWriteRequest request, MBeanServerConnection server)
            throws MBeanException, AttributeNotFoundException, InstanceNotFoundException,
            ReflectionException, IntrospectionException, InvalidAttributeValueException, IllegalAccessException, InvocationTargetException, IOException {

        MBeanInfo mInfo = server.getMBeanInfo(request.getObjectName());
        MBeanAttributeInfo aInfo = null;

        for (MBeanAttributeInfo i : mInfo.getAttributes()) {
            if (i.getName().equals(request.getAttributeName())) {
                aInfo = i;
                break;
            }
        }

        if (aInfo == null) {
            throw new AttributeNotFoundException("No such attribute: " + request.getAttributeName());
        }

        // it can be write-only though
        boolean writeOnly = aInfo.isWritable() && !aInfo.isReadable();

        // Old value, will throw an exception if attribute is not known. That's good.
        Object oldValue = writeOnly ? null : server.getAttribute(request.getObjectName(), request.getAttributeName());
        Object[] values;
        if (aInfo instanceof OpenMBeanAttributeInfo) {
            OpenMBeanAttributeInfo info = (OpenMBeanAttributeInfo) aInfo;
            values = getValues(info.getOpenType(), oldValue, request);
        } else {
            // aInfo is != null otherwise getAttribute() would have already thrown an ArgumentNotFoundException
            values = getValues(aInfo.getType(), oldValue, request);
        }
        Attribute attribute = new Attribute(request.getAttributeName(),values[0]);
        server.setAttribute(request.getObjectName(),attribute);
        return values[1];
    }

    /**
     * Get values for a write request. This method returns an array with two objects.
     * If no path is given (pRequest.getExtraArgs() == null), the returned values
     * are the new value and the old value. However, if a path is set, the returned new value
     * is the outer value (which can be set by an corresponding JMX set operation) where the
     * new value is set via the path expression. The old value is the value of the object specified
     * by the given path.
     *
     *
     * @param pType type of the outermost object to set as returned by an MBeanInfo structure.
     * @param pCurrentValue the object of the outermost object which can be null
     * @param pRequest the initial request
     * @return object array with two elements, element 0 is the value to set (see above), element 1
     *         is the old value.
     *
     * @throws AttributeNotFoundException if no such attribute exists (as specified in the request)
     * @throws IllegalAccessException if access to MBean fails
     * @throws InvocationTargetException reflection error when setting an object's attribute
     */
    private Object[] getValues(String pType, Object pCurrentValue, JolokiaWriteRequest pRequest)
            throws AttributeNotFoundException, IllegalAccessException, InvocationTargetException {
        List pathParts = pRequest.getPathParts();
        Object newValue = pRequest.getValue();

        if (pathParts != null && !pathParts.isEmpty()) {
            if (pCurrentValue == null ) {
                throw new IllegalArgumentException(
                        "Cannot set value with path when parent object is not set");
            }

            // We set an inner value, hence we have to return provided value itself for resetting
            // it later back via JMX
            return new Object[] {
                    pCurrentValue,
                    context.getMandatoryService(Serializer.class).setInnerValue(pCurrentValue, newValue, pathParts)
            };

        } else {
            // Return the objectified value
            return new Object[] {
                    context.getMandatoryService(Serializer.class).deserialize(pType, newValue),
                    pCurrentValue
            };
        }
    }

    private Object[] getValues(OpenType pOpenType, Object pCurrentValue, JolokiaWriteRequest pRequest) {
        // TODO: What to do when path is not null ? Simplest: Throw exception. Advanced: Extract other values and create
        // a new CompositeData with old values and the new value.
        // However, since this is probably out of scope, we will simply throw an exception if the path is not empty.
        List pathParts = pRequest.getPathParts();
        if (pathParts != null && !pathParts.isEmpty()) {
            throw new IllegalArgumentException("Cannot set value for OpenType " + pOpenType + " with inner path " +
                                               pRequest.getPath() + " since OpenTypes are immutable");
        }
        return new Object[] {
                context.getMandatoryService(Serializer.class).deserializeOpenType(pOpenType, pRequest.getValue()),
                pCurrentValue
        };
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy