Package org.jboss.as.host.controller.mgmt

Source Code of org.jboss.as.host.controller.mgmt.RemoteDomainControllerSlaveClient$ExecuteSynchronousTransactionalRequest

package org.jboss.as.host.controller.mgmt;

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

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.jboss.as.controller.Cancellable;
import org.jboss.as.controller.ControllerResource;
import org.jboss.as.controller.ControllerTransactionContext;
import org.jboss.as.controller.ModelController;
import org.jboss.as.controller.OperationResult;
import org.jboss.as.controller.ResultHandler;
import org.jboss.as.controller.client.ModelControllerClientProtocol;
import org.jboss.as.controller.client.Operation;
import org.jboss.as.controller.remote.ModelControllerClientToModelControllerAdapter;
import org.jboss.as.controller.remote.TransactionalModelControllerOperationHandler;
import org.jboss.as.domain.controller.DomainControllerSlaveClient;
import org.jboss.as.protocol.StreamUtils;
import org.jboss.as.protocol.mgmt.ManagementRequest;
import org.jboss.as.protocol.mgmt.ManagementRequestConnectionStrategy;
import org.jboss.dmr.ModelNode;
import org.jboss.logging.Logger;

class RemoteDomainControllerSlaveClient implements DomainControllerSlaveClient {

    private static final Logger log = Logger.getLogger("org.jboss.as.domain.controller");
    private static final int CONNECTION_TIMEOUT = 5000;

    // We delegate non-transactional requests
    private final ModelController delegate;
//    private final Connection connection;
    private final String hostId;
    private final InetAddress slaveAddress;
    private final int slavePort;
//    private final ManagementRequestConnectionStrategy connectionStrategy;
    private final ThreadFactory threadFactory = Executors.defaultThreadFactory();
    private final ExecutorService executorService = Executors.newCachedThreadPool(threadFactory);

    public RemoteDomainControllerSlaveClient(String hostId, InetAddress slaveAddress, int slavePort) {
        this.hostId = hostId;
        this.slaveAddress = slaveAddress;
        this.slavePort = slavePort;
//        this.connection = connection;
        this.delegate = new ModelControllerClientToModelControllerAdapter(slaveAddress, slavePort);
//        this.connectionStrategy = new ManagementRequestConnectionStrategy.ExistingConnectionStrategy(connection);
    }

//    public RemoteDomainControllerSlaveClient(String hostId, Connection connection) {
//        this.hostId = hostId;
//        this.connection = connection;
//        this.delegate = new ModelControllerClientToModelControllerAdapter(connection);
//        this.connectionStrategy = new ManagementRequestConnectionStrategy.ExistingConnectionStrategy(connection);
//    }

    @Override
    public OperationResult execute(Operation operation, ResultHandler handler) {
        return delegate.execute(operation, handler);
    }

    @Override
    public ModelNode execute(Operation operation) throws CancellationException {
        return delegate.execute(operation);
    }

    @Override
    public ModelNode execute(final Operation operation, ControllerTransactionContext transaction) throws CancellationException {
        if (operation == null) {
            throw new IllegalArgumentException("Null operation");
        }
        try {
            return new ExecuteSynchronousTransactionalRequest(operation, transaction).executeForResult(getConnectionStrategy());
        } catch (ExecutionException e) {
            if (e.getCause() instanceof CancellationException) {
                throw new CancellationException(e.getCause().getMessage());
            }
            throw new RuntimeException("Failed to execute operation ", e);
        } catch (Exception e) {
            throw new RuntimeException("Failed to execute operation ", e);
        }
    }

