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