/*
* JBoss, Home of Professional Open Source.
* Copyright 2011, 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.clustering.infinispan.subsystem;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.infinispan.Cache;
import org.infinispan.server.commons.controller.ReloadRequiredAddStepHandler;
import org.infinispan.server.commons.dmr.ModelNodes;
import org.infinispan.server.commons.naming.BinderServiceBuilder;
import org.infinispan.server.commons.naming.JndiNameFactory;
import org.infinispan.server.commons.service.AliasServiceBuilder;
import org.infinispan.server.infinispan.spi.CacheContainer;
import org.infinispan.server.infinispan.spi.service.CacheContainerServiceName;
import org.infinispan.server.infinispan.spi.service.CacheContainerServiceNameFactory;
import org.infinispan.server.infinispan.spi.service.CacheServiceName;
import org.infinispan.server.infinispan.spi.service.CacheServiceNameFactory;
import org.infinispan.server.jgroups.spi.ChannelFactory;
import org.infinispan.server.jgroups.spi.service.ChannelBuilder;
import org.infinispan.server.jgroups.spi.service.ChannelConnectorBuilder;
import org.infinispan.server.jgroups.spi.service.ChannelServiceName;
import org.infinispan.server.jgroups.spi.service.ChannelServiceNameFactory;
import org.infinispan.server.jgroups.spi.service.ProtocolStackServiceName;
import org.infinispan.server.jgroups.subsystem.JGroupsBindingFactory;
import org.jboss.as.controller.AbstractAddStepHandler;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.operations.common.Util;
import org.jboss.as.controller.registry.Resource;
import org.jboss.as.naming.deployment.ContextNames;
import org.jboss.as.server.ServerEnvironment;
import org.jboss.dmr.ModelNode;
import org.jboss.modules.ModuleIdentifier;
import org.jboss.msc.service.ServiceTarget;
import org.jgroups.JChannel;
/**
* Add operation handler for /subsystem=infinispan/cache-container=*
* @author Paul Ferraro
* @author Tristan Tarrant
* @author Richard Achmatowicz
*/
public class CacheContainerAddHandler extends AbstractAddStepHandler {
CacheContainerAddHandler() {
super(CacheContainerResource.CACHE_CONTAINER_ATTRIBUTES);
}
@Override
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
// Because we use child resources in a read-only manner to configure the cache container, replace the local model with the full model
installRuntimeServices(context, operation, Resource.Tools.readModel(context.readResource(PathAddress.EMPTY_ADDRESS)));
}
@Override
protected Resource createResource(OperationContext context) {
//HEALTH is a synthetic resource - we don't have it in XML but we would like to include it in the runtime
Resource resource = super.createResource(context);
PathAddress healthAddress = context.getCurrentAddress().append(ModelKeys.HEALTH, ModelKeys.HEALTH_NAME);
context.addStep(Util.createAddOperation(healthAddress), new ReloadRequiredAddStepHandler(), OperationContext.Stage.MODEL);
return resource;
}
static void installRuntimeServices(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
String name = context.getCurrentAddressValue();
ServiceTarget target = context.getServiceTarget();
// pick up the attribute values from the model
// make default cache non required (AS7-3488)
String defaultCache = ModelNodes.asString(CacheContainerResource.DEFAULT_CACHE.resolveModelAttribute(context, model));
String jndiName = ModelNodes.asString(CacheContainerResource.JNDI_NAME.resolveModelAttribute(context, model));
ModuleIdentifier module = ModelNodes.asModuleIdentifier(CacheContainerResource.CACHE_CONTAINER_MODULE.resolveModelAttribute(context, model));
CacheContainerConfigurationBuilder configBuilder = new CacheContainerConfigurationBuilder(name)
.setModule(module)
.setStatisticsEnabled(CacheContainerResource.STATISTICS.resolveModelAttribute(context, model).asBoolean());
if (model.hasDefined(TransportResource.TRANSPORT_PATH.getKey())) {
ModelNode transport = model.get(TransportResource.TRANSPORT_PATH.getKeyValuePair());
String channel = ModelNodes.asString(TransportResource.CHANNEL.resolveModelAttribute(context, transport), ChannelServiceNameFactory.DEFAULT_CHANNEL);
TransportConfigurationBuilder transportBuilder = configBuilder.setTransport()
.setLockTimeout(TransportResource.LOCK_TIMEOUT.resolveModelAttribute(context, transport).asLong(), TimeUnit.MILLISECONDS)
.setStrictPeerToPeer(TransportResource.STRICT_PEER_TO_PEER.resolveModelAttribute(context, transport).asBoolean());
if (transport.hasDefined(ModelKeys.INITIAL_CLUSTER_SIZE)) {
transportBuilder.setInitialClusterSize(TransportResource.INITIAL_CLUSTER_SIZE.resolveModelAttribute(context, transport).asInt());
}
if (transport.hasDefined(ModelKeys.INITIAL_CLUSTER_TIMEOUT)) {
transportBuilder.setInitialClusterTimeout(TransportResource.INITIAL_CLUSTER_TIMEOUT.resolveModelAttribute(context, transport).asLong());
}
transportBuilder.build(target).install();
if (!name.equals(channel)) {
new BinderServiceBuilder<>(JGroupsBindingFactory.createChannelBinding(name), ChannelServiceName.CHANNEL.getServiceName(name), JChannel.class).build(target).install();
new ChannelBuilder(name).build(target).install();
new ChannelConnectorBuilder(name).build(target).install();
new AliasServiceBuilder<>(ChannelServiceName.FACTORY.getServiceName(name), ProtocolStackServiceName.CHANNEL_FACTORY.getServiceName(channel), ChannelFactory.class).build(target).install();
}
}
if (model.hasDefined(GlobalStateResource.GLOBAL_STATE_PATH.getKey())) {
ModelNode globalState = model.get(GlobalStateResource.GLOBAL_STATE_PATH.getKeyValuePair());
final String defaultPersistentLocation = InfinispanExtension.SUBSYSTEM_NAME + File.separatorChar + name;
GlobalStateLocationConfigurationBuilder globalStateBuilder = configBuilder.setGlobalState();
if (globalState.hasDefined(ModelKeys.PERSISTENT_LOCATION)) {
ModelNode persistentLocation = globalState.get(ModelKeys.PERSISTENT_LOCATION);
final String path = ModelNodes.asString(GlobalStateResource.PATH.resolveModelAttribute(context, persistentLocation), defaultPersistentLocation);
final String relativeTo = ModelNodes.asString(GlobalStateResource.TEMPORARY_RELATIVE_TO.resolveModelAttribute(context, persistentLocation));
globalStateBuilder.setPersistencePath(path).setPersistenceRelativeTo(relativeTo);
} else {
globalStateBuilder.setPersistencePath(defaultPersistentLocation).setPersistenceRelativeTo(ServerEnvironment.SERVER_DATA_DIR);
}
if (globalState.hasDefined(ModelKeys.TEMPORARY_LOCATION)) {
ModelNode persistentLocation = globalState.get(ModelKeys.TEMPORARY_LOCATION);
final String path = ModelNodes.asString(GlobalStateResource.PATH.resolveModelAttribute(context, persistentLocation), defaultPersistentLocation);
final String relativeTo = ModelNodes.asString(GlobalStateResource.TEMPORARY_RELATIVE_TO.resolveModelAttribute(context, persistentLocation));
globalStateBuilder.setTemporaryPath(path).setTemporaryRelativeTo(relativeTo);
} else {
globalStateBuilder.setTemporaryPath(defaultPersistentLocation).setTemporaryRelativeTo(ServerEnvironment.SERVER_TEMP_DIR);
}
}
AuthorizationConfigurationBuilder authorizationConfig = null;
if (model.hasDefined(ModelKeys.SECURITY) && model.get(ModelKeys.SECURITY).hasDefined(ModelKeys.SECURITY_NAME)) {
ModelNode securityModel = model.get(ModelKeys.SECURITY, ModelKeys.SECURITY_NAME);
if (securityModel.hasDefined(ModelKeys.AUTHORIZATION) && securityModel.get(ModelKeys.AUTHORIZATION).hasDefined(ModelKeys.AUTHORIZATION_NAME)) {
ModelNode authzModel = securityModel.get(ModelKeys.AUTHORIZATION, ModelKeys.AUTHORIZATION_NAME);
authorizationConfig = configBuilder.setAuthorization();
if (authzModel.hasDefined(ModelKeys.AUDIT_LOGGER)) {
authorizationConfig.setAuditLogger(ModelNodes.asString(CacheContainerAuthorizationResource.AUDIT_LOGGER.resolveModelAttribute(context, authzModel)));
}
authorizationConfig.setPrincipalMapper(ModelNodes.asString(CacheContainerAuthorizationResource.MAPPER.resolveModelAttribute(context, authzModel)));
for(ModelNode roleNode : authzModel.get(ModelKeys.ROLE).asList()) {
ModelNode role = roleNode.get(0);
String roleName = AuthorizationRoleResource.NAME.resolveModelAttribute(context, role).asString();
List<String> permissions = new ArrayList<>();
for(ModelNode permission : AuthorizationRoleResource.PERMISSIONS.resolveModelAttribute(context, role).asList()) {
permissions.add(permission.asString());
}
authorizationConfig.getRoles().put(roleName, permissions);
}
}
}
// Install cache container configuration service
configBuilder.build(target).install();
// Install cache container service
CacheContainerBuilder containerBuilder = new CacheContainerBuilder(name, defaultCache);
if (model.hasDefined(CacheContainerResource.ALIASES.getName())) {
for (ModelNode alias : operation.get(CacheContainerResource.ALIASES.getName()).asList()) {
containerBuilder.addAlias(alias.asString());
}
}
containerBuilder.build(target).install();
// Install cache container jndi binding
ContextNames.BindInfo binding = InfinispanBindingFactory.createCacheContainerBinding(name);
BinderServiceBuilder<CacheContainer> bindingBuilder = new BinderServiceBuilder<>(binding, CacheContainerServiceName.CACHE_CONTAINER.getServiceName(name), CacheContainer.class);
if (jndiName != null) {
bindingBuilder.alias(ContextNames.bindInfoFor(JndiNameFactory.parse(jndiName).getAbsoluteName()));
}
bindingBuilder.build(target).install();
if ((defaultCache != null) && !defaultCache.equals(CacheServiceNameFactory.DEFAULT_CACHE)) {
for (CacheServiceNameFactory nameFactory : CacheServiceName.values()) {
new AliasServiceBuilder<>(nameFactory.getServiceName(name), nameFactory.getServiceName(name, defaultCache), Object.class).build(target).install();
}
new BinderServiceBuilder<>(InfinispanBindingFactory.createCacheBinding(name, CacheServiceNameFactory.DEFAULT_CACHE), CacheServiceName.CACHE.getServiceName(name), Cache.class).build(target).install();
}
}
static void removeRuntimeServices(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
String name = context.getCurrentAddressValue();
// remove the BinderService entry
context.removeService(InfinispanBindingFactory.createCacheContainerBinding(name).getBinderServiceName());
for (CacheContainerServiceNameFactory factory : CacheContainerServiceName.values()) {
context.removeService(factory.getServiceName(name));
}
if (model.hasDefined(TransportResource.TRANSPORT_PATH.getKey())) {
context.removeService(new TransportConfigurationBuilder(name).getServiceName());
context.removeService(JGroupsBindingFactory.createChannelBinding(name).getBinderServiceName());
for (ChannelServiceNameFactory factory : ChannelServiceName.values()) {
context.removeService(factory.getServiceName(name));
}
}
}
}