    @Override
    public OperationResult execute(final Operation operation, final ResultHandler handler,
            final ControllerTransactionContext transaction) {

        if (operation == null) {
            throw new IllegalArgumentException("Null execution context");
        }
        if (handler == null) {
            throw new IllegalArgumentException("Null handler");
        }
        if (transaction == null) {
            throw new IllegalArgumentException("Null transaction");
        }

        final AsynchronousOperation result = new AsynchronousOperation();
        executorService.execute (new Runnable() {
            @Override
            public void run() {
                try {
                    Future<ModelNode> f = new ExecuteAsyncTransactionalRequest(result, operation, handler, transaction).execute(getConnectionStrategy());

                    while (true) {
                        try {
                            //Avoid this thread hanging forever if the client gets shut down
                            f.get(500, TimeUnit.MILLISECONDS);
                            break;
                        } catch (TimeoutException e) {
                            if (executorService.isShutdown()) {
                                break;
                            }
                        }
                    }

                } catch (Exception e) {
                    throw new RuntimeException("Failed to execute operation ", e);
                }
            }
        });
        return new OperationResult() {
            @Override
            public Cancellable getCancellable() {
                return result;
            }

            @Override
            public ModelNode getCompensatingOperation() {
                return result.getCompensatingOperation();
            }
        };
    }

    @Override
    public String getId() {
        return hostId;
    }

    @Override
    public boolean isActive() {
//        return connection.getPeerAddress() != null;
        try {
            return new IsActiveRequest().executeForResult(getConnectionStrategy());
        } catch (Exception e) {
            return false;
        }
    }

    private ModelNode readNode(InputStream in) throws IOException {
        ModelNode node = new ModelNode();
        node.readExternal(in);
        return node;
    }

    private ManagementRequestConnectionStrategy getConnectionStrategy() {
        return new ManagementRequestConnectionStrategy.EstablishConnectingStrategy(slaveAddress, slavePort,
                CONNECTION_TIMEOUT, executorService, threadFactory);
    }

    private abstract class ModelControllerRequest<T> extends ManagementRequest<T>{
        @Override
        protected byte getHandlerId() {
            return TransactionalModelControllerOperationHandler.HANDLER_ID;
        }
    }

    private class AsynchronousOperation implements Cancellable {

        private SimpleFuture<ModelNode> compensatingOperation = new SimpleFuture<ModelNode>();
        // GuardedBy compensatingOperation
        private boolean compensatingOpSet = false;
        private SimpleFuture<Integer> asynchronousId = new SimpleFuture<Integer>();

        @Override
        public boolean cancel() {
            setCompensatingOperation(new ModelNode());
            try {
                int i = asynchronousId.get().intValue();
                if (i >= 0) {
                    return new CancelAsynchronousOperationRequest(i).executeForResult(getConnectionStrategy());
                }
                else return false;
            } catch (Exception e) {
                throw new RuntimeException("Could not cancel request ", e);
            }
        }

        void setAsynchronousId(int i) {
            asynchronousId.set(Integer.valueOf(i));
        }

        void setCompensatingOperation(ModelNode compensatingOp) {
            synchronized (compensatingOperation) {
                if (!compensatingOpSet) {
                    compensatingOperation.set(compensatingOp);
                    compensatingOpSet = true;
                }
            }
        }

        ModelNode getCompensatingOperation() {
            try {
                return compensatingOperation.get();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException("Could not obtain compensating operation", e);
            } catch (ExecutionException e) {
                throw new RuntimeException("Could not obtain compensating operation", e);
            }
        }
    }

    private class ExecuteSynchronousTransactionalRequest extends TransactionalRequest<ModelNode> {

        ExecuteSynchronousTransactionalRequest(final Operation operation, final ControllerTransactionContext transaction) {
            super(operation, transaction);
        }

        @Override
        protected byte getRequestCode() {
            return TransactionalModelControllerOperationHandler.EXECUTE_TRANSACTIONAL_SYNCHRONOUS_REQUEST;
        }

        @Override
        protected byte getResponseCode() {
            return TransactionalModelControllerOperationHandler.EXECUTE_TRANSACTIONAL_SYNCHRONOUS_RESPONSE;
        }

        /** {@inheritDoc} */
        @Override
        protected ModelNode receiveResponse(InputStream input) throws IOException {
            expectHeader(input, ModelControllerClientProtocol.PARAM_OPERATION);
            return readNode(input);
        }
    }

    private class ExecuteAsyncTransactionalRequest extends TransactionalRequest<ModelNode> {

        private final AsynchronousOperation result;
        private final ResultHandler handler;

