Permalink
Browse files

Add ability to add content as part of the deployment overlay content …

…add operation
  • Loading branch information...
1 parent 9635f9a commit 22fd8dcb1a8871769d8fb0d5ad2b848808f0e863 @stuartwdouglas stuartwdouglas committed Sep 6, 2012
@@ -385,5 +385,8 @@ deployment-overlay.deployment.regular-expression=If the deployment name is a reg
deployment-overlay.content.add=Adds a piece of content to a deployment overlay
deployment-overlay.content.remove=Removes a piece of content
deployment-overlay.content.path=The archive path that this content item overrides. e.g. To override a web.xml in a war packaged in an ear this would be mywar.war/WEB-INF/web.xml .
-deployment-overlay.content.content=The content hash
-
+deployment-overlay.content.content=The deployment overlay content item
+deployment-overlay.content.content.hash=The content hash
+deployment-overlay.content.content.input-stream-index=The index into the operation's attached input streams of the input stream that contains deployment content that should be uploaded to the domain's or standalone server's deployment content repository.
+deployment-overlay.content.content.bytes=Byte array containing the deployment content that should uploaded to the domain's or standalone server's deployment content repository..
+deployment-overlay.content.content.url=The URL at which the deployment content is available for upload to the domain's or standalone server's deployment content repository.. Note that the URL must be accessible from the target of the operation (i.e. the Domain Controller or standalone server).
@@ -392,6 +392,12 @@
@LogMessage(level = WARN)
@Message(id = 15968, value= "jboss-deployment-dependencies cannot be used in a sub deployment, it must be specified at ear level: %s")
void deploymentDependenciesAreATopLevelElement(String name);
+
+ @LogMessage(level = Logger.Level.ERROR)
+ @Message(id = 15969, value = "No deployment overlay content with hash %s is available in the deployment content repository for deployment %s at location %s. Because this Host Controller is booting in ADMIN-ONLY mode, boot will be allowed to proceed to provide administrators an opportunity to correct this problem. If this Host Controller were not in ADMIN-ONLY mode this would be a fatal boot failure.")
+ void reportAdminOnlyMissingDeploymentOverlayContent(String contentHash, String deploymentName, String contentName);
+
+
// NOTE
}
@@ -441,7 +441,7 @@ OperationFailedException illegalCombinationOfHttpManagementInterfaceConfiguratio
@Message(id = 18716, value = "Could not create server base directory: %s")
IllegalStateException couldNotCreateServerBaseDirectory(File file);
- @Message(id = 18717, value = "No deployment content with hash %s is available in the deployment content repository for deployment '%s'. This is a fatal boot error. To correct the problem, either restart with the --admin-only switch set and use the CLI to install the missing content or remove it from the configuration, or remove the deployment from the xml configuraiton file and restart.")
+ @Message(id = 18717, value = "No deployment content with hash %s is available in the deployment content repository for deployment '%s'. This is a fatal boot error. To correct the problem, either restart with the --admin-only switch set and use the CLI to install the missing content or remove it from the configuration, or remove the deployment from the xml configuration file and restart.")
OperationFailedException noSuchDeploymentContentAtBoot(String contentHash, String deploymentName);
/** Label for DEBUG log listing of the server's system properties */
@@ -636,4 +636,11 @@ OperationFailedException illegalCombinationOfHttpManagementInterfaceConfiguratio
@Message(id = 18777, value = "Wildcard character * is only allowed at the beginning or end of the deployment name %s")
OperationFailedException wildcardOnlyAllowedAtStartOrEnd(String str);
+
+
+ @Message(id = 18778, value = "No deployment overlay content with hash %s is available in the deployment content repository for deployment overlay '%s' at location %s. This is a fatal boot error. To correct the problem, either restart with the --admin-only switch set and use the CLI to install the missing content or remove it from the configuration, or remove the deployment overlay from the xml configuration file and restart.")
+ OperationFailedException noSuchDeploymentOverlayContentAtBoot(String contentHash, String deploymentOverlayName, String contentFile);
+
+ @Message(id = 18779, value = "No deployment overlay content with hash %s is available in the deployment content repository.")
+ OperationFailedException noSuchDeploymentOverlayContent(String hash);
}
@@ -1,26 +1,50 @@
package org.jboss.as.server.deploymentoverlay;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
import java.util.Arrays;
import java.util.List;
import org.jboss.as.controller.AbstractAddStepHandler;
import org.jboss.as.controller.AttributeDefinition;
+import org.jboss.as.controller.HashUtil;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.PathAddress;
+import org.jboss.as.controller.RunningMode;
import org.jboss.as.controller.ServiceVerificationHandler;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
+import org.jboss.as.controller.operations.validation.AbstractParameterValidator;
+import org.jboss.as.controller.operations.validation.ListValidator;
+import org.jboss.as.controller.operations.validation.ModelTypeValidator;
+import org.jboss.as.controller.operations.validation.ParametersOfValidator;
+import org.jboss.as.controller.operations.validation.ParametersValidator;
+import org.jboss.as.controller.operations.validation.StringLengthValidator;
+import org.jboss.as.controller.registry.Resource;
+import org.jboss.as.protocol.StreamUtils;
import org.jboss.as.repository.ContentRepository;
import org.jboss.as.repository.DeploymentFileRepository;
+import org.jboss.as.server.ServerLogger;
import org.jboss.as.server.ServerMessages;
-import org.jboss.as.server.deploymentoverlay.service.DeploymentOverlayService;
import org.jboss.as.server.deploymentoverlay.service.ContentService;
+import org.jboss.as.server.deploymentoverlay.service.DeploymentOverlayService;
import org.jboss.dmr.ModelNode;
+import org.jboss.dmr.ModelType;
import org.jboss.msc.service.ServiceBuilder;
import org.jboss.msc.service.ServiceController;
import org.jboss.msc.service.ServiceName;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.BYTES;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.CONTENT;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ENABLED;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.HASH;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.INPUT_STREAM_INDEX;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RUNTIME_NAME;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.URL;
+import static org.jboss.as.controller.operations.validation.ChainedParameterValidator.chain;
/**
* @author Stuart Douglas
@@ -30,21 +54,58 @@
protected final ContentRepository contentRepository;
private final DeploymentFileRepository remoteRepository;
+ protected final ParametersValidator validator = new ParametersValidator();
+ protected final ParametersValidator managedContentValidator = new ParametersValidator();
+
public ContentAdd(final ContentRepository contentRepository, final DeploymentFileRepository remoteRepository) {
this.contentRepository = contentRepository;
this.remoteRepository = remoteRepository;
+ this.validator.registerValidator(RUNTIME_NAME, new StringLengthValidator(1, Integer.MAX_VALUE, true, false));
+ this.validator.registerValidator(ENABLED, new ModelTypeValidator(ModelType.BOOLEAN, true));
+ final ParametersValidator contentValidator = new ParametersValidator();
+ // existing managed content
+ contentValidator.registerValidator(HASH, new ModelTypeValidator(ModelType.BYTES, true));
+ // content additions
+ contentValidator.registerValidator(INPUT_STREAM_INDEX, new ModelTypeValidator(ModelType.INT, true));
+ contentValidator.registerValidator(BYTES, new ModelTypeValidator(ModelType.BYTES, true));
+ contentValidator.registerValidator(URL, new StringLengthValidator(1, true));
+ this.validator.registerValidator(CONTENT, chain(new ListValidator(new ParametersOfValidator(contentValidator)),
+ new AbstractParameterValidator() {
+ @Override
+ public void validateParameter(String parameterName, ModelNode value) throws OperationFailedException {
+ validateOnePieceOfContent(value);
+ }
+ }));
+ this.managedContentValidator.registerValidator(HASH, new ModelTypeValidator(ModelType.BYTES));
+ }
+
+ @Override
+ protected void populateModel(final OperationContext context, final ModelNode operation, final Resource resource) throws OperationFailedException {
+ final PathAddress address = PathAddress.pathAddress(operation.get(OP_ADDR));
+ final String path = address.getLastElement().getValue();
+ final String name = address.getElement(address.size() - 2).getValue();
+ ModelNode content = operation.get(CONTENT);
+ if (content.hasDefined(HASH)) {
+ managedContentValidator.validate(content);
+ byte[] hash = content.require(HASH).asBytes();
+ addFromHash(hash, name, path, context);
+ } else {
+ addFromContentAdditionParameter(context, content);
+ }
+ super.populateModel(context, operation, resource);
}
@Override
protected void populateModel(final ModelNode operation, final ModelNode model) throws OperationFailedException {
- for(AttributeDefinition attr : ContentDefinition.attributes()) {
+
+ for (AttributeDefinition attr : ContentDefinition.attributes()) {
attr.validateAndSet(operation, model);
}
- final byte[] hash = operation.get(ContentDefinition.CONTENT.getName()).asBytes();
- if(remoteRepository != null) {
+ final byte[] hash = operation.get(CONTENT).get(HASH).asBytes();
+ if (remoteRepository != null) {
remoteRepository.getDeploymentFiles(hash);
}
- if(!contentRepository.syncContent(hash)) {
+ if (!contentRepository.syncContent(hash)) {
throw ServerMessages.MESSAGES.noSuchDeploymentContent(Arrays.toString(hash));
}
}
@@ -55,7 +116,7 @@ protected void performRuntime(final OperationContext context, final ModelNode op
final PathAddress address = PathAddress.pathAddress(operation.get(OP_ADDR));
final String path = address.getLastElement().getValue();
final String name = address.getElement(address.size() - 2).getValue();
- final byte[] content = model.get(ModelDescriptionConstants.CONTENT).asBytes();
+ final byte[] content = model.get(ModelDescriptionConstants.CONTENT).get(HASH).asBytes();
installServices(context, verificationHandler, newControllers, name, path, content);
@@ -68,12 +129,89 @@ static void installServices(final OperationContext context, final ServiceVerific
ServiceBuilder<ContentService> builder = context.getServiceTarget().addService(serviceName, service)
.addDependency(DeploymentOverlayService.SERVICE_NAME.append(name), DeploymentOverlayService.class, service.getDeploymentOverlayServiceInjectedValue())
.addDependency(ContentRepository.SERVICE_NAME, ContentRepository.class, service.getContentRepositoryInjectedValue());
- if(verificationHandler != null) {
+ if (verificationHandler != null) {
builder.addListener(verificationHandler);
}
final ServiceController<ContentService> controller = builder.install();
- if(newControllers != null) {
+ if (newControllers != null) {
newControllers.add(controller);
}
}
+
+ protected static void validateOnePieceOfContent(final ModelNode content) throws OperationFailedException {
+ if (content.asList().size() != 1)
+ throw ServerMessages.MESSAGES.multipleContentItemsNotSupported();
+ }
+
+ byte[] addFromHash(byte[] hash, String deploymentOverlayName, final String contentName, final OperationContext context) throws OperationFailedException {
+ if (!contentRepository.syncContent(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
+ ServerLogger.DEPLOYMENT_LOGGER.reportAdminOnlyMissingDeploymentOverlayContent(HashUtil.bytesToHexString(hash), deploymentOverlayName, contentName);
+
+ } else {
+ throw ServerMessages.MESSAGES.noSuchDeploymentOverlayContentAtBoot(HashUtil.bytesToHexString(hash), deploymentOverlayName, contentName);
+ }
+ } else {
+ throw ServerMessages.MESSAGES.noSuchDeploymentOverlayContent(HashUtil.bytesToHexString(hash));
+ }
+ }
+ return hash;
+ }
+
+ byte[] addFromContentAdditionParameter(OperationContext context, ModelNode contentItemNode) throws OperationFailedException {
+ byte[] hash;
+ InputStream in = getInputStream(context, contentItemNode);
+ try {
+ try {
+ hash = contentRepository.addContent(in);
+ } catch (IOException e) {
+ throw createFailureException(e.toString());
+ }
+
+ } finally {
+ StreamUtils.safeClose(in);
+ }
+ contentItemNode.clear(); // AS7-1029
+ contentItemNode.get(HASH).set(hash);
+ return hash;
+ }
+
+ protected static OperationFailedException createFailureException(String msg) {
+ return new OperationFailedException(new ModelNode(msg));
+ }
+
+ protected static InputStream getInputStream(OperationContext context, ModelNode operation) throws OperationFailedException {
+ InputStream in = null;
+ if (operation.hasDefined(INPUT_STREAM_INDEX)) {
+ int streamIndex = operation.get(INPUT_STREAM_INDEX).asInt();
+ int maxIndex = context.getAttachmentStreamCount();
+ if (streamIndex > maxIndex) {
+ throw ServerMessages.MESSAGES.invalidStreamIndex(INPUT_STREAM_INDEX, streamIndex, maxIndex);
+ }
+ in = context.getAttachmentStream(streamIndex);
+ } else if (operation.hasDefined(BYTES)) {
+ try {
+ in = new ByteArrayInputStream(operation.get(BYTES).asBytes());
+ } catch (IllegalArgumentException iae) {
+ throw ServerMessages.MESSAGES.invalidStreamBytes(BYTES);
+ }
+ } else if (operation.hasDefined(URL)) {
+ final String urlSpec = operation.get(URL).asString();
+ try {
+ in = new java.net.URL(urlSpec).openStream();
+ } catch (MalformedURLException e) {
+ throw ServerMessages.MESSAGES.invalidStreamURL(e, urlSpec);
+ } catch (IOException e) {
+ throw ServerMessages.MESSAGES.invalidStreamURL(e, urlSpec);
+ }
+ }
+ if (in == null) {
+ // Won't happen, as we call hasValidContentAdditionParameterDefined first
+ throw new IllegalStateException();
+ }
+ return in;
+ }
}
Oops, something went wrong.

0 comments on commit 22fd8dc

Please sign in to comment.