
com.alachisoft.ncache.client.internal.messaging.MessageManager Maven / Gradle / Ivy
package com.alachisoft.ncache.client.internal.messaging;
import Alachisoft.NCache.Common.*;
import Alachisoft.NCache.Common.BitSet;
import Alachisoft.NCache.Common.Enum.TopicOperationType;
import Alachisoft.NCache.Common.Threading.Monitor;
import Alachisoft.NCache.Management.Statistics.StatisticsCounter;
import com.alachisoft.ncache.client.MessageItem;
import com.alachisoft.ncache.client.internal.caching.EventManager;
import com.alachisoft.ncache.client.internal.caching.*;
import Alachisoft.NCache.Common.ErrorHandling.ErrorCodes;
import Alachisoft.NCache.Common.ErrorHandling.ErrorMessages;
import com.alachisoft.ncache.runtime.caching.Topic;
import com.alachisoft.ncache.runtime.caching.WriteMode;
import com.alachisoft.ncache.runtime.caching.messaging.TopicPriority;
import com.alachisoft.ncache.runtime.caching.messaging.TopicSearchOptions;
import com.alachisoft.ncache.runtime.exceptions.CacheException;
import com.alachisoft.ncache.runtime.exceptions.OperationFailedException;
import com.alachisoft.ncache.runtime.util.TimeSpan;
import javax.xml.crypto.Data;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import static com.alachisoft.ncache.runtime.caching.messaging.TopicSearchOptions.ByName;
import static com.alachisoft.ncache.runtime.caching.messaging.TopicSearchOptions.ByPattern;
import static tangible.DotNetToJavaStringHelper.isNullOrEmpty;
public class MessageManager implements IDisposable, TopicReRegister, PollNotificationListener {
private static final int pollingInterval = 10; // polling interval is in seconds; i.e. 10 seconds
private final ConcurrentHashMap topicsMap;
private final EventManager eventManager;
private final Object lockObj = new Object();
private CacheImplBase cacheImpl;
private Thread pollingThread;
private boolean poll;
private Date _lastPoll = new Date();
private StatisticsCounter perfStatsCollector;
private boolean isNotificationRegister = false;
private long version;
public MessageManager(EventManager eventManager, StatisticsCounter perfStatsCollector) {
topicsMap = new ConcurrentHashMap();
this.eventManager = eventManager;
this.perfStatsCollector = perfStatsCollector;
}
public final void initialize() {
eventManager.registerPollingEvent(this, EventTypeInternal.PubSub);
}
public final TopicReRegister getReregisterTopicListener() {
return this;
}
public boolean getIsValidName(String topicName, TopicOperationType type) {
if (type != TopicOperationType.GetPatternBased) {
return true;
}
try {
String regexPattern = MessageUtil.wildcardToRegex(topicName);
Pattern.compile(regexPattern);
return true;
} catch (Exception e) {
return false;
}
}
public final Topic getOrCreateTopic(TopicIdentity topicPair, TopicOperationType type, boolean internalOperation) throws CacheException {
String topicName = topicPair.getTopicName();
if (isNullOrEmpty(topicName)) {
throw new IllegalArgumentException("Value cannot be null or empty." + System.lineSeparator() + "Parameter name: topicName");
}
if (!getIsValidName(topicName, type)) {
throw new OperationFailedException(Alachisoft.NCache.Common.ErrorHandling.ErrorCodes.PubSub.INVALID_TOPIC_PATTERN, Alachisoft.NCache.Common.ErrorHandling.ErrorMessages.getErrorMessage(Alachisoft.NCache.Common.ErrorHandling.ErrorCodes.PubSub.INVALID_TOPIC_PATTERN));
}
if (!internalOperation && isDefaultTopicName(topicName)) {
throw new OperationFailedException(Alachisoft.NCache.Common.ErrorHandling.ErrorCodes.PubSub.DEFAULT_TOPICS, Alachisoft.NCache.Common.ErrorHandling.ErrorMessages.getErrorMessage(Alachisoft.NCache.Common.ErrorHandling.ErrorCodes.PubSub.DEFAULT_TOPICS));
}
if (cacheImpl == null) {
throw new OperationFailedException(Alachisoft.NCache.Common.ErrorHandling.ErrorCodes.CacheInit.CACHE_NOT_INIT, Alachisoft.NCache.Common.ErrorHandling.ErrorMessages.getErrorMessage(Alachisoft.NCache.Common.ErrorHandling.ErrorCodes.CacheInit.CACHE_NOT_INIT));
}
TopicImpl topic = null;
TopicPriority topicPriority = topicPair.getTopicPriority();
tangible.RefObject tempRef_topicPriority = new tangible.RefObject(topicPriority);
if (cacheImpl.getOrCreate(topicName, tempRef_topicPriority, type)) {
synchronized (this) {
if(type == TopicOperationType.Get)
topicPair.setTopicPriority(tempRef_topicPriority.argvalue);
topic = topicsMap.get(topicPair);
if (topic != null) {
if (topic.getIsClosed()) {
topicsMap.remove(topicPair, topic);
TopicSearchOptions searchOptions = topic.getSearchOptions();
topic = new TopicImpl(topicName, topicPair.getTopicPriority(), cacheImpl, perfStatsCollector,
this);
topic.setSearchOptions(searchOptions);
}
topicsMap.putIfAbsent(topicPair, topic);
topic.IncrementRefCount();
return topic;
}
topic = new TopicImpl(topicName, topicPair.getTopicPriority(), cacheImpl, perfStatsCollector, this);
if (type == TopicOperationType.GetPatternBased) {
topic.setSearchOptions(ByPattern);
}
topic.IncrementRefCount();
topicsMap.putIfAbsent(topicPair, topic);
}
}
return topic;
}
public final void stopPollingIfRequired(com.alachisoft.ncache.client.internal.caching.TopicImpl topic) {
boolean keepPollingOn = false;
if (topic == null || topic.getActiveSubscriptions() <= 0) {
synchronized (this) {
for (com.alachisoft.ncache.client.internal.caching.TopicImpl registerTopic : topicsMap.values()) {
if (registerTopic.getActiveSubscriptions() > 0 || registerTopic.getHasFailureDeliveryNotification()) {
keepPollingOn = true;
break;
}
}
if (!keepPollingOn) {
stopPolling();
}
}
}
}
private void stopPolling() {
try {
synchronized (this) {
poll = false;
isNotificationRegister = false;
if (pollingThread != null) {
pollingThread.interrupt();
}
pollingThread = null;
if (ContinuousQueryManager.getTracingEnabled()) {
System.out.println("Thread : " + pollingThread.getName() + " stopped at " + new Date().toString());
}
}
} catch (RuntimeException e) {
}
}
public final void onSubscriptionCreated(TopicImpl topic, TopicSubscriptionImpl topicSubscription) {
startPolling();
}
public final void startPolling() {
synchronized (this) {
if (!isNotificationRegister) {
startPollForMessage();
isNotificationRegister = true;
}
}
}
private void startPollForMessage() {
poll = true;
pollingThread = new Thread(new Runnable() {
@Override
public void run() {
pollForMessage();
}
});
pollingThread.setDaemon(true);
pollingThread.setName(cacheImpl.getName() + ":TopicPollingThread");
pollingThread.start();
if (ContinuousQueryManager.getTracingEnabled()) {
System.out.println("Thread : " + pollingThread.getName() + " started at " + new Date().toString());
}
}
private void pollForMessage() {
long currentVersion = -1;
while (poll) {
try {
synchronized (lockObj) {
//wait only if there is no change event fired from server side causing verion update
if (currentVersion == version) {
Monitor.wait(lockObj,pollingInterval * 1000);
}
}
TimeSpan diff = TimeSpan.subtract(new Date(), _lastPoll);
// if (ContinuousQueryManager.getTracingEnabled()) {
// System.out.println("MessageMaanger.pollForMessage() -> Time Poll: " + diff.getMilliseconds());
//
// }
currentVersion = version;
poll();
} catch (InterruptedException e) {
break;
}catch (Exception e) {
//restarts poll if exception occured
}
}
}
private void poll() throws CacheException {
BitSet flagMap = new BitSet();
ReceivedMessages assignedResponse = cacheImpl.getMessageData(flagMap);
if (assignedResponse != null) {
// if (ContinuousQueryManager.getTracingEnabled()) {
// for (Map.Entry> pair : map.entrySet()) {
// System.out.println("MessageMaanger.Poll() -> topic({ " + pair.getKey() + "}) message count :{ " + pair.getValue().size() + "}");
// }
// }
sendMessageAcknowledgements(assignedResponse);
deliverValidMessagesToClient(assignedResponse);
topicValidation(assignedResponse);
}
_lastPoll=new Date();
}
@Override
public final void dispose() {
stopPolling();
for (com.alachisoft.ncache.client.internal.caching.TopicImpl messageTopic : topicsMap.values()) {
messageTopic.disposeInternal(false);
}
topicsMap.clear();
cacheImpl = null;
if (ContinuousQueryManager.getTracingEnabled()) {
System.out.println("MessageManager disposed at " + new Date().toString());
Thread.dumpStack();
}
}
@Override
public final void onPollNotified() {
// if (ContinuousQueryManager.getTracingEnabled()) {
// System.out.println("MessageMaanger.onPollNotified() -> Time Poll: " + LocalDateTime.now().toString());
// }
synchronized (lockObj) {
version++;
Monitor.pulse(lockObj);
}
}
public final void setCacheImpl(CacheImplBase value) {
cacheImpl = value;
}
public final void topicDisposeItself(com.alachisoft.ncache.client.internal.caching.TopicImpl topic) {
synchronized (this) {
TopicIdentity topicPair = new TopicIdentity(topic.getName(), topic.getSearchOptions());
TopicImpl existingTopic = topicsMap.get(topicPair);
if (existingTopic != null && topic == existingTopic) {
topicsMap.remove(topicPair);
}
}
}
public final void deleteTopic(String topicName) throws CacheException {
if (cacheImpl == null) {
throw new OperationFailedException(Alachisoft.NCache.Common.ErrorHandling.ErrorCodes.CacheInit.CACHE_NOT_INIT, ErrorMessages.resolveError(ErrorCodes.CacheInit.CACHE_NOT_INIT));
}
if (isDefaultTopicName(topicName)) {
return;
}
TopicIdentity topicPair = new TopicIdentity(topicName, ByName);
com.alachisoft.ncache.client.internal.caching.TopicImpl topic = topicsMap.get(topicPair);
if (topicsMap.remove(topicPair, topic)) {
if (topic.getSearchOptions() == ByName) {
topic.disposeInternal(true);
topic.fireDeleteNotification();
stopPollingIfRequired(topic);
}
}
cacheImpl.removeTopic(topicName, true);
}
private void sendMesasgeAcknowledgment(HashMap> acknowledgmentIdList) throws Exception {
cacheImpl.acknowledgeMessageReceipt(acknowledgmentIdList);
}
@Override
public void onTopicReregisterListener() throws Exception {
for (TopicImpl topic : topicsMap.values()) {
if (topic.getSearchOptions() == ByName) {
TopicPriority topicPriority = topic.getPriority();
tangible.RefObject tempRef_topicPriority = new tangible.RefObject(topicPriority);
cacheImpl.getOrCreate(topic.getName(), tempRef_topicPriority, TopicOperationType.Create);
}
topic.reRegisterSubscribers(topic.getSearchOptions());
}
}
public final boolean isDefaultTopicName(String topicName) {
boolean isDefaultTopicName = false;
if (!isNullOrEmpty(topicName)) {
isDefaultTopicName = topicName.equals(TopicConstant.CQEventsTopic);
isDefaultTopicName = isDefaultTopicName || topicName.equals(TopicConstant.GeneralEventsTopic);
isDefaultTopicName = isDefaultTopicName || topicName.equals(TopicConstant.ItemLevelEventsTopic);
isDefaultTopicName = isDefaultTopicName || topicName.equals(TopicConstant.CollectionEventsTopic);
}
return isDefaultTopicName;
}
private void sendMessageAcknowledgements(ReceivedMessages assignedResponse) throws CacheException {
HashMap> ackIdList = new HashMap>();
for (Map.Entry> pair : assignedResponse.getAssignedMessages().entrySet()) {
List messageIds = new ArrayList();
for (MessageItem messageItem : pair.getValue()) {
messageIds.add(messageItem.getMessageId());
}
if (messageIds.size() > 0) {
ackIdList.put(pair.getKey(), messageIds);
}
}
if (ackIdList.size() > 0) {
try {
sendMesasgeAcknowledgment(ackIdList);
} catch (Exception e) {
throw new CacheException(e.getMessage(), e.getCause());
}
}
}
private void deliverValidMessagesToClient(ReceivedMessages assignedResponse) {
int count = 0;
for (Map.Entry> pair : assignedResponse.getAssignedMessages().entrySet()) {
TopicImpl selectedTopic = null;
for (TopicImpl topic : topicsMap.values()) {
selectedTopic = getValidTopic(topic, pair.getKey());
if (selectedTopic != null) {
// if (ContinuousQueryManager.getTracingEnabled()) {
//// System.out.println("MessageMaanger.Poll() -> topic({ "+ selectedTopic +"}) message count :{ "+pair.getValue().size()+"}");
//// }
if (pair.getValue() != null && pair.getValue().size() > 0) {
count += pair.getValue().size();
selectedTopic.updateSyncData(pair.getValue(), pair.getKey());
}
}
}
}
if (perfStatsCollector != null) {
perfStatsCollector.incrementMessageDeliverPerSec(count);
}
}
private void topicValidation(ReceivedMessages assignedResponse) throws CacheException {
ArrayList removeList = new ArrayList();
for (TopicImpl topic : topicsMap.values()) {
TopicIdentity topicPair = new TopicIdentity(topic.getName(), topic.getSearchOptions());
if (!assignedResponse.getAssignedMessages().containsKey(topic.getName()) && !assignedResponse.getRegisteredPatterns().contains(topic.getName())) {
if (topic.getHasFailureDeliveryNotification() || topic.getActiveSubscriptions() > 0) {
if (topic.getSearchOptions() == ByName) {
if (getOrCreateTopic(topicPair, TopicOperationType.Get, true) != null) {
topic.reRegisterSubscribers(topic.getSearchOptions());
}
} else if (topic.getSearchOptions() == ByPattern) {
if (getOrCreateTopic(topicPair, TopicOperationType.GetPatternBased, true) != null) {
topic.reRegisterSubscribers(topic.getSearchOptions());
}
} else {
removeList.add(topic.getName());
topic.fireDeleteNotification();
}
}
}
}
}
private TopicImpl getValidTopic(TopicImpl topic, String serverSideTopicName) {
switch (topic.getSearchOptions()) {
case ByPattern:
String regexPattern = MessageUtil.wildcardToRegex(topic.getName());
//Check Logic while Testing
regexPattern.equalsIgnoreCase(serverSideTopicName);
return topic;
case ByName:
if (topic.getName().equals(serverSideTopicName)) {
return topic;
}
break;
}
return null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy