Package org.jboss.as.protocol.mgmt

Source Code of org.jboss.as.protocol.mgmt.ManagementRequest

/*
* JBoss, Home of Professional Open Source.
* Copyright 2010, 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.as.protocol.mgmt;

import static org.jboss.as.protocol.ProtocolUtils.expectHeader;
import static org.jboss.as.protocol.StreamUtils.safeClose;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;

import org.jboss.as.protocol.ByteDataInput;
import org.jboss.as.protocol.ByteDataOutput;
import org.jboss.as.protocol.Connection;
import org.jboss.as.protocol.MessageHandler;
import org.jboss.as.protocol.SimpleByteDataInput;
import org.jboss.as.protocol.SimpleByteDataOutput;
import org.jboss.as.protocol.StreamUtils;

/**
* Base management request used for remote requests.  Provides the basic mechanism for connecting to a remote host controller
* for performing a task.  It will manage connecting and retrieving the correct response.
*
* @author John Bailey
*/
public abstract class ManagementRequest<T> extends AbstractMessageHandler {
    private int requestId = 0;
    private final ResponseFuture<T> future = new ResponseFuture<T>();
    private ManagementRequestConnectionStrategy connectionStrategy;
    // @GuardedBy(resultLock)
    private T result;
    /**
     * Ensures the assignment of 'result' by thread running responseBodyHandler
     * is visible to thread running responseEndHandler.
     */
    private final Object resultLock = new Object();

    /**
     * Get the handler id of the request.  These should match the id of a @{link org.jboss.as.host.controller.management.ManagementOperationHandler}.
     *
     * @return The handler id
     */
    protected abstract byte getHandlerId();

    /**
     * Execute the request by connecting and then delegating to the implementation's execute
     * and return a future used to get the response when complete.
     *
     * @param connectionStrategy The connection strategy
     * @return A future to retrieve the result when the request is complete
     * @throws IOException if any problems occur
     */
    public Future<T> execute(final ManagementRequestConnectionStrategy connectionStrategy) throws IOException {
        this.connectionStrategy = connectionStrategy;
        OutputStream dataOutput = null;
        ByteDataOutput output = null;
        try {
            final Connection connection = connectionStrategy.getConnection();
            connection.backupMessageHandler();

            connection.setMessageHandler(initiatingMessageHandler);
            dataOutput = connection.writeMessage();
            output = new SimpleByteDataOutput(dataOutput);
            // Start by writing the header
            final ManagementRequestHeader managementRequestHeader = new ManagementRequestHeader(ManagementProtocol.VERSION, requestId, getHandlerId());
            managementRequestHeader.write(output);
            connection.setMessageHandler(initiatingMessageHandler);
            output.close();
            dataOutput.close();
        } finally {
            safeClose(output);
            safeClose(dataOutput);
        }
        return future;
    }

    /**
     * Execute the request and wait for the result.
     *
     * @param connectionStrategy The connection strategy
     * @return The result
     * @throws IOException If any problems occur
     */
    public T executeForResult(final ManagementRequestConnectionStrategy connectionStrategy) throws Exception {
        return execute(connectionStrategy).get();
    }

    /** {@inheritDoc} */
    @Override
    public void handle(Connection connection, InputStream input) throws IOException {
        try {
            connection.setMessageHandler(responseBodyHandler);
            expectHeader(input, ManagementProtocol.RESPONSE_START);
            byte responseCode = StreamUtils.readByte(input);
            if (responseCode != getResponseCode()) {
                throw new IOException("Invalid response code.  Expecting '" + getResponseCode() + "' received '" + responseCode + "'");
            }
        } catch (Exception e) {
            future.setException(e);
        }
    }

    private MessageHandler initiatingMessageHandler = new AbstractMessageHandler() {
        @Override
        public final void handle(final Connection connection, final InputStream inputStream) throws IOException {
            final ManagementResponseHeader responseHeader;
            ByteDataInput input = null;
            try {
                input = new SimpleByteDataInput(inputStream);
                responseHeader = new ManagementResponseHeader(input);
                if (requestId != responseHeader.getResponseId()) {
                    throw new IOException("Invalid request ID expecting " + requestId + " received " + responseHeader.getResponseId());
                }
                connection.setMessageHandler(ManagementRequest.this);
                sendRequest(responseHeader.getVersion(), connection);
            } catch (Exception e) {
                future.setException(e);
            } finally {
                safeClose(input);
                if (future.isDone()) {
                    // We must have failed above and set the exception.
                    // If we fail sending we shouldn't expect a response,
                    // so consider the connection complete
                    connectionStrategy.complete();
                }
            }
        }
    };

