/* * Copyright Terracotta, Inc. * * 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.ehcache.clustered; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; import java.util.Collections; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import org.ehcache.PersistentCacheManager; import org.ehcache.clustered.client.config.builders.ClusteringServiceConfigurationBuilder; import org.ehcache.clustered.client.internal.InternalClusterTierManagerClientEntity; import org.ehcache.clustered.common.EhcacheEntityVersion; import org.ehcache.config.builders.CacheManagerBuilder; import org.ehcache.StateTransitionException; import org.ehcache.xml.XmlConfiguration; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; import org.terracotta.connection.Connection; import org.terracotta.connection.ConnectionException; import org.terracotta.connection.entity.Entity; import org.terracotta.connection.entity.EntityRef; import org.terracotta.exception.EntityNotFoundException; import org.terracotta.exception.EntityNotProvidedException; import org.terracotta.exception.EntityVersionMismatchException; import org.terracotta.testing.rules.BasicExternalCluster; import org.terracotta.testing.rules.Cluster; import static org.ehcache.config.builders.CacheManagerBuilder.newCacheManagerBuilder; import static org.ehcache.config.builders.CacheManagerBuilder.newCacheManager; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; public class CacheManagerLifecycleEhcacheIntegrationTest { private static final String RESOURCE_CONFIG = "<config xmlns:ohr='http://www.terracotta.org/config/offheap-resource'>" + "<ohr:offheap-resources>" + "<ohr:resource name=\"primary-server-resource\" unit=\"MB\">64</ohr:resource>" + "</ohr:offheap-resources>" + "</config>\n"; @ClassRule public static Cluster CLUSTER = new BasicExternalCluster(new File("build/cluster"), 1, Collections.<File>emptyList(), "", RESOURCE_CONFIG, ""); private static Connection ASSERTION_CONNECTION; @BeforeClass public static void waitForActive() throws Exception { CLUSTER.getClusterControl().waitForActive(); ASSERTION_CONNECTION = CLUSTER.newConnection(); } @Test public void testAutoCreatedCacheManager() throws Exception { assertEntityNotExists(InternalClusterTierManagerClientEntity.class, "testAutoCreatedCacheManager"); PersistentCacheManager manager = newCacheManagerBuilder() .with(ClusteringServiceConfigurationBuilder.cluster(CLUSTER.getConnectionURI().resolve("/testAutoCreatedCacheManager")).autoCreate().build()) .build(); assertEntityNotExists(InternalClusterTierManagerClientEntity.class, "testAutoCreatedCacheManager"); manager.init(); try { assertEntityExists(InternalClusterTierManagerClientEntity.class, "testAutoCreatedCacheManager"); } finally { manager.close(); } } @Test public void testAutoCreatedCacheManagerUsingXml() throws Exception { URL xml = CacheManagerLifecycleEhcacheIntegrationTest.class.getResource("/configs/clustered.xml"); URL substitutedXml = substitute(xml, "cluster-uri", CLUSTER.getConnectionURI().toString()); PersistentCacheManager manager = (PersistentCacheManager) newCacheManager(new XmlConfiguration(substitutedXml)); assertEntityNotExists(InternalClusterTierManagerClientEntity.class, "testAutoCreatedCacheManagerUsingXml"); manager.init(); try { assertEntityExists(InternalClusterTierManagerClientEntity.class, "testAutoCreatedCacheManagerUsingXml"); } finally { manager.close(); } } @Test public void testMultipleClientsAutoCreatingCacheManager() throws Exception { assertEntityNotExists(InternalClusterTierManagerClientEntity.class, "testMultipleClientsAutoCreatingCacheManager"); final CacheManagerBuilder<PersistentCacheManager> managerBuilder = newCacheManagerBuilder() .with(ClusteringServiceConfigurationBuilder.cluster(CLUSTER.getConnectionURI().resolve("/testMultipleClientsAutoCreatingCacheManager")).autoCreate().build()); Callable<PersistentCacheManager> task = new Callable<PersistentCacheManager>() { @Override public PersistentCacheManager call() throws Exception { PersistentCacheManager manager = managerBuilder.build(); manager.init(); return manager; } }; assertEntityNotExists(InternalClusterTierManagerClientEntity.class, "testMultipleClientsAutoCreatingCacheManager"); ExecutorService executor = Executors.newCachedThreadPool(); try { List<Future<PersistentCacheManager>> results = executor.invokeAll(Collections.nCopies(4, task), 30, TimeUnit.SECONDS); for (Future<PersistentCacheManager> result : results) { assertThat(result.isDone(), is(true)); } for (Future<PersistentCacheManager> result : results) { result.get().close(); } assertEntityExists(InternalClusterTierManagerClientEntity.class, "testMultipleClientsAutoCreatingCacheManager"); } finally { executor.shutdown(); } } @Test public void testCacheManagerNotExistingFailsOnInit() throws Exception { try { newCacheManagerBuilder() .with(ClusteringServiceConfigurationBuilder.cluster(CLUSTER.getConnectionURI().resolve("/testCacheManagerNotExistingFailsOnInit")).build()) .build(true); fail("Expected StateTransitionException"); } catch (StateTransitionException e) { //expected } } private static <T extends Entity> void assertEntityExists(Class<T> entityClazz, String entityName) throws ConnectionException, IOException { Connection connection = getAssertionConnection(); try { fetchEntity(connection, entityClazz, entityName); } catch (EntityNotFoundException ex) { throw new AssertionError(ex); } finally { connection.close(); } } private static <T extends Entity> void assertEntityNotExists(Class<T> entityClazz, String entityName) throws ConnectionException, IOException { Connection connection = getAssertionConnection(); try { fetchEntity(connection, entityClazz, entityName); throw new AssertionError("Expected EntityNotFoundException"); } catch (EntityNotFoundException ex) { //expected } finally { connection.close(); } } private static <T extends Entity> void fetchEntity(Connection connection, Class<T> aClass, String myCacheManager) throws EntityNotFoundException, ConnectionException { try { connection.getEntityRef(aClass, EhcacheEntityVersion.ENTITY_VERSION, myCacheManager).fetchEntity(null).close(); } catch (EntityNotProvidedException e) { throw new AssertionError(e); } catch (EntityVersionMismatchException e) { throw new AssertionError(e); } } private synchronized static Connection getAssertionConnection() throws ConnectionException { return new Connection() { @Override public<T extends Entity, C, U> EntityRef<T, C, U> getEntityRef(Class<T> cls, long version, String name) throws EntityNotProvidedException { return ASSERTION_CONNECTION.getEntityRef(cls, version, name); } @Override public void close() throws IOException { //no-op } }; } @AfterClass public static void closeAssertionConnection() throws IOException { ASSERTION_CONNECTION.close(); } static URL substitute(URL input, String variable, String substitution) throws IOException { File output = File.createTempFile(input.getFile(), ".substituted", new File("build")); BufferedWriter writer = new BufferedWriter(new FileWriter(output)); try { BufferedReader reader = new BufferedReader(new InputStreamReader(input.openStream(), "UTF-8")); try { while (true) { String line = reader.readLine(); if (line == null) { break; } else { writer.write(line.replace("${" + variable + "}", substitution)); writer.newLine(); } } } finally { reader.close(); } } finally { writer.close(); } return output.toURI().toURL(); } }