/* * JBoss, Home of Professional Open Source * Copyright 2011 Red Hat Inc. and/or its affiliates and other contributors * as indicated by the @authors tag. All rights reserved. * See the copyright.txt in the distribution for a * full listing of individual contributors. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License, v. 2.1. * This program is distributed in the hope that it will be useful, but WITHOUT A * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public License, * v.2.1 along with this distribution; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ package org.jboss.as.domain.controller.operations.deployment; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR; import static org.jboss.as.server.controller.resources.DeploymentAttributes.CONTENT_ARCHIVE; import static org.jboss.as.server.controller.resources.DeploymentAttributes.CONTENT_HASH; import static org.jboss.as.server.controller.resources.DeploymentAttributes.CONTENT_RESOURCE; import static org.jboss.as.server.controller.resources.DeploymentAttributes.DOMAIN_ADD_ATTRIBUTES; import static org.jboss.as.server.controller.resources.DeploymentAttributes.EMPTY; import static org.jboss.as.server.controller.resources.DeploymentAttributes.RUNTIME_NAME; import java.io.IOException; import org.jboss.as.controller.AttributeDefinition; import org.jboss.as.controller.HashUtil; import org.jboss.as.controller.OperationContext; import org.jboss.as.controller.OperationContext.ResultAction; import org.jboss.as.controller.OperationFailedException; import org.jboss.as.controller.OperationStepHandler; import org.jboss.as.controller.PathAddress; import org.jboss.as.controller.RunningMode; 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.HostFileRepository; import org.jboss.as.server.deployment.DeploymentHandlerUtil; import org.jboss.as.server.deployment.DeploymentHandlerUtils; import org.jboss.as.server.deployment.ModelContentReference; import org.jboss.dmr.ModelNode; /** * Handles addition of a deployment to the model. * * @author Brian Stansberry (c) 2011 Red Hat Inc. */ public class DeploymentAddHandler implements OperationStepHandler { public static final String OPERATION_NAME = ADD; private final ContentRepository contentRepository; private final HostFileRepository fileRepository; /** Constructor for a slave Host Controller */ public DeploymentAddHandler(final HostFileRepository fileRepository, final ContentRepository contentRepository) { this.contentRepository = contentRepository; this.fileRepository = fileRepository; } /** * 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 DeploymentAddHandler(final ContentRepository contentRepository) { this.contentRepository = contentRepository; this.fileRepository = null; } /** * {@inheritDoc} */ public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { final Resource resource = context.createResource(PathAddress.EMPTY_ADDRESS); ModelNode newModel = resource.getModel(); // Store the rest of the attributes. // If we correct any of them (e.g. WFLY-3184) then pass the correction on to any slaves ModelNode correctedOperation = operation.clone(); for (AttributeDefinition def : DOMAIN_ADD_ATTRIBUTES) { def.validateAndSet(correctedOperation, newModel); correctedOperation.get(def.getName()).set(newModel.get(def.getName())); } // TODO: JBAS-9020: for the moment overlays are not supported, so there is a single content item ModelNode contentItemNode = newModel.require(CONTENT_RESOURCE.getName()).require(0); final ModelNode opAddr = correctedOperation.get(OP_ADDR); final PathAddress address = PathAddress.pathAddress(opAddr); final String name = address.getLastElement().getValue(); if (!newModel.hasDefined(RUNTIME_NAME.getName())) { newModel.get(RUNTIME_NAME.getName()).set(name); } byte[] hash = null; if (contentItemNode.hasDefined(CONTENT_HASH.getName())) { DeploymentHandlerUtil.isArchive(contentItemNode); hash = contentItemNode.require(CONTENT_HASH.getName()).asBytes(); // If we are the master, validate that we actually have this content. If we're not the master // we do not need the content until it's added to a server group we care about, so we defer // pulling it until then if (fileRepository == null && contentRepository != null && !contentRepository.hasContent(hash)) { if (context.isBooting()) { if (context.getRunningMode() == RunningMode.ADMIN_ONLY) { // The deployment content is missing, which would be a fatal boot error if we were going to actually // install services. In ADMIN-ONLY mode we allow it to give the admin a chance to correct the problem DomainControllerLogger.ROOT_LOGGER.reportAdminOnlyMissingDeploymentContent(HashUtil.bytesToHexString(hash), name); } else { throw createFailureException(DomainControllerLogger.ROOT_LOGGER.noDeploymentContentWithHashAtBoot(HashUtil.bytesToHexString(hash), name)); } } else { throw createFailureException(DomainControllerLogger.ROOT_LOGGER.noDeploymentContentWithHash(HashUtil.bytesToHexString(hash))); } } else if (fileRepository != null) { // Ensure the local repo has the files fileRepository.getDeploymentFiles(ModelContentReference.fromModelAddress(address, hash)); } } else if (contentItemNode.hasDefined(EMPTY.getName())) { // Store and transform operation hash = DeploymentUploadUtil.storeEmptyContentAndTransformOperation(context, correctedOperation, contentRepository); contentItemNode.get(CONTENT_HASH.getName()).set(hash); contentItemNode.get(CONTENT_ARCHIVE.getName()).set(false); ModelNode content = new ModelNode(); content.add(contentItemNode); newModel.get(CONTENT_RESOURCE.getName()).set(content); } else if (DeploymentHandlerUtils.hasValidContentAdditionParameterDefined(contentItemNode)) { if (fileRepository != null || contentRepository == null) { // This is a slave DC. We can't handle this operation; it should have been fixed up on the master DC throw createFailureException(DomainControllerLogger.ROOT_LOGGER.slaveCannotAcceptUploads()); } try { // Store and transform operation hash = DeploymentUploadUtil.storeContentAndTransformOperation(context, correctedOperation, contentRepository); } catch (IOException e) { throw createFailureException(e.toString()); } contentItemNode = new ModelNode(); contentItemNode.get(CONTENT_HASH.getName()).set(hash); // We have altered contentItemNode from what's in the newModel, so store it back to model ModelNode content = new ModelNode(); content.add(contentItemNode); newModel.get(CONTENT_RESOURCE.getName()).set(content); } // else would have failed validation if (contentRepository != null && hash != null) { final byte[] contentHash = hash; context.completeStep(new OperationContext.ResultHandler() { public void handleResult(ResultAction resultAction, OperationContext context, ModelNode operation) { if (resultAction == ResultAction.KEEP) { contentRepository.addContentReference(ModelContentReference.fromModelAddress(address, contentHash)); } } }); } } private static OperationFailedException createFailureException(String msg) { return new OperationFailedException(msg); } }