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 }