/*
* Copyright (c) 2008-2012, Hazel Bilisim Ltd. 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.impl;
import com.hazelcast.config.ListenerConfig;
import com.hazelcast.config.TopicConfig;
import com.hazelcast.core.EntryEvent;
import com.hazelcast.core.Instance.InstanceType;
import com.hazelcast.impl.monitor.LocalTopicStatsImpl;
import com.hazelcast.nio.Address;
import com.hazelcast.nio.Data;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import static com.hazelcast.nio.IOUtil.toData;
public class TopicManager extends BaseManager {
final boolean FLOW_CONTROL_ENABLED;
TopicManager(Node node) {
super(node);
FLOW_CONTROL_ENABLED = node.getGroupProperties().TOPIC_FLOW_CONTROL_ENABLED.getBoolean();
}
Map<String, TopicInstance> mapTopics = new HashMap<String, TopicInstance>();
public TopicInstance getTopicInstance(String name) {
TopicInstance ti = mapTopics.get(name);
if (ti == null) {
ti = new TopicInstance(this, name);
mapTopics.put(name, ti);
}
return ti;
}
public void syncForDead(Address deadAddress) {
Collection<TopicInstance> instances = mapTopics.values();
for (TopicInstance instance : instances) {
instance.removeListener(deadAddress);
}
}
public void syncForAdd() {
}
@Override
void registerListener(boolean add, String name, Data key, Address address,
boolean includeValue) {
TopicInstance instance = getTopicInstance(name);
if (add) {
instance.addListener(address, includeValue);
} else {
instance.removeListener(address);
}
}
void destroy(String name) {
TopicInstance instance = mapTopics.remove(name);
if (instance != null) {
instance.mapListeners.clear();
node.listenerManager.removeAllRegisteredListeners(name);
}
}
void doPublish(String name, Object msg) {
Data dataMsg = null;
try {
dataMsg = toData(msg);
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
if (FLOW_CONTROL_ENABLED) {
while (node.connectionManager.getTotalWriteQueueSize() > 10000) {
try {
//noinspection BusyWait
Thread.sleep(10);
} catch (InterruptedException ignored) {
}
}
}
enqueueAndReturn(new TopicPublishProcess(name, dataMsg));
}
class TopicPublishProcess implements Processable {
final Data dataMsg;
final String name;
public TopicPublishProcess(String name, Data dataMsg) {
super();
this.dataMsg = dataMsg;
this.name = name;
}
public void process() {
getTopicInstance(name).publish(dataMsg);
}
}
public final class TopicInstance {
private final TopicManager topicManager;
private final String name;
private final Map<Address, Boolean> mapListeners = new HashMap<Address, Boolean>();
public TopicInstance(final TopicManager topicManager, final String name) {
if (topicManager == null) {
throw new NullPointerException("topic manager cannot be null");
}
if (name == null) {
throw new NullPointerException("topic name cannot be null");
}
this.topicManager = topicManager;
this.name = name;
initializeListeners();
}
private void initializeListeners() {
final TopicConfig topicConfig = node.config.findMatchingTopicConfig(name);
for (ListenerConfig lc : topicConfig.getMessageListenerConfigs()) {
try {
node.listenerManager.createAndAddListenerItem(name, lc, InstanceType.TOPIC);
for (MemberImpl member : node.clusterManager.getMembers()) {
addListener(member.getAddress(), true);
}
} catch (Exception e) {
logger.log(Level.SEVERE, e.getMessage(), e);
}
}
}
public void addListener(final Address address, final boolean includeValue) {
mapListeners.put(address, includeValue);
}
public void removeListener(final Address address) {
mapListeners.remove(address);
}
public void publish(final Data msg) {
topicManager.fireMapEvent(mapListeners, name, EntryEvent.TYPE_ADDED, msg, thisAddress);
}
public LocalTopicStatsImpl getTopicStats() {
return new LocalTopicStatsImpl();
}
}
}