@Override public void execute(final OperationContext context, final ModelNode operation) throws OperationFailedException { if (context.hasFailureDescription()) { // abort context.setRollbackOnly(); context.completeStep(); return; } final Set<String> outstanding = new HashSet<String>(hostProxies.keySet()); final List< TransactionalProtocolClient.PreparedOperation<HostControllerUpdateTask.ProxyOperation>> results = new ArrayList< TransactionalProtocolClient.PreparedOperation< HostControllerUpdateTask.ProxyOperation>>(); final Map<String, HostControllerUpdateTask.ExecutedHostRequest> finalResults = new HashMap<String, HostControllerUpdateTask.ExecutedHostRequest>(); final HostControllerUpdateTask.ProxyOperationListener listener = new HostControllerUpdateTask.ProxyOperationListener(); for (Map.Entry<String, ProxyController> entry : hostProxies.entrySet()) { // Create the proxy task final String host = entry.getKey(); final TransformingProxyController proxyController = (TransformingProxyController) entry.getValue(); List<DomainOperationTransformer> transformers = context.getAttachment(OperationAttachments.SLAVE_SERVER_OPERATION_TRANSFORMERS); ModelNode op = operation; if (transformers != null) { for (final DomainOperationTransformer transformer : transformers) { op = transformer.transform(context, op); } } final HostControllerUpdateTask task = new HostControllerUpdateTask(host, op.clone(), context, proxyController); // Execute the operation on the remote host final HostControllerUpdateTask.ExecutedHostRequest finalResult = task.execute(listener); finalResults.put(host, finalResult); } // Wait for all hosts to reach the prepared state boolean interrupted = false; try { try { while (outstanding.size() > 0) { final TransactionalProtocolClient.PreparedOperation< HostControllerUpdateTask.ProxyOperation> prepared = listener.retrievePreparedOperation(); final String hostName = prepared.getOperation().getName(); if (!outstanding.remove(hostName)) { continue; } final ModelNode preparedResult = prepared.getPreparedResult(); if (HOST_CONTROLLER_LOGGER.isTraceEnabled()) { HOST_CONTROLLER_LOGGER.tracef( "Preliminary result for remote host %s is %s", hostName, preparedResult); } domainOperationContext.addHostControllerResult(hostName, preparedResult); results.add(prepared); } } catch (InterruptedException ie) { interrupted = true; // Set rollback only domainOperationContext.setFailureReported(true); // Rollback all HCs for (final HostControllerUpdateTask.ExecutedHostRequest finalResult : finalResults.values()) { finalResult.asyncCancel(); } // Wait that all hosts are rolled back!? for (final Map.Entry<String, HostControllerUpdateTask.ExecutedHostRequest> entry : finalResults.entrySet()) { final String hostName = entry.getKey(); try { final HostControllerUpdateTask.ExecutedHostRequest request = entry.getValue(); final ModelNode result = request.getFinalResult().get(); final ModelNode transformedResult = request.transformResult(result); domainOperationContext.addHostControllerResult(hostName, transformedResult); } catch (Exception e) { final ModelNode result = new ModelNode(); result.get(OUTCOME).set(FAILED); if (e instanceof InterruptedException) { result .get(FAILURE_DESCRIPTION) .set(MESSAGES.interruptedAwaitingResultFromHost(entry.getKey())); interrupted = true; } else { result .get(FAILURE_DESCRIPTION) .set(MESSAGES.exceptionAwaitingResultFromHost(entry.getKey(), e.getMessage())); } domainOperationContext.addHostControllerResult(hostName, result); } } } context.completeStep(); } finally { try { // Inform the remote hosts whether to commit or roll back their updates // Do this in parallel boolean rollback = domainOperationContext.isCompleteRollback(); for (final TransactionalProtocolClient.PreparedOperation< HostControllerUpdateTask.ProxyOperation> prepared : results) { if (prepared.isDone()) { continue; } if (!rollback) { prepared.commit(); } else { prepared.rollback(); } } // Now get the final results from the hosts for (final TransactionalProtocolClient.PreparedOperation< HostControllerUpdateTask.ProxyOperation> prepared : results) { final String hostName = prepared.getOperation().getName(); try { final ModelNode finalResult = prepared.getFinalResult().get(); domainOperationContext.addHostControllerResult(hostName, finalResult); if (HOST_CONTROLLER_LOGGER.isTraceEnabled()) { HOST_CONTROLLER_LOGGER.tracef( "Final result for remote host %s is %s", hostName, finalResult); } } catch (InterruptedException e) { interrupted = true; CONTROLLER_LOGGER.interruptedAwaitingFinalResponse(hostName); } catch (ExecutionException e) { CONTROLLER_LOGGER.caughtExceptionAwaitingFinalResponse(e.getCause(), hostName); } } } finally { if (interrupted) { Thread.currentThread().interrupt(); } } } }