/jboss-as-7.1.1.Final/controller/src/main/java/org/jboss/as/controller/RestartParentResourceHandlerBase.java
Java | 205 lines | 100 code | 24 blank | 81 comment | 20 complexity | 8ba39cae1babf3d3dc249ff61d93c411 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 individual contributors
4 * as indicated by the @author tags. See the copyright.txt file in the
5 * distribution for a full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */
22package org.jboss.as.controller;
23
24import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
25
26import java.util.NoSuchElementException;
27
28import org.jboss.as.controller.operations.common.Util;
29import org.jboss.as.controller.registry.Resource;
30import org.jboss.dmr.ModelNode;
31import org.jboss.msc.service.ServiceController;
32import org.jboss.msc.service.ServiceName;
33
34/**
35 * Simple remove handler that, if allowed, restarts a parent resource when a child is removed.
36 * Otherwise the server is put into a forced reload.
37 *
38 * @author Jason T. Greene
39 */
40public abstract class RestartParentResourceHandlerBase implements OperationStepHandler {
41 private final String parentKeyName;
42
43 protected RestartParentResourceHandlerBase(String parentKeyName) {
44 this.parentKeyName = parentKeyName;
45 }
46
47 @Override
48 public void execute(OperationContext context, ModelNode operation) throws OperationFailedException {
49
50 // Do the simple model part
51 updateModel(context, operation);
52
53 if (!context.isBooting() && requiresRuntime(context)) {
54 context.addStep(new OperationStepHandler() {
55 @Override
56 public void execute(OperationContext context, ModelNode operation) throws OperationFailedException {
57
58 PathAddress address = getParentAddress(PathAddress.pathAddress(operation.require(OP_ADDR)));
59 ServiceName serviceName = getParentServiceName(address);
60 final ServiceController<?> service = serviceName != null ?
61 context.getServiceRegistry(false).getService(serviceName) : null;
62
63 ModelNode parentModel = null;
64 boolean servicesRestarted = false;
65 final boolean reloadRequired = service != null && !isResourceServiceRestartAllowed(context, service);
66 if (reloadRequired) {
67 context.reloadRequired();
68 } else if (service != null ) {
69 parentModel = getModel(context, address);
70 if (parentModel != null && context.markResourceRestarted(address, this)) {
71 removeServices(context, serviceName, parentModel);
72 final ServiceVerificationHandler verificationHandler = new ServiceVerificationHandler();
73 recreateParentService(context, address, parentModel, verificationHandler);
74 context.addStep(verificationHandler, OperationContext.Stage.VERIFY);
75 servicesRestarted = true;
76 }
77 } // else No parent service, nothing to do
78
79 // If we restarted services, keep the model that drove the new services so we can
80 // revert the change on rollback
81 final ModelNode invalidatedParentModel = servicesRestarted ? parentModel : null;
82
83 context.completeStep(new OperationContext.RollbackHandler() {
84 @Override
85 public void handleRollback(OperationContext context, ModelNode operation) {
86 if (reloadRequired) {
87 context.revertReloadRequired();
88 } else if (invalidatedParentModel != null) {
89 recoverServices(context, operation, invalidatedParentModel);
90 }
91 }
92 });
93 }
94 }, OperationContext.Stage.RUNTIME);
95 }
96 context.completeStep(OperationContext.RollbackHandler.NOOP_ROLLBACK_HANDLER);
97 }
98
99 /**
100 * Gets whether this operation needs to update the runtime. The default implementation returns {@code true}
101 * if {@link OperationContext#getProcessType() the process type} is not {@link ProcessType#HOST_CONTROLLER}.
102 *
103 * @param context the operation context
104 * @return {@code true} if the operation should update the runtime; {@code false} if it only updates the configuration
105 * model
106 */
107 protected boolean requiresRuntime(OperationContext context) {
108 return context.getProcessType() != ProcessType.HOST_CONTROLLER;
109 }
110
111 /**
112 * Gets whether a restart of the parent resource's services is allowed. This default implementation
113 * checks whether {@link OperationContext#isResourceServiceRestartAllowed() the context allows resource service restarts};
114 * subclasses could also check the state of the {@code service}.
115 *
116 * @param context the operation context
117 * @param service the parent service
118 * @return {@code true} if a restart is allowed; {@code false}
119 */
120 protected boolean isResourceServiceRestartAllowed(final OperationContext context, final ServiceController<?> service) {
121 return context.isResourceServiceRestartAllowed();
122 }
123
124 /**
125 * Removes services. This default implementation simply
126 * {@link OperationContext#removeService(ServiceController) instructs the context to remove the parentService}.
127 * Subclasses could use the provided {@code parentModel} to identify and remove other services.
128 *
129 * @param context the operation context
130 * @param parentService the name of the parent service
131 * @param parentModel the model associated with the parent resource, including nodes for any child resources
132 *
133 * @throws OperationFailedException if there is a problem removing the services
134 */
135 protected void removeServices(final OperationContext context, final ServiceName parentService, final ModelNode parentModel) throws OperationFailedException {
136 context.removeService(parentService);
137 }
138
139 /**
140 * Performs the update to the persistent configuration model.
141 *
142 * @param context the operation context
143 * @param operation the operation
144 * @throws OperationFailedException if there is a problem updating the model
145 */
146 protected abstract void updateModel(final OperationContext context, final ModelNode operation) throws OperationFailedException;
147
148 /**
149 * Recreate the parent service(s) using the given model.
150 *
151 * @param context the operation context
152 * @param parentAddress the address of the parent resource
153 * @param parentModel the current configuration model for the parent resource and its children
154 * @param verificationHandler handler for verifying newly installed services
155 *
156 * @throws OperationFailedException if there is a problem installing the services
157 */
158 protected abstract void recreateParentService(OperationContext context, PathAddress parentAddress, ModelNode parentModel, ServiceVerificationHandler verificationHandler) throws OperationFailedException;
159
160 /**
161 * Gets the name of the parent service.
162 *
163 * @param parentAddress the address of the parent resource
164 * @return the service name
165 */
166 protected abstract ServiceName getParentServiceName(PathAddress parentAddress);
167
168
169 protected PathAddress getParentAddress(PathAddress address) {
170 return Util.getParentAddressByKey(address, parentKeyName);
171 }
172
173 private void recoverServices(final OperationContext context, final ModelNode operation, final ModelNode invalidatedParentModel) {
174 PathAddress address = getParentAddress(PathAddress.pathAddress(operation.require(OP_ADDR)));
175 ServiceName serviceName = getParentServiceName(address);
176
177 ModelNode parentModel = getOriginalModel(context, address);
178 if (parentModel != null && context.revertResourceRestarted(address, this)) {
179 try {
180 removeServices(context, serviceName, invalidatedParentModel);
181 recreateParentService(context, address, parentModel, null);
182 } catch (OperationFailedException e) {
183 throw ControllerMessages.MESSAGES.failedToRecoverServices(e);
184 }
185 }
186 }
187
188 private ModelNode getModel(OperationContext ctx, PathAddress address) {
189 try {
190 Resource resource = ctx.readResourceFromRoot(address);
191 return Resource.Tools.readModel(resource);
192 } catch (NoSuchElementException e) {
193 return null;
194 }
195 }
196
197 private ModelNode getOriginalModel(OperationContext ctx, PathAddress address) {
198 try {
199 Resource resource = ctx.getOriginalRootResource().navigate(address);
200 return Resource.Tools.readModel(resource);
201 } catch (NoSuchElementException e) {
202 return null;
203 }
204 }
205}