/*
* 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.management.registry;
import org.ehcache.Cache;
import org.ehcache.Status;
import org.ehcache.core.events.CacheManagerListener;
import org.ehcache.core.spi.service.CacheManagerProviderService;
import org.ehcache.core.spi.service.ExecutionService;
import org.ehcache.core.spi.store.InternalCacheManager;
import org.ehcache.core.spi.time.TimeSourceService;
import org.ehcache.management.CollectorService;
import org.ehcache.management.ManagementRegistryService;
import org.ehcache.management.ManagementRegistryServiceConfiguration;
import org.ehcache.spi.service.Service;
import org.ehcache.spi.service.ServiceDependencies;
import org.ehcache.spi.service.ServiceProvider;
import org.terracotta.management.model.notification.ContextualNotification;
import org.terracotta.management.model.stats.ContextualStatistics;
import org.terracotta.management.registry.collect.DefaultStatisticCollector;
import org.terracotta.management.registry.collect.StatisticCollector;
import java.util.Collection;
import java.util.concurrent.ScheduledExecutorService;
import static org.ehcache.impl.internal.executor.ExecutorUtil.shutdownNow;
@ServiceDependencies({CacheManagerProviderService.class, ManagementRegistryService.class, ExecutionService.class, TimeSourceService.class})
public class DefaultCollectorService implements CollectorService, CacheManagerListener {
private enum EhcacheNotification {
CACHE_ADDED,
CACHE_REMOVED,
CACHE_MANAGER_AVAILABLE,
CACHE_MANAGER_MAINTENANCE,
CACHE_MANAGER_CLOSED,
}
private final Collector collector;
private volatile ManagementRegistryService managementRegistry;
private volatile ScheduledExecutorService scheduledExecutorService;
private volatile InternalCacheManager cacheManager;
private volatile ManagementRegistryServiceConfiguration configuration;
private volatile DefaultStatisticCollector statisticCollector;
public DefaultCollectorService() {
this(Collector.EMPTY);
}
public DefaultCollectorService(Collector collector) {
this.collector = collector;
}
@Override
public synchronized void start(ServiceProvider<Service> serviceProvider) {
managementRegistry = serviceProvider.getService(ManagementRegistryService.class);
configuration = managementRegistry.getConfiguration();
cacheManager = serviceProvider.getService(CacheManagerProviderService.class).getCacheManager();
scheduledExecutorService = serviceProvider.getService(ExecutionService.class).getScheduledExecutor(configuration.getCollectorExecutorAlias());
statisticCollector = new DefaultStatisticCollector(
managementRegistry,
scheduledExecutorService,
new StatisticCollector.Collector() {
@Override
public void onStatistics(Collection<ContextualStatistics> statistics) {
collector.onStatistics(statistics);
}
});
cacheManager.registerListener(this);
}
@Override
public synchronized void stop() {
// do not call deregisterListener here because the stateTransition event for UNINITIALIZED won't be caught.
// so deregisterListener is done in the stateTransition listener
//cacheManager.deregisterListener(this);
statisticCollector.stopStatisticCollector();
shutdownNow(scheduledExecutorService);
}
@Override
public void cacheAdded(String alias, Cache<?, ?> cache) {
collector.onNotification(
new ContextualNotification(
configuration.getContext().with("cacheName", alias),
EhcacheNotification.CACHE_ADDED.name()));
}
@Override
public void cacheRemoved(String alias, Cache<?, ?> cache) {
collector.onNotification(
new ContextualNotification(
configuration.getContext().with("cacheName", alias),
EhcacheNotification.CACHE_REMOVED.name()));
}
@Override
public void stateTransition(Status from, Status to) {
switch (to) {
case AVAILABLE:
// .register() call should be there when CM is AVAILABLE
// this is to expose the stats collector for management calls
managementRegistry.register(statisticCollector);
collector.onNotification(
new ContextualNotification(
configuration.getContext(),
EhcacheNotification.CACHE_MANAGER_AVAILABLE.name()));
break;
case MAINTENANCE:
collector.onNotification(
new ContextualNotification(
configuration.getContext(),
EhcacheNotification.CACHE_MANAGER_MAINTENANCE.name()));
break;
case UNINITIALIZED:
collector.onNotification(
new ContextualNotification(
configuration.getContext(),
EhcacheNotification.CACHE_MANAGER_CLOSED.name()));
// deregister me - should not be in stop() - see other comments
cacheManager.deregisterListener(this);
break;
default:
throw new AssertionError("Unsupported state: " + to);
}
}
}