/jboss-as-7.1.1.Final/host-controller/src/main/java/org/jboss/as/domain/controller/operations/deployment/DeploymentAddHandler.java
Java | 242 lines | 169 code | 21 blank | 52 comment | 25 complexity | 0fa79267bf8db160ad8e83aa5ced69b7 MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0
1/*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2011 Red Hat Inc. and/or its affiliates and other contributors
4 * as indicated by the @authors tag. All rights reserved.
5 * See the copyright.txt in the distribution for a
6 * full listing of individual contributors.
7 *
8 * This copyrighted material is made available to anyone wishing to use,
9 * modify, copy, or redistribute it subject to the terms and conditions
10 * of the GNU Lesser General Public License, v. 2.1.
11 * This program is distributed in the hope that it will be useful, but WITHOUT A
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public License,
15 * v.2.1 along with this distribution; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1301, USA.
18 */
19package org.jboss.as.domain.controller.operations.deployment;
20
21import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD;
22import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ARCHIVE;
23import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.BYTES;
24import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.CONTENT;
25import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.HASH;
26import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.INPUT_STREAM_INDEX;
27import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.NAME;
28import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
29import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.PATH;
30import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RELATIVE_TO;
31import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RUNTIME_NAME;
32import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.URL;
33import static org.jboss.as.controller.operations.validation.ChainedParameterValidator.chain;
34import static org.jboss.as.domain.controller.DomainControllerMessages.MESSAGES;
35
36import java.io.ByteArrayInputStream;
37import java.io.IOException;
38import java.io.InputStream;
39import java.net.MalformedURLException;
40import java.net.URL;
41import java.util.Arrays;
42import java.util.List;
43import java.util.Locale;
44
45import org.jboss.as.controller.HashUtil;
46import org.jboss.as.controller.OperationContext;
47import org.jboss.as.controller.OperationFailedException;
48import org.jboss.as.controller.OperationStepHandler;
49import org.jboss.as.controller.PathAddress;
50import org.jboss.as.controller.RunningMode;
51import org.jboss.as.controller.descriptions.DescriptionProvider;
52import org.jboss.as.controller.descriptions.common.DeploymentDescription;
53import org.jboss.as.controller.operations.validation.AbstractParameterValidator;
54import org.jboss.as.controller.operations.validation.ListValidator;
55import org.jboss.as.controller.operations.validation.ModelTypeValidator;
56import org.jboss.as.controller.operations.validation.ParametersOfValidator;
57import org.jboss.as.controller.operations.validation.ParametersValidator;
58import org.jboss.as.controller.operations.validation.StringLengthValidator;
59import org.jboss.as.controller.registry.Resource;
60import org.jboss.as.domain.controller.DomainControllerLogger;
61import org.jboss.as.protocol.StreamUtils;
62import org.jboss.as.repository.ContentRepository;
63import org.jboss.dmr.ModelNode;
64import org.jboss.dmr.ModelType;
65
66/**
67 * Handles addition of a deployment to the model.
68 *
69 * @author Brian Stansberry (c) 2011 Red Hat Inc.
70 */
71public class DeploymentAddHandler implements OperationStepHandler, DescriptionProvider {
72
73 public static final String OPERATION_NAME = ADD;
74
75 private static final List<String> CONTENT_ADDITION_PARAMETERS = Arrays.asList(INPUT_STREAM_INDEX, BYTES, URL);
76
77 private final ContentRepository contentRepository;
78
79 private final ParametersValidator validator = new ParametersValidator();
80 private final ParametersValidator unmanagedContentValidator = new ParametersValidator();
81 private final ParametersValidator managedContentValidator = new ParametersValidator();
82
83 /** Constructor for a slave Host Controller */
84 public DeploymentAddHandler() {
85 this(null);
86 }
87
88 /**
89 * Constructor for a master Host Controller
90 *
91 * @param contentRepository the master content repository. If {@code null} this handler will function as a slave handler would.
92 */
93 public DeploymentAddHandler(final ContentRepository contentRepository) {
94 this.contentRepository = contentRepository;
95 this.validator.registerValidator(RUNTIME_NAME, new StringLengthValidator(1, Integer.MAX_VALUE, true, false));
96 final ParametersValidator contentValidator = new ParametersValidator();
97 // existing managed content
98 contentValidator.registerValidator(HASH, new ModelTypeValidator(ModelType.BYTES, true));
99 // existing unmanaged content
100 contentValidator.registerValidator(ARCHIVE, new ModelTypeValidator(ModelType.BOOLEAN, true));
101 contentValidator.registerValidator(PATH, new StringLengthValidator(1, true));
102 contentValidator.registerValidator(RELATIVE_TO, new ModelTypeValidator(ModelType.STRING, true));
103 // content additions
104 contentValidator.registerValidator(INPUT_STREAM_INDEX, new ModelTypeValidator(ModelType.INT, true));
105 contentValidator.registerValidator(BYTES, new ModelTypeValidator(ModelType.BYTES, true));
106 contentValidator.registerValidator(URL, new StringLengthValidator(1, true));
107 this.validator.registerValidator(CONTENT, chain(new ListValidator(new ParametersOfValidator(contentValidator)),
108 new AbstractParameterValidator() {
109 @Override
110 public void validateParameter(String parameterName, ModelNode value) throws OperationFailedException {
111 validateOnePieceOfContent(value);
112 }
113 }));
114 this.managedContentValidator.registerValidator(HASH, new ModelTypeValidator(ModelType.BYTES));
115 this.unmanagedContentValidator.registerValidator(ARCHIVE, new ModelTypeValidator(ModelType.BOOLEAN));
116 this.unmanagedContentValidator.registerValidator(PATH, new StringLengthValidator(1));
117 }
118
119 @Override
120 public ModelNode getModelDescription(Locale locale) {
121 return DeploymentDescription.getAddDeploymentOperation(locale, false);
122 }
123
124 /**
125 * {@inheritDoc}
126 */
127 public void execute(OperationContext context, ModelNode operation) throws OperationFailedException {
128 validator.validate(operation);
129 PathAddress address = PathAddress.pathAddress(operation.get(OP_ADDR));
130 String name = address.getLastElement().getValue();
131 String runtimeName = operation.hasDefined(RUNTIME_NAME) ? operation.get(RUNTIME_NAME).asString() : name;
132
133 byte[] hash = null;
134 // clone it, so we can modify it to our own content
135 final ModelNode content = operation.require(CONTENT).clone();
136 // TODO: JBAS-9020: for the moment overlays are not supported, so there is a single content item
137 final ModelNode contentItemNode = content.require(0);
138 if (contentItemNode.hasDefined(HASH)) {
139 managedContentValidator.validate(contentItemNode);
140 hash = contentItemNode.require(HASH).asBytes();
141 // If we are the master, validate that we actually have this content. If we're not the master
142 // we do not need the content until it's added to a server group we care about, so we defer
143 // pulling it until then
144 if (contentRepository != null && !contentRepository.hasContent(hash)) {
145 if (context.isBooting()) {
146 if (context.getRunningMode() == RunningMode.ADMIN_ONLY) {
147 // The deployment content is missing, which would be a fatal boot error if we were going to actually
148 // install services. In ADMIN-ONLY mode we allow it to give the admin a chance to correct the problem
149 DomainControllerLogger.HOST_CONTROLLER_LOGGER.reportAdminOnlyMissingDeploymentContent(HashUtil.bytesToHexString(hash), name);
150 } else {
151 throw createFailureException(MESSAGES.noDeploymentContentWithHashAtBoot(HashUtil.bytesToHexString(hash), name));
152 }
153 } else {
154 throw createFailureException(MESSAGES.noDeploymentContentWithHash(HashUtil.bytesToHexString(hash)));
155 }
156 }
157 } else if (hasValidContentAdditionParameterDefined(contentItemNode)) {
158 if (contentRepository == null) {
159 // This is a slave DC. We can't handle this operation; it should have been fixed up on the master DC
160 throw createFailureException(MESSAGES.slaveCannotAcceptUploads());
161 }
162
163 InputStream in = getInputStream(context, contentItemNode);
164 try {
165 try {
166 hash = contentRepository.addContent(in);
167 } catch (IOException e) {
168 throw createFailureException(e.toString());
169 }
170
171 } finally {
172 StreamUtils.safeClose(in);
173 }
174 contentItemNode.clear(); // AS7-1029
175 contentItemNode.get(HASH).set(hash);
176 } else {
177 // Unmanaged content, the user is responsible for replication
178 // Just validate the required attributes are present
179 unmanagedContentValidator.validate(contentItemNode);
180 }
181
182 final Resource resource = context.createResource(PathAddress.EMPTY_ADDRESS);
183 final ModelNode subModel = resource.getModel();
184 subModel.get(NAME).set(name);
185 subModel.get(RUNTIME_NAME).set(runtimeName);
186 subModel.get(CONTENT).set(content);
187
188 context.completeStep(OperationContext.RollbackHandler.NOOP_ROLLBACK_HANDLER);
189 }
190
191 private static InputStream getInputStream(OperationContext context, ModelNode operation) throws OperationFailedException {
192 InputStream in = null;
193 String message = "";
194 if (operation.hasDefined(INPUT_STREAM_INDEX)) {
195 int streamIndex = operation.get(INPUT_STREAM_INDEX).asInt();
196 message = MESSAGES.nullStream(streamIndex);
197 in = context.getAttachmentStream(streamIndex);
198 } else if (operation.hasDefined(BYTES)) {
199 message = MESSAGES.invalidByteStream();
200 in = new ByteArrayInputStream(operation.get(BYTES).asBytes());
201 } else if (operation.hasDefined(URL)) {
202 final String urlSpec = operation.get(URL).asString();
203 try {
204 message = MESSAGES.invalidUrlStream();
205 in = new URL(urlSpec).openStream();
206 } catch (MalformedURLException e) {
207 throw createFailureException(message);
208 } catch (IOException e) {
209 throw createFailureException(message);
210 }
211 }
212 if (in == null) {
213 throw createFailureException(message);
214 }
215 return in;
216 }
217
218 /**
219 * Checks to see if a valid deployment parameter has been defined.
220 *
221 * @param operation the operation to check.
222 * @return {@code true} of the parameter is valid, otherwise {@code false}.
223 */
224 private static boolean hasValidContentAdditionParameterDefined(ModelNode operation) {
225 for (String s : CONTENT_ADDITION_PARAMETERS) {
226 if (operation.hasDefined(s)) {
227 return true;
228 }
229 }
230 return false;
231 }
232
233 private static OperationFailedException createFailureException(String msg) {
234 return new OperationFailedException(msg);
235 }
236
237 private static void validateOnePieceOfContent(final ModelNode content) throws OperationFailedException {
238 // TODO: implement overlays
239 if (content.asList().size() != 1)
240 throw createFailureException(MESSAGES.as7431());
241 }
242}