Package org.jboss.as.controller.client.impl

Source Code of org.jboss.as.controller.client.impl.AbstractModelControllerClient$ExecuteRequestContext

/*
* JBoss, Home of Professional Open Source
* Copyright 2011 Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the @authors tag. All rights reserved.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* 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,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA  02110-1301, USA.
*/
package org.jboss.as.controller.client.impl;

import static org.jboss.as.controller.client.ControllerClientLogger.ROOT_LOGGER;
import static org.jboss.as.controller.client.ControllerClientMessages.MESSAGES;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInput;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.jboss.as.controller.client.MessageSeverity;
import org.jboss.as.controller.client.ModelControllerClient;
import org.jboss.as.controller.client.Operation;
import org.jboss.as.controller.client.OperationAttachments;
import org.jboss.as.controller.client.OperationMessageHandler;
import org.jboss.as.protocol.mgmt.FlushableDataOutput;
import org.jboss.as.protocol.mgmt.ManagementBatchIdManager;
import org.jboss.as.protocol.mgmt.ManagementClientChannelStrategy;
import org.jboss.as.protocol.mgmt.ManagementOperationHandler;
import org.jboss.as.protocol.mgmt.ManagementRequest;
import org.jboss.as.protocol.mgmt.ManagementRequestHandler;
import org.jboss.as.protocol.mgmt.ManagementResponseHandler;
import org.jboss.as.protocol.mgmt.ProtocolUtils;
import org.jboss.as.protocol.mgmt.RequestProcessingException;
import org.jboss.dmr.ModelNode;
import org.jboss.remoting3.Channel;
import org.jboss.remoting3.CloseHandler;
import org.jboss.threads.AsyncFuture;


/**
*
* @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
* @version $Revision: 1.1 $
*/
public abstract class AbstractModelControllerClient implements ModelControllerClient, ManagementOperationHandler {
    private final Map<Integer, ExecuteRequestContext> activeRequests = Collections.synchronizedMap(new HashMap<Integer, ExecuteRequestContext>());
    protected final ExecutorService executor = Executors.newCachedThreadPool();

