001 /*
002 * $Id: BasicMessageList.java 366395 2006-01-06 02:42:19Z niallp $
003 * $Revision: 366395 $
004 * $Date: 2006-01-06 02:42:19 +0000 (Fri, 06 Jan 2006) $
005 *
006 * ====================================================================
007 *
008 * Copyright 2003-2006 The Apache Software Foundation
009 *
010 * Licensed under the Apache License, Version 2.0 (the "License");
011 * you may not use this file except in compliance with the License.
012 * You may obtain a copy of the License at
013 *
014 * http://www.apache.org/licenses/LICENSE-2.0
015 *
016 * Unless required by applicable law or agreed to in writing, software
017 * distributed under the License is distributed on an "AS IS" BASIS,
018 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
019 * See the License for the specific language governing permissions and
020 * limitations under the License.
021 *
022 */
023
024 package org.apache.commons.resources.impl;
025
026 import java.io.Serializable;
027 import java.util.ArrayList;
028 import java.util.Collections;
029 import java.util.Comparator;
030 import java.util.HashMap;
031 import java.util.Iterator;
032 import java.util.List;
033 import java.util.Map;
034
035 import org.apache.commons.resources.Message;
036 import org.apache.commons.resources.MessageList;
037
038 /**
039 * A basic implementation of a MessageList.
040 * <p>
041 * Orginally based on org.apache.struts.action.ActionMessages, Revision 49670.
042 */
043 public class BasicMessageList implements Serializable, MessageList {
044
045 /**
046 * Compares MessageItems.
047 */
048 private static final Comparator ACTION_ITEM_COMPARATOR = new Comparator() {
049 public int compare(Object o1, Object o2) {
050 return ((MessageItem) o1).getOrder() - ((MessageItem) o2).getOrder();
051 }
052 };
053
054 /**
055 * Have the messages been retrieved from this object?
056 */
057 private boolean accessed = false;
058
059 /**
060 * The accumulated set of <code>Message</code> objects (represented
061 * as a List) for each property, keyed by property name.
062 */
063 private Map messages = new HashMap();
064
065 /**
066 * The current number of the property/key being added. This is used
067 * to maintain the order messages are added.
068 */
069 private int count = 0;
070
071 // --------------------------------------------------------- Public Methods
072
073 /**
074 * Create an empty <code>MessageList</code> object.
075 */
076 public BasicMessageList() {
077 super();
078 }
079
080 /**
081 * Create an <code>MessageList</code> object initialized to use
082 * the given value for the "global" message key.
083 *
084 * @param globalMessageKey The new default global message key
085 */
086 public BasicMessageList(String globalMessageKey) {
087 super();
088 this.setGlobalMessageKey(globalMessageKey);
089 }
090
091 /**
092 * Create an <code>MessageList</code> object initialized with the given
093 * messages.
094 *
095 * @param messages The messages to be initially added to this object.
096 */
097 public BasicMessageList(MessageList messages) {
098 super();
099 this.add(messages);
100 }
101
102 /**
103 * Create an <code>MessageList</code> object initialized with the given
104 * messages and the given global message key.
105 *
106 * @param globalMessageKey The new default global message key
107 * @param messages The messages to be initially added to this object.
108 *
109 */
110 public BasicMessageList(String globalMessageKey, MessageList messages) {
111 super();
112 this.setGlobalMessageKey(globalMessageKey);
113 this.add(messages);
114 }
115
116 /**
117 * The "global" message key for this MessageList
118 * [GLOBAL_MESSAGE_KEY].
119 */
120 private String globalMessageKey = GLOBAL_MESSAGE_KEY;
121
122 /**
123 * @return The default global message key
124 */
125 public String getGlobalMessageKey() {
126 return this.globalMessageKey;
127 }
128
129 /**
130 * @param globalMessageKey The new default global message key
131 */
132 public void setGlobalMessageKey(String globalMessageKey) {
133 this.globalMessageKey = globalMessageKey;
134 }
135
136 /**
137 * Add a message to the set of messages for the specified property. An
138 * order of the property/key is maintained based on the initial addition
139 * of the property/key.
140 *
141 * @param property Property name (or MessageList.GLOBAL_MESSAGE_KEY)
142 * @param message The message to be added
143 */
144 public void add(String property, Message message) {
145
146 MessageItem item = (MessageItem) messages.get(property);
147 List list = null;
148
149 if (item == null) {
150 list = new ArrayList();
151 item = new MessageItem(list, this.count++);
152
153 messages.put(property, item);
154 } else {
155 list = item.getList();
156 }
157
158 list.add(message);
159
160 }
161
162 /**
163 * Add a message to the set of messages for the "global" property. An
164 * order of the property/key is maintained based on the initial addition
165 * of the property/key.
166 *
167 * @param message The message to be added
168 */
169 public void add(Message message) {
170 this.add(getGlobalMessageKey(), message);
171 }
172
173 /**
174 * Adds the messages from the given <code>MessageList</code> object to
175 * this set of messages. The messages are added in the order they are returned from
176 * the properties() method. If a message's property is already in the current
177 * <code>MessageList</code> object it is added to the end of the list for that
178 * property. If a message's property is not in the current list it is added to the end
179 * of the properties.
180 *
181 * @param messageList The <code>MessageList</code> object to be added.
182 */
183 public void add(MessageList messageList) {
184 // loop over properties
185 Iterator props = messageList.properties();
186 while (props.hasNext()) {
187 String property = (String) props.next();
188
189 // loop over messages for each property
190 Iterator msgs = messageList.get(property);
191 while (msgs.hasNext()) {
192 Message msg = (Message) msgs.next();
193 this.add(property, msg);
194 }
195
196 }
197 }
198
199 /**
200 * Clear all messages recorded by this object.
201 */
202 public void clear() {
203 this.messages.clear();
204 }
205
206 /**
207 * Determines if the MessageList's messages have been accessed one or more
208 * times. Returns <code>true</code> if the <code>get()</code> or
209 * <code>get(String)</code> methods are called.
210 * @return <code>true</code> if the messages have been accessed one or more
211 * times.
212 */
213 public boolean isAccessed() {
214 return this.accessed;
215 }
216
217 /**
218 * @return Return <code>true</code> if there are no messages recorded
219 * in this collection, or <code>false</code> otherwise.
220 */
221 public boolean isEmpty() {
222 return messages.isEmpty();
223 }
224
225 /**
226 * Return the set of all recorded messages, without distinction
227 * by which property the messages are associated with. If there are
228 * no messages recorded, an empty enumeration is returned.
229 *
230 * @return All messages.
231 */
232 public Iterator get() {
233 this.accessed = true;
234
235 if (messages.isEmpty()) {
236 return Collections.EMPTY_LIST.iterator();
237 }
238
239 ArrayList results = new ArrayList();
240 ArrayList actionItems = new ArrayList();
241
242 for (Iterator i = messages.values().iterator(); i.hasNext();) {
243 actionItems.add(i.next());
244 }
245
246 // Sort MessageItems based on the initial order the
247 // property/key was added to MessageList.
248 Collections.sort(actionItems, ACTION_ITEM_COMPARATOR);
249
250 for (Iterator i = actionItems.iterator(); i.hasNext();) {
251 MessageItem ami = (MessageItem) i.next();
252
253 for (Iterator msgs = ami.getList().iterator(); msgs.hasNext();) {
254 results.add(msgs.next());
255 }
256 }
257
258 return results.iterator();
259 }
260
261 /**
262 * Return the set of messages related to a specific property.
263 * If there are no such messages, an empty enumeration is returned.
264 *
265 * @param property Property name
266 * @return Messages related to a specific property.
267 */
268 public Iterator get(String property) {
269 this.accessed = true;
270
271 MessageItem item = (MessageItem) messages.get(property);
272
273 return (item == null)
274 ? Collections.EMPTY_LIST.iterator()
275 : item.getList().iterator();
276 }
277
278 /**
279 * Return the set of property names for which at least one message has
280 * been recorded. If there are no messages, an empty Iterator is returned.
281 * If you have recorded global messages, the String value of
282 * <code>MessageList.GLOBAL_MESSAGE</code> will be one of the returned
283 * property names.
284 *
285 * @return The property names.
286 */
287 public Iterator properties() {
288 return messages.keySet().iterator();
289 }
290
291 /**
292 * Return the number of messages recorded for all properties (including
293 * global messages). <strong>NOTE</strong> - it is more efficient to call
294 * <code>isEmpty()</code> if all you care about is whether or not there are
295 * any messages at all.
296 *
297 * @return The number of messages.
298 */
299 public int size() {
300
301 int total = 0;
302
303 for (Iterator i = messages.values().iterator(); i.hasNext();) {
304 MessageItem ami = (MessageItem) i.next();
305 total += ami.getList().size();
306 }
307
308 return total;
309 }
310
311 /**
312 * Return the number of messages associated with the specified property.
313 *
314 * @param property Property name (or MessageList.GLOBAL_MESSAGE_KEY
315 * @return The number of messages for a specific property.
316 */
317 public int size(String property) {
318
319 MessageItem ami = (MessageItem) messages.get(property);
320
321 return (ami == null) ? 0 : ami.getList().size();
322 }
323
324 /**
325 * Returns a String representation of this MessageList's
326 * [property name]=[message list] mapping.
327 * @see java.lang.Object#toString()
328 */
329 public String toString() {
330 return this.messages.toString();
331 }
332
333 /**
334 * Holds messages for a specified property.
335 */
336 protected static class MessageItem implements Serializable {
337
338 /**
339 * The list of <code>Message</code>s.
340 */
341 private List list = null;
342
343 /**
344 * The position in the list of messages.
345 */
346 private int order = 0;
347
348 /**
349 * Construct a MessageItem with a list of messages
350 * and specified order.
351 * @param list List of Messages.
352 * @param order Order.
353 */
354 public MessageItem(List list, int order) {
355 this.list = list;
356 this.order = order;
357 }
358
359 /**
360 * @return The list of messsages.
361 */
362 public List getList() {
363 return list;
364 }
365
366 /**
367 * @param list The list of messsages.
368 */
369 public void setList(List list) {
370 this.list = list;
371 }
372
373 /**
374 * @return The order.
375 */
376 public int getOrder() {
377 return order;
378 }
379
380 /**
381 * @param order The order.
382 */
383 public void setOrder(int order) {
384 this.order = order;
385 }
386
387 }
388
389 }