All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.infinispan.server.state.ServerStateManagerImpl Maven / Gradle / Ivy

The newest version!
package org.infinispan.server.state;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ConcurrentHashMap;

import org.infinispan.Cache;
import org.infinispan.commons.dataconversion.internal.Json;
import org.infinispan.commons.marshall.ProtoStreamTypeIds;
import org.infinispan.commons.util.concurrent.CompletableFutures;
import org.infinispan.globalstate.GlobalConfigurationManager;
import org.infinispan.globalstate.ScopeFilter;
import org.infinispan.globalstate.ScopedState;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.notifications.Listener;
import org.infinispan.notifications.cachelistener.annotation.CacheEntryCreated;
import org.infinispan.notifications.cachelistener.annotation.CacheEntryModified;
import org.infinispan.notifications.cachelistener.annotation.CacheEntryRemoved;
import org.infinispan.notifications.cachelistener.event.CacheEntryCreatedEvent;
import org.infinispan.notifications.cachelistener.event.CacheEntryEvent;
import org.infinispan.notifications.cachelistener.event.CacheEntryModifiedEvent;
import org.infinispan.notifications.cachelistener.event.CacheEntryRemovedEvent;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.annotations.ProtoTypeId;
import org.infinispan.security.AuthorizationPermission;
import org.infinispan.security.Security;
import org.infinispan.security.actions.SecurityActions;
import org.infinispan.server.Server;
import org.infinispan.server.core.ProtocolServer;
import org.infinispan.server.core.ServerManagement;
import org.infinispan.server.core.ServerStateManager;
import org.infinispan.server.core.transport.CompositeChannelMatcher;
import org.infinispan.server.core.transport.ConnectionMetadata;
import org.infinispan.server.core.transport.IpFilterRuleChannelMatcher;
import org.infinispan.server.core.transport.IpSubnetFilterRule;
import org.infinispan.server.core.transport.Transport;

import io.netty.channel.Channel;
import io.netty.channel.group.ChannelGroup;
import io.netty.handler.ipfilter.IpFilterRuleType;
import io.netty.handler.ssl.SslHandler;