    @Override
    public void close() throws IOException {
        executor.shutdown();
        try {
            executor.awaitTermination(2, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        executor.shutdownNow();
    }

    @Override
    public ModelNode execute(ModelNode operation) throws IOException {
        return execute(operation, null);
    }

    @Override
    public ModelNode execute(Operation operation) throws IOException {
        return execute(operation, null);
    }

    @Override
    public ModelNode execute(ModelNode operation, OperationMessageHandler messageHandler) throws IOException {
        return executeSynch(operation, null, messageHandler);
    }

    @Override
    public ModelNode execute(Operation operation, OperationMessageHandler messageHandler) throws IOException {
        return executeSynch(operation.getOperation(), operation, messageHandler);
    }

    @Override
    public AsyncFuture<ModelNode> executeAsync(ModelNode operation, OperationMessageHandler messageHandler) {
        return executeAsync(operation, null, messageHandler);
    }

    @Override
    public AsyncFuture<ModelNode> executeAsync(Operation operation, OperationMessageHandler messageHandler) {
        return executeAsync(operation.getOperation(), operation, messageHandler);
    }

    /** {@inheritDoc} */
    @Override
    public ManagementRequestHandler getRequestHandler(final byte id) {
        if (id == ModelControllerProtocol.HANDLE_REPORT_REQUEST) {
            return new HandleReportRequestHandler();
        } else if (id == ModelControllerProtocol.GET_INPUTSTREAM_REQUEST) {
            return new ReadAttachmentInputStreamRequestHandler();
        }
        return null;
    }

    protected abstract ManagementClientChannelStrategy getClientChannelStrategy() throws URISyntaxException, IOException;

    private ModelNode executeSynch(ModelNode operation, OperationAttachments attachments, OperationMessageHandler messageHandler) throws IOException {
        final int batchId = ManagementBatchIdManager.DEFAULT.createBatchId();

        try {
            return new ExecuteRequest(batchId, false, operation, messageHandler, attachments).executeForResult(executor, getClientChannelStrategy());
        } catch (Exception e) {
            ManagementBatchIdManager.DEFAULT.freeBatchId(batchId);
            Throwable cause = e;
            if (e instanceof ExecutionException) {
                cause = e.getCause();
            }
            if (cause instanceof IOException) {
                throw (IOException)cause;
            }
            if (cause instanceof RuntimeException) {
                throw (RuntimeException)cause;
            }
            throw new IOException(cause);
        }
    }

    private AsyncFuture<ModelNode> executeAsync(ModelNode operation, OperationAttachments attachments, OperationMessageHandler messageHandler) {
        final int batchId = ManagementBatchIdManager.DEFAULT.createBatchId();
        try {
            return new DelegatingCancellableAsyncFuture(new ExecuteRequest(batchId, true, operation, messageHandler, attachments).execute(executor, getClientChannelStrategy()), batchId);
        } catch (Exception e) {
            ManagementBatchIdManager.DEFAULT.freeBatchId(batchId);
            if (e instanceof RuntimeException) {
                throw (RuntimeException)e;
            }
            throw new RuntimeException(e);
        }
    }

    /**
     * Propagates an execute() call from this proxy controller to the remote target controller
     */
    private class ExecuteRequest extends ManagementRequest<ModelNode> {

        private final ExecuteRequestContext executeRequestContext;
        private final ModelNode operation;
        private final boolean async;

        ExecuteRequest(final int batchId, final boolean async, final ModelNode operation, final OperationMessageHandler messageHandler, final OperationAttachments attachments) {
            super(batchId);
            this.operation = operation;
            this.async = async;
            executeRequestContext = new ExecuteRequestContext(this, messageHandler, attachments);
        }

        @Override
        protected byte getRequestCode() {
            return async ? ModelControllerProtocol.EXECUTE_ASYNC_CLIENT_REQUEST : ModelControllerProtocol.EXECUTE_CLIENT_REQUEST;
        }

        protected CloseHandler<Channel> getRequestCloseHandler(){
            return executeRequestContext.getRequestCloseHandler();
        }

        @Override
        protected void writeRequest(final int protocolVersion, final FlushableDataOutput output) throws IOException {
            try {
                ROOT_LOGGER.tracef("Client writing request %d", getBatchId());
                activeRequests.put(getBatchId(), executeRequestContext);

                output.write(ModelControllerProtocol.PARAM_OPERATION);
                operation.writeExternal(output);
                output.write(ModelControllerProtocol.PARAM_INPUTSTREAMS_LENGTH);
                int inputStreamLength = 0;
                if (executeRequestContext.getAttachments() != null) {
                    List<InputStream> streams = executeRequestContext.getAttachments().getInputStreams();
                    if (streams != null) {
                        inputStreamLength = streams.size();
                    }
                }
                output.writeInt(inputStreamLength);
                ROOT_LOGGER.tracef("Client wrote request %d successfully", getBatchId());
            } catch (Exception e) {
                ROOT_LOGGER.tracef(e, "Client wrote request %d with error", getBatchId());
                setError(e);
                if (e instanceof IOException) {
                    throw (IOException)e;
                }
                if (e instanceof RuntimeException) {
                    throw (RuntimeException)e;
                }
                throw new IOException(e);
            }
        }

        protected ManagementResponseHandler<ModelNode> getResponseHandler() {
            return new ManagementResponseHandler<ModelNode>() {
                @Override
                protected ModelNode readResponse(final DataInput input) throws IOException {
                    ROOT_LOGGER.tracef("Client reading response %d", getBatchId());
                    try {
                        ProtocolUtils.expectHeader(input, ModelControllerProtocol.PARAM_RESPONSE);
                        ModelNode node = new ModelNode();
                        node.readExternal(input);
                        ROOT_LOGGER.tracef("Client read response %d successfully", getBatchId());
                        return node;
                    } catch (Exception e) {
                        ROOT_LOGGER.tracef(e, "Client read response %d with error", getBatchId());
                        //super.setError(new ClientException(e));
                        setError(e);
                        if (e instanceof IOException) {
                            throw (IOException)e;
                        }
                        if (e instanceof RuntimeException) {
                            throw (RuntimeException)e;
                        }
                        throw new IOException(e);
                    } finally {
                        ManagementBatchIdManager.DEFAULT.freeBatchId(getBatchId());
                        activeRequests.remove(getBatchId());
                        executeRequestContext.done();
                    }
                }
            };
        }

        @Override
        protected void setError(final Exception e) {
            super.setError(e instanceof IOException ? e : new IOException(e));
        }
    }

    /**
     * Handles {@link OperationMessageHandler#handleReport(org.jboss.as.controller.client.MessageSeverity, String)} calls
     * done in the remote target controller
     */
    private class HandleReportRequestHandler extends ManagementRequestHandler {

        @Override
        protected void readRequest(final DataInput input) throws IOException {
            int batchId = getHeader().getBatchId();
            ProtocolUtils.expectHeader(input, ModelControllerProtocol.PARAM_MESSAGE_SEVERITY);
            MessageSeverity severity = Enum.valueOf(MessageSeverity.class, input.readUTF());
            ProtocolUtils.expectHeader(input, ModelControllerProtocol.PARAM_MESSAGE);
            String message = input.readUTF();

            ExecuteRequestContext requestContext = activeRequests.get(batchId);
            if (requestContext == null) {
                throw MESSAGES.noActiveRequest(batchId);
            }
            if (requestContext.getMessageHandler() != null) {
                requestContext.getMessageHandler().handleReport(severity, message);
            }
        }

        protected void processRequest() {

        }
    }

    /**
     * Handles reads on the inputstreams returned by {@link OperationAttachments#getInputStreams()}
     * done in the remote target controller
     */
    private class ReadAttachmentInputStreamRequestHandler extends ManagementRequestHandler {
        InputStream attachmentInput;
        byte[] bytes;
        @Override
        protected void readRequest(final DataInput input) throws IOException {
            int batchId = getHeader().getBatchId();
            ROOT_LOGGER.tracef("Client got inputstream request %d",  batchId);
            ProtocolUtils.expectHeader(input, ModelControllerProtocol.PARAM_INPUTSTREAM_INDEX);
            int index = input.readInt();

            ExecuteRequestContext requestContext = activeRequests.get(batchId);
            if (requestContext == null) {
                throw MESSAGES.noActiveRequest(batchId);
            }
            InputStream in = requestContext.getAttachments().getInputStreams().get(index);
            attachmentInput = in != null ? new BufferedInputStream(in) : null;
        }

        protected void processRequest() throws RequestProcessingException {
            try {
                ByteArrayOutputStream bout = new ByteArrayOutputStream();
                if (attachmentInput != null) {
                    int i = attachmentInput.read();
                    while (i != -1) {
                        bout.write(i);
                        i = attachmentInput.read();
                    }
                }
                bytes = bout.toByteArray();
            } catch (IOException e) {
                throw new RequestProcessingException(e);
            } finally {
                //Think the caller is responsible for closing these
                //IoUtils.safeClose(attachmentInput);
            }
        }


        @Override
        protected void writeResponse(final FlushableDataOutput output) throws IOException {
            output.write(ModelControllerProtocol.PARAM_INPUTSTREAM_LENGTH);
            output.writeInt(bytes.length);
            output.write(ModelControllerProtocol.PARAM_INPUTSTREAM_CONTENTS);
            output.write(bytes);
            ROOT_LOGGER.tracef("Client handled inputstream request %d",  getHeader().getBatchId());
        }
    }

    private static class ExecuteRequestContext {
        final ExecuteRequest executeRequest;
        final OperationMessageHandler messageHandler;
        final OperationAttachments attachments;
        volatile boolean done;

        ExecuteRequestContext(final ExecuteRequest executeRequest, final OperationMessageHandler messageHandler, final OperationAttachments attachments) {
            this.executeRequest = executeRequest;
            this.messageHandler = messageHandler;
            this.attachments = attachments;
        }

        CloseHandler<Channel> getRequestCloseHandler(){
            return new CloseHandler<Channel>() {
                public void handleClose(final Channel closed, final IOException exception) {
                    if (!done) {
                        executeRequest.setError(MESSAGES.channelClosed(exception));
                    }
                }
            };
        }

        OperationMessageHandler getMessageHandler() {
            return messageHandler;
        }

        OperationAttachments getAttachments() {
            return attachments;
        }

        void done() {
            this.done = true;
        }
    }

    private class DelegatingCancellableAsyncFuture implements AsyncFuture<ModelNode>{
        private final AsyncFuture<ModelNode> delegate;
        private final int batchId;
        private volatile boolean isCancelled;

        public DelegatingCancellableAsyncFuture(AsyncFuture<ModelNode> delegate, int batchId) {
            this.delegate = delegate;
            this.batchId = batchId;
        }

        public org.jboss.threads.AsyncFuture.Status await() throws InterruptedException {
            return delegate.await();
        }

        public org.jboss.threads.AsyncFuture.Status await(long timeout, TimeUnit unit) throws InterruptedException {
            return delegate.await(timeout, unit);
        }

        public ModelNode getUninterruptibly() throws CancellationException, ExecutionException {
            return delegate.getUninterruptibly();
        }

        public ModelNode getUninterruptibly(long timeout, TimeUnit unit) throws CancellationException, ExecutionException,
                TimeoutException {
            return delegate.getUninterruptibly(timeout, unit);
        }

        public org.jboss.threads.AsyncFuture.Status awaitUninterruptibly() {
            return delegate.awaitUninterruptibly();
        }

        public org.jboss.threads.AsyncFuture.Status awaitUninterruptibly(long timeout, TimeUnit unit) {
            return delegate.awaitUninterruptibly(timeout, unit);
        }

        public boolean isDone() {
            return delegate.isDone();
        }

        public org.jboss.threads.AsyncFuture.Status getStatus() {
            return delegate.getStatus();
        }

        public <A> void addListener(org.jboss.threads.AsyncFuture.Listener<? super ModelNode, A> listener, A attachment) {
            delegate.addListener(listener, attachment);
        }

        public ModelNode get() throws InterruptedException, ExecutionException {
            return delegate.get();
        }

        public ModelNode get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
            return delegate.get(timeout, unit);
        }

        @Override
        public boolean isCancelled() {
            return isCancelled;
        }

        @Override
        public boolean cancel(boolean interruptionDesired) {
            if (!activeRequests.containsKey(batchId)) {
                return false;
            }
            try {
                new CancelAsyncRequest().executeForResult(executor, getClientChannelStrategy());
                if (isDone()) {
                    isCancelled = false;
                }
                isCancelled = true;
                return isCancelled;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }

        @Override
        public void asyncCancel(boolean interruptionDesired) {
            try {
                new CancelAsyncRequest().execute(executor, getClientChannelStrategy());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }


        private class CancelAsyncRequest extends ManagementRequest<Void>{

            public CancelAsyncRequest() {
                super(batchId);
            }

            @Override
            protected byte getRequestCode() {
                return ModelControllerProtocol.CANCEL_ASYNC_REQUEST;
            }


            @Override
            protected ManagementResponseHandler<Void> getResponseHandler() {
                return ManagementResponseHandler.EMPTY_RESPONSE;
            }
        }
    }
}
TOP

Related Classes of org.jboss.as.controller.client.impl.AbstractModelControllerClient$ExecuteRequestContext

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.