/* * (C) Copyright 2006-2015 Nuxeo SA (http://nuxeo.com/) and others. * * 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. * * Contributors: * dmetzler */ package org.nuxeo.ecm.platform.ec.notification; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.nuxeo.ecm.core.api.CoreSession; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.platform.notification.api.Notification; import org.nuxeo.ecm.platform.notification.api.NotificationManager; import org.nuxeo.runtime.api.Framework; /** * Encapsulates all notification storage logic in the Notifiable facet. * * @since 7.3 */ public class SubscriptionAdapter { public static final String NOTIFIABLE_FACET = "Notifiable"; private static final String NOTIF_PROPERTY = "notif:notifications"; private static final String NOTIF_SUBSCRIBERSKEY = "subscribers"; private static final String NOTIF_NAMEKEY = "name"; private DocumentModel doc; public SubscriptionAdapter(DocumentModel doc) { this.doc = doc; } /** * Take the document storage propery and put it in a map. * <dl> * <dt>key</dt> * <dd>notificationName</dd> * <dt>value</dt> * <dd>list of subscribers</dd> * </dl> * After having modified the map, update the doc with {@link #setNotificationMap(Map)} * * @return */ private Map<String, Set<String>> getNotificationMap() { if (!doc.hasFacet(SubscriptionAdapter.NOTIFIABLE_FACET)) { return new HashMap<>(); } Map<String, Set<String>> result = new HashMap<String, Set<String>>(); @SuppressWarnings("unchecked") List<Map<String, Serializable>> props = (List<Map<String, Serializable>>) doc.getPropertyValue(NOTIF_PROPERTY); for (Map<String, Serializable> prop : props) { String notificationName = (String) prop.get(NOTIF_NAMEKEY); String[] subscribers = (String[]) prop.get(NOTIF_SUBSCRIBERSKEY); if (subscribers != null && subscribers.length > 0) { if (!result.containsKey(notificationName)) { Set<String> subscribersSet = new HashSet<String>(); result.put(notificationName, subscribersSet); } result.get(notificationName).addAll(Arrays.asList(subscribers)); } } return result; } /** * Take a map and store it in the document's notification property. To get the original map, use * {@link #getNotificationMap()} */ private void setNotificationMap(Map<String, Set<String>> map) { List<Map<String, Serializable>> props = new ArrayList<Map<String, Serializable>>(); for (Entry<String, Set<String>> entry : map.entrySet()) { Set<String> subscribers = entry.getValue(); if (!subscribers.isEmpty()) { Map<String, Serializable> propMap = new HashMap<>(); propMap.put(NOTIF_NAMEKEY, entry.getKey()); propMap.put(NOTIF_SUBSCRIBERSKEY, new ArrayList<String>(subscribers)); props.add(propMap); } } if (!props.isEmpty()) { if (!doc.hasFacet(SubscriptionAdapter.NOTIFIABLE_FACET)) { doc.addFacet(SubscriptionAdapter.NOTIFIABLE_FACET); } } doc.setPropertyValue(NOTIF_PROPERTY, (Serializable) props); } /** * Return the list of subscribers name for a given notification. * * @param notification * @return */ public List<String> getNotificationSubscribers(String notification) { Set<String> subscribers = getNotificationMap().get(notification); return subscribers != null ? new ArrayList<>(subscribers) : Collections.emptyList(); } /** * Return the list of of subscriptions for a given user * * @return */ public List<String> getUserSubscriptions(String username) { List<String> result = new ArrayList<String>(); for (Entry<String, Set<String>> entry : getNotificationMap().entrySet()) { if (entry.getValue().contains(username)) { result.add(entry.getKey()); } } return result; } /** * Add a subscription to a notification for a given user. * * @param username * @param notification */ public void addSubscription(String username, String notification) { Map<String, Set<String>> notificationMap = getNotificationMap(); if (!notificationMap.containsKey(notification)) { notificationMap.put(notification, new HashSet<>()); } notificationMap.get(notification).add(username); setNotificationMap(notificationMap); } /** * Add a subscription to all notification for a given user * * @param username */ public void addSubscriptionsToAll(String username) { Set<String> notificationNames = new HashSet<String>(); NotificationManager ns = Framework.getLocalService(NotificationManager.class); for (Notification notif : ns.getNotificationsForSubscriptions(doc.getType())) { notificationNames.add(notif.getName()); } CoreSession session = doc.getCoreSession(); if (session != null) { for (DocumentModel parent : session.getParentDocuments(doc.getRef())) { for (Notification notif : ns.getNotificationsForSubscriptions(parent.getType())) { notificationNames.add(notif.getName()); } } } // add subscriptions to every relevant notification for (String name : notificationNames) { addSubscription(username, name); } } /** * Remove a subscription to a notification for a given user. * * @param username * @param notification */ public void removeUserNotificationSubscription(String username, String notification) { Map<String, Set<String>> map = getNotificationMap(); if (map.containsKey(notification)) { map.get(notification).remove(username); } setNotificationMap(map); } /** * Copy the subscriptions of the current doc to the targetted document. * * @param targetDoc */ public void copySubscriptionsTo(DocumentModel targetDoc) { if (!targetDoc.hasFacet(NOTIFIABLE_FACET)) { targetDoc.addFacet(NOTIFIABLE_FACET); } targetDoc.setPropertyValue(NOTIF_PROPERTY, doc.getPropertyValue(NOTIF_PROPERTY)); } }