/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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.wso2.carbon.event.processor.manager.core.internal;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IMap;
import com.hazelcast.core.Member;
import org.apache.commons.lang.ArrayUtils;
import org.apache.log4j.Logger;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.databridge.commons.Event;
import org.wso2.carbon.event.processor.manager.commons.transport.client.TCPEventPublisher;
import org.wso2.carbon.event.processor.manager.commons.transport.client.TCPEventPublisherConfig;
import org.wso2.carbon.event.processor.manager.commons.transport.server.StreamCallback;
import org.wso2.carbon.event.processor.manager.commons.transport.server.TCPEventServer;
import org.wso2.carbon.event.processor.manager.commons.transport.server.TCPEventServerConfig;
import org.wso2.carbon.event.processor.manager.commons.utils.HostAndPort;
import org.wso2.carbon.event.processor.manager.core.EventManagementUtil;
import org.wso2.carbon.event.processor.manager.core.EventSync;
import org.wso2.carbon.event.processor.manager.core.internal.ds.EventManagementServiceValueHolder;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class EventHandler {
private static Logger log = Logger.getLogger(EventHandler.class);
private TCPEventServer tcpEventServer = null;
private IMap<String, HostAndPort> members = null;
private ConcurrentHashMap<HostAndPort, TCPEventPublisher> tcpEventPublisherPool = new ConcurrentHashMap<HostAndPort, TCPEventPublisher>();
private ConcurrentHashMap<String, EventSync> eventSyncMap = new ConcurrentHashMap<String, EventSync>();
private HostAndPort localMember;
private TCPEventPublisherConfig localEventPublisherConfiguration;
private boolean allowEventSync = true;
private boolean isMemberNode;
private boolean allowContinueProcess=false;
public void init(String memberType, HostAndPort localMember,
TCPEventPublisherConfig localEventPublisherConfiguration, boolean isMemberNode) {
this.isMemberNode = isMemberNode;
HazelcastInstance hazelcastInstance = EventManagementServiceValueHolder.getHazelcastInstance();
this.members = hazelcastInstance.getMap(memberType);
this.localMember = localMember;
registerLocalMember();
this.localEventPublisherConfiguration = localEventPublisherConfiguration;
}
public void registerLocalMember() {
if (isMemberNode && members != null) {
this.members.set(EventManagementServiceValueHolder.getHazelcastInstance().getCluster().getLocalMember().getUuid(), localMember);
}
}
public void removeMember(String uuid) {
if (members != null) {
members.remove(uuid);
}
}
public void shutdown() {
if (members != null) {
members.remove(EventManagementServiceValueHolder.getHazelcastInstance().getCluster().getLocalMember().getUuid());
}
for (TCPEventPublisher publisher : tcpEventPublisherPool.values()) {
publisher.shutdown();
}
if (tcpEventServer != null) {
tcpEventServer.shutdown();
}
}
public void syncEvent(String syncId, Event event) {
if (allowEventSync) {
for (TCPEventPublisher publisher : tcpEventPublisherPool.values()) {
if (publisher != null) {
try {
Object[] eventData = ArrayUtils.addAll(ArrayUtils.addAll(event.getMetaData(), event.getCorrelationData()), event.getPayloadData());
publisher.sendEvent(syncId, event.getTimeStamp(), eventData, event.getArbitraryDataMap(), true);
} catch (IOException e) {
log.error("Error sending sync events to " + syncId, e);
}
}
}
}
}
public synchronized void registerEventSync(EventSync eventSync) {
if(allowContinueProcess){
eventSync.setContinueProcess(allowContinueProcess);
}
eventSyncMap.putIfAbsent(EventManagementUtil.getSyncIdFromDatabridgeStream(eventSync.getStreamDefinition()), eventSync);
for (TCPEventPublisher tcpEventPublisher : tcpEventPublisherPool.values()) {
tcpEventPublisher.addStreamDefinition(EventManagementUtil.constructStreamDefinition(
EventManagementUtil.getSyncIdFromDatabridgeStream(eventSync.getStreamDefinition()),
eventSync.getStreamDefinition()));
}
if (tcpEventServer != null) {
tcpEventServer.addStreamDefinition(EventManagementUtil.constructStreamDefinition(
EventManagementUtil.getSyncIdFromDatabridgeStream(eventSync.getStreamDefinition()),
eventSync.getStreamDefinition()));
}
}
public void unregisterEventSync(String syncId) {
EventSync eventSync = eventSyncMap.remove(syncId);
if (eventSync != null) {
for (TCPEventPublisher tcpEventPublisher : tcpEventPublisherPool.values()) {
tcpEventPublisher.removeStreamDefinition(EventManagementUtil.constructStreamDefinition(
EventManagementUtil.getSyncIdFromDatabridgeStream(eventSync.getStreamDefinition()),
eventSync.getStreamDefinition()));
}
if (tcpEventServer != null) {
tcpEventServer.removeStreamDefinition(EventManagementUtil.getSyncIdFromDatabridgeStream(eventSync.getStreamDefinition()));
}
}
}
public void startServer(HostAndPort member) {
if (tcpEventServer == null) {
TCPEventServerConfig tcpEventServerConfig = new TCPEventServerConfig(member.getHostName(), member.getPort());
tcpEventServer = new TCPEventServer(tcpEventServerConfig, new StreamCallback() {
@Override
public void receive(String streamId, long timestamp, Object[] event, Map<String, String> arbitraryMapData) {
int index = streamId.indexOf("/");
if (index != -1) {
int tenantId = Integer.parseInt(streamId.substring(0, index));
try {
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(tenantId);
PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(true);
EventSync eventSync = eventSyncMap.get(streamId);
if (log.isDebugEnabled()) {
log.debug("Event Received to :" + streamId);
}
if (eventSync != null) {
eventSync.process(EventManagementUtil.getWso2Event(eventSync.getOriginalEventStreamId(), eventSync.getStreamDefinition(), timestamp, event));
}
} catch (Exception e) {
log.error("Unable to process events for tenant :" + tenantId + " on stream:" + streamId.substring(index), e);
} finally {
PrivilegedCarbonContext.endTenantFlow();
}
}
}
}, null);
for (EventSync eventSync : eventSyncMap.values()) {
tcpEventServer.addStreamDefinition(EventManagementUtil.constructStreamDefinition(
EventManagementUtil.getSyncIdFromDatabridgeStream(eventSync.getStreamDefinition()),
eventSync.getStreamDefinition()));
}
try {
tcpEventServer.start();
log.info("Event Management TCPEventServer for EventReceiver started on port " + member.getPort());
} catch (IOException e) {
log.error("Unable to start TCPEventServer for EventReceiver started on port " + member.getPort());
}
}
}
public void checkMemberUpdate() {
cleanupMembers();
updateEventPublishers();
}
private synchronized void updateEventPublishers() {
if (members != null) {
List<HostAndPort> memberList = new ArrayList<HostAndPort>(members.values());
memberList.remove(localMember);
List<HostAndPort> currentMembers = new ArrayList<>(tcpEventPublisherPool.keySet());
for (HostAndPort member : memberList) {
if (!currentMembers.remove(member)) {
addEventPublisher(member);
}
}
for (HostAndPort member : currentMembers) {
removeEventPublisher(member);
}
}
}
public synchronized void addEventPublisher(HostAndPort member) {
try {
if (!tcpEventPublisherPool.containsKey(member)) {
TCPEventPublisher tcpEventPublisher = new TCPEventPublisher(member.getHostName() + ":" + member.getPort(),
localEventPublisherConfiguration, false, null);
for (EventSync eventSync : eventSyncMap.values()) {
tcpEventPublisher.addStreamDefinition(EventManagementUtil.constructStreamDefinition(
EventManagementUtil.getSyncIdFromDatabridgeStream(eventSync.getStreamDefinition()),
eventSync.getStreamDefinition()));
}
tcpEventPublisherPool.putIfAbsent(member, tcpEventPublisher);
log.info("CEP sync publisher initiated to Member '" + member.getHostName() + ":" + member.getPort() + "'");
}
} catch (IOException e) {
log.error("Error occurred while trying to start the publisher: " + e.getMessage(), e);
}
}
private synchronized void removeEventPublisher(HostAndPort member) {
TCPEventPublisher tcpEventPublisher = tcpEventPublisherPool.remove(member);
if (tcpEventPublisher != null) {
tcpEventPublisher.shutdown();
log.info("CEP sync publisher disconnected from Member '" + member.getHostName() + ":" + member.getPort() + "'");
}
}
private void cleanupMembers() {
if (members != null) {
Set<String> activeMemberUuidSet = new HashSet<String>();
for (Member member : EventManagementServiceValueHolder.getHazelcastInstance().getCluster().getMembers()) {
activeMemberUuidSet.add(member.getUuid());
}
List<String> currentMemberUuidList = new ArrayList<String>(members.keySet());
for (String memberUuid : currentMemberUuidList) {
if (!activeMemberUuidSet.contains(memberUuid)) {
members.remove(memberUuid);
}
}
}
}
public void allowEventSync(boolean allowEventSync) {
this.allowEventSync = allowEventSync;
}
public synchronized void allowContinueProcess(boolean allowContinueProcess){
this.allowContinueProcess = allowContinueProcess;
for (EventSync eventSync : eventSyncMap.values()) {
eventSync.setContinueProcess(allowContinueProcess);
}
}
}