private CountDownLatch copy(
     ExecutorService executor, List<String> relativePaths, String managementName, byte[] newHash)
     throws IOException {
   final CountDownLatch result;
   Path runtimeDeployedPath =
       DeploymentHandlerUtil.getExplodedDeploymentRoot(serverEnvironment, managementName);
   if (Files.exists(runtimeDeployedPath)) {
     result = new CountDownLatch(1);
     Runnable r =
         new Runnable() {
           @Override
           public void run() {
             try {
               contentRepository.copyExplodedContentFiles(
                   newHash, relativePaths, runtimeDeployedPath);
             } catch (ExplodedContentException ex) {
               ServerLogger.DEPLOYMENT_LOGGER.couldNotCopyFiles(ex, managementName);
             } finally {
               result.countDown();
             }
           }
         };
     executor.submit(r);
   } else {
     result = null;
   }
   return result;
 }
 @Override
 public void execute(OperationContext context, ModelNode operation)
     throws OperationFailedException {
   if (context.getProcessType() == ProcessType.SELF_CONTAINED) {
     throw ServerLogger.ROOT_LOGGER.cannotAddContentToSelfContainedServer();
   }
   final Resource deploymentResource = context.readResourceForUpdate(PathAddress.EMPTY_ADDRESS);
   ModelNode contentItemNode = getContentItem(deploymentResource);
   // Validate this op is available
   if (!isManaged(contentItemNode)) {
     throw ServerLogger.ROOT_LOGGER.cannotAddContentToUnmanagedDeployment();
   } else if (isArchive(contentItemNode)) {
     throw ServerLogger.ROOT_LOGGER.cannotAddContentToUnexplodedDeployment();
   }
   final String managementName = context.getCurrentAddress().getLastElement().getValue();
   final PathAddress address = PathAddress.pathAddress(DEPLOYMENT, managementName);
   final byte[] oldHash = CONTENT_HASH.resolveModelAttribute(context, contentItemNode).asBytes();
   final boolean overwrite = OVERWRITE.resolveModelAttribute(context, operation).asBoolean(true);
   List<ModelNode> contents = EXPLODED_CONTENT.resolveModelAttribute(context, operation).asList();
   final List<ExplodedContent> addedFiles = new ArrayList<>(contents.size());
   final byte[] newHash;
   if (contents.size() == 1 && contents.get(0).hasDefined(HASH)) {
     newHash =
         DeploymentHandlerUtil.addFromHash(
             contentRepository, contents.get(0), managementName, address, context);
     if (operation.hasDefined(DeploymentAttributes.UPDATED_PATHS.getName())) {
       for (ModelNode addedFile :
           DeploymentAttributes.UPDATED_PATHS.resolveModelAttribute(context, operation).asList()) {
         addedFiles.add(new ExplodedContent(addedFile.asString()));
       }
     }
   } else {
     for (ModelNode content : contents) {
       InputStream in;
       if (DeploymentHandlerUtils.hasValidContentAdditionParameterDefined(content)) {
         in = DeploymentHandlerUtils.getInputStream(context, content);
       } else {
         in = null;
       }
       String path = TARGET_PATH.resolveModelAttribute(context, content).asString();
       addedFiles.add(new ExplodedContent(path, in));
     }
     try {
       newHash = contentRepository.addContentToExploded(oldHash, addedFiles, overwrite);
     } catch (ExplodedContentException e) {
       throw createFailureException(e.toString());
     }
   }
   final List<String> relativePaths =
       addedFiles.stream().map(ExplodedContent::getRelativePath).collect(Collectors.toList());
   contentItemNode.get(CONTENT_HASH.getName()).set(newHash);
   contentItemNode.get(CONTENT_ARCHIVE.getName()).set(false);
   if (!addedFiles.isEmpty()
       && ENABLED.resolveModelAttribute(context, deploymentResource.getModel()).asBoolean()) {
     context.addStep(
         new OperationStepHandler() {
           @Override
           public void execute(OperationContext context, ModelNode operation)
               throws OperationFailedException {
             try {
               ExecutorService executor =
                   (ExecutorService)
                       context
                           .getServiceRegistry(false)
                           .getRequiredService(JBOSS_SERVER_EXECUTOR)
                           .getValue();
               CountDownLatch latch = copy(executor, relativePaths, managementName, newHash);
               if (latch != null) {
                 try {
                   if (!latch.await(60, TimeUnit.SECONDS)) {
                     return;
                   }
                 } catch (InterruptedException e) {
                   Thread.currentThread().interrupt();
                   throw createFailureException(e.toString());
                 }
               }
             } catch (IOException e) {
               throw createFailureException(e.toString());
             }
           }
         },
         OperationContext.Stage.RUNTIME);
   }
   context.completeStep(
       new OperationContext.ResultHandler() {
         @Override
         public void handleResult(
             ResultAction resultAction, OperationContext context, ModelNode operation) {
           if (resultAction == ResultAction.KEEP) {
             if (oldHash != null && (newHash == null || !Arrays.equals(oldHash, newHash))) {
               // The old content is no longer used; clean from repos
               contentRepository.removeContent(
                   ModelContentReference.fromModelAddress(address, oldHash));
             }
             if (newHash != null) {
               contentRepository.addContentReference(
                   ModelContentReference.fromModelAddress(address, newHash));
             }
           } else if (newHash != null && (oldHash == null || !Arrays.equals(oldHash, newHash))) {
             // Due to rollback, the new content isn't used; clean from repos
             contentRepository.removeContent(
                 ModelContentReference.fromModelAddress(address, newHash));
           }
         }
       });
 }