001/* 002 * (C) Copyright 2006-2015 Nuxeo SAS (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * dmetzler 016 */ 017package org.nuxeo.ecm.platform.ec.notification; 018 019import java.io.Serializable; 020import java.util.ArrayList; 021import java.util.Arrays; 022import java.util.Collections; 023import java.util.HashMap; 024import java.util.HashSet; 025import java.util.List; 026import java.util.Map; 027import java.util.Map.Entry; 028import java.util.Set; 029 030import org.nuxeo.ecm.core.api.CoreSession; 031import org.nuxeo.ecm.core.api.DocumentModel; 032import org.nuxeo.ecm.platform.notification.api.Notification; 033import org.nuxeo.ecm.platform.notification.api.NotificationManager; 034import org.nuxeo.runtime.api.Framework; 035 036/** 037 * Encapsulates all notification storage logic in the Notifiable facet. 038 * 039 * @since 7.3 040 */ 041public class SubscriptionAdapter { 042 043 public static final String NOTIFIABLE_FACET = "Notifiable"; 044 045 private static final String NOTIF_PROPERTY = "notif:notifications"; 046 047 private static final String NOTIF_SUBSCRIBERSKEY = "subscribers"; 048 049 private static final String NOTIF_NAMEKEY = "name"; 050 051 private DocumentModel doc; 052 053 public SubscriptionAdapter(DocumentModel doc) { 054 this.doc = doc; 055 } 056 057 /** 058 * Take the document storage propery and put it in a map. 059 * <dl> 060 * <dt>key</dt> 061 * <dd>notificationName</dd> 062 * <dt>value</dt> 063 * <dd>list of subscribers</dd> 064 * </dl> 065 * After having modified the map, update the doc with {@link #setNotificationMap(Map)} 066 * 067 * @return 068 */ 069 private Map<String, Set<String>> getNotificationMap() { 070 071 if (!doc.hasFacet(SubscriptionAdapter.NOTIFIABLE_FACET)) { 072 return new HashMap<>(); 073 } 074 075 Map<String, Set<String>> result = new HashMap<String, Set<String>>(); 076 077 @SuppressWarnings("unchecked") 078 List<Map<String, Serializable>> props = (List<Map<String, Serializable>>) doc.getPropertyValue(NOTIF_PROPERTY); 079 for (Map<String, Serializable> prop : props) { 080 String notificationName = (String) prop.get(NOTIF_NAMEKEY); 081 String[] subscribers = (String[]) prop.get(NOTIF_SUBSCRIBERSKEY); 082 083 if (subscribers != null && subscribers.length > 0) { 084 if (!result.containsKey(notificationName)) { 085 Set<String> subscribersSet = new HashSet<String>(); 086 result.put(notificationName, subscribersSet); 087 } 088 result.get(notificationName).addAll(Arrays.asList(subscribers)); 089 } 090 } 091 return result; 092 093 } 094 095 /** 096 * Take a map and store it in the document's notification property. To get the original map, use 097 * {@link #getNotificationMap()} 098 */ 099 private void setNotificationMap(Map<String, Set<String>> map) { 100 List<Map<String, Serializable>> props = new ArrayList<Map<String, Serializable>>(); 101 for (Entry<String, Set<String>> entry : map.entrySet()) { 102 Map<String, Serializable> propMap = new HashMap<>(); 103 propMap.put(NOTIF_NAMEKEY, entry.getKey()); 104 propMap.put(NOTIF_SUBSCRIBERSKEY, new ArrayList<String>(entry.getValue())); 105 props.add(propMap); 106 } 107 108 if (!props.isEmpty()) { 109 if (!doc.hasFacet(SubscriptionAdapter.NOTIFIABLE_FACET)) { 110 doc.addFacet(SubscriptionAdapter.NOTIFIABLE_FACET); 111 } 112 113 doc.setPropertyValue(NOTIF_PROPERTY, (Serializable) props); 114 } 115 } 116 117 /** 118 * Return the list of subscribers name for a given notification. 119 * 120 * @param notification 121 * @return 122 */ 123 public List<String> getNotificationSubscribers(String notification) { 124 Set<String> subscribers = getNotificationMap().get(notification); 125 return subscribers != null ? new ArrayList<>(subscribers) : Collections.emptyList(); 126 } 127 128 /** 129 * Return the list of of subscriptions for a given user 130 * 131 * @return 132 */ 133 public List<String> getUserSubscriptions(String username) { 134 List<String> result = new ArrayList<String>(); 135 for (Entry<String, Set<String>> entry : getNotificationMap().entrySet()) { 136 if (entry.getValue().contains(username)) { 137 result.add(entry.getKey()); 138 } 139 } 140 return result; 141 } 142 143 /** 144 * Add a subscription to a notification for a given user. 145 * 146 * @param username 147 * @param notification 148 */ 149 public void addSubscription(String username, String notification) { 150 Map<String, Set<String>> notificationMap = getNotificationMap(); 151 if (!notificationMap.containsKey(notification)) { 152 notificationMap.put(notification, new HashSet<>()); 153 } 154 notificationMap.get(notification).add(username); 155 setNotificationMap(notificationMap); 156 } 157 158 /** 159 * Add a subscription to all notification for a given user 160 * 161 * @param username 162 */ 163 public void addSubscriptionsToAll(String username) { 164 165 Set<String> notificationNames = new HashSet<String>(); 166 167 NotificationManager ns = Framework.getLocalService(NotificationManager.class); 168 169 for (Notification notif : ns.getNotificationsForSubscriptions(doc.getType())) { 170 notificationNames.add(notif.getName()); 171 } 172 173 CoreSession session = doc.getCoreSession(); 174 175 if (session != null) { 176 for (DocumentModel parent : session.getParentDocuments(doc.getRef())) { 177 for (Notification notif : ns.getNotificationsForSubscriptions(parent.getType())) { 178 notificationNames.add(notif.getName()); 179 } 180 } 181 } 182 183 // add subscriptions to every relevant notification 184 for (String name : notificationNames) { 185 addSubscription(username, name); 186 } 187 188 } 189 190 /** 191 * Remove a subscription to a notification for a given user. 192 * 193 * @param username 194 * @param notification 195 */ 196 public void removeUserNotificationSubscription(String username, String notification) { 197 Map<String, Set<String>> map = getNotificationMap(); 198 if (map.containsKey(notification)) { 199 map.get(notification).remove(username); 200 } 201 setNotificationMap(map); 202 } 203 204 /** 205 * Copy the subscriptions of the current doc to the targetted document. 206 * 207 * @param targetDoc 208 */ 209 public void copySubscriptionsTo(DocumentModel targetDoc) { 210 if(!targetDoc.hasFacet(NOTIFIABLE_FACET)) { 211 targetDoc.addFacet(NOTIFIABLE_FACET); 212 } 213 targetDoc.setPropertyValue(NOTIF_PROPERTY, doc.getPropertyValue(NOTIF_PROPERTY)); 214 } 215 216}