/* * #%L * Nazgul Project: nazgul-core-cache-impl-hazelcast * %% * Copyright (C) 2010 - 2017 jGuru Europe AB * %% * Licensed under the jGuru Europe AB license (the "License"), based * on Apache License, Version 2.0; you may not use this file except * in compliance with the License. * * You may obtain a copy of the License at * * http://www.jguru.se/licenses/jguruCorporateSourceLicense-2.0.txt * * 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. * #L% * */ package se.jguru.nazgul.core.cache.impl.hazelcast; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.joran.JoranConfigurator; import ch.qos.logback.core.joran.spi.JoranException; import com.hazelcast.config.Config; import com.hazelcast.config.TcpIpConfig; import com.hazelcast.core.DistributedObject; import com.hazelcast.core.Hazelcast; import com.hazelcast.core.HazelcastInstance; import com.hazelcast.core.MultiMap; import org.junit.AfterClass; import org.junit.Before; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import se.jguru.nazgul.core.algorithms.api.NetworkAlgorithms; import se.jguru.nazgul.core.cache.impl.hazelcast.clients.HazelcastCacheMember; import se.jguru.nazgul.core.cache.impl.hazelcast.grid.GridOperations; import java.lang.reflect.Field; import java.net.URL; import java.util.Collection; import java.util.Map; import java.util.Set; import java.util.TreeSet; /** * Trivial abstract class which shuts down Hazelcast completely after each testcase. * * @author <a href="mailto:lj@jguru.se">Lennart Jörelid</a>, jGuru Europe AB */ public abstract class AbstractHazelcastCacheTest { // Our log private static final Logger log = LoggerFactory.getLogger(AbstractHazelcastCacheTest.class); public static final String DEFAULT_LOGBACK_CONFIGURATION_PATH = "config/logging/logback-test.xml"; // Shared state private static String localHostNonLoopbackAddr; @Before public void setupSharedState() { localHostNonLoopbackAddr = NetworkAlgorithms.getAllLocalNetworkAddresses( NetworkAlgorithms.PUBLIC_IPV4_FILTER, null) .stream() .findFirst().orElseThrow(() -> new RuntimeException("Cannot build the HazelcastCacheImplementation " + "project without any active Inet4Address")); } /** * Acquires a AbstractHazelcastInstanceWrapper instance, invigorated by the provided * configuration file. * * @param configFile The classpath-relative resource path to a Hazelcast configuration file. * @return A fully set-up AbstractHazelcastInstanceWrapper instance. */ protected static HazelcastCacheMember getCache(final String configFile) { // Add a local, non-loopback interface. final Config config = HazelcastCacheMember.readConfigFile(configFile); final TcpIpConfig tcpIpConfig = config.getNetworkConfig().getJoin().getTcpIpConfig(); tcpIpConfig.addMember(localHostNonLoopbackAddr); log.info("Got Config: " + config); return new HazelcastCacheMember(config); } public static void configureLogging() { configureLogging(DEFAULT_LOGBACK_CONFIGURATION_PATH); } public static void configureLogging(final String logbackConfigResource) { // Really close the Hazelcast cluster. Hazelcast.shutdownAll(); // Make certain that Hazelcast uses the slf4j logging factory. System.setProperty("hazelcast.logging.type", "slf4j"); // Load the Logback configuration using the native JoranConfigurator final ClassLoader ctxClassLoader = Thread.currentThread().getContextClassLoader(); final URL logbackConfiguration = ctxClassLoader.getResource(logbackConfigResource); final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); context.reset(); final JoranConfigurator configurator = new JoranConfigurator(); configurator.setContext(context); try { configurator.doConfigure(logbackConfiguration); } catch (JoranException e) { e.printStackTrace(); } if (log.isDebugEnabled()) { log.debug("Read SLF4J config from: " + logbackConfiguration.toString()); } } @AfterClass public static void teardownHazelcastCacheInstance() { Hazelcast.shutdownAll(); Hazelcast.shutdownAll(); } protected void purgeCache(final AbstractHazelcastInstanceWrapper cache) { if (cache == null) { log.warn("Can not purge null cache"); return; } try { final HazelcastInstance current = getInternalInstance(cache); if (current != null) { for (final DistributedObject currentDistributedObject : current.getDistributedObjects()) { final String instanceName = currentDistributedObject.getName(); // We don't want to destroy our internal maps for the cache if (!(instanceName.endsWith(GridOperations.CLUSTER_ADMIN_TOPIC))) { if (currentDistributedObject instanceof MultiMap) { MultiMap map = (MultiMap) currentDistributedObject; map.clear(); } else if (currentDistributedObject instanceof Map) { Map map = (Map) currentDistributedObject; map.clear(); } else if (currentDistributedObject instanceof Collection) { Collection collection = (Collection) currentDistributedObject; collection.clear(); } final Set<String> listeners = new TreeSet<String>(cache.getListenerIDsFor(currentDistributedObject)); for (final String listenerId : listeners) { cache.removeListenerFor(currentDistributedObject, listenerId); } // can't use this - it clears internal state of hazelcast // if (!(instanceId.endsWith(CLUSTERWIDE_SHARED_CACHE_MAP) || // instanceId.endsWith(CLUSTERWIDE_LISTENERID_MAP))) { // instance.destroy(); // } } } final Set<String> listeners = new TreeSet<String>(cache.getLocallyRegisteredListeners().keySet()); for (final String listenerId : listeners) { cache.removeInstanceListener(listenerId); } } } catch (final Exception e) { log.warn("Unable to purge cache", e); } } protected HazelcastInstance getInternalInstance(final AbstractHazelcastInstanceWrapper cache) { final String fieldName = "cacheInstance"; try { Field instanceField = cache.getClass().getSuperclass().getDeclaredField(fieldName); instanceField.setAccessible(true); final HazelcastInstance toReturn = (HazelcastInstance) instanceField.get(cache); if (toReturn == null) { log.warn("Found null HazelcastInstance in field '" + fieldName + "'."); } return toReturn; } catch (Exception e) { throw new IllegalArgumentException("Could not acquire the cacheInstance", e); } } }