/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.notifications;
import com.liferay.portal.kernel.notifications.Channel;
import com.liferay.portal.kernel.notifications.ChannelException;
import com.liferay.portal.kernel.notifications.ChannelHub;
import com.liferay.portal.kernel.notifications.ChannelListener;
import com.liferay.portal.kernel.notifications.NotificationEvent;
import com.liferay.portal.kernel.notifications.UnknownChannelException;
import com.liferay.portal.kernel.service.UserNotificationEventLocalServiceUtil;
import com.liferay.portal.util.PropsValues;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* @author Edward Han
* @author Brian Wing Shun Chan
* @author Shuyang Zhou
*/
public class ChannelHubImpl implements ChannelHub {
public ChannelHubImpl(long companyId) {
_companyId = companyId;
}
@Override
public void cleanUp() throws ChannelException {
for (Channel channel : _channels.values()) {
channel.cleanUp();
}
}
@Override
public void cleanUp(long userId) throws ChannelException {
Channel channel = getChannel(userId);
channel.cleanUp();
}
@Override
public void confirmDelivery(
long userId, Collection<String> notificationEventUuids)
throws ChannelException {
confirmDelivery(userId, notificationEventUuids, false);
}
@Override
public void confirmDelivery(
long userId, Collection<String> notificationEventUuids,
boolean archive)
throws ChannelException {
Channel channel = getChannel(userId);
channel.confirmDelivery(notificationEventUuids, archive);
}
@Override
public void confirmDelivery(long userId, String notificationEventUuid)
throws ChannelException {
confirmDelivery(userId, notificationEventUuid, false);
}
@Override
public void confirmDelivery(
long userId, String notificationEventUuid, boolean archive)
throws ChannelException {
Channel channel = getChannel(userId);
channel.confirmDelivery(notificationEventUuid, archive);
}
@Override
public Channel createChannel(long userId) throws ChannelException {
if (_channels.containsKey(userId)) {
return _channels.get(userId);
}
Channel channel = new ChannelImpl(_companyId, userId);
Channel oldChannel = _channels.putIfAbsent(userId, channel);
if (oldChannel != null) {
channel.sendNotificationEvents(oldChannel.getNotificationEvents());
}
channel.init();
return channel;
}
@Override
public void deleteUserNotificiationEvent(
long userId, String notificationEventUuid)
throws ChannelException {
Channel channel = getChannel(userId);
channel.deleteUserNotificiationEvent(notificationEventUuid);
}
@Override
public void deleteUserNotificiationEvents(
long userId, Collection<String> notificationEventUuids)
throws ChannelException {
Channel channel = getChannel(userId);
channel.deleteUserNotificiationEvents(notificationEventUuids);
}
@Override
public void destroy() throws ChannelException {
Set<Map.Entry<Long, Channel>> channels = _channels.entrySet();
Iterator<Map.Entry<Long, Channel>> itr = channels.iterator();
while (itr.hasNext()) {
Channel channel = itr.next().getValue();
channel.close();
itr.remove();
}
}
@Override
public Channel destroyChannel(long userId) throws ChannelException {
Channel channel = _channels.remove(userId);
if (channel != null) {
channel.close();
}
return channel;
}
@Override
public Channel fetchChannel(long userId) throws ChannelException {
return fetchChannel(userId, false);
}
@Override
public Channel fetchChannel(long userId, boolean createIfAbsent)
throws ChannelException {
Channel channel = _channels.get(userId);
if (channel == null) {
synchronized (_channels) {
channel = _channels.get(userId);
if (channel == null) {
if (createIfAbsent) {
channel = createChannel(userId);
}
}
}
}
return channel;
}
@Override
public List<NotificationEvent> fetchNotificationEvents(long userId)
throws ChannelException {
return fetchNotificationEvents(userId, false);
}
@Override
public List<NotificationEvent> fetchNotificationEvents(
long userId, boolean flush)
throws ChannelException {
Channel channel = fetchChannel(userId);
if (channel == null) {
return Collections.emptyList();
}
return channel.getNotificationEvents(flush);
}
@Override
public void flush() throws ChannelException {
for (Channel channel : _channels.values()) {
channel.flush();
}
}
@Override
public void flush(long userId) throws ChannelException {
Channel channel = fetchChannel(userId);
if (channel != null) {
channel.flush();
}
}
@Override
public void flush(long userId, long timestamp) throws ChannelException {
Channel channel = fetchChannel(userId);
if (channel != null) {
channel.flush(timestamp);
}
}
@Override
public Channel getChannel(long userId) throws ChannelException {
return getChannel(userId, false);
}
@Override
public Channel getChannel(long userId, boolean createIfAbsent)
throws ChannelException {
Channel channel = fetchChannel(userId, createIfAbsent);
if (channel == null) {
throw new UnknownChannelException(
"No channel exists with user id " + userId);
}
return channel;
}
public long getCompanyId() {
return _companyId;
}
@Override
public List<NotificationEvent> getNotificationEvents(long userId)
throws ChannelException {
return getNotificationEvents(userId, false);
}
@Override
public List<NotificationEvent> getNotificationEvents(
long userId, boolean flush)
throws ChannelException {
Channel channel = getChannel(userId, false);
return channel.getNotificationEvents(flush);
}
@Override
public Collection<Long> getUserIds() {
return Collections.unmodifiableSet(_channels.keySet());
}
@Override
public void registerChannelListener(
long userId, ChannelListener channelListener)
throws ChannelException {
Channel channel = getChannel(userId);
channel.registerChannelListener(channelListener);
}
@Override
public void removeTransientNotificationEvents(
long userId, Collection<NotificationEvent> notificationEvents)
throws ChannelException {
Channel channel = fetchChannel(userId);
if (channel != null) {
channel.removeTransientNotificationEvents(notificationEvents);
}
}
@Override
public void removeTransientNotificationEventsByUuid(
long userId, Collection<String> notificationEventUuids)
throws ChannelException {
Channel channel = fetchChannel(userId);
if (channel != null) {
channel.removeTransientNotificationEventsByUuid(
notificationEventUuids);
}
}
@Override
public void sendNotificationEvent(
long userId, NotificationEvent notificationEvent)
throws ChannelException {
Channel channel = fetchChannel(userId);
if (channel != null) {
channel.sendNotificationEvent(notificationEvent);
return;
}
if (!PropsValues.USER_NOTIFICATION_EVENT_CONFIRMATION_ENABLED ||
!notificationEvent.isDeliveryRequired()) {
return;
}
try {
UserNotificationEventLocalServiceUtil.addUserNotificationEvent(
userId, notificationEvent);
}
catch (Exception e) {
throw new ChannelException("Unable to send event", e);
}
}
@Override
public void sendNotificationEvents(
long userId, Collection<NotificationEvent> notificationEvents)
throws ChannelException {
Channel channel = fetchChannel(userId);
if (channel != null) {
channel.sendNotificationEvents(notificationEvents);
return;
}
if (!PropsValues.USER_NOTIFICATION_EVENT_CONFIRMATION_ENABLED) {
return;
}
List<NotificationEvent> persistedNotificationEvents = new ArrayList<>(
notificationEvents.size());
for (NotificationEvent notificationEvent : notificationEvents) {
if (notificationEvent.isDeliveryRequired()) {
persistedNotificationEvents.add(notificationEvent);
}
}
try {
UserNotificationEventLocalServiceUtil.addUserNotificationEvents(
userId, persistedNotificationEvents);
}
catch (Exception e) {
throw new ChannelException("Unable to send events", e);
}
}
@Override
public void storeNotificationEvent(
long userId, NotificationEvent notificationEvent)
throws ChannelException {
Channel channel = fetchChannel(userId);
if (channel != null) {
channel.storeNotificationEvent(
notificationEvent, System.currentTimeMillis());
}
}
@Override
public void unregisterChannelListener(
long userId, ChannelListener channelListener)
throws ChannelException {
Channel channel = getChannel(userId);
channel.unregisterChannelListener(channelListener);
}
private final ConcurrentMap<Long, Channel> _channels =
new ConcurrentHashMap<>();
private final long _companyId;
}