    /**
     * Execute the request body.  This is run after the connection is established and the headers are exchanged.
     *
     * @param protocolVersion The active protocol version for the request
     * @param connection      The connection
     * @throws IOException If any errors occur
     */
    protected void sendRequest(final int protocolVersion, final Connection connection) throws IOException {
        OutputStream outputStream = null;
        ByteDataOutput output = null;
        try {
            outputStream = connection.writeMessage();
            output = new SimpleByteDataOutput(outputStream);
            output.writeByte(ManagementProtocol.REQUEST_OPERATION);
            output.writeByte(getRequestCode());
            output.writeByte(ManagementProtocol.REQUEST_START);
            output.close();
            outputStream.close();
        } finally {
            safeClose(output);
            safeClose(outputStream);
        }

        try {
            outputStream = connection.writeMessage();
            outputStream.write(ManagementProtocol.REQUEST_BODY);
            sendRequest(protocolVersion, outputStream);
            outputStream.close();
        } finally {
            safeClose(outputStream);
        }

        try {
            outputStream = connection.writeMessage();
            output = new SimpleByteDataOutput(outputStream);
            output.writeByte(ManagementProtocol.REQUEST_END);
            output.close();
            outputStream.close();
        } finally {
            safeClose(output);
            safeClose(outputStream);
        }
    }

    protected void sendRequest(final int protocolVersion, final OutputStream output) throws IOException {
    }

    protected abstract byte getRequestCode();

    protected abstract byte getResponseCode();

    private MessageHandler responseBodyHandler = new AbstractMessageHandler() {
        @Override
        public final void handle(final Connection connection, final InputStream input) throws IOException {
            try {
                connection.setMessageHandler(responseEndHandler);
                expectHeader(input, ManagementProtocol.RESPONSE_BODY);
                synchronized (resultLock) {
                    result = receiveResponse(input);
                }
            }
            catch (Exception e) {
                future.setException(e);
            }
        }

        @Override
        public void handleFinished(Connection connection) throws IOException {
            super.handleFinished(connection);

            future.setException(new EOFException("Connection closed"));
        }

        @Override
        public void handleFailure(Connection connection, IOException e) throws IOException {
            super.handleFailure(connection, e);
            future.setException(e);
        }
    };

    private MessageHandler responseEndHandler = new AbstractMessageHandler() {
        @Override
        public final void handle(final Connection connection, final InputStream input) throws IOException {
            try {
                connection.restoreMessageHandler();
                expectHeader(input, ManagementProtocol.RESPONSE_END);
                synchronized (resultLock) {
                    future.set(result);
                }
            }
            catch (Exception e) {
                future.setException(e);
            }
            finally {
                connectionStrategy.complete();
            }
        }

        @Override
        public void handleFinished(Connection connection) throws IOException {
            super.handleFinished(connection);

            future.setException(new EOFException("Connection closed"));
        }

        @Override
        public void handleFailure(Connection connection, IOException e) throws IOException {
            super.handleFailure(connection, e);
            future.setException(e);
        }
    };

    protected T receiveResponse(final InputStream input) throws IOException {
        return null;
    }

    private final class ResponseFuture<R> implements Future<R>{
        private volatile R result;
        private volatile Exception exception;
        private AtomicBoolean valueSet = new AtomicBoolean();

        public R get() throws InterruptedException, ExecutionException {
            boolean intr = false;
            try {
                synchronized (this) {
                    while (!valueSet.get()) {
                        try {
                            wait();
                        } catch (InterruptedException e) {
                            intr = true;
                        }
                    }
                }
                if (exception != null) {
                    throw new ExecutionException(exception);
                }
                return result;
            } finally {
                if (intr) Thread.currentThread().interrupt();
            }
        }


        void set(final R result) {
            synchronized (this) {
                if(valueSet.compareAndSet(false, true)) {
                    this.result = result;
                    notifyAll();
                }
            }
        }

        void setException(final Exception exception) {
            synchronized (this) {
                if(valueSet.compareAndSet(false, true)) {
                    this.exception = exception;
                    notifyAll();
                }
            }
        }

        public boolean cancel(boolean mayInterruptIfRunning) {
            return false;
        }

        public boolean isCancelled() {
            return false;
        }

        public synchronized boolean isDone() {
            return result != null || exception != null;
        }

        public R get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
            return null;
        }
    }
}
TOP

Related Classes of org.jboss.as.protocol.mgmt.ManagementRequest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.