PageRenderTime 118ms CodeModel.GetById 28ms app.highlight 71ms RepoModel.GetById 1ms app.codeStats 0ms

/jboss-as-7.1.1.Final/controller-client/src/main/java/org/jboss/as/controller/client/impl/AbstractModelControllerClient.java

#
Java | 413 lines | 290 code | 65 blank | 58 comment | 13 complexity | 4cc736d359f6c3b11113b9280b76c8c6 MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0
  1/*
  2 * JBoss, Home of Professional Open Source
  3 * Copyright 2011 Red Hat Inc. and/or its affiliates and other contributors
  4 * as indicated by the @authors tag. All rights reserved.
  5 * See the copyright.txt in the distribution for a
  6 * full listing of individual contributors.
  7 *
  8 * This copyrighted material is made available to anyone wishing to use,
  9 * modify, copy, or redistribute it subject to the terms and conditions
 10 * of the GNU Lesser General Public License, v. 2.1.
 11 * This program is distributed in the hope that it will be useful, but WITHOUT A
 12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 13 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 14 * You should have received a copy of the GNU Lesser General Public License,
 15 * v.2.1 along with this distribution; if not, write to the Free Software
 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 17 * MA  02110-1301, USA.
 18 */
 19package org.jboss.as.controller.client.impl;
 20
 21import java.io.ByteArrayOutputStream;
 22import java.io.DataInput;
 23import java.io.IOException;
 24import java.io.InputStream;
 25import java.util.List;
 26import java.util.concurrent.CancellationException;
 27import java.util.concurrent.ExecutionException;
 28import java.util.concurrent.TimeUnit;
 29import java.util.concurrent.TimeoutException;
 30
 31import org.jboss.as.controller.client.MessageSeverity;
 32import org.jboss.as.controller.client.ModelControllerClient;
 33import org.jboss.as.controller.client.Operation;
 34import org.jboss.as.controller.client.OperationBuilder;
 35import org.jboss.as.controller.client.OperationMessageHandler;
 36import org.jboss.as.protocol.StreamUtils;
 37import org.jboss.as.protocol.mgmt.AbstractManagementRequest;
 38import org.jboss.as.protocol.mgmt.ActiveOperation;
 39import org.jboss.as.protocol.mgmt.FlushableDataOutput;
 40import org.jboss.as.protocol.mgmt.ManagementChannelAssociation;
 41import org.jboss.as.protocol.mgmt.ManagementProtocol;
 42import org.jboss.as.protocol.mgmt.ManagementRequest;
 43import org.jboss.as.protocol.mgmt.ManagementRequestContext;
 44import org.jboss.as.protocol.mgmt.ManagementRequestHandler;
 45import org.jboss.as.protocol.mgmt.ManagementRequestHandlerFactory;
 46import org.jboss.as.protocol.mgmt.ManagementRequestHeader;
 47import org.jboss.as.protocol.mgmt.ManagementResponseHeader;
 48import static org.jboss.as.protocol.mgmt.ProtocolUtils.expectHeader;
 49import org.jboss.dmr.ModelNode;
 50import org.jboss.threads.AsyncFuture;
 51
 52
 53/**
 54 *
 55 * @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
 56 */
 57public abstract class AbstractModelControllerClient implements ModelControllerClient, ManagementRequestHandlerFactory {
 58
 59    private static ManagementRequestHandler<ModelNode, OperationExecutionContext> MESSAGE_HANDLER = new HandleReportRequestHandler();
 60    private static ManagementRequestHandler<ModelNode, OperationExecutionContext> GET_INPUT_STREAM = new ReadAttachmentInputStreamRequestHandler();
 61
 62    private static final OperationMessageHandler NO_OP_HANDLER = new OperationMessageHandler() {
 63
 64        @Override
 65        public void handleReport(MessageSeverity severity, String message) {
 66            //
 67        }
 68
 69    };
 70
 71    /**
 72     * Get the mgmt channel association.
 73     *
 74     * @return the channel association
 75     * @throws IOException
 76     */
 77    protected abstract ManagementChannelAssociation getChannelAssociation() throws IOException;
 78
 79    @Override
 80    public ModelNode execute(final ModelNode operation) throws IOException {
 81        return executeForResult(OperationExecutionContext.create(operation));
 82    }
 83
 84    @Override
 85    public ModelNode execute(final Operation operation) throws IOException {
 86        return executeForResult(OperationExecutionContext.create(operation));
 87    }
 88
 89    @Override
 90    public ModelNode execute(final ModelNode operation, final OperationMessageHandler messageHandler) throws IOException {
 91        return executeForResult(OperationExecutionContext.create(operation, messageHandler));
 92    }
 93
 94    @Override
 95    public ModelNode execute(Operation operation, OperationMessageHandler messageHandler) throws IOException {
 96        return executeForResult(OperationExecutionContext.create(operation, messageHandler));
 97    }
 98
 99    @Override
100    public AsyncFuture<ModelNode> executeAsync(final ModelNode operation, final OperationMessageHandler messageHandler) {
101        try {
102            return execute(OperationExecutionContext.create(operation, messageHandler));
103        } catch (IOException e)  {
104            throw new RuntimeException(e);
105        }
106    }
107
108    @Override
109    public AsyncFuture<ModelNode> executeAsync(final Operation operation, final OperationMessageHandler messageHandler) {
110        try {
111            return execute(OperationExecutionContext.create(operation, messageHandler));
112        } catch (IOException e) {
113            throw new RuntimeException(e);
114        }
115    }
116
117    @Override
118    public ManagementRequestHandler<?, ?> resolveHandler(RequestHandlerChain handlers, ManagementRequestHeader header) {
119        final byte operationType = header.getOperationId();
120        if (operationType == ModelControllerProtocol.HANDLE_REPORT_REQUEST) {
121            return MESSAGE_HANDLER;
122        } else if (operationType == ModelControllerProtocol.GET_INPUTSTREAM_REQUEST) {
123            return GET_INPUT_STREAM;
124        }
125        return handlers.resolveNext();
126    }
127
128    /**
129     * Execute for result.
130     *
131     * @param executionContext the execution context
132     * @return the result
133     * @throws IOException for any error
134     */
135    private ModelNode executeForResult(final OperationExecutionContext executionContext) throws IOException {
136        try {
137            return execute(executionContext).get();
138        } catch(Exception e) {
139            throw new IOException(e);
140        }
141    }
142
143    /**
144     * Execute a request.
145     *
146     * @param executionContext the execution context
147     * @return the future result
148     * @throws IOException
149     */
150    private AsyncFuture<ModelNode> execute(final OperationExecutionContext executionContext) throws IOException {
151        return executeRequest(new AbstractManagementRequest<ModelNode, OperationExecutionContext>() {
152
153            @Override
154            public byte getOperationType() {
155                return ModelControllerProtocol.EXECUTE_ASYNC_CLIENT_REQUEST;
156            }
157
158            @Override
159            protected void sendRequest(final ActiveOperation.ResultHandler<ModelNode> resultHandler,
160                                       final ManagementRequestContext<OperationExecutionContext> context,
161                                       final FlushableDataOutput output) throws IOException {
162                // Write the operation
163                final List<InputStream> streams = executionContext.operation.getInputStreams();
164                final ModelNode operation = executionContext.operation.getOperation();
165                int inputStreamLength = 0;
166                if (streams != null) {
167                    inputStreamLength = streams.size();
168                }
169                output.write(ModelControllerProtocol.PARAM_OPERATION);
170                operation.writeExternal(output);
171                output.write(ModelControllerProtocol.PARAM_INPUTSTREAMS_LENGTH);
172                output.writeInt(inputStreamLength);
173            }
174
175            @Override
176            public void handleRequest(final DataInput input, final ActiveOperation.ResultHandler<ModelNode> resultHandler, final ManagementRequestContext<OperationExecutionContext> context) throws IOException {
177                expectHeader(input, ModelControllerProtocol.PARAM_RESPONSE);
178                final ModelNode node = new ModelNode();
179                node.readExternal(input);
180                resultHandler.done(node);
181                expectHeader(input, ManagementProtocol.RESPONSE_END);
182            }
183        }, executionContext);
184    }
185
186    private static class ReadAttachmentInputStreamRequestHandler implements ManagementRequestHandler<ModelNode, OperationExecutionContext> {
187
188        @Override
189        public void handleRequest(final DataInput input, final ActiveOperation.ResultHandler<ModelNode> resultHandler,
190                              final ManagementRequestContext<OperationExecutionContext> context) throws IOException {
191            // Read the inputStream index
192            expectHeader(input, ModelControllerProtocol.PARAM_INPUTSTREAM_INDEX);
193            final int index = input.readInt();
194            context.executeAsync(new ManagementRequestContext.AsyncTask<OperationExecutionContext>() {
195                @Override
196                public void execute(final ManagementRequestContext<OperationExecutionContext> context) throws Exception {
197                    final OperationExecutionContext exec = context.getAttachment();
198                    final ManagementRequestHeader header = ManagementRequestHeader.class.cast(context.getRequestHeader());
199                    final ManagementResponseHeader response = new ManagementResponseHeader(header.getVersion(), header.getRequestId(), null);
200                    final InputStream is = exec.getOperation().getInputStreams().get(index);
201                    try {
202                        final ByteArrayOutputStream bout = copyStream(is);
203                        final FlushableDataOutput output = context.writeMessage(response);
204                        try {
205                            output.writeByte(ModelControllerProtocol.PARAM_INPUTSTREAM_LENGTH);
206                            output.writeInt(bout.size());
207                            output.writeByte(ModelControllerProtocol.PARAM_INPUTSTREAM_CONTENTS);
208                            output.write(bout.toByteArray());
209                            output.writeByte(ManagementProtocol.RESPONSE_END);
210                            output.close();
211                        } finally {
212                            StreamUtils.safeClose(output);
213                        }
214                    } finally {
215                        // the caller is responsible for closing the input streams
216                        // StreamUtils.safeClose(is);
217                    }
218                }
219            });
220        }
221
222        protected ByteArrayOutputStream copyStream(final InputStream is) throws IOException {
223            final ByteArrayOutputStream bout = new ByteArrayOutputStream();
224            // Hmm, a null input-stream should be a failure?
225            if(is != null) {
226                StreamUtils.copyStream(is, bout);
227            }
228            return bout;
229        }
230
231    }
232
233    private static class HandleReportRequestHandler implements ManagementRequestHandler<ModelNode, OperationExecutionContext> {
234
235        @Override
236        public void handleRequest(final DataInput input, final ActiveOperation.ResultHandler<ModelNode> resultHandler, final ManagementRequestContext<OperationExecutionContext> context) throws IOException {
237            expectHeader(input, ModelControllerProtocol.PARAM_MESSAGE_SEVERITY);
238            final MessageSeverity severity = Enum.valueOf(MessageSeverity.class, input.readUTF());
239            expectHeader(input, ModelControllerProtocol.PARAM_MESSAGE);
240            final String message = input.readUTF();
241            expectHeader(input, ManagementProtocol.REQUEST_END);
242
243            final OperationExecutionContext requestContext = context.getAttachment();
244            // perhaps execute async
245            final OperationMessageHandler handler = requestContext.getOperationMessageHandler();
246            handler.handleReport(severity, message);
247        }
248
249    }
250
251    protected AsyncFuture<ModelNode> executeRequest(final ManagementRequest<ModelNode, OperationExecutionContext> request, final OperationExecutionContext attachment) throws IOException {
252        final ActiveOperation<ModelNode, OperationExecutionContext> support = getChannelAssociation().executeRequest(request, attachment);
253        return new DelegatingCancellableAsyncFuture(support.getResult(), support.getOperationId());
254    }
255
256    static class OperationExecutionContext implements ActiveOperation.CompletedCallback<ModelNode> {
257
258        private final Operation operation;
259        private final OperationMessageHandler handler;
260
261        OperationExecutionContext(final Operation operation, final OperationMessageHandler handler) {
262            this.operation = operation;
263            this.handler = handler != null ? handler : NO_OP_HANDLER;
264        }
265
266        Operation getOperation() {
267            return operation;
268        }
269
270        OperationMessageHandler getOperationMessageHandler() {
271            return handler;
272        }
273
274        @Override
275        public void completed(ModelNode result) {
276            closeAttachments();
277        }
278
279        @Override
280        public void failed(Exception e) {
281            closeAttachments();
282        }
283
284        @Override
285        public void cancelled() {
286            closeAttachments();
287        }
288
289        private void closeAttachments() {
290            if(operation.isAutoCloseStreams()) {
291                StreamUtils.safeClose(operation);
292            }
293        }
294
295        static OperationExecutionContext create(final ModelNode operation) {
296            return create(new OperationBuilder(operation).build(), NO_OP_HANDLER);
297        }
298
299        static OperationExecutionContext create(final Operation operation) {
300            return create(operation, NO_OP_HANDLER);
301        }
302
303        static OperationExecutionContext create(final ModelNode operation, final OperationMessageHandler handler) {
304            return create(new OperationBuilder(operation).build(), handler);
305        }
306
307        static OperationExecutionContext create(final Operation operation, final OperationMessageHandler handler) {
308            return new OperationExecutionContext(operation, handler);
309        }
310
311    }
312
313    /**
314     * Wraps the request execution AsyncFuture in an AsyncFuture impl that handles cancellation by sending a cancellation
315     * request to the remote side.
316     */
317    private class DelegatingCancellableAsyncFuture implements AsyncFuture<ModelNode>{
318        private final int batchId;
319        private final AsyncFuture<ModelNode> delegate;
320
321        public DelegatingCancellableAsyncFuture(AsyncFuture<ModelNode> delegate, int batchId) {
322            this.delegate = delegate;
323            this.batchId = batchId;
324        }
325
326        public org.jboss.threads.AsyncFuture.Status await() throws InterruptedException {
327            return delegate.await();
328        }
329
330        public org.jboss.threads.AsyncFuture.Status await(long timeout, TimeUnit unit) throws InterruptedException {
331            return delegate.await(timeout, unit);
332        }
333
334        public ModelNode getUninterruptibly() throws CancellationException, ExecutionException {
335            return delegate.getUninterruptibly();
336        }
337
338        public ModelNode getUninterruptibly(long timeout, TimeUnit unit) throws CancellationException, ExecutionException, TimeoutException {
339            return delegate.getUninterruptibly(timeout, unit);
340        }
341
342        public org.jboss.threads.AsyncFuture.Status awaitUninterruptibly() {
343            return delegate.awaitUninterruptibly();
344        }
345
346        public org.jboss.threads.AsyncFuture.Status awaitUninterruptibly(long timeout, TimeUnit unit) {
347            return delegate.awaitUninterruptibly(timeout, unit);
348        }
349
350        public boolean isDone() {
351            return delegate.isDone();
352        }
353
354        public org.jboss.threads.AsyncFuture.Status getStatus() {
355            return delegate.getStatus();
356        }
357
358        public <A> void addListener(org.jboss.threads.AsyncFuture.Listener<? super ModelNode, A> listener, A attachment) {
359            delegate.addListener(listener, attachment);
360        }
361
362        public ModelNode get() throws InterruptedException, ExecutionException {
363            return delegate.get();
364        }
365
366        public ModelNode get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
367            return delegate.get(timeout, unit);
368        }
369
370        @Override
371        public boolean isCancelled() {
372            return delegate.getStatus() == Status.CANCELLED;
373        }
374
375        @Override
376        public boolean cancel(boolean interruptionDesired) {
377            asyncCancel(interruptionDesired);
378            return awaitUninterruptibly() == Status.CANCELLED;
379        }
380
381        @Override
382        public void asyncCancel(boolean interruptionDesired) {
383            try {
384                getChannelAssociation().executeRequest(batchId, new CancelAsyncRequest());
385            } catch (Exception e) {
386                throw new RuntimeException(e);
387            }
388        }
389    }
390
391    /**
392     * Request cancelling the remote operation.
393     */
394    private static class CancelAsyncRequest extends AbstractManagementRequest<ModelNode, OperationExecutionContext> {
395
396        @Override
397        public byte getOperationType() {
398            return ModelControllerProtocol.CANCEL_ASYNC_REQUEST;
399        }
400
401        @Override
402        protected void sendRequest(ActiveOperation.ResultHandler<ModelNode> resultHandler, ManagementRequestContext<OperationExecutionContext> context, FlushableDataOutput output) throws IOException {
403            //
404        }
405
406        @Override
407        public void handleRequest(DataInput input, ActiveOperation.ResultHandler<ModelNode> resultHandler, ManagementRequestContext<OperationExecutionContext> context) throws IOException {
408            // Once the remote operation returns, we can set the cancelled status
409            resultHandler.cancel();
410        }
411    }
412
413}