001: package net.suberic.util;
002:
003: import javax.mail.*;
004: import java.util.*;
005:
006: /**
007: * This class manages a list of Items.
008: */
009:
010: public class ItemManager implements ValueChangeListener {
011:
012: // an ordered list of item id's
013: private List itemIdList;
014:
015: // the mapping from the item id's to the items themselves
016: private HashMap itemIdMap = new HashMap();
017:
018: // for convenience, the itemList itself.
019: private List itemList;
020:
021: //the ItemListChange listeners
022: private List listenerList = new LinkedList();
023:
024: // the resource which defines this ItemList
025: private String resourceString;
026:
027: // the current value.
028: private String currentValue;
029:
030: // the VariableBundle which contains the Item information.
031: private VariableBundle sourceBundle;
032:
033: // the ItemCreator which is used to create new items.
034: private ItemCreator itemCreator;
035:
036: /**
037: * Create an ItemManager which loads information from the given
038: * VariableBundle using the given newResourceString, and creates new
039: * Items using the given ItemCreator.
040: */
041: public ItemManager(String newResourceString,
042: VariableBundle newSourceBundle, ItemCreator newItemCreator) {
043: resourceString = newResourceString;
044: sourceBundle = newSourceBundle;
045: itemCreator = newItemCreator;
046:
047: createItemList();
048: sourceBundle.addValueChangeListener(this , resourceString);
049: }
050:
051: //-----------------------
052: // public interface.
053:
054: /**
055: * This returns a Vector with all the currently registered Item
056: * objects.
057: */
058: public synchronized java.util.Vector getItems() {
059: return new Vector(itemList);
060: }
061:
062: /**
063: * This returns the Item with the given itemName if it exists; otherwise,
064: * returns null.
065: */
066: public synchronized Item getItem(String itemID) {
067: if (itemID != null && itemIdList.contains(itemID))
068: return (Item) itemIdMap.get(itemID);
069: else
070: return null;
071: }
072:
073: /**
074: * This adds the item with the given name to the item list.
075: */
076: public synchronized void addItem(String itemName) {
077: addItem(new String[] { itemName });
078: }
079:
080: /**
081: * This adds the items with the given itemNames to the items list.
082: */
083: public synchronized void addItem(String[] itemName) {
084: if (itemName != null && itemName.length > 0) {
085: StringBuffer itemString = new StringBuffer();
086: for (int i = 0; i < itemName.length; i++) {
087: if (!itemIdList.contains(itemName[i]))
088: itemString.append(itemName[i] + ":");
089: }
090: if (itemString.length() > 0)
091: appendToItemString(new String(itemString
092: .deleteCharAt(itemString.length() - 1)));
093: }
094: }
095:
096: /**
097: * This adds the given item to the items list.
098: */
099: public synchronized void addItem(Item newItem) {
100: addItem(new Item[] { newItem });
101: }
102:
103: /**
104: * This adds the given items to the items list.
105: */
106: public synchronized void addItem(Item[] newItem) {
107: if (newItem != null) {
108: String[] itemNames = new String[newItem.length];
109: for (int i = 0; i < itemNames.length; i++) {
110: itemNames[i] = newItem[i].getItemID();
111: // we'll go ahead and add this here. this will make it so, later
112: // on, when we add the item to the main list, we get this Item,
113: // rather than creating a new one.
114: if (getItem(itemNames[i]) == null)
115: itemIdMap.put(itemNames[i], newItem[i]);
116: }
117:
118: addItem(itemNames);
119: }
120: }
121:
122: /**
123: * This removes the item with the given itemName.
124: */
125: public synchronized void removeItem(String itemName) {
126: removeFromItemString(new String[] { itemName });
127: }
128:
129: /**
130: * This removes the items with the given itemNames.
131: */
132: public synchronized void removeItem(String[] itemNames) {
133: // this is probably not necessary at all, but what the hell?
134:
135: if (itemNames == null || itemNames.length < 1)
136: return;
137:
138: Vector matches = new Vector();
139: for (int i = 0; i < itemNames.length; i++) {
140: if (itemIdList.contains(itemNames[i]))
141: matches.add(itemNames[i]);
142:
143: }
144:
145: if (matches.size() < 1)
146: return;
147:
148: String[] removedItems = new String[matches.size()];
149:
150: matches.toArray(removedItems);
151:
152: removeFromItemString(removedItems);
153: }
154:
155: /**
156: * This removes the given Item.
157: */
158: public synchronized void removeItem(Item item) {
159: if (item != null)
160: removeItem(item.getItemID());
161: }
162:
163: /**
164: * This removes the given Items.
165: */
166: public synchronized void removeItem(Item[] item) {
167: if (item != null && item.length > 0) {
168: String[] itemNames = new String[item.length];
169: for (int i = 0; i < item.length; i++) {
170: if (item[i] != null)
171: itemNames[i] = item[i].getItemID();
172: }
173:
174: removeItem(itemNames);
175: }
176: }
177:
178: /**
179: * This compares the itemList object with the resourceString property, and
180: * updates the itemList appropriately.
181: *
182: * This method is called from valueChanged() when the underlying resource
183: * changes. It actually goes through and updates the objects on the
184: * ItemManager, and then notifies its ItemListChangedListeners by calling
185: * fireItemListChangeEvent().
186: */
187: public synchronized void refreshItems() {
188: if (!sourceBundle.getProperty(resourceString).equals(
189: currentValue)) {
190: currentValue = sourceBundle.getProperty(resourceString);
191:
192: LinkedList newIdList = new LinkedList();
193: LinkedList newItemList = new LinkedList();
194:
195: Vector addedItemList = new Vector();
196: Vector removedIdList = new Vector(itemIdList);
197:
198: StringTokenizer tokens = new StringTokenizer(sourceBundle
199: .getProperty(resourceString, ""), ":");
200:
201: String itemID;
202:
203: // at the end of this loop, we should end up with a newIdList which is a
204: // list of the currently valid item id's, a newItemList which is a list
205: // of the currently valid items, an addedItemList which is a list of added
206: // items, and a removedIdList which is a list of removed id's.
207: while (tokens.hasMoreTokens()) {
208: itemID = tokens.nextToken();
209: newIdList.add(itemID);
210:
211: if (itemIdList.contains(itemID)) {
212: removedIdList.remove(itemID);
213: } else {
214: // this is being added.
215: Item currentItem = (Item) itemIdMap.get(itemID);
216: if (currentItem == null) {
217: itemIdMap.put(itemID, itemCreator.createItem(
218: sourceBundle, resourceString, itemID));
219: }
220: addedItemList.add(itemIdMap.get(itemID));
221: }
222: newItemList.add(itemIdMap.get(itemID));
223: }
224:
225: Item[] removedItems = new Item[removedIdList.size()];
226: for (int i = 0; i < removedIdList.size(); i++) {
227: Item currentItem = (Item) itemIdMap.get(removedIdList
228: .get(i));
229: if (currentItem != null) {
230: itemIdMap.remove(removedIdList.get(i));
231: removedItems[i] = currentItem;
232: }
233: }
234:
235: Item[] addedItems = new Item[addedItemList.size()];
236: addedItemList.toArray(addedItems);
237:
238: itemList = newItemList;
239: itemIdList = newIdList;
240:
241: fireItemListChangeEvent(new ItemListChangeEvent(this ,
242: addedItems, removedItems));
243: }
244: }
245:
246: /**
247: * As defined in net.suberic.util.ValueChangeListener.
248: *
249: * This listens for changes to the source property and calls
250: * refreshItems() when it gets one.
251: */
252: public void valueChanged(String changedValue) {
253: if (changedValue.equals(resourceString))
254: refreshItems();
255: }
256:
257: /**
258: * This adds a ItemListChangeListener to the local listener list.
259: */
260: public void addItemListChangeListener(ItemListChangeListener ilcl) {
261: if (!listenerList.contains(ilcl))
262: listenerList.add(ilcl);
263: }
264:
265: /**
266: * This removes a ItemListChangeListener from the local listener list.
267: */
268: public void removeItemListChangeListener(ItemListChangeListener ilcl) {
269: listenerList.remove(ilcl);
270: }
271:
272: /**
273: * This notifies all listeners that the ItemList has changed.
274: */
275: public void fireItemListChangeEvent(ItemListChangeEvent e) {
276: for (int i = 0; i < listenerList.size(); i++)
277: ((ItemListChangeListener) listenerList.get(i))
278: .itemListChanged(e);
279: }
280:
281: //---------------------------
282: // the background stuff.
283:
284: /**
285: * This loads and creates all the Items using the resourceString property
286: * of the sourceBundle.
287: */
288: private void createItemList() {
289: itemList = new LinkedList();
290: itemIdList = new LinkedList();
291: String itemID = null;
292:
293: currentValue = sourceBundle.getProperty(resourceString, "");
294: StringTokenizer tokens = new StringTokenizer(currentValue, ":");
295:
296: while (tokens.hasMoreTokens()) {
297: itemID = (String) tokens.nextToken();
298: Item newItem = itemCreator.createItem(sourceBundle,
299: resourceString, itemID);
300: itemList.add(newItem);
301: itemIdList.add(itemID);
302: itemIdMap.put(itemID, newItem);
303: }
304:
305: }
306:
307: /**
308: * This appends the newItemString to the "Item" property.
309: */
310: private void appendToItemString(String newItemString) {
311: String oldValue = sourceBundle.getProperty("Item");
312: String newValue;
313: if (oldValue.length() > 0
314: && oldValue.charAt(oldValue.length() - 1) != ':') {
315: newValue = oldValue + ":" + newItemString;
316: } else {
317: newValue = oldValue + newItemString;
318: }
319:
320: sourceBundle.setProperty(resourceString, newValue);
321: }
322:
323: /**
324: * This removes the item names in the itemNames array from the
325: * "Item" property.
326: */
327: private void removeFromItemString(String[] itemNames) {
328: StringTokenizer tokens = new StringTokenizer(sourceBundle
329: .getProperty(resourceString, ""), ":");
330:
331: boolean first = true;
332: StringBuffer newValue = new StringBuffer();
333: String itemID;
334:
335: while (tokens.hasMoreTokens()) {
336: itemID = tokens.nextToken();
337: boolean keep = true;
338:
339: for (int i = 0; keep == true && i < itemNames.length; i++) {
340: if (itemID.equals(itemNames[i]))
341: keep = false;
342: }
343: if (keep) {
344: if (!first)
345: newValue.append(":");
346:
347: newValue.append(itemID);
348: first = false;
349: }
350:
351: }
352:
353: sourceBundle.setProperty(resourceString, newValue.toString());
354: }
355:
356: }
|