        ExecuteAsyncTransactionalRequest(final AsynchronousOperation result, final Operation operation,
                final ResultHandler handler, final ControllerTransactionContext transaction) {
            super(operation, transaction);
            this.result = result;
            this.handler = handler;
        }

        @Override
        protected byte getRequestCode() {
            return TransactionalModelControllerOperationHandler.EXECUTE_TRANSACTIONAL_REQUEST;
        }

        @Override
        protected byte getResponseCode() {
            return TransactionalModelControllerOperationHandler.EXECUTE_TRANSACTIONAL_RESPONSE;
        }

        /** {@inheritDoc} */
        @Override
        protected ModelNode receiveResponse(InputStream input) throws IOException {
            try {
                LOOP:
                while (true) {
                    int command = input.read();
                    switch (command) {
                        case ModelControllerClientProtocol.PARAM_OPERATION : {
                            result.setCompensatingOperation(readNode(input));
                            break;
                        }
                        case ModelControllerClientProtocol.PARAM_HANDLE_RESULT_FRAGMENT:{
                            expectHeader(input, ModelControllerClientProtocol.PARAM_LOCATION);
                            int length = StreamUtils.readInt(input);
                            String[] location = new String[length];
                            for (int i = 0 ; i < length ; i++) {
                                location[i] = StreamUtils.readUTFZBytes(input);
                            }
                            expectHeader(input, ModelControllerClientProtocol.PARAM_OPERATION);
                            ModelNode node = readNode(input);
                            handler.handleResultFragment(location, node);
                            break;
                        }
                        case ModelControllerClientProtocol.PARAM_HANDLE_CANCELLATION:{
                            handler.handleCancellation();
                            break LOOP;
                        }
                        case ModelControllerClientProtocol.PARAM_HANDLE_RESULT_FAILED:{
                            ModelNode node = readNode(input);
                            handler.handleFailed(node);
                            break LOOP;
                        }
                        case ModelControllerClientProtocol.PARAM_HANDLE_RESULT_COMPLETE:{
                            handler.handleResultComplete();
                            break LOOP;
                        }
                        case ModelControllerClientProtocol.PARAM_REQUEST_ID:{
                            result.setAsynchronousId(StreamUtils.readInt(input));
                            break;
                        }
                        default:{
                            throw new IllegalStateException("Unknown response code " + command);
                        }
                    }
                }
            } catch (Exception e) {
                handler.handleFailed(new ModelNode().set(e.toString()));
            }
            return null;
        }
    }

    private abstract class TransactionalRequest<T> extends ModelControllerRequest<T> {

        private final Operation operation;
        private final ModelNode transactionId;

        TransactionalRequest(final Operation operation, final ControllerTransactionContext transaction) {
            this.operation = operation;
            this.transactionId = transaction.getTransactionId();
            transaction.registerResource(new ControllerResourceProxy(transactionId));
        }

        /** {@inheritDoc} */
        @Override
        protected void sendRequest(int protocolVersion, OutputStream output) throws IOException {
            output.write(TransactionalModelControllerOperationHandler.TRANSACTION_ID);
            transactionId.writeExternal(output);
            output.write(ModelControllerClientProtocol.PARAM_OPERATION);
            operation.getOperation().writeExternal(output);

            List<InputStream> streams = operation.getInputStreams();
            for (InputStream in : streams) {
                output.write(ModelControllerClientProtocol.PARAM_INPUT_STREAM);
                //Just copy the stream contents for now - remoting will handle this better
                ByteArrayOutputStream bout = new ByteArrayOutputStream();
                try {
                    byte[] buffer = new byte[8192];
                    int read;
                    while ((read = in.read(buffer)) != -1) {
                        bout.write(buffer, 0, read);
                    }
                } finally {
                    StreamUtils.safeClose(in);
                }

                byte[] bytes = bout.toByteArray();
                StreamUtils.writeInt(output, bytes.length);
                try {
                    for (byte b : bytes) {
                        output.write(b);
                    }
                } finally {
                    StreamUtils.safeClose(in);
                }
            }
            output.write(ModelControllerClientProtocol.PARAM_REQUEST_END);
        }
    }

    private class CommitTransactionRequest extends ModelControllerRequest<Boolean> {