/**
 * Manages cluster-wide server state for a given {@link EmbeddedCacheManager}. This handles:
 * 
    *
  • ignored caches
  • *
  • protocol servers
  • *
  • ip filters
  • *
* * @since 12.1 */ public final class ServerStateManagerImpl implements ServerStateManager { private static final String CONNECTOR_STATE_SCOPE = "connector-state"; private static final String CONNECTOR_IPFILTER_SCOPE = "connector-ipfilter"; private static final ScopedState IGNORED_CACHES_KEY = new ScopedState("ignored-caches", "ignored-caches"); private final EmbeddedCacheManager cacheManager; private final Server server; private final Cache cache; private final IgnoredCaches ignored = new IgnoredCaches(); private volatile boolean hasIgnores; public ServerStateManagerImpl(Server server, EmbeddedCacheManager cacheManager, GlobalConfigurationManager configurationManager) { this.server = server; this.cacheManager = cacheManager; this.cache = configurationManager.getStateCache(); } @Override public void start() { updateLocalIgnoredCaches((IgnoredCaches) cache.get(IGNORED_CACHES_KEY)); // Register the listeners which will react on cache.addListener(new IgnoredCachesListener(), new ScopeFilter(IGNORED_CACHES_KEY.getScope()), null); cache.addListener(new ConnectorStateListener(), new ScopeFilter(CONNECTOR_STATE_SCOPE), null); cache.addListener(new ConnectorIpFilterListener(), new ScopeFilter(CONNECTOR_IPFILTER_SCOPE), null); } @Override public void stop() { } @Override public CompletableFuture unignoreCache(String cacheName) { SecurityActions.checkPermission(cacheManager, AuthorizationPermission.ADMIN); synchronized (this) { ignored.caches.remove(cacheName); hasIgnores = !ignored.caches.isEmpty(); return cache.putAsync(IGNORED_CACHES_KEY, ignored).thenApply(r -> null); } } @Override public CompletableFuture ignoreCache(String cacheName) { SecurityActions.checkPermission(cacheManager, AuthorizationPermission.ADMIN); synchronized (this) { ignored.caches.add(cacheName); hasIgnores = true; return cache.putAsync(IGNORED_CACHES_KEY, ignored).thenApply(r -> null); } } @Override public Set getIgnoredCaches() { return Collections.unmodifiableSet(ignored.caches); } @Override public boolean isCacheIgnored(String cacheName) { return hasIgnores && ignored.caches.contains(cacheName); } @Override public CompletableFuture connectorStart(String name) { SecurityActions.checkPermission(cacheManager, AuthorizationPermission.ADMIN); return cache.removeAsync(new ScopedState(CONNECTOR_STATE_SCOPE, name), true).thenApply(v -> null); } @Override public CompletableFuture connectorStop(String name) { SecurityActions.checkPermission(cacheManager, AuthorizationPermission.ADMIN); return cache.putAsync(new ScopedState(CONNECTOR_STATE_SCOPE, name), true).thenApply(v -> null); } @Override public CompletableFuture connectorStatus(String name) { SecurityActions.checkPermission(cacheManager, AuthorizationPermission.ADMIN); return cache.containsKeyAsync(new ScopedState(CONNECTOR_STATE_SCOPE, name)).thenApply(v -> !v); } @Override public CompletableFuture setConnectorIpFilterRule(String name, Collection filterRule) { SecurityActions.checkPermission(cacheManager, AuthorizationPermission.ADMIN); IpFilterRules ipFilterRules = new IpFilterRules(); filterRule.forEach(r -> ipFilterRules.rules.add(new IpFilterRule(r))); return cache.putAsync(new ScopedState(CONNECTOR_IPFILTER_SCOPE, name), ipFilterRules).thenApply(v -> null); } @Override public CompletableFuture clearConnectorIpFilterRules(String name) { SecurityActions.checkPermission(cacheManager, AuthorizationPermission.ADMIN); return cache.putAsync(new ScopedState(CONNECTOR_IPFILTER_SCOPE, name), new IpFilterRules()).thenApply(v -> null); } @Override public CompletableFuture listConnections() { Json r = Json.array(); for (Map.Entry ps : server.getProtocolServers().entrySet()) { Transport transport = ps.getValue().getTransport(); if (transport != null) { ChannelGroup channels = transport.getAcceptedChannels(); channels.forEach(ch -> { ConnectionMetadata metadata = ConnectionMetadata.getInstance(ch); Json o = Json.object(); o.set("id", metadata.id()); o.set("server-node-name", server.getCacheManager().getAddress().toString()); o.set("name", metadata.clientName()); o.set("created", metadata.created()); o.set("principal", Security.getSubjectUserPrincipalName(metadata.subject())); o.set("local-address", metadata.localAddress().toString()); o.set("remote-address", metadata.remoteAddress().toString()); o.set("protocol-version", metadata.protocolVersion()); o.set("client-library", metadata.clientLibraryName()); o.set("client-version", metadata.clientLibraryVersion()); SslHandler ssl = ch.pipeline().get(SslHandler.class); if (ssl != null) { o.set("ssl-application-protocol", ssl.applicationProtocol()); o.set("ssl-cipher-suite", ssl.engine().getSession().getCipherSuite()); o.set("ssl-protocol", ssl.engine().getSession().getProtocol()); } r.add(o); }); } } return CompletableFuture.completedFuture(r); } @Override public Json clientsReport() { Json result = Json.object(); for (ProtocolServer protocolServer : server.getProtocolServers().values()) { Transport transport = protocolServer.getTransport(); if (transport == null) { continue; } ChannelGroup channels = transport.getAcceptedChannels(); if (channels.isEmpty()) { continue; } HashSet clientNames = new HashSet<>(); HashSet protocolVersions = new HashSet<>(); HashSet clientLibraryNames = new HashSet<>(); HashSet clientLibraryVersions = new HashSet<>(); for (Channel channel : channels) { ConnectionMetadata metadata = ConnectionMetadata.getInstance(channel); String clientName = metadata.clientName(); if (clientName != null) { clientNames.add(clientName); } String protocolVersion = metadata.protocolVersion(); if (protocolVersion != null) { protocolVersions.add(protocolVersion); } String clientLibraryName = metadata.clientLibraryName(); if (clientLibraryName != null) { clientLibraryNames.add(clientLibraryName); } String clientLibraryVersion = metadata.clientLibraryVersion(); if (clientLibraryVersion != null) { clientLibraryVersions.add(clientLibraryVersion); } } Json protocolServerReport = Json.object(); if (!clientNames.isEmpty()){ protocolServerReport.set("client-names", Json.make(clientNames)); } if (!protocolVersions.isEmpty()){ protocolServerReport.set("protocol-versions", Json.make(protocolVersions)); } if (!clientLibraryNames.isEmpty()){ protocolServerReport.set("client-library-names", Json.make(clientLibraryNames)); } if (!clientLibraryVersions.isEmpty()){ protocolServerReport.set("client-library-versions", Json.make(clientLibraryVersions)); } result.set(protocolServer.getName(), protocolServerReport); } return result; } @Override public ServerManagement managedServer() { return server; } private void updateLocalIgnoredCaches(IgnoredCaches ignored) { if (ignored != null) { synchronized (this) { this.ignored.caches.clear(); this.ignored.caches.addAll(ignored.caches); hasIgnores = !this.ignored.caches.isEmpty(); } } } private CompletionStage updateIpFilters(String connector, Collection rules) { ProtocolServer protocolServer = server.getProtocolServers().get(connector); if (rules.isEmpty()) { protocolServer.getConfiguration().ipFilter().rules(Collections.emptyList()); Server.log.connectorIpFilterCleared(connector); return CompletableFutures.completedNull(); } else { List localRules = new ArrayList<>(rules.size()); for (IpFilterRule rule : rules) { localRules.add(new IpSubnetFilterRule(rule.cidr, IpFilterRuleType.valueOf(rule.type))); } protocolServer.getConfiguration().ipFilter().rules(localRules); Transport transport = getTransport(protocolServer); CompositeChannelMatcher matcher = new CompositeChannelMatcher(protocolServer.getChannelMatcher(), new IpFilterRuleChannelMatcher(localRules)); return transport.closeChannels(matcher).thenApply(v -> { Server.log.connectorIpFilterSet(connector, localRules); return v; }); } } @Listener(observation = Listener.Observation.POST, includeCurrentState = true, clustered = true) private final class IgnoredCachesListener { @CacheEntryCreated public void created(CacheEntryCreatedEvent e) { if (!e.isOriginLocal()) { updateLocalIgnoredCaches(e.getValue()); } } @CacheEntryModified public void modified(CacheEntryModifiedEvent e) { if (!e.isOriginLocal()) { updateLocalIgnoredCaches(e.getValue()); } } } @Listener(observation = Listener.Observation.POST, includeCurrentState = true, clustered = true) private final class ConnectorStateListener { @CacheEntryCreated public CompletionStage created(CacheEntryCreatedEvent e) { // stop the connector String connector = e.getKey().getName(); ProtocolServer protocolServer = server.getProtocolServers().get(connector); protocolServer.getConfiguration().disable(); // Close all active connections Transport transport = getTransport(protocolServer); return transport.closeChannels(protocolServer.getChannelMatcher()).thenApply(v -> { Server.log.connectorStopped(connector); return v; }); } @CacheEntryRemoved public void removed(CacheEntryRemovedEvent e) { // start the connector String connector = e.getKey().getName(); server.getProtocolServers().get(connector).getConfiguration().enable(); Server.log.connectorStarted(connector); } } private Transport getTransport(ProtocolServer protocolServer) { Transport transport = protocolServer.getTransport(); if (transport == null) { transport = protocolServer.getEnclosingProtocolServer().getTransport(); } return transport; } @Listener(observation = Listener.Observation.POST, includeCurrentState = true, clustered = true) private final class ConnectorIpFilterListener { @CacheEntryCreated @CacheEntryModified public CompletionStage modified(CacheEntryEvent e) { return updateIpFilters(e.getKey().getName(), e.getValue().rules); } } @ProtoTypeId(ProtoStreamTypeIds.IGNORED_CACHES) static final class IgnoredCaches { @ProtoField(number = 1, collectionImplementation = HashSet.class) final Set caches; IgnoredCaches() { this(ConcurrentHashMap.newKeySet()); } @ProtoFactory IgnoredCaches(Set caches) { // ProtoStream cannot use KeySetView directly as it does not have a zero args constructor this.caches = ConcurrentHashMap.newKeySet(caches.size()); this.caches.addAll(caches); } @Override public String toString() { return "IgnoredCaches" + caches; } } @ProtoTypeId(ProtoStreamTypeIds.IP_FILTER_RULE) static final class IpFilterRule { @ProtoField(number = 1) final String cidr; @ProtoField(number = 2) final String type; @ProtoFactory IpFilterRule(String cidr, String type) { this.cidr = cidr; this.type = type; } IpFilterRule(IpSubnetFilterRule filterRule) { this(filterRule.cidr(), filterRule.ruleType().name()); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; IpFilterRule that = (IpFilterRule) o; return cidr.equals(that.cidr) && type.equals(that.type); } @Override public int hashCode() { return Objects.hash(cidr, type); } } @ProtoTypeId(ProtoStreamTypeIds.IP_FILTER_RULES) static final class IpFilterRules { @ProtoField(number = 1, collectionImplementation = LinkedHashSet.class) final Set rules; IpFilterRules() { this(new LinkedHashSet<>()); } @ProtoFactory IpFilterRules(Set rules) { this.rules = new LinkedHashSet<>(rules.size()); this.rules.addAll(rules); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy