/*
* Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved.
*
* 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 com.hazelcast.map.impl.querycache.subscriber;
import com.hazelcast.config.QueryCacheConfig;
import com.hazelcast.logging.ILogger;
import com.hazelcast.logging.Logger;
import com.hazelcast.map.impl.ListenerAdapter;
import com.hazelcast.map.impl.querycache.QueryCacheConfigurator;
import com.hazelcast.map.impl.querycache.QueryCacheContext;
import com.hazelcast.map.impl.querycache.QueryCacheEventService;
import com.hazelcast.map.impl.querycache.accumulator.AccumulatorInfo;
import com.hazelcast.map.impl.querycache.accumulator.AccumulatorInfoSupplier;
import com.hazelcast.map.listener.MapListener;
import com.hazelcast.query.Predicate;
import static com.hazelcast.map.impl.querycache.accumulator.AccumulatorInfo.createAccumulatorInfo;
import static com.hazelcast.map.impl.querycache.subscriber.NullQueryCache.NULL_QUERY_CACHE;
import static com.hazelcast.util.ExceptionUtil.rethrow;
/**
* Provides generic functionality for {@code QueryCacheEndToEndConstructor} implementations.
*
* @see QueryCacheEndToEndConstructor
*/
public abstract class AbstractQueryCacheEndToEndConstructor implements QueryCacheEndToEndConstructor {
protected static final int OPERATION_WAIT_TIMEOUT_MINUTES = 5;
protected final String mapName;
protected final QueryCacheRequest request;
protected final QueryCacheContext context;
protected final SubscriberContext subscriberContext;
protected final ILogger logger = Logger.getLogger(getClass());
protected Predicate predicate;
protected boolean includeValue;
protected InternalQueryCache queryCache;
protected String publisherListenerId;
public AbstractQueryCacheEndToEndConstructor(QueryCacheRequest request) {
this.request = request;
this.mapName = request.getMapName();
this.context = request.getContext();
this.subscriberContext = context.getSubscriberContext();
}
@Override
public final void createSubscriberAccumulator(AccumulatorInfo info) {
QueryCacheEventService eventService = context.getQueryCacheEventService();
ListenerAdapter listener = new SubscriberListener(context, info);
publisherListenerId = eventService.listenPublisher(info.getMapName(), info.getCacheName(), listener);
}
/**
* Here order of method calls should not change.
*/
@Override
public final InternalQueryCache createNew(String arg) {
try {
QueryCacheConfig queryCacheConfig = initQueryCacheConfig(request);
if (queryCacheConfig == null) {
return NULL_QUERY_CACHE;
}
queryCache = createUnderlyingQueryCache(request);
// this is users listener which can be given as a parameter
// when calling `IMap.getQueryCache` method
addListener(request);
AccumulatorInfo info = createAccumulatorInfo(queryCacheConfig, mapName, request.getCacheName(), predicate);
addInfoToSubscriberContext(info);
info.setPublishable(true);
createSubscriberAccumulator(info);
createPublisherAccumulator(info);
queryCache.setPublisherListenerId(publisherListenerId);
} catch (Throwable throwable) {
removeQueryCacheConfig(mapName, request.getUserGivenCacheName());
throw rethrow(throwable);
}
return queryCache;
}
/**
* This is the cache which we store all key-value pairs.
*/
private InternalQueryCache createUnderlyingQueryCache(QueryCacheRequest request) {
SubscriberContext subscriberContext = context.getSubscriberContext();
QueryCacheFactory queryCacheFactory = subscriberContext.getQueryCacheFactory();
return queryCacheFactory.create(request);
}
private void addInfoToSubscriberContext(AccumulatorInfo info) {
SubscriberContext subscriberContext = context.getSubscriberContext();
AccumulatorInfoSupplier accumulatorInfoSupplier = subscriberContext.getAccumulatorInfoSupplier();
accumulatorInfoSupplier.putIfAbsent(info.getMapName(), info.getCacheName(), info);
}
private String addListener(QueryCacheRequest request) {
MapListener listener = request.getListener();
if (listener == null) {
return null;
}
QueryCacheEventService eventService = subscriberContext.getEventService();
return eventService.addListener(request.getMapName(), request.getCacheName(), listener);
}
public String getCacheName() {
return request.getCacheName();
}
protected Object toObject(Object data) {
return context.toObject(data);
}
protected QueryCacheConfig initQueryCacheConfig(QueryCacheRequest request) {
Predicate predicate = request.getPredicate();
QueryCacheConfig queryCacheConfig;
if (predicate == null) {
queryCacheConfig = getOrNullQueryCacheConfig(mapName, request.getUserGivenCacheName());
} else {
queryCacheConfig = getOrCreateQueryCacheConfig(mapName, request.getUserGivenCacheName());
queryCacheConfig.setIncludeValue(request.isIncludeValue());
queryCacheConfig.getPredicateConfig().setImplementation(predicate);
}
if (queryCacheConfig == null) {
return null;
}
// init some required parameters
this.includeValue = queryCacheConfig.isIncludeValue();
this.predicate = queryCacheConfig.getPredicateConfig().getImplementation();
return queryCacheConfig;
}
private QueryCacheConfig getOrCreateQueryCacheConfig(String mapName, String cacheName) {
QueryCacheConfigurator queryCacheConfigurator = subscriberContext.geQueryCacheConfigurator();
return queryCacheConfigurator.getOrCreateConfiguration(mapName, cacheName);
}
private QueryCacheConfig getOrNullQueryCacheConfig(String mapName, String cacheName) {
QueryCacheConfigurator queryCacheConfigurator = subscriberContext.geQueryCacheConfigurator();
return queryCacheConfigurator.getOrNull(mapName, cacheName);
}
private void removeQueryCacheConfig(String mapName, String cacheName) {
QueryCacheConfigurator queryCacheConfigurator = subscriberContext.geQueryCacheConfigurator();
queryCacheConfigurator.removeConfiguration(mapName, cacheName);
}
}