xref: /OpenGrok/opengrok-indexer/src/main/java/org/opengrok/indexer/web/messages/MessagesUtils.java (revision c6f0939b1c668e9f8e1e276424439c3106b3a029)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * See LICENSE.txt included in this distribution for the specific
9  * language governing permissions and limitations under the License.
10  *
11  * When distributing Covered Code, include this CDDL HEADER in each
12  * file and include the License file at LICENSE.txt.
13  * If applicable, add the following below this CDDL HEADER, with the
14  * fields enclosed by brackets "[]" replaced with your own identifying
15  * information: Portions Copyright [yyyy] [name of copyright owner]
16  *
17  * CDDL HEADER END
18  */
19 
20 /*
21  * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
22  */
23 package org.opengrok.indexer.web.messages;
24 
25 import com.fasterxml.jackson.core.JsonProcessingException;
26 import com.fasterxml.jackson.databind.ObjectMapper;
27 import org.opengrok.indexer.configuration.Group;
28 import org.opengrok.indexer.configuration.Project;
29 import org.opengrok.indexer.configuration.RuntimeEnvironment;
30 import org.opengrok.indexer.logger.LoggerFactory;
31 import org.opengrok.indexer.web.Util;
32 
33 import java.io.IOException;
34 import java.io.Writer;
35 import java.sql.Date;
36 import java.text.SimpleDateFormat;
37 import java.util.ArrayList;
38 import java.util.Arrays;
39 import java.util.Collection;
40 import java.util.HashSet;
41 import java.util.List;
42 import java.util.Set;
43 import java.util.SortedSet;
44 import java.util.logging.Level;
45 import java.util.logging.Logger;
46 import java.util.stream.Collectors;
47 
48 public final class MessagesUtils {
49 
50     private static final Logger LOGGER = LoggerFactory.getLogger(MessagesUtils.class);
51 
MessagesUtils()52     private MessagesUtils() {
53         // private to ensure static
54     }
55 
56     static final class TaggedMessagesContainer implements JSONable {
57 
58         private final String tag;
59         private final SortedSet<MessagesContainer.AcceptedMessage> messages;
60 
TaggedMessagesContainer(String tag, SortedSet<MessagesContainer.AcceptedMessage> messages)61         TaggedMessagesContainer(String tag, SortedSet<MessagesContainer.AcceptedMessage> messages) {
62             this.tag = tag;
63             this.messages = messages;
64         }
65 
getTag()66         public String getTag() {
67             return tag;
68         }
69 
getMessages()70         public SortedSet<MessagesContainer.AcceptedMessage> getMessages() {
71             return messages;
72         }
73     }
74 
75     /**
76      * Print list of messages into output.
77      *
78      * @param out output
79      * @param set set of messages
80      */
printMessages(Writer out, SortedSet<MessagesContainer.AcceptedMessage> set)81     public static void printMessages(Writer out, SortedSet<MessagesContainer.AcceptedMessage> set) {
82         printMessages(out, set, false);
83     }
84 
85     /**
86      * Print set of messages into output.
87      * @param out output
88      * @param set set of messages
89      * @param limited if the container should be limited
90      */
printMessages(Writer out, SortedSet<MessagesContainer.AcceptedMessage> set, boolean limited)91     private static void printMessages(Writer out, SortedSet<MessagesContainer.AcceptedMessage> set, boolean limited) {
92         SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
93         if (!set.isEmpty()) {
94             try {
95                 out.write("<ul class=\"message-group");
96                 if (limited) {
97                     out.write(" limited");
98                 }
99                 out.write("\">\n");
100                 for (MessagesContainer.AcceptedMessage m : set) {
101                     out.write("<li class=\"message-group-item ");
102                     out.write(Util.encode(m.getMessage().getMessageLevel().toString()));
103                     out.write("\" title=\"Expires on ");
104                     out.write(Util.encode(df.format(Date.from(m.getExpirationTime()))));
105                     out.write("\">");
106                     out.write(Util.encode(df.format(Date.from(m.getAcceptedTime()))));
107                     out.write(": ");
108                     out.write(m.getMessage().getText());
109                     out.write("</li>");
110                 }
111                 out.write("</ul>");
112             } catch (IOException ex) {
113                 LOGGER.log(Level.WARNING,
114                         "An error occurred for a group of messages", ex);
115             }
116         }
117     }
118 
119     /**
120      * Print set of tagged messages into JSON object.
121      *
122      * @return JSON string or empty string
123      */
taggedMessagesToJson(Set<TaggedMessagesContainer> messages)124     private static String taggedMessagesToJson(Set<TaggedMessagesContainer> messages) {
125         if (messages.isEmpty()) {
126             return JSONable.EMPTY;
127         }
128 
129         ObjectMapper mapper = new ObjectMapper();
130 
131         try {
132             return mapper.writeValueAsString(messages);
133         } catch (JsonProcessingException e) {
134             LOGGER.log(Level.WARNING, String.format("failed to encode '%s' to JSON: ", messages), e);
135             return JSONable.EMPTY;
136         }
137     }
138 
139     /**
140      * Print messages for given tags into JSON array.
141      *
142      * @param tags list of tags
143      * @return JSON array of the messages (the same as the parameter)
144      */
messagesToJson(String... tags)145     public static String messagesToJson(String... tags) {
146         Set<TaggedMessagesContainer> messages = new HashSet<>();
147 
148         for (String tag : tags) {
149             SortedSet<MessagesContainer.AcceptedMessage> messagesWithTag = RuntimeEnvironment.getInstance().getMessages(tag);
150             if (messagesWithTag.isEmpty()) {
151                 continue;
152             }
153 
154             TaggedMessagesContainer container = new TaggedMessagesContainer(tag, messagesWithTag);
155             messages.add(container);
156         }
157 
158         return taggedMessagesToJson(messages);
159     }
160 
161     /**
162      * Print messages for given tags into JSON array.
163      *
164      * @param tags list of tags
165      * @return json array of the messages
166      * @see #messagesToJson(String...)
167      */
messagesToJson(List<String> tags)168     private static String messagesToJson(List<String> tags) {
169         return messagesToJson(tags.toArray(new String[0]));
170     }
171 
172     /**
173      * Print messages for given project into JSON. These messages are
174      * tagged by project description or tagged by any of the project's group name.
175      *
176      * @param project the project
177      * @param additionalTags additional list of tags
178      * @return JSON string
179      * @see #messagesToJson(String...)
180      */
messagesToJson(Project project, String... additionalTags)181     public static String messagesToJson(Project project, String... additionalTags) {
182         if (project == null) {
183             return JSONable.EMPTY;
184         }
185 
186         List<String> tags = new ArrayList<>(Arrays.asList(additionalTags));
187         tags.add(project.getName());
188         project.getGroups().stream().map(Group::getName).forEach(tags::add);
189 
190         return messagesToJson(tags);
191     }
192 
193     /**
194      * Print messages for given project into JSON array. These messages are
195      * tagged by project description or tagged by any of the project's group
196      * name.
197      *
198      * @param project the project
199      * @return the json array
200      * @see #messagesToJson(Project, String...)
201      */
messagesToJson(Project project)202     public static String messagesToJson(Project project) {
203         return messagesToJson(project, new String[0]);
204     }
205 
206     /**
207      * Print messages for given group into JSON.
208      *
209      * @param group the group
210      * @param additionalTags additional list of tags
211      * @return JSON string
212      * @see #messagesToJson(java.util.List)
213      */
messagesToJson(Group group, String... additionalTags)214     private static String messagesToJson(Group group, String... additionalTags) {
215         List<String> tags = new ArrayList<>();
216 
217         tags.add(group.getName());
218         tags.addAll(Arrays.asList(additionalTags));
219 
220         return messagesToJson(tags);
221     }
222 
223     /**
224      * Convert messages for given group into JSON.
225      *
226      * @param group the group
227      * @return JSON string
228      * @see #messagesToJson(Group, String...)
229      */
messagesToJson(Group group)230     public static String messagesToJson(Group group) {
231         return messagesToJson(group, new String[0]);
232     }
233 
234     /**
235      * @return name of highest cssClass of messages present in the system or null.
236      */
getHighestMessageLevel(Collection<MessagesContainer.AcceptedMessage> messages)237     static String getHighestMessageLevel(Collection<MessagesContainer.AcceptedMessage> messages) {
238         return messages.
239                 stream().
240                 map(MessagesContainer.AcceptedMessage::getMessageLevel).
241                 max(Message.MessageLevel.VALUE_COMPARATOR).
242                 map(Message.MessageLevel::toString).
243                 orElse(null);
244     }
245 
246     /**
247      * @param tags message tags
248      * @return name of highest cssClass of messages present in the system or null.
249      */
getMessageLevel(String... tags)250     public static String getMessageLevel(String... tags) {
251         Set<MessagesContainer.AcceptedMessage> messages;
252         RuntimeEnvironment env = RuntimeEnvironment.getInstance();
253 
254         messages = Arrays.stream(tags).
255                 map(env::getMessages).
256                 flatMap(Collection::stream).
257                 collect(Collectors.toSet());
258 
259         return getHighestMessageLevel(messages);
260     }
261 }
262