/*
* JBoss, Home of Professional Open Source.
* Copyright 2015, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY 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 along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.as.server.deployment;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBDEPLOYMENT;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBSYSTEM;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.logging.ControllerLogger;
import org.jboss.as.controller.registry.ImmutableManagementResourceRegistration;
import org.jboss.as.controller.registry.ManagementResourceRegistration;
import org.jboss.as.controller.registry.Resource;
import org.jboss.dmr.ModelNode;
/**
* Support for creation of resources on deployments or retrieving the model of a resource on deployments.
*
* @author <a href="mailto:jperkins@redhat.com">James R. Perkins</a>
*/
public final class DeploymentResourceSupport {
static final AttachmentKey<Resource> DEPLOYMENT_RESOURCE = AttachmentKey.create(Resource.class);
static final AttachmentKey<ImmutableManagementResourceRegistration> REGISTRATION_ATTACHMENT = AttachmentKey.create(ImmutableManagementResourceRegistration.class);
static final AttachmentKey<ManagementResourceRegistration> MUTABLE_REGISTRATION_ATTACHMENT = AttachmentKey.create(ManagementResourceRegistration.class);
private final DeploymentUnit deploymentUnit;
protected DeploymentResourceSupport(final DeploymentUnit deploymentUnit) {
this.deploymentUnit = deploymentUnit;
}
/**
* Checks to see if a subsystem resource has already been registered for the deployment.
*
* @param subsystemName the name of the subsystem
*
* @return {@code true} if the subsystem exists on the deployment otherwise {@code false}
*/
public boolean hasDeploymentSubsystemModel(final String subsystemName) {
final Resource root = deploymentUnit.getAttachment(DEPLOYMENT_RESOURCE);
final PathElement subsystem = PathElement.pathElement(SUBSYSTEM, subsystemName);
return root.hasChild(subsystem);
}
/**
* Get the subsystem deployment model root.
*
* <p>
* If the subsystem resource does not exist one will be created.
* </p>
*
* @param subsystemName the subsystem name.
*
* @return the model
*/
public ModelNode getDeploymentSubsystemModel(final String subsystemName) {
assert subsystemName != null : "The subsystemName cannot be null";
return getDeploymentSubModel(subsystemName, PathAddress.EMPTY_ADDRESS, null, deploymentUnit);
}
/**
* Registers the resource to the parent deployment resource. The model returned is that of the resource parameter.
*
* @param subsystemName the subsystem name
* @param resource the resource to be used for the subsystem on the deployment
*
* @return the model
*
* @throws java.lang.IllegalStateException if the subsystem resource already exists
*/
public ModelNode registerDeploymentSubsystemResource(final String subsystemName, final Resource resource) {
assert subsystemName != null : "The subsystemName cannot be null";
assert resource != null : "The resource cannot be null";
return registerDeploymentSubResource(subsystemName, PathAddress.EMPTY_ADDRESS, resource);
}
/**
* Checks to see if a resource has already been registered for the specified address on the subsystem.
*
* @param subsystemName the name of the subsystem
* @param address the address to check
*
* @return {@code true} if the address exists on the subsystem otherwise {@code false}
*/
public boolean hasDeploymentSubModel(final String subsystemName, final PathElement address) {
final Resource root = deploymentUnit.getAttachment(DEPLOYMENT_RESOURCE);
final PathElement subsystem = PathElement.pathElement(SUBSYSTEM, subsystemName);
return root.hasChild(subsystem) && (address == null || root.getChild(subsystem).hasChild(address));
}
/**
* Checks to see if a resource has already been registered for the specified address on the subsystem.
*
* @param subsystemName the name of the subsystem
* @param address the address to check
*
* @return {@code true} if the address exists on the subsystem otherwise {@code false}
*/
public boolean hasDeploymentSubModel(final String subsystemName, final PathAddress address) {
final Resource root = deploymentUnit.getAttachment(DEPLOYMENT_RESOURCE);
final PathElement subsystem = PathElement.pathElement(SUBSYSTEM, subsystemName);
boolean found = false;
if (root.hasChild(subsystem)) {
if (address == PathAddress.EMPTY_ADDRESS) {
return true;
}
Resource parent = root.getChild(subsystem);
for (PathElement child : address) {
if (parent.hasChild(child)) {
found = true;
parent = parent.getChild(child);
} else {
found = false;
break;
}
}
}
return found;
}
/**
* Gets the sub-model for a components from the deployment itself. Operations, metrics and descriptions have to be
* registered as part of the subsystem registration {@link org.jboss.as.controller.ExtensionContext} and
* {@link org.jboss.as.controller.SubsystemRegistration#registerDeploymentModel(org.jboss.as.controller.ResourceDefinition)}.
*
* <p>
* If the subsystem resource does not exist it will be created. If no resource exists for the address parameter on
* the resource it also be created.
* </p>
*
* @param subsystemName the name of the subsystem
* @param address the path address this sub-model should return the model for
*
* @return the model for the resource
*/
public ModelNode getDeploymentSubModel(final String subsystemName, final PathElement address) {
assert subsystemName != null : "The subsystemName cannot be null";
return getDeploymentSubModel(subsystemName, address, deploymentUnit);
}
/**
* Gets the sub-model for a components from the deployment itself. Operations, metrics and descriptions have to be
* registered as part of the subsystem registration {@link org.jboss.as.controller.ExtensionContext} and
* {@link org.jboss.as.controller.SubsystemRegistration#registerDeploymentModel(org.jboss.as.controller.ResourceDefinition)}.
*
* <p>
* The subsystem resource as well as each {@link org.jboss.as.controller.PathAddress#getParent()} parent element}
* from the address will be created if it does not already exist.
* </p>
*
* @param subsystemName the name of the subsystem
* @param address the path address this sub-model should return the model for
*
* @return the model for the resource
*/
public ModelNode getDeploymentSubModel(final String subsystemName, final PathAddress address) {
assert subsystemName != null : "The subsystemName cannot be null";
assert address != null : "The address cannot be null";
return getDeploymentSubModel(subsystemName, address, null, deploymentUnit);
}
/**
* Registers the provided resource as the resource for the {@link org.jboss.as.controller.PathAddress#getLastElement()
* last element} of the address. Operations, metrics and descriptions have to be registered as part of the
* subsystem registration {@link org.jboss.as.controller.ExtensionContext} and {@link
* org.jboss.as.controller.SubsystemRegistration#registerDeploymentModel(org.jboss.as.controller.ResourceDefinition)}.
*
* <p>
* The subsystem resource as well as each {@link org.jboss.as.controller.PathAddress#getParent()} parent element}
* from the address will be created if it does not already exist.
* </p>
*
* @param subsystemName the subsystem name the model was registered
* @param address the path address this sub-model should be created in
* @param resource the resource to be registered as sub-module
*
* @return the {@link org.jboss.as.controller.registry.Resource#getModel() model} from the resource parameter
*
* @throws java.lang.IllegalStateException if the {@link org.jboss.as.controller.PathAddress#getLastElement() last}
* resource already exists
*/
public ModelNode registerDeploymentSubResource(final String subsystemName, final PathAddress address, final Resource resource) {
final Resource root = deploymentUnit.getAttachment(DEPLOYMENT_RESOURCE);
synchronized (root) {
final ImmutableManagementResourceRegistration registration = deploymentUnit.getAttachment(REGISTRATION_ATTACHMENT);
final PathElement subsystemPath = PathElement.pathElement(SUBSYSTEM, subsystemName);
if (address == PathAddress.EMPTY_ADDRESS) {
return register(root, subsystemPath, resource).getModel();
}
Resource parent = getOrCreate(root, subsystemPath);
int count = address.size() - 1;
for (int index = 0; index < count; index++) {
parent = getOrCreate(parent, address.getElement(index));
}
final ImmutableManagementResourceRegistration subModel = registration.getSubModel(getSubsystemAddress(subsystemName, address));
if (subModel == null) {
throw new IllegalStateException(address.toString());
}
return register(parent, address.getLastElement(), resource).getModel();
}
}
/**
* Gets or creates the a resource for the sub-deployment on the parent deployments resource.
*
* @param deploymentName the name of the deployment
* @param parent the parent deployment used to find the parent resource
*
* @return the already registered resource or a newly created resource
*/
static Resource getOrCreateSubDeployment(final String deploymentName, final DeploymentUnit parent) {
final Resource root = parent.getAttachment(DEPLOYMENT_RESOURCE);
return getOrCreate(root, PathElement.pathElement(SUBDEPLOYMENT, deploymentName));
}
/**
* Cleans up the subsystem children for the deployment and each sub-deployment resource.
*
* @param resource the subsystem resource to clean up
*/
static void cleanup(final Resource resource) {
synchronized (resource) {
for (final Resource.ResourceEntry entry : resource.getChildren(SUBSYSTEM)) {
resource.removeChild(entry.getPathElement());
}
for (final Resource.ResourceEntry entry : resource.getChildren(SUBDEPLOYMENT)) {
resource.removeChild(entry.getPathElement());
}
}
}
/**
* @see #getDeploymentSubModel(String, org.jboss.as.controller.PathElement, DeploymentUnit)
*/
static ModelNode getDeploymentSubModel(final String subsystemName, final PathElement address, final DeploymentUnit unit) {
final Resource root = unit.getAttachment(DEPLOYMENT_RESOURCE);
synchronized (root) {
final ImmutableManagementResourceRegistration registration = unit.getAttachment(REGISTRATION_ATTACHMENT);
final PathElement subsystemPath = PathElement.pathElement(SUBSYSTEM, subsystemName);
if (address == null) {
return getOrCreate(root, subsystemPath, null).getModel();
}
Resource parent = getOrCreate(root, subsystemPath);
final ImmutableManagementResourceRegistration subModel = registration.getSubModel(PathAddress.pathAddress(subsystemPath, address));
if (subModel == null) {
throw new IllegalStateException(address.toString());
}
return getOrCreate(parent, address, null).getModel();
}
}
/**
* @see #getDeploymentSubModel(String, org.jboss.as.controller.PathAddress)
*/
static ModelNode getDeploymentSubModel(final String subsystemName, final PathAddress address, final Resource resource, final DeploymentUnit unit) {
final Resource root = unit.getAttachment(DEPLOYMENT_RESOURCE);
synchronized (root) {
final ImmutableManagementResourceRegistration registration = unit.getAttachment(REGISTRATION_ATTACHMENT);
final PathElement subsystemPath = PathElement.pathElement(SUBSYSTEM, subsystemName);
if (address == PathAddress.EMPTY_ADDRESS) {
return getOrCreate(root, subsystemPath, resource).getModel();
}
Resource parent = getOrCreate(root, subsystemPath);
int count = address.size() - 1;
for (int index = 0; index < count; index++) {
parent = getOrCreate(parent, address.getElement(index));
}
final ImmutableManagementResourceRegistration subModel = registration.getSubModel(getSubsystemAddress(subsystemName, address));
if (subModel == null) {
throw new IllegalStateException(address.toString());
}
return getOrCreate(parent, address.getLastElement(), resource).getModel();
}
}
private static Resource getOrCreate(final Resource parent, final PathElement element) {
return getOrCreate(parent, element, null);
}
private static Resource getOrCreate(final Resource parent, final PathElement element, final Resource desired) {
synchronized (parent) {
if (parent.hasChild(element)) {
if (desired == null) {
return parent.requireChild(element);
} else {
throw new IllegalStateException();
}
} else {
return register(parent, element, desired);
}
}
}
private static Resource register(final Resource parent, final PathElement element, final Resource desired) {
synchronized (parent) {
Resource toRegister = desired;
if (toRegister == null) {
toRegister = Resource.Factory.create(true);
} else if (!toRegister.isRuntime()) {
throw ControllerLogger.ROOT_LOGGER.deploymentResourceMustBeRuntimeOnly();
}
parent.registerChild(element, toRegister);
return toRegister;
}
}
private static PathAddress getSubsystemAddress(final String subsystemName, final PathAddress elements) {
PathAddress address = PathAddress.EMPTY_ADDRESS.append(PathElement.pathElement(SUBSYSTEM, subsystemName));
address = address.append(elements);
return address;
}
}