package com.ullink.slack.review.subscription; import org.mapdb.DB; import javax.inject.Inject; import javax.inject.Singleton; import java.util.*; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; @Singleton public class SubscriptionImpl implements SubscriptionService { private Map<String, List<String>> projectSubscriptionMap; private Map<String, List<String>> userSubscriptionMap; @Inject private DB db; private ReadWriteLock lock = new ReentrantReadWriteLock(); @Inject public SubscriptionImpl(DB db) { projectSubscriptionMap = db.<String, List<String>> getTreeMap("ProjectSubscription"); userSubscriptionMap = db.<String, List<String>> getTreeMap("UserSubscription"); } @Override public Collection<String> getChannelsListeningToProject(String projectName) { Lock readLock = lock.readLock(); readLock.lock(); try { List<String> channelList = projectSubscriptionMap.get(projectName); if (channelList != null) { return new ArrayList<String>(channelList); } } finally { readLock.unlock(); } return Collections.emptyList(); } @Override public Collection<String> getChannelsListeningToUser(String userName) { Lock readLock = lock.readLock(); readLock.lock(); try { List<String> channelList = userSubscriptionMap.get(userName); if (channelList != null) { return new ArrayList<String>(channelList); } } finally { readLock.unlock(); } return Collections.emptyList(); } @Override public Collection<String> getChannelSubscriptions(String channelId) { Lock readLock = lock.readLock(); readLock.lock(); try { // full scan... Set<String> projectList = projectSubscriptionMap.keySet(); Set<String> userList = userSubscriptionMap.keySet(); List<String> toReturn = new ArrayList<String>(); for (String projectId : projectList) { if (getChannelsListeningToProject(projectId).contains(channelId)) { toReturn.add("Project: " + projectId); } } for (String userId : userList) { if (getChannelsListeningToUser(userId).contains(channelId)) { toReturn.add("User: @" + userId); } } return toReturn; } finally { readLock.unlock(); } } @Override public void subscribeOnProject(String projectName, String channelId) { Lock writeLock = lock.writeLock(); writeLock.lock(); try { Collection<String> requestList = getChannelsListeningToProject(projectName); ArrayList<String> newList = new ArrayList<String>(requestList); for (String subscribingChannelId : newList) { if (channelId.equals(subscribingChannelId)) { // already subscribed return; } } newList.add(channelId); projectSubscriptionMap.put(projectName, newList); db.commit(); } catch (Throwable e) { e.printStackTrace(); db.rollback(); } finally { writeLock.unlock(); } } @Override public void unsubscribeOnProject(String projectName, String channelId) { Lock writeLock = lock.writeLock(); writeLock.lock(); try { Collection<String> requestList = getChannelsListeningToProject(projectName); ArrayList<String> newList = new ArrayList<String>(requestList); for (Iterator<String> channelIterator = newList.iterator(); channelIterator.hasNext();) { String subscribingChannelId = channelIterator.next(); if (channelId.equals(subscribingChannelId)) { channelIterator.remove(); } } projectSubscriptionMap.put(projectName, newList); db.commit(); } catch (Throwable e) { e.printStackTrace(); db.rollback(); } finally { writeLock.unlock(); } } @Override public void subscribeOnUser(String userName, String channelId) { Lock writeLock = lock.writeLock(); writeLock.lock(); try { Collection<String> requestList = getChannelsListeningToUser(userName); ArrayList<String> newList = new ArrayList<String>(requestList); for (String subscribingChannelId : newList) { if (channelId.equals(subscribingChannelId)) { // already subscribed return; } } newList.add(channelId); userSubscriptionMap.put(userName, newList); db.commit(); } catch (Throwable e) { e.printStackTrace(); db.rollback(); } finally { writeLock.unlock(); } } @Override public void unsubscribeOnUser(String userName, String channelId){ Lock writeLock = lock.writeLock(); writeLock.lock(); try { Collection<String> requestList = getChannelsListeningToUser(userName); ArrayList<String> newList = new ArrayList<String>(requestList); for (Iterator<String> channelIterator = newList.iterator(); channelIterator.hasNext();) { String subscribingChannelId = channelIterator.next(); if (channelId.equals(subscribingChannelId)) { channelIterator.remove(); } } userSubscriptionMap.put(userName, newList); db.commit(); } catch (Throwable e) { e.printStackTrace(); db.rollback(); } finally { writeLock.unlock(); } } }