1
2
3
4
5
6
7 package ch.colabproject.colab.api.ws;
8
9 import ch.colabproject.colab.api.model.WithWebsocketChannels;
10 import ch.colabproject.colab.api.persistence.jpa.card.CardTypeDao;
11 import ch.colabproject.colab.api.persistence.jpa.project.ProjectDao;
12 import ch.colabproject.colab.api.persistence.jpa.team.TeamMemberDao;
13 import ch.colabproject.colab.api.persistence.jpa.user.UserDao;
14 import ch.colabproject.colab.api.ws.channel.model.WebsocketChannel;
15 import ch.colabproject.colab.api.ws.channel.tool.ChannelsBuilders.ChannelsBuilder;
16 import ch.colabproject.colab.api.ws.channel.tool.ChannelsBuilders.ForAdminChannelsBuilder;
17 import ch.colabproject.colab.api.ws.message.IndexEntry;
18 import ch.colabproject.colab.api.ws.message.PrecomputedWsMessages;
19 import ch.colabproject.colab.api.ws.message.WsMessage;
20 import ch.colabproject.colab.api.ws.message.WsUpdateMessage;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23
24 import javax.websocket.EncodeException;
25 import java.util.*;
26
27
28
29
30
31
32 public class WebsocketMessagePreparer {
33
34
35 private static final Logger logger = LoggerFactory.getLogger(WebsocketMessagePreparer.class);
36
37
38
39
40 private WebsocketMessagePreparer() {
41 throw new UnsupportedOperationException(
42 "This is a utility class and cannot be instantiated");
43 }
44
45
46
47
48
49
50
51
52
53 private static WsUpdateMessage getOrCreateWsUpdateMessage(
54 Map<WebsocketChannel, List<WsMessage>> messagesByChannel,
55 WebsocketChannel key
56 ) {
57 logger.trace("GetOrCreate WsUpdateMessge for channel {}", key);
58 if (!messagesByChannel.containsKey(key)) {
59 logger.trace(" -> create channel {}", key);
60 messagesByChannel.put(key, List.of(new WsUpdateMessage()));
61 return (WsUpdateMessage) messagesByChannel.get(key).get(0);
62 } else {
63 List<WsMessage> get = messagesByChannel.get(key);
64 logger.trace(" -> use existing channel {} := {}", key, get);
65 Optional<WsMessage> find = get.stream()
66 .filter(message -> message instanceof WsUpdateMessage)
67 .findFirst();
68 if (find.isPresent()) {
69 logger.trace(" -> use existing message {}", find.get());
70 return (WsUpdateMessage) find.get();
71 } else {
72 logger.trace(" -> create emtpy message");
73 WsUpdateMessage wsUpdateMessage = new WsUpdateMessage();
74 get.add(wsUpdateMessage);
75 return wsUpdateMessage;
76 }
77 }
78 }
79
80
81
82
83
84
85
86
87 private static void addAsUpdated(
88 Map<WebsocketChannel, List<WsMessage>> messagesByChannel,
89 WebsocketChannel channel,
90 WithWebsocketChannels entity) {
91 Collection<WithWebsocketChannels> set = WebsocketMessagePreparer
92 .getOrCreateWsUpdateMessage(messagesByChannel, channel).getUpdated();
93 logger.trace("Add {} to updated set {}", entity, set);
94 set.add(entity);
95 if (logger.isTraceEnabled()) {
96 set.forEach(e -> {
97 logger.trace("Entity: {}", e);
98 logger.trace("Entity hashCode: {}", e.hashCode());
99 logger.trace("Entity equals new: {}", e.equals(entity));
100 });
101 }
102 }
103
104
105
106
107
108
109
110
111 private static void addAsDeleted(Map<WebsocketChannel, List<WsMessage>> byChannels,
112 WebsocketChannel channel,
113 IndexEntry entry) {
114 Collection<IndexEntry> set = WebsocketMessagePreparer
115 .getOrCreateWsUpdateMessage(byChannels, channel)
116 .getDeleted();
117 logger.trace("Add {} to deleted set {}", entry, set);
118 set.add(entry);
119 }
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135 public static PrecomputedWsMessages prepareWsMessage(
136 UserDao userDao,
137 TeamMemberDao teamDao,
138 CardTypeDao cardTypeDao,
139 ProjectDao projectDao,
140 Set<WithWebsocketChannels> updated,
141 Set<IndexEntry> deleted
142 ) throws EncodeException {
143 Map<WebsocketChannel, List<WsMessage>> messagesByChannel = new HashMap<>();
144 logger.debug("Prepare WsMessage. Update:{}; Deleted:{}", updated, deleted);
145
146 updated.forEach(object -> {
147 logger.trace("Process updated entity {}", object);
148 object.getChannelsBuilder().computeChannels(userDao, teamDao, cardTypeDao, projectDao)
149 .forEach(channel -> {
150 addAsUpdated(messagesByChannel, channel, object);
151 });
152 });
153
154 deleted.forEach(object -> {
155 logger.trace("Process deleted entry {}", object);
156 object.getChannelsBuilder().computeChannels(userDao, teamDao, cardTypeDao, projectDao)
157 .forEach(
158 channel -> {
159 addAsDeleted(messagesByChannel, channel, object);
160 });
161 });
162
163 return PrecomputedWsMessages.build(messagesByChannel);
164 }
165
166
167
168
169
170
171
172
173
174
175
176 public static PrecomputedWsMessages prepareWsMessageForAdmins(
177 UserDao userDao,
178 WsMessage message
179 ) throws EncodeException {
180 return prepareWsMessage(userDao, null, null, null, new ForAdminChannelsBuilder(), message);
181 }
182
183
184
185
186
187
188
189
190
191
192
193
194
195 public static PrecomputedWsMessages prepareWsMessage(
196 UserDao userDao,
197 TeamMemberDao teamDao,
198 CardTypeDao cardTypeDao,
199 ProjectDao projectDao,
200 ChannelsBuilder channelBuilder,
201 WsMessage message
202 ) throws EncodeException {
203 Map<WebsocketChannel, List<WsMessage>> messagesByChannel = new HashMap<>();
204
205 channelBuilder.computeChannels(userDao, teamDao, cardTypeDao, projectDao).forEach(channel -> {
206 messagesByChannel.put(channel, List.of(message));
207 });
208
209 return PrecomputedWsMessages.build(messagesByChannel);
210 }
211
212 }