/*
* Copyright 2016 JBoss by Red Hat.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.as.domain.controller.operations.deployment;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ARCHIVE;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.CONTENT;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.HASH;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
import static org.jboss.as.server.controller.resources.DeploymentAttributes.CONTENT_HASH;
import static org.jboss.as.server.deployment.DeploymentHandlerUtil.getContentItem;
import static org.jboss.as.server.deployment.DeploymentHandlerUtil.isArchive;
import static org.jboss.as.server.deployment.DeploymentHandlerUtil.isManaged;
import java.util.Arrays;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.OperationStepHandler;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.ProcessType;
import org.jboss.as.controller.registry.Resource;
import org.jboss.as.domain.controller.logging.DomainControllerLogger;
import org.jboss.as.repository.ContentRepository;
import org.jboss.as.repository.ExplodedContentException;
import org.jboss.as.repository.HostFileRepository;
import org.jboss.as.server.deployment.ModelContentReference;
import org.jboss.dmr.ModelNode;
/**
* Handler for the "remove-content" operation over an exploded managed deployment.
* @author Emmanuel Hugonnet (c) 2016 Red Hat, inc.
*/
public class ExplodedDeploymentRemoveContentHandler implements OperationStepHandler {
private final ContentRepository contentRepository;
private final HostFileRepository fileRepository;
private final boolean backup;
/**
* Constructor for a slave Host Controller
*
* @param fileRepository
* @param contentRepository
*/
public ExplodedDeploymentRemoveContentHandler(final boolean backup, final HostFileRepository fileRepository, final ContentRepository contentRepository) {
this.contentRepository = contentRepository;
this.fileRepository = fileRepository;
this.backup = backup;
}
/**
* Constructor for a master Host Controller
*
* @param contentRepository the master content repository. If {@code null} this handler will function as a slave
* handler would.
*/
public ExplodedDeploymentRemoveContentHandler(final ContentRepository contentRepository) {
assert contentRepository != null : "Null contentRepository";
this.contentRepository = contentRepository;
this.fileRepository = null;
this.backup = false;
}
@Override
public void execute(OperationContext context, ModelNode operation) throws OperationFailedException {
if (context.getProcessType() == ProcessType.SELF_CONTAINED) {
throw DomainControllerLogger.ROOT_LOGGER.cannotRemoveContentFromSelfContainedServer();
}
final Resource deploymentResource = context.readResourceForUpdate(PathAddress.EMPTY_ADDRESS);
ModelNode deploymentModel = deploymentResource.getModel();
ModelNode contentItem = getContentItem(deploymentResource);
// Validate this op is available
if (!isManaged(contentItem)) {
throw DomainControllerLogger.ROOT_LOGGER.cannotRemoveContentFromUnmanagedDeployment();
} else if (isArchive(contentItem)) {
throw DomainControllerLogger.ROOT_LOGGER.cannotRemoveContentFromUnexplodedDeployment();
}
final PathAddress address = PathAddress.pathAddress(operation.require(OP_ADDR));
final byte[] oldHash = CONTENT_HASH.resolveModelAttribute(context, contentItem).asBytes();
final byte[] newHash;
if (fileRepository == null && contentRepository != null) { //Master DC
try {
newHash = DeploymentUploadUtil.removeContentFromExplodedAndTransformOperation(context, operation, contentRepository);
} catch (ExplodedContentException e) {
throw new OperationFailedException(e.getMessage());
}
} else { //Slave HC
newHash = DeploymentUploadUtil.synchronizeSlaveHostController(operation, address, fileRepository, contentRepository, backup, oldHash);
}
contentItem.get(CONTENT_HASH.getName()).set(newHash);
if (newHash != null) {
contentItem = new ModelNode();
contentItem.get(HASH).set(newHash);
contentItem.get(ARCHIVE).set(false);
ModelNode content = new ModelNode();
content.add(contentItem);
deploymentModel.get(CONTENT).set(content);
context.completeStep(new OperationContext.ResultHandler() {
@Override
public void handleResult(OperationContext.ResultAction resultAction, OperationContext context, ModelNode operation) {
if (resultAction == OperationContext.ResultAction.KEEP) {
if (contentRepository != null) { //Master DC or backup
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 (fileRepository != null) { // backup DC needs to pull the content
fileRepository.getDeploymentFiles(ModelContentReference.fromModelAddress(address, newHash));
}
if (contentRepository != null) {
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));
}
}
}
}
});
}
}
}