001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.feedback; 018 019import java.io.Serializable; 020import java.util.ArrayList; 021import java.util.Collections; 022import java.util.Iterator; 023import java.util.List; 024import java.util.concurrent.CopyOnWriteArrayList; 025 026import org.apache.wicket.Component; 027import org.apache.wicket.util.io.IClusterable; 028import org.apache.wicket.util.string.StringList; 029import org.slf4j.Logger; 030import org.slf4j.LoggerFactory; 031 032/** 033 * Holds list of feedback messages. The list can be added to, cleared, queried and filtered. 034 * <p> 035 * WARNING: This class should typically NOT be used directly. 036 * <p> 037 * 038 * @author Eelco Hillenius 039 * @author Jonathan Locke 040 */ 041public final class FeedbackMessages implements IClusterable, Iterable<FeedbackMessage> 042{ 043 /** Log. */ 044 private static final Logger log = LoggerFactory.getLogger(FeedbackMessages.class); 045 046 private static final long serialVersionUID = 1L; 047 048 /** 049 * Holds a list of {@link org.apache.wicket.feedback.FeedbackMessage}s. 050 */ 051 private final List<FeedbackMessage> messages; 052 053 /** 054 * Construct. 055 */ 056 public FeedbackMessages() 057 { 058 messages = new CopyOnWriteArrayList<>(); 059 } 060 061 /** 062 * Adds a message. 063 * 064 * @param message 065 * the message 066 */ 067 public final void add(FeedbackMessage message) 068 { 069 log.debug("Adding feedback message '{}'", message); 070 071 synchronized (messages) 072 { 073 messages.add(message); 074 } 075 } 076 077 /** 078 * Adds a message 079 * 080 * @param reporter 081 * @param message 082 * @param level 083 */ 084 public final void add(Component reporter, Serializable message, int level) 085 { 086 add(new FeedbackMessage(reporter, message, level)); 087 } 088 089 /** 090 * Adds a new ui message with level DEBUG to the current messages. 091 * 092 * @param reporter 093 * the reporting component 094 * @param message 095 * the actual message 096 */ 097 public final void debug(Component reporter, Serializable message) 098 { 099 add(new FeedbackMessage(reporter, message, FeedbackMessage.DEBUG)); 100 } 101 102 /** 103 * Adds a new ui message with level INFO to the current messages. 104 * 105 * @param reporter 106 * The reporting component 107 * @param message 108 * The actual message 109 */ 110 public final void info(Component reporter, Serializable message) 111 { 112 add(new FeedbackMessage(reporter, message, FeedbackMessage.INFO)); 113 } 114 115 /** 116 * Adds a new ui message with level SUCCESS to the current messages. 117 * 118 * @param reporter 119 * The reporting component 120 * @param message 121 * The actual message 122 */ 123 public final void success(Component reporter, Serializable message) 124 { 125 add(new FeedbackMessage(reporter, message, FeedbackMessage.SUCCESS)); 126 } 127 128 /** 129 * Adds a new ui message with level WARNING to the current messages. 130 * 131 * @param reporter 132 * the reporting component 133 * @param message 134 * the actual message 135 */ 136 public final void warn(Component reporter, Serializable message) 137 { 138 add(new FeedbackMessage(reporter, message, FeedbackMessage.WARNING)); 139 } 140 141 /** 142 * Adds a new ui message with level ERROR to the current messages. 143 * 144 * @param reporter 145 * the reporting component 146 * @param message 147 * the actual message 148 */ 149 public final void error(Component reporter, Serializable message) 150 { 151 add(new FeedbackMessage(reporter, message, FeedbackMessage.ERROR)); 152 } 153 154 /** 155 * Adds a new ui message with level FATAL to the current messages. 156 * 157 * @param reporter 158 * the reporting component 159 * @param message 160 * the actual message 161 */ 162 public final void fatal(Component reporter, Serializable message) 163 { 164 add(new FeedbackMessage(reporter, message, FeedbackMessage.FATAL)); 165 } 166 167 /** 168 * Clears any existing messages. 169 * 170 * @return The number of messages deleted 171 */ 172 public final int clear() 173 { 174 return clear(null); 175 } 176 177 /** 178 * Clears all messages that are accepted by the filter. 179 * 180 * @param filter 181 * Filter for selecting messages. If null, all messages will be returned 182 * @return The number of messages deleted 183 */ 184 public final int clear(final IFeedbackMessageFilter filter) 185 { 186 if (messages.isEmpty()) 187 { 188 return 0; 189 } 190 191 List<FeedbackMessage> toDelete = messages(filter); 192 193 for (FeedbackMessage message : toDelete) 194 { 195 message.detach(); 196 } 197 198 synchronized(messages) 199 { 200 int sizeBefore = messages.size(); 201 messages.removeAll(toDelete); 202 int sizeAfter = messages.size(); 203 return sizeAfter - sizeBefore; 204 } 205 } 206 207 /** 208 * @param filter 209 * Filter for selecting messages 210 * @return True if one or more messages matches the filter 211 */ 212 public final boolean hasMessage(final IFeedbackMessageFilter filter) 213 { 214 for (final FeedbackMessage message : messages) 215 { 216 if (filter == null || filter.accept(message)) 217 { 218 return true; 219 } 220 } 221 return false; 222 } 223 224 /** 225 * Checks if a message of the specified {@code level} or greater was registered.<br /> 226 * To check for a precise {@code level} use {@link #hasMessage(IFeedbackMessageFilter)} 227 * and pass it a reference to {@link org.apache.wicket.feedback.ExactLevelFeedbackMessageFilter}. 228 * 229 * @param level 230 * The level of the message 231 * @return {@code true} if a message with the specified {@code level} or greater was registered 232 */ 233 public final boolean hasMessage(final int level) 234 { 235 for (FeedbackMessage message : messages) 236 { 237 if (message.isLevel(level)) 238 { 239 return true; 240 } 241 } 242 return false; 243 } 244 245 /** 246 * Retrieves the first message 247 * 248 * @return message or {@code null} if none 249 */ 250 public final FeedbackMessage first() 251 { 252 return messages.size() > 0 ? messages.get(0) : null; 253 } 254 255 /** 256 * Retrieves the first message that level is greater than or equal to the given level 257 * 258 * @param level 259 * The minimum level of the message 260 * @return a message with the same or a higher level, or {@code null} if none 261 */ 262 public final FeedbackMessage first(final int level) 263 { 264 for (FeedbackMessage message : messages) 265 { 266 if (message.isLevel(level)) 267 { 268 return message; 269 } 270 } 271 return null; 272 } 273 274 /** 275 * Gets an iterator over stored messages 276 * 277 * @return iterator over stored messages 278 */ 279 @Override 280 public final Iterator<FeedbackMessage> iterator() 281 { 282 return messages.iterator(); 283 } 284 285 /** 286 * Gets a list of messages from the page using a filter. 287 * 288 * @param filter 289 * Filter for selecting messages. If null, all messages will be returned 290 * @return The messages or an empty list if no messages are found 291 */ 292 public final List<FeedbackMessage> messages(final IFeedbackMessageFilter filter) 293 { 294 if (messages.isEmpty()) 295 { 296 return Collections.emptyList(); 297 } 298 299 final List<FeedbackMessage> list = new ArrayList<FeedbackMessage>(); 300 for (final FeedbackMessage message : messages) 301 { 302 if (filter == null || filter.accept(message)) 303 { 304 list.add(message); 305 } 306 } 307 return list; 308 } 309 310 /** 311 * Gets whether there are no messages. 312 * 313 * @return True when there are no messages 314 */ 315 public final boolean isEmpty() 316 { 317 return messages.isEmpty(); 318 } 319 320 /** 321 * Gets the number of messages 322 * 323 * @return the number of messages 324 */ 325 public final int size() 326 { 327 return messages.size(); 328 } 329 330 /** 331 * Gets the number of messages. 332 * 333 * @param filter 334 * Filter for counting messages. If null, the count of all messages will be returned 335 * 336 * @return the number of messages 337 */ 338 public final int size(final IFeedbackMessageFilter filter) 339 { 340 int count = 0; 341 for (final FeedbackMessage message : messages) 342 { 343 if (filter == null || filter.accept(message)) 344 { 345 count++; 346 } 347 } 348 return count; 349 } 350 351 /** 352 * @see java.lang.Object#toString() 353 */ 354 @Override 355 public String toString() 356 { 357 return "[feedbackMessages = " + StringList.valueOf(messages) + ']'; 358 } 359 360 /** 361 * Retrieves all stored messages as an unmodifiable list 362 * 363 * @return stored messages as unmodifiable list 364 */ 365 public List<FeedbackMessage> toList() 366 { 367 return Collections.unmodifiableList(messages); 368 } 369 370 /** 371 * Detaches each stored message 372 */ 373 public void detach() 374 { 375 for (FeedbackMessage message : messages) 376 { 377 message.detach(); 378 } 379 } 380}