/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}