/** * Copyright 2015-2016 Red Hat, Inc, and individual contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.wildfly.swarm.topology.jgroups.runtime; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.jboss.as.network.SocketBinding; import org.jboss.msc.inject.Injector; import org.jboss.msc.service.Service; import org.jboss.msc.service.StartContext; import org.jboss.msc.service.StartException; import org.jboss.msc.service.StopContext; import org.jboss.msc.value.InjectedValue; import org.wildfly.clustering.dispatcher.CommandDispatcher; import org.wildfly.clustering.dispatcher.CommandDispatcherFactory; import org.wildfly.clustering.group.Group; import org.wildfly.clustering.group.Node; import org.wildfly.swarm.topology.TopologyConnector; import org.wildfly.swarm.topology.TopologyMessages; import org.wildfly.swarm.topology.runtime.Registration; import org.wildfly.swarm.topology.runtime.TopologyManager; /** * @author Bob McWhirter */ public class JGroupsTopologyConnector implements Service<JGroupsTopologyConnector>, Group.Listener, TopologyConnector { public JGroupsTopologyConnector() { } public Injector<CommandDispatcherFactory> getCommandDispatcherFactoryInjector() { return this.commandDispatcherFactoryInjector; } public Injector<TopologyManager> getTopologyManagerInjector() { return this.topologyManagerInjector; } @Override public void start(StartContext startContext) throws StartException { this.commandDispatcherFactoryInjector.getValue().getGroup().addListener(this); this.dispatcher = this.commandDispatcherFactoryInjector.getValue().createCommandDispatcher("netflix.runtime.manager", this); this.node = this.commandDispatcherFactoryInjector.getValue().getGroup().getLocalNode(); try { requestAdvertisements(); } catch (Exception e) { throw new StartException(e); } } @Override public void stop(StopContext stopContext) { this.dispatcher.close(); } @Override public JGroupsTopologyConnector getValue() throws IllegalStateException, IllegalArgumentException { return this; } @Override public void membershipChanged(List<Node> previousMembers, List<Node> members, boolean merged) { try { advertiseAll(); } catch (Exception e) { TopologyMessages.MESSAGES.errorStartingAdvertisement(e); } List<Node> removed = new ArrayList<>(); removed.addAll(previousMembers); removed.removeAll(members); removed.forEach((e) -> { this.topologyManagerInjector.getValue().unregisterAll(sourceKey(e)); }); } public synchronized void advertise(String name, SocketBinding binding, String... tags) throws Exception { Registration registration = new Registration(sourceKey(this.node), name, binding.getAddress().getHostAddress(), binding.getAbsolutePort(), tags); this.registrations.put(name + ":" + binding.getName(), registration); advertise(registration); } public synchronized void advertise(Registration registration) throws Exception { this.topologyManagerInjector.getValue().register(registration); doAdvertise(registration); } public synchronized void unadvertise(String appName, SocketBinding binding) throws Exception { Registration registration = this.registrations.remove(appName + ":" + binding.getName()); if (registration != null) { this.dispatcher.submitOnCluster(new UnadvertiseCommand(registration)); } } protected void requestAdvertisements() throws Exception { this.dispatcher.submitOnCluster(new RequestAdvertisementsCommand(), this.node); } protected synchronized void advertiseAll() throws Exception { for (Registration each : this.topologyManagerInjector.getValue().registrationsForSourceKey(sourceKey(this.node))) { doAdvertise(each); } } protected void doAdvertise(Registration registration) throws Exception { this.dispatcher.submitOnCluster(new AdvertiseCommand(registration)); } void register(Registration registration) { this.topologyManagerInjector.getValue().register(registration); } void unregister(Registration registration) { this.topologyManagerInjector.getValue().unregister(registration); } String sourceKey(Node node) { return node.getName() + ":" + node.getSocketAddress().toString(); } private InjectedValue<CommandDispatcherFactory> commandDispatcherFactoryInjector = new InjectedValue<>(); private InjectedValue<TopologyManager> topologyManagerInjector = new InjectedValue<>(); private CommandDispatcher<JGroupsTopologyConnector> dispatcher; private Node node; private Map<String, Registration> registrations = new ConcurrentHashMap<>(); }