package org.infinispan.server.core; import java.net.InetSocketAddress; import javax.management.DynamicMBean; import javax.management.MBeanServer; import javax.management.ObjectName; import org.infinispan.commons.CacheException; import org.infinispan.commons.logging.LogFactory; import org.infinispan.configuration.global.GlobalConfiguration; import org.infinispan.factories.components.ManageableComponentMetadata; import org.infinispan.jmx.JmxUtil; import org.infinispan.jmx.ResourceDMBean; import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.server.core.configuration.ProtocolServerConfiguration; import org.infinispan.server.core.logging.Log; import org.infinispan.server.core.transport.NettyTransport; import io.netty.channel.epoll.Epoll; /** * A common protocol server dealing with common property parameter validation and assignment and transport lifecycle. * * @author Galder ZamarreƱo * @author wburns * @since 4.1 */ public abstract class AbstractProtocolServer<A extends ProtocolServerConfiguration> extends AbstractCacheIgnoreAware implements ProtocolServer<A> { private static final Log log = LogFactory.getLog(AbstractProtocolServer.class, Log.class); private final String protocolName; protected NettyTransport transport; protected EmbeddedCacheManager cacheManager; protected A configuration; private ObjectName transportObjName; private MBeanServer mbeanServer; private static final String USE_EPOLL_PROPERTY = "infinispan.server.channel.epoll"; private static final boolean IS_LINUX = System.getProperty("os.name").toLowerCase().startsWith("linux"); private static final boolean EPOLL_DISABLED = System.getProperty(USE_EPOLL_PROPERTY, "true").equalsIgnoreCase("false"); private static final boolean USE_NATIVE_EPOLL; static { if (Epoll.isAvailable()) { USE_NATIVE_EPOLL = !EPOLL_DISABLED && IS_LINUX; } else { if (IS_LINUX) { log.epollNotAvailable(Epoll.unavailabilityCause().toString()); } USE_NATIVE_EPOLL = false; } } protected AbstractProtocolServer(String protocolName) { this.protocolName = protocolName; } protected void startInternal(A configuration, EmbeddedCacheManager cacheManager) { this.configuration = configuration; this.cacheManager = cacheManager; if (log.isDebugEnabled()) { log.debugf("Starting server with configuration: %s", configuration); } // Start default cache startDefaultCache(); if(configuration.startTransport()) startTransport(); } @Override public final void start(A configuration, EmbeddedCacheManager cacheManager) { try { configuration.ignoredCaches().forEach(this::ignoreCache); startInternal(configuration, cacheManager); } catch (RuntimeException t) { stop(); throw t; } } protected void startTransport() { InetSocketAddress address = new InetSocketAddress(configuration.host(), configuration.port()); transport = new NettyTransport(address, configuration, getQualifiedName(), cacheManager, USE_NATIVE_EPOLL); transport.initializeHandler(getInitializer()); // Register transport MBean regardless registerTransportMBean(); transport.start(); } protected void registerTransportMBean() { GlobalConfiguration globalCfg = cacheManager.getCacheManagerConfiguration(); mbeanServer = JmxUtil.lookupMBeanServer(globalCfg); String groupName = String.format("type=Server,name=%s", getQualifiedName()); String jmxDomain = JmxUtil.buildJmxDomain(globalCfg, mbeanServer, groupName); // Pick up metadata from the component metadata repository ManageableComponentMetadata meta = LifecycleCallbacks.componentMetadataRepo .findComponentMetadata(transport.getClass()).toManageableComponentMetadata(); try { // And use this metadata when registering the transport as a dynamic MBean DynamicMBean dynamicMBean = new ResourceDMBean(transport, meta); transportObjName = new ObjectName(String.format("%s:%s,component=%s", jmxDomain, groupName, meta.getJmxObjectName())); JmxUtil.registerMBean(dynamicMBean, transportObjName, mbeanServer); } catch (Exception e) { throw new RuntimeException(e); } } protected void unregisterTransportMBean() throws Exception { if (mbeanServer != null && transportObjName != null) { // Unregister mbean(s) JmxUtil.unregisterMBean(transportObjName, mbeanServer); } } public String getQualifiedName() { return protocolName + (configuration.name().length() > 0 ? "-" : "") + configuration.name(); } @Override public void stop() { boolean isDebug = log.isDebugEnabled(); if (isDebug && configuration != null) log.debugf("Stopping server listening in %s:%d", configuration.host(), configuration.port()); if (transport != null) transport.stop(); try { unregisterTransportMBean(); } catch (Exception e) { throw new CacheException(e); } if (isDebug) log.debug("Server stopped"); } public EmbeddedCacheManager getCacheManager() { return cacheManager; } public String getHost() { return configuration.host(); } public int getPort() { return configuration.port(); } @Override public A getConfiguration() { return configuration; } protected void startDefaultCache() { cacheManager.getCache(configuration.defaultCacheName()); } public boolean isTransportEnabled() { return transport != null; } public NettyTransport getTransport() { return transport; } }