        private final ModelNode transactionId;

        CommitTransactionRequest(final ModelNode transactionId) {
            this.transactionId = transactionId;
        }

        @Override
        protected byte getRequestCode() {
            return TransactionalModelControllerOperationHandler.TRANSACTION_COMMIT_REQUEST;
        }

        @Override
        protected byte getResponseCode() {
            return TransactionalModelControllerOperationHandler.TRANSACTION_COMMIT_RESPONSE;
        }

        /** {@inheritDoc} */
        @Override
        protected void sendRequest(int protocolVersion, OutputStream output) throws IOException {
            output.write(TransactionalModelControllerOperationHandler.TRANSACTION_ID);
            transactionId.writeExternal(output);
        }
    }

    private class RollbackTransactionRequest extends ModelControllerRequest<Boolean> {

        private final ModelNode transactionId;

        RollbackTransactionRequest(final ModelNode transactionId) {
            this.transactionId = transactionId;
        }

        @Override
        protected byte getRequestCode() {
            return TransactionalModelControllerOperationHandler.TRANSACTION_ROLLBACK_REQUEST;
        }

        @Override
        protected byte getResponseCode() {
            return TransactionalModelControllerOperationHandler.TRANSACTION_ROLLBACK_RESPONSE;
        }

        /** {@inheritDoc} */
        @Override
        protected void sendRequest(int protocolVersion, OutputStream output) throws IOException {
            output.write(TransactionalModelControllerOperationHandler.TRANSACTION_ID);
            transactionId.writeExternal(output);
        }
    }

    private class ControllerResourceProxy implements ControllerResource {

        private final ModelNode transactionId;

        ControllerResourceProxy(final ModelNode transactionId) {
            this.transactionId = transactionId;
        }

        @Override
        public void commit() {
            try {
                new CommitTransactionRequest(transactionId).executeForResult(getConnectionStrategy());
            } catch (Exception e) {
                log.errorf(e, "Failed committing management transaction %s on host %s", transactionId, hostId);
                // TODO flag the host as out of sync
            }
        }

        @Override
        public void rollback() {
            try {
                new RollbackTransactionRequest(transactionId).executeForResult(getConnectionStrategy());
            } catch (Exception e) {
                // Less serious as failing to roll back just means the tx is sitting around
                log.warnf(e, "Failed rolling back management transaction %s on host %s", transactionId, hostId);
            }
        }
    }

    private class CancelAsynchronousOperationRequest extends ModelControllerRequest<Boolean> {

        private final int asynchronousId;

        CancelAsynchronousOperationRequest(int asynchronousId) {
            this.asynchronousId = asynchronousId;
        }

        @Override
        protected byte getRequestCode() {
            return ModelControllerClientProtocol.CANCEL_ASYNCHRONOUS_OPERATION_REQUEST;
        }

        @Override
        protected byte getResponseCode() {
            return ModelControllerClientProtocol.CANCEL_ASYNCHRONOUS_OPERATION_RESPONSE;
        }

        /** {@inheritDoc} */
        @Override
        protected void sendRequest(int protocolVersion, OutputStream output) throws IOException {
            output.write(ModelControllerClientProtocol.PARAM_REQUEST_ID);
            StreamUtils.writeInt(output, asynchronousId);
        }


        /** {@inheritDoc} */
        @Override
        protected Boolean receiveResponse(InputStream input) throws IOException {
            return StreamUtils.readBoolean(input);
        }
    }

    private class IsActiveRequest extends ModelControllerRequest<Boolean> {
        @Override
        public final byte getRequestCode() {
            return DomainControllerProtocol.IS_ACTIVE_REQUEST;
        }

        @Override
        protected final byte getResponseCode() {
            return DomainControllerProtocol.IS_ACTIVE_RESPONSE;
        }

        @Override
        protected Boolean receiveResponse(final InputStream input) throws IOException {
            return true// If we made it here, we correctly established a connection
        }
    }

}
TOP

Related Classes of org.jboss.as.host.controller.mgmt.RemoteDomainControllerSlaveClient$ExecuteSynchronousTransactionalRequest

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.