PageRenderTime 43ms CodeModel.GetById 18ms 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. */
  19. package org.jboss.as.controller.client.impl;
  20. import java.io.ByteArrayOutputStream;
  21. import java.io.DataInput;
  22. import java.io.IOException;
  23. import java.io.InputStream;
  24. import java.util.List;
  25. import java.util.concurrent.CancellationException;
  26. import java.util.concurrent.ExecutionException;
  27. import java.util.concurrent.TimeUnit;
  28. import java.util.concurrent.TimeoutException;
  29. import org.jboss.as.controller.client.MessageSeverity;
  30. import org.jboss.as.controller.client.ModelControllerClient;
  31. import org.jboss.as.controller.client.Operation;
  32. import org.jboss.as.controller.client.OperationBuilder;
  33. import org.jboss.as.controller.client.OperationMessageHandler;
  34. import org.jboss.as.protocol.StreamUtils;
  35. import org.jboss.as.protocol.mgmt.AbstractManagementRequest;
  36. import org.jboss.as.protocol.mgmt.ActiveOperation;
  37. import org.jboss.as.protocol.mgmt.FlushableDataOutput;
  38. import org.jboss.as.protocol.mgmt.ManagementChannelAssociation;
  39. import org.jboss.as.protocol.mgmt.ManagementProtocol;
  40. import org.jboss.as.protocol.mgmt.ManagementRequest;
  41. import org.jboss.as.protocol.mgmt.ManagementRequestContext;
  42. import org.jboss.as.protocol.mgmt.ManagementRequestHandler;
  43. import org.jboss.as.protocol.mgmt.ManagementRequestHandlerFactory;
  44. import org.jboss.as.protocol.mgmt.ManagementRequestHeader;
  45. import org.jboss.as.protocol.mgmt.ManagementResponseHeader;
  46. import static org.jboss.as.protocol.mgmt.ProtocolUtils.expectHeader;
  47. import org.jboss.dmr.ModelNode;
  48. import org.jboss.threads.AsyncFuture;
  49. /**
  50. *
  51. * @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
  52. */
  53. public abstract class AbstractModelControllerClient implements ModelControllerClient, ManagementRequestHandlerFactory {
  54. private static ManagementRequestHandler<ModelNode, OperationExecutionContext> MESSAGE_HANDLER = new HandleReportRequestHandler();
  55. private static ManagementRequestHandler<ModelNode, OperationExecutionContext> GET_INPUT_STREAM = new ReadAttachmentInputStreamRequestHandler();
  56. private static final OperationMessageHandler NO_OP_HANDLER = new OperationMessageHandler() {
  57. @Override
  58. public void handleReport(MessageSeverity severity, String message) {
  59. //
  60. }
  61. };
  62. /**
  63. * Get the mgmt channel association.
  64. *
  65. * @return the channel association
  66. * @throws IOException
  67. */
  68. protected abstract ManagementChannelAssociation getChannelAssociation() throws IOException;
  69. @Override
  70. public ModelNode execute(final ModelNode operation) throws IOException {
  71. return executeForResult(OperationExecutionContext.create(operation));
  72. }
  73. @Override
  74. public ModelNode execute(final Operation operation) throws IOException {
  75. return executeForResult(OperationExecutionContext.create(operation));
  76. }
  77. @Override
  78. public ModelNode execute(final ModelNode operation, final OperationMessageHandler messageHandler) throws IOException {
  79. return executeForResult(OperationExecutionContext.create(operation, messageHandler));
  80. }
  81. @Override
  82. public ModelNode execute(Operation operation, OperationMessageHandler messageHandler) throws IOException {
  83. return executeForResult(OperationExecutionContext.create(operation, messageHandler));
  84. }
  85. @Override
  86. public AsyncFuture<ModelNode> executeAsync(final ModelNode operation, final OperationMessageHandler messageHandler) {
  87. try {
  88. return execute(OperationExecutionContext.create(operation, messageHandler));
  89. } catch (IOException e) {
  90. throw new RuntimeException(e);
  91. }
  92. }
  93. @Override
  94. public AsyncFuture<ModelNode> executeAsync(final Operation operation, final OperationMessageHandler messageHandler) {
  95. try {
  96. return execute(OperationExecutionContext.create(operation, messageHandler));
  97. } catch (IOException e) {
  98. throw new RuntimeException(e);
  99. }
  100. }
  101. @Override
  102. public ManagementRequestHandler<?, ?> resolveHandler(RequestHandlerChain handlers, ManagementRequestHeader header) {
  103. final byte operationType = header.getOperationId();
  104. if (operationType == ModelControllerProtocol.HANDLE_REPORT_REQUEST) {
  105. return MESSAGE_HANDLER;
  106. } else if (operationType == ModelControllerProtocol.GET_INPUTSTREAM_REQUEST) {
  107. return GET_INPUT_STREAM;
  108. }
  109. return handlers.resolveNext();
  110. }
  111. /**
  112. * Execute for result.
  113. *
  114. * @param executionContext the execution context
  115. * @return the result
  116. * @throws IOException for any error
  117. */
  118. private ModelNode executeForResult(final OperationExecutionContext executionContext) throws IOException {
  119. try {
  120. return execute(executionContext).get();
  121. } catch(Exception e) {
  122. throw new IOException(e);
  123. }
  124. }
  125. /**
  126. * Execute a request.
  127. *
  128. * @param executionContext the execution context
  129. * @return the future result
  130. * @throws IOException
  131. */
  132. private AsyncFuture<ModelNode> execute(final OperationExecutionContext executionContext) throws IOException {
  133. return executeRequest(new AbstractManagementRequest<ModelNode, OperationExecutionContext>() {
  134. @Override
  135. public byte getOperationType() {
  136. return ModelControllerProtocol.EXECUTE_ASYNC_CLIENT_REQUEST;
  137. }
  138. @Override
  139. protected void sendRequest(final ActiveOperation.ResultHandler<ModelNode> resultHandler,
  140. final ManagementRequestContext<OperationExecutionContext> context,
  141. final FlushableDataOutput output) throws IOException {
  142. // Write the operation
  143. final List<InputStream> streams = executionContext.operation.getInputStreams();
  144. final ModelNode operation = executionContext.operation.getOperation();
  145. int inputStreamLength = 0;
  146. if (streams != null) {
  147. inputStreamLength = streams.size();
  148. }
  149. output.write(ModelControllerProtocol.PARAM_OPERATION);
  150. operation.writeExternal(output);
  151. output.write(ModelControllerProtocol.PARAM_INPUTSTREAMS_LENGTH);
  152. output.writeInt(inputStreamLength);
  153. }
  154. @Override
  155. public void handleRequest(final DataInput input, final ActiveOperation.ResultHandler<ModelNode> resultHandler, final ManagementRequestContext<OperationExecutionContext> context) throws IOException {
  156. expectHeader(input, ModelControllerProtocol.PARAM_RESPONSE);
  157. final ModelNode node = new ModelNode();
  158. node.readExternal(input);
  159. resultHandler.done(node);
  160. expectHeader(input, ManagementProtocol.RESPONSE_END);
  161. }
  162. }, executionContext);
  163. }
  164. private static class ReadAttachmentInputStreamRequestHandler implements ManagementRequestHandler<ModelNode, OperationExecutionContext> {
  165. @Override
  166. public void handleRequest(final DataInput input, final ActiveOperation.ResultHandler<ModelNode> resultHandler,
  167. final ManagementRequestContext<OperationExecutionContext> context) throws IOException {
  168. // Read the inputStream index
  169. expectHeader(input, ModelControllerProtocol.PARAM_INPUTSTREAM_INDEX);
  170. final int index = input.readInt();
  171. context.executeAsync(new ManagementRequestContext.AsyncTask<OperationExecutionContext>() {
  172. @Override
  173. public void execute(final ManagementRequestContext<OperationExecutionContext> context) throws Exception {
  174. final OperationExecutionContext exec = context.getAttachment();
  175. final ManagementRequestHeader header = ManagementRequestHeader.class.cast(context.getRequestHeader());
  176. final ManagementResponseHeader response = new ManagementResponseHeader(header.getVersion(), header.getRequestId(), null);
  177. final InputStream is = exec.getOperation().getInputStreams().get(index);
  178. try {
  179. final ByteArrayOutputStream bout = copyStream(is);
  180. final FlushableDataOutput output = context.writeMessage(response);
  181. try {
  182. output.writeByte(ModelControllerProtocol.PARAM_INPUTSTREAM_LENGTH);
  183. output.writeInt(bout.size());
  184. output.writeByte(ModelControllerProtocol.PARAM_INPUTSTREAM_CONTENTS);
  185. output.write(bout.toByteArray());
  186. output.writeByte(ManagementProtocol.RESPONSE_END);
  187. output.close();
  188. } finally {
  189. StreamUtils.safeClose(output);
  190. }
  191. } finally {
  192. // the caller is responsible for closing the input streams
  193. // StreamUtils.safeClose(is);
  194. }
  195. }
  196. });
  197. }
  198. protected ByteArrayOutputStream copyStream(final InputStream is) throws IOException {
  199. final ByteArrayOutputStream bout = new ByteArrayOutputStream();
  200. // Hmm, a null input-stream should be a failure?
  201. if(is != null) {
  202. StreamUtils.copyStream(is, bout);
  203. }
  204. return bout;
  205. }
  206. }
  207. private static class HandleReportRequestHandler implements ManagementRequestHandler<ModelNode, OperationExecutionContext> {
  208. @Override
  209. public void handleRequest(final DataInput input, final ActiveOperation.ResultHandler<ModelNode> resultHandler, final ManagementRequestContext<OperationExecutionContext> context) throws IOException {
  210. expectHeader(input, ModelControllerProtocol.PARAM_MESSAGE_SEVERITY);
  211. final MessageSeverity severity = Enum.valueOf(MessageSeverity.class, input.readUTF());
  212. expectHeader(input, ModelControllerProtocol.PARAM_MESSAGE);
  213. final String message = input.readUTF();
  214. expectHeader(input, ManagementProtocol.REQUEST_END);
  215. final OperationExecutionContext requestContext = context.getAttachment();
  216. // perhaps execute async
  217. final OperationMessageHandler handler = requestContext.getOperationMessageHandler();
  218. handler.handleReport(severity, message);
  219. }
  220. }
  221. protected AsyncFuture<ModelNode> executeRequest(final ManagementRequest<ModelNode, OperationExecutionContext> request, final OperationExecutionContext attachment) throws IOException {
  222. final ActiveOperation<ModelNode, OperationExecutionContext> support = getChannelAssociation().executeRequest(request, attachment);
  223. return new DelegatingCancellableAsyncFuture(support.getResult(), support.getOperationId());
  224. }
  225. static class OperationExecutionContext implements ActiveOperation.CompletedCallback<ModelNode> {
  226. private final Operation operation;
  227. private final OperationMessageHandler handler;
  228. OperationExecutionContext(final Operation operation, final OperationMessageHandler handler) {
  229. this.operation = operation;
  230. this.handler = handler != null ? handler : NO_OP_HANDLER;
  231. }
  232. Operation getOperation() {
  233. return operation;
  234. }
  235. OperationMessageHandler getOperationMessageHandler() {
  236. return handler;
  237. }
  238. @Override
  239. public void completed(ModelNode result) {
  240. closeAttachments();
  241. }
  242. @Override
  243. public void failed(Exception e) {
  244. closeAttachments();
  245. }
  246. @Override
  247. public void cancelled() {
  248. closeAttachments();
  249. }
  250. private void closeAttachments() {
  251. if(operation.isAutoCloseStreams()) {
  252. StreamUtils.safeClose(operation);
  253. }
  254. }
  255. static OperationExecutionContext create(final ModelNode operation) {
  256. return create(new OperationBuilder(operation).build(), NO_OP_HANDLER);
  257. }
  258. static OperationExecutionContext create(final Operation operation) {
  259. return create(operation, NO_OP_HANDLER);
  260. }
  261. static OperationExecutionContext create(final ModelNode operation, final OperationMessageHandler handler) {
  262. return create(new OperationBuilder(operation).build(), handler);
  263. }
  264. static OperationExecutionContext create(final Operation operation, final OperationMessageHandler handler) {
  265. return new OperationExecutionContext(operation, handler);
  266. }
  267. }
  268. /**
  269. * Wraps the request execution AsyncFuture in an AsyncFuture impl that handles cancellation by sending a cancellation
  270. * request to the remote side.
  271. */
  272. private class DelegatingCancellableAsyncFuture implements AsyncFuture<ModelNode>{
  273. private final int batchId;
  274. private final AsyncFuture<ModelNode> delegate;
  275. public DelegatingCancellableAsyncFuture(AsyncFuture<ModelNode> delegate, int batchId) {
  276. this.delegate = delegate;
  277. this.batchId = batchId;
  278. }
  279. public org.jboss.threads.AsyncFuture.Status await() throws InterruptedException {
  280. return delegate.await();
  281. }
  282. public org.jboss.threads.AsyncFuture.Status await(long timeout, TimeUnit unit) throws InterruptedException {
  283. return delegate.await(timeout, unit);
  284. }
  285. public ModelNode getUninterruptibly() throws CancellationException, ExecutionException {
  286. return delegate.getUninterruptibly();
  287. }
  288. public ModelNode getUninterruptibly(long timeout, TimeUnit unit) throws CancellationException, ExecutionException, TimeoutException {
  289. return delegate.getUninterruptibly(timeout, unit);
  290. }
  291. public org.jboss.threads.AsyncFuture.Status awaitUninterruptibly() {
  292. return delegate.awaitUninterruptibly();
  293. }
  294. public org.jboss.threads.AsyncFuture.Status awaitUninterruptibly(long timeout, TimeUnit unit) {
  295. return delegate.awaitUninterruptibly(timeout, unit);
  296. }
  297. public boolean isDone() {
  298. return delegate.isDone();
  299. }
  300. public org.jboss.threads.AsyncFuture.Status getStatus() {
  301. return delegate.getStatus();
  302. }
  303. public <A> void addListener(org.jboss.threads.AsyncFuture.Listener<? super ModelNode, A> listener, A attachment) {
  304. delegate.addListener(listener, attachment);
  305. }
  306. public ModelNode get() throws InterruptedException, ExecutionException {
  307. return delegate.get();
  308. }
  309. public ModelNode get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
  310. return delegate.get(timeout, unit);
  311. }
  312. @Override
  313. public boolean isCancelled() {
  314. return delegate.getStatus() == Status.CANCELLED;
  315. }
  316. @Override
  317. public boolean cancel(boolean interruptionDesired) {
  318. asyncCancel(interruptionDesired);
  319. return awaitUninterruptibly() == Status.CANCELLED;
  320. }
  321. @Override
  322. public void asyncCancel(boolean interruptionDesired) {
  323. try {
  324. getChannelAssociation().executeRequest(batchId, new CancelAsyncRequest());
  325. } catch (Exception e) {
  326. throw new RuntimeException(e);
  327. }
  328. }
  329. }
  330. /**
  331. * Request cancelling the remote operation.
  332. */
  333. private static class CancelAsyncRequest extends AbstractManagementRequest<ModelNode, OperationExecutionContext> {
  334. @Override
  335. public byte getOperationType() {
  336. return ModelControllerProtocol.CANCEL_ASYNC_REQUEST;
  337. }
  338. @Override
  339. protected void sendRequest(ActiveOperation.ResultHandler<ModelNode> resultHandler, ManagementRequestContext<OperationExecutionContext> context, FlushableDataOutput output) throws IOException {
  340. //
  341. }
  342. @Override
  343. public void handleRequest(DataInput input, ActiveOperation.ResultHandler<ModelNode> resultHandler, ManagementRequestContext<OperationExecutionContext> context) throws IOException {
  344. // Once the remote operation returns, we can set the cancelled status
  345. resultHandler.cancel();
  346. }
  347. }
  348. }