/*
* 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.infinispan.server.jgroups.subsystem;
import org.infinispan.server.commons.dmr.ModelNodes;
import org.infinispan.server.commons.naming.BinderServiceBuilder;
import org.infinispan.server.jgroups.logging.JGroupsLogger;
import org.infinispan.server.jgroups.spi.ChannelFactory;
import org.infinispan.server.jgroups.spi.ProtocolConfiguration;
import org.infinispan.server.jgroups.spi.service.ProtocolStackServiceName;
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.registry.Resource;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.Property;
import org.jboss.msc.service.ServiceTarget;
/**
* @author Paul Ferraro
* @author Richard Achmatowicz
* @author Radoslav Husar
*/
public class StackAddHandler extends AbstractAddStepHandler {
@Override
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
installRuntimeServices(context, operation, Resource.Tools.readModel(context.readResource(PathAddress.EMPTY_ADDRESS)));
}
static void installRuntimeServices(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
String name = context.getCurrentAddressValue();
if (!model.hasDefined(TransportResourceDefinition.WILDCARD_PATH.getKey())) {
throw JGroupsLogger.ROOT_LOGGER.transportNotDefined(name);
}
ServiceTarget target = context.getServiceTarget();
Property property = model.get(TransportResourceDefinition.WILDCARD_PATH.getKey()).asProperty();
String type = property.getName();
ModelNode transport = property.getValue();
String machine = ModelNodes.asString(TransportResourceDefinition.MACHINE.resolveModelAttribute(context, transport));
String rack = ModelNodes.asString(TransportResourceDefinition.RACK.resolveModelAttribute(context, transport));
String site = ModelNodes.asString(TransportResourceDefinition.SITE.resolveModelAttribute(context, transport));
JChannelFactoryBuilder builder = new JChannelFactoryBuilder(name);
TransportConfigurationBuilder transportBuilder = builder.setTransport(type)
.setModule(ModelNodes.asModuleIdentifier(ProtocolResourceDefinition.MODULE.resolveModelAttribute(context, transport)))
.setShared(TransportResourceDefinition.SHARED.resolveModelAttribute(context, transport).asBoolean())
.setTopology(site, rack, machine)
.setSocketBinding(ModelNodes.asString(ProtocolResourceDefinition.SOCKET_BINDING.resolveModelAttribute(context, transport)))
.setDiagnosticsSocket(ModelNodes.asString(TransportResourceDefinition.DIAGNOSTICS_SOCKET_BINDING.resolveModelAttribute(context, transport)));
addProtocolProperties(context, transport, transportBuilder);
// Setup thread pool configuration via JGroups properties
addThreadPoolConfigurationProperties(ThreadPoolResourceDefinition.DEFAULT, "thread_pool", context, transport, transportBuilder);
transportBuilder.build(target).install();
if (model.hasDefined(RelayResourceDefinition.PATH.getKey())) {
ModelNode relay = model.get(RelayResourceDefinition.PATH.getKeyValuePair());
String siteName = RelayResourceDefinition.SITE.resolveModelAttribute(context, relay).asString();
RelayConfigurationBuilder relayBuilder = builder.setRelay(siteName);
if (relay.hasDefined(RemoteSiteResourceDefinition.WILDCARD_PATH.getKey())) {
for (Property remoteSiteProperty: relay.get(RemoteSiteResourceDefinition.WILDCARD_PATH.getKey()).asPropertyList()) {
String remoteSiteName = remoteSiteProperty.getName();
String channelName = RemoteSiteResourceDefinition.CHANNEL.resolveModelAttribute(context, remoteSiteProperty.getValue()).asString();
relayBuilder.addRemoteSite(remoteSiteName, channelName).build(target).install();
}
}
addProtocolProperties(context, relay, relayBuilder).build(target).install();
}
if (model.hasDefined(SaslResourceDefinition.PATH.getKey())) {
ModelNode sasl = model.get(SaslResourceDefinition.PATH.getKeyValuePair());
String mech = SaslResourceDefinition.MECH.resolveModelAttribute(context, sasl).asString();
String securityRealm = SaslResourceDefinition.SECURITY_REALM.resolveModelAttribute(context, sasl).asString();
SaslConfigurationBuilder saslBuilder = builder.setSasl(mech, securityRealm);
ModelNode resolvedValue;
final String clusterRole = (resolvedValue = SaslResourceDefinition.CLUSTER_ROLE.resolveModelAttribute(context, sasl)).isDefined() ? resolvedValue.asString() : null;
saslBuilder.setClusterRole(clusterRole);
addProtocolProperties(context, sasl, saslBuilder).build(target).install();
}
if (model.hasDefined(ProtocolResourceDefinition.WILDCARD_PATH.getKey())) {
for (Property protocolProperty : model.get(ProtocolResourceDefinition.WILDCARD_PATH.getKey()).asPropertyList()) {
ModelNode protocol = protocolProperty.getValue();
ProtocolConfigurationBuilder protocolBuilder = builder.addProtocol(protocolProperty.getName())
.setModule(ModelNodes.asModuleIdentifier(ProtocolResourceDefinition.MODULE.resolveModelAttribute(context, protocol)))
.setSocketBinding(ModelNodes.asString(ProtocolResourceDefinition.SOCKET_BINDING.resolveModelAttribute(context, protocol)));
addProtocolProperties(context, protocol, protocolBuilder).build(target).install();
}
}
builder.build(target).install();
new BinderServiceBuilder<>(JGroupsBindingFactory.createChannelFactoryBinding(name), ProtocolStackServiceName.CHANNEL_FACTORY.getServiceName(name), ChannelFactory.class).build(target).install();
}
static void removeRuntimeServices(OperationContext context, ModelNode operation, ModelNode model) {
String name = context.getCurrentAddressValue();
// remove the ChannelFactoryServiceService
context.removeService(JGroupsBindingFactory.createChannelFactoryBinding(name).getBinderServiceName());
context.removeService(ProtocolStackServiceName.CHANNEL_FACTORY.getServiceName(name));
Property transport = model.get(TransportResourceDefinition.WILDCARD_PATH.getKey()).asProperty();
context.removeService(new TransportConfigurationBuilder(name, transport.getName()).getServiceName());
if (model.hasDefined(ProtocolResourceDefinition.WILDCARD_PATH.getKey())) {
for (Property protocol : model.get(ProtocolResourceDefinition.WILDCARD_PATH.getKey()).asPropertyList()) {
context.removeService(new ProtocolConfigurationBuilder(name, protocol.getName()).getServiceName());
}
}
if (model.hasDefined(RelayResourceDefinition.PATH.getKey())) {
context.removeService(new RelayConfigurationBuilder(name).getServiceName());
ModelNode relay = model.get(RelayResourceDefinition.PATH.getKeyValuePair());
if (relay.hasDefined(RemoteSiteResourceDefinition.WILDCARD_PATH.getKey())) {
for (Property remoteSite: relay.get(RemoteSiteResourceDefinition.WILDCARD_PATH.getKey()).asPropertyList()) {
context.removeService(new RemoteSiteConfigurationBuilder(name, remoteSite.getName()).getServiceName());
}
}
}
if (model.hasDefined(SaslResourceDefinition.PATH.getKey())) {
context.removeService(new SaslConfigurationBuilder(name).getServiceName());
}
}
static <C extends ProtocolConfiguration, B extends AbstractProtocolConfigurationBuilder<C>> B addProtocolProperties(OperationContext context, ModelNode protocol, B builder) throws OperationFailedException {
if (protocol.hasDefined(ProtocolResourceDefinition.PROPERTIES.getName())) {
for (Property property : ProtocolResourceDefinition.PROPERTIES.resolveModelAttribute(context, protocol).asPropertyList()) {
builder.addProperty(property.getName(), property.getValue().asString());
}
}
return builder;
}
static <C extends ProtocolConfiguration, B extends AbstractProtocolConfigurationBuilder<C>> B addThreadPoolConfigurationProperties(ThreadPoolResourceDefinition pool, String propertyPrefix, OperationContext context, ModelNode transport, B builder) throws OperationFailedException {
ModelNode threadModel = transport.get(pool.getPathElement().getKeyValuePair());
builder.addProperty(propertyPrefix + ".min_threads", pool.getMinThreads().resolveModelAttribute(context, threadModel).asString())
.addProperty(propertyPrefix + ".max_threads", pool.getMaxThreads().resolveModelAttribute(context, threadModel).asString());
// keepalive_time in milliseconds
long keepaliveTime = pool.getKeepaliveTime().resolveModelAttribute(context, threadModel).asLong();
builder.addProperty(propertyPrefix + ".keep_alive_time", String.valueOf(keepaliveTime));
return builder;
}
}