001: /***
002: * jwma Java WebMail
003: * Copyright (c) 2000-2003 jwma team
004: *
005: * jwma is free software; you can distribute and use this source
006: * under the terms of the BSD-style license received along with
007: * the distribution.
008: ***/package dtw.webmail.plugin.std;
009:
010: import dtw.webmail.JwmaKernel;
011: import dtw.webmail.model.*;
012: import dtw.webmail.util.*;
013: import org.apache.log4j.Logger;
014: import org.exolab.castor.jdo.Database;
015: import org.exolab.castor.jdo.PersistenceException;
016: import org.exolab.castor.jdo.TimeStampable;
017:
018: import java.util.*;
019:
020: /**
021: * Class implementing a specialized <tt>JwmaContactsImpl</tt>
022: * for being persisted with the Castor Plugins.
023: *
024: * @author Dieter Wimberger
025: * @version 0.9.7 07/02/2003
026: */
027: public class CastorContacts extends AbstractIdentifiable implements
028: JwmaContactsImpl, Associator, TimeStampable {
029:
030: private static Logger log = Logger.getLogger(CastorContacts.class);
031:
032: private List m_Contacts;
033: private List m_Groups;
034: private Map m_Frequent;
035: private Set m_Categories;
036: private ContactFilter m_ContactFilter;
037: private CategoryFilter m_CategoryFilter;
038:
039: private List m_RemovedAssociations;
040: private boolean m_Update;
041: private long m_Timestamp = TimeStampable.NO_TIMESTAMP;
042:
043: public CastorContacts() {
044: log.debug("CastorContacts()");
045: m_RemovedAssociations = Collections
046: .synchronizedList(new ArrayList(5));
047:
048: m_Contacts = new ContactsCollection();
049: m_Groups = new GroupsCollection();
050: m_Frequent = Collections.synchronizedMap(new HashMap());
051: m_Categories = Collections.synchronizedSet(new HashSet());
052: m_CategoryFilter = new CategoryFilter("");
053: m_ContactFilter = new DummyFilter();
054: }//constructor
055:
056: /** Methods for Castor to set/get collections **/
057: public Collection getContactsCollection() {
058: //log.debug("Getting contacts collection.");
059: return m_Contacts;
060: }//getContactsCollection
061:
062: public void setContactsCollection(Collection collection) {
063: //log.debug("Setting contacts collection!");
064: //update map and caches
065: for (Iterator iter = collection.iterator(); iter.hasNext();) {
066: CastorContact ct = (CastorContact) iter.next();
067: addContact(ct);
068: if (ct.isFrequentRecipient()) {
069: addFrequentRecipient(ct);
070: }
071: addContactCategory(ct.getCategory());
072: }
073: }//setContactsCollection
074:
075: public Collection getGroupsCollection() {
076: //log.debug("Getting groups collection.");
077: return m_Groups;
078: }//getGroupsCollection
079:
080: public void setGroupsCollection(Collection collection) {
081: //log.debug("Setting groups collection!");
082: for (Iterator iter = collection.iterator(); iter.hasNext();) {
083: addContactGroup((CastorContactGroup) iter.next());
084: }
085: }//setGroupsCollection
086:
087: public String[] listContactCategories() {
088: String[] cats = new String[m_Categories.size()];
089: return (String[]) m_Categories.toArray(cats);
090: }//listContactCategories
091:
092: public void addContactCategory(String category) {
093: if (category != null && category.length() > 0) {
094: m_Categories.add(category);
095: }
096: }//addContactCategory
097:
098: public boolean existsContactCategory(String category) {
099: if (category != null && category.length() > 0) {
100: return m_Categories.contains(category);
101: }
102: return false;
103: }//existsContactCategory
104:
105: public boolean containsContact(String uid) {
106: //search list
107: for (Iterator iter = m_Contacts.iterator(); iter.hasNext();) {
108: //equals allows to pass uid
109: JwmaContact ct = (JwmaContact) iter.next();
110: if (ct.equals(uid)) {
111: return true;
112: }
113: }
114: return false;
115: }//containsContact
116:
117: public JwmaContact getContact(String uid) {
118: //search list
119: for (Iterator iter = m_Contacts.iterator(); iter.hasNext();) {
120: //equals allows to pass uid
121: JwmaContact ct = (JwmaContact) iter.next();
122: if (ct.equals(uid)) {
123: return ct;
124: }
125: }
126: return null;
127: }//getContact
128:
129: public JwmaContact getContactByNickname(String nick) {
130: //search list
131: for (Iterator iter = m_Contacts.iterator(); iter.hasNext();) {
132: JwmaContact ct = (JwmaContact) iter.next();
133: String[] nicknames = StringUtil
134: .split(ct.getNickname(), ",");
135: for (int i = 0; i < nicknames.length; i++) {
136: if (nick.equals(nicknames[i])) {
137: return ct;
138: }
139: }
140: }
141: return null;
142: }//getContactByNickname
143:
144: public boolean containsContactWithNickname(String nick) {
145: //search list
146: for (Iterator iter = m_Contacts.iterator(); iter.hasNext();) {
147: JwmaContact ct = (JwmaContact) iter.next();
148: String[] nicknames = StringUtil
149: .split(ct.getNickname(), ",");
150: for (int i = 0; i < nicknames.length; i++) {
151: if (nick.equals(nicknames[i])) {
152: return true;
153: }
154: }
155: }
156: return false;
157: }//containsContactWithNickname
158:
159: public JwmaContactImpl createContact() {
160: return new CastorContact();
161: }//createContact
162:
163: public JwmaContact[] listContacts() {
164: List contacts = new ArrayList(m_Contacts.size());
165: for (Iterator iter = m_Contacts.iterator(); iter.hasNext();) {
166: JwmaContact ct = (JwmaContact) iter.next();
167: if (m_CategoryFilter.isAllowed(ct)
168: && m_ContactFilter.isAllowed(ct)) {
169: contacts.add(ct);
170: }
171: }
172:
173: JwmaContact[] cts = new JwmaContact[contacts.size()];
174: return (JwmaContact[]) contacts.toArray(cts);
175: }//listContacts
176:
177: public void addContact(JwmaContactImpl contact) {
178: //add to wrapped list
179: m_Contacts.add(contact);
180:
181: //associate
182: ((CastorContact) contact).setAssociatorUID(this .getUID());
183: }//addContact
184:
185: public void removeContact(JwmaContactImpl contact) {
186: //remove
187: m_Contacts.remove(contact);
188: //remove group memberships
189: for (Iterator iter = m_Groups.iterator(); iter.hasNext();) {
190: JwmaContactGroupImpl group = (JwmaContactGroupImpl) iter
191: .next();
192: if (group.containsContact(contact.getUID())) {
193: group.removeContact(contact);
194: }
195: }
196: //remove from caches
197: removeFrequentRecipient(contact);
198: //remove from associated
199: ((CastorContact) contact).resetAssociatorUID();
200: m_RemovedAssociations.add(contact);
201: }//removeContact
202:
203: public JwmaContact[] listFrequentRecipients() {
204: JwmaContact[] cts = new JwmaContact[m_Frequent.size()];
205: return (JwmaContact[]) m_Frequent.values().toArray(cts);
206: }//listFrequentRecipients
207:
208: public void addFrequentRecipient(JwmaContactImpl contact) {
209: //if (contact.isFrequentRecipient()) {
210: m_Frequent.put(contact.getUID(), contact);
211: contact.setFrequentRecipient(true);
212: //}
213: }//addFrequentRecipient
214:
215: public void removeFrequentRecipient(JwmaContactImpl contact) {
216: if (m_Frequent.remove(contact.getUID()) != null) {
217: contact.setFrequentRecipient(false);
218: }
219: }//removeFrequentRecipient
220:
221: public boolean containsContactGroup(String uid) {
222: //search list
223: for (Iterator iter = m_Groups.iterator(); iter.hasNext();) {
224: //equals allows to pass uid
225: JwmaContactGroup ctg = (JwmaContactGroup) iter.next();
226: if (ctg.equals(uid)) {
227: return true;
228: }
229: }
230: return false;
231: }//containsContactGroup
232:
233: public boolean containsContactGroupName(String name) {
234: //search list
235: for (Iterator iter = m_Groups.iterator(); iter.hasNext();) {
236: //equals allows to pass uid
237: JwmaContactGroup ctg = (JwmaContactGroup) iter.next();
238: if (ctg.getName().equals(name)) {
239: return true;
240: }
241: }
242: return false;
243: }//containsContactGroup
244:
245: public JwmaContactGroup getContactGroup(String cuid) {
246: //search list
247: for (Iterator iter = m_Groups.iterator(); iter.hasNext();) {
248: //equals allows to pass uid
249: JwmaContactGroup ctg = (JwmaContactGroup) iter.next();
250: if (ctg.equals(cuid)) {
251: return ctg;
252: }
253: }
254: return null;
255: }//getContactGroup
256:
257: public JwmaContactGroup getContactGroupByName(String name) {
258: //search list
259: for (Iterator iter = m_Groups.iterator(); iter.hasNext();) {
260: //equals allows to pass uid
261: JwmaContactGroup ctg = (JwmaContactGroup) iter.next();
262: if (ctg.getName().equals(name)) {
263: return ctg;
264: }
265: }
266: //should not happen
267: return null;
268: }//getContactGroup
269:
270: public JwmaContactGroup[] listContactGroups() {
271: JwmaContactGroup[] ctg = new JwmaContactGroup[m_Groups.size()];
272: return (JwmaContactGroup[]) m_Groups.toArray(ctg);
273: }//listContactGroups
274:
275: public void addContactGroup(JwmaContactGroupImpl group) {
276: log.debug("Adding group:" + group.getName());
277: m_Groups.add(group);
278: //associate
279: ((CastorContactGroup) group).setAssociatorUID(this .getUID());
280: log.debug("Added group:" + group.getName());
281: }//addContactGroup
282:
283: public void removeContactGroup(JwmaContactGroupImpl group) {
284: m_Groups.remove(group.getUID());
285: ((CastorContactGroup) group).resetAssociatorUID();
286: m_RemovedAssociations.add(group);
287: }//removeContactGroup
288:
289: public JwmaContactGroupImpl createContactGroup(String name)
290: throws JwmaException {
291:
292: return new CastorContactGroup(this , name);
293: }//createContactGroup
294:
295: public void setContactFilter(ContactFilter filter) {
296: if (filter != null) {
297: m_ContactFilter = filter;
298: } else {
299: m_ContactFilter = new DummyFilter();
300: }
301: }//setContactFilter
302:
303: public ContactFilter getContactFilter() {
304: return m_ContactFilter;
305: }//ContactFilter
306:
307: public void setCategoryFilter(String category) {
308: m_CategoryFilter.setCategory(category);
309: }//setCategoryFilter
310:
311: public String getCategoryFilter() {
312: return m_CategoryFilter.getCategory();
313: }//getCategoryFilter
314:
315: public Iterator getLastnameStarts() {
316: ArrayList chars = new ArrayList(m_Contacts.size());
317: boolean contained = false;
318:
319: for (Iterator iter = m_Contacts.iterator(); iter.hasNext();) {
320: String firstchar = ((JwmaContact) iter.next())
321: .getLastname().substring(0, 1).toUpperCase();
322: //log.debug("firstchar="+firstchar);
323: contained = false;
324: for (Iterator iterc = chars.iterator(); iterc.hasNext();) {
325: if (((String) iterc.next()).equals(firstchar)) {
326: contained = true;
327: break;
328: }
329: }
330: if (!contained) {
331: chars.add(firstchar);
332: //log.debug("Added firstchar="+firstchar);
333: }
334: }
335: return chars.listIterator();
336: }//listLastnameStarts
337:
338: public List getRemovedAssociations() {
339: return m_RemovedAssociations;
340: }//getRemovedAssociations
341:
342: public void updateContacts(Database db) throws PersistenceException {
343: m_Update = true;
344: try {
345: persistContacts(db);
346: } finally {
347: m_Update = false;
348: }
349: }//updateDatabase
350:
351: public void persistContacts(Database db)
352: throws PersistenceException {
353:
354: //1. store this
355: storeObject(db, this );
356:
357: //2. iterate over contacts, ensure order by indexing
358: int i = 0;
359: for (Iterator iter = m_Contacts.iterator(); iter.hasNext(); i++) {
360: Object next = iter.next();
361: storeObject(db, next);
362: }
363:
364: //3. iterate over groups, ensure order by indexing
365: i = 0;
366: for (Iterator iter = m_Groups.iterator(); iter.hasNext(); i++) {
367: Object next = iter.next();
368: storeObject(db, next);
369: }
370: }//persistPreferences
371:
372: private void storeObject(Database db, Object o)
373: throws PersistenceException {
374: if (db == null || o == null) {
375: return;
376: } else if (db.isPersistent(o) || m_Update) {
377: log.debug(JwmaKernel.getReference().getLogMessage(
378: "jwma.plugin.castor.objupdate")
379: + o.toString());
380: if (o instanceof Associator) {
381: cleanupAssociations(db, ((Associator) o)
382: .getRemovedAssociations());
383: }
384: db.update(o);
385: } else {
386: log.debug(JwmaKernel.getReference().getLogMessage(
387: "jwma.plugin.castor.objcreate")
388: + o.toString());
389: db.create(o);
390: }
391: }//storeObject
392:
393: private void cleanupAssociations(Database db, List l)
394: throws PersistenceException {
395:
396: Object o = null;
397: for (Iterator iter = l.iterator(); iter.hasNext();) {
398: AssociatedAbstractIdentifiable assoc = (AssociatedAbstractIdentifiable) iter
399: .next();
400: //check if object has an association
401: if (!assoc.isAssociated()) {
402: log.debug(JwmaKernel.getReference().getLogMessage(
403: "jwma.plugin.castor.objremove")
404: + assoc.getClass() + " " + assoc.toString());
405: //needs to be loaded in this transaction :( hack but works
406: try {
407: o = db.load(assoc.getClass(), assoc.getUID());
408: } catch (PersistenceException pex) {
409: /*more hack, required to work*/
410: }
411: db.remove(o);
412: }
413: }
414: //and definately, remove the references
415: l.clear();
416: }//cleanupAssociations
417:
418: public long jdoGetTimeStamp() {
419: return m_Timestamp;
420: }//jdoGetTimeStamp
421:
422: public void jdoSetTimeStamp(long timeStamp) {
423: m_Timestamp = timeStamp;
424: }//jdoSetTimeStamp
425:
426: private class DummyFilter implements ContactFilter {
427:
428: public boolean isAllowed(JwmaContact contact) {
429: return true;
430: }//isAllowed
431:
432: public boolean isFiltered(JwmaContact contact) {
433: return false;
434: }//isFiltered
435:
436: public String toString() {
437: return "";
438: }//toString
439:
440: }//inner class DummyFilter
441:
442: /**
443: * Workaround CastorXML collection handling:
444: * Does not really use "setCollection", rather it uses
445: * getCollection() and adds to the collection.
446: *
447: */
448: private class ContactsCollection extends ArrayList {
449:
450: public ContactsCollection() {
451: super ();
452: }//constructor
453:
454: public boolean add(Object o) {
455: CastorContact ct = (CastorContact) o;
456: //update caches
457: if (ct.isFrequentRecipient()) {
458: addFrequentRecipient(ct);
459: }
460: addContactCategory(ct.getCategory());
461: //add to list
462: return super .add(o);
463: }//add
464:
465: }//inner class ContactsCollection
466:
467: /**
468: * Workaround CastorXML collection handling:
469: * Does not really use "setCollection", rather it uses
470: * getCollection() and adds to the collection.
471: */
472: private class GroupsCollection extends ArrayList {
473:
474: public GroupsCollection() {
475: super ();
476: }//constructor
477:
478: public boolean add(Object o) {
479: CastorContactGroup ctg = (CastorContactGroup) o;
480: ctg.setContactsDB(CastorContacts.this );
481: //add to list
482: return super .add(o);
483: }//add
484:
485: }//inner class ContactsCollection
486:
487: }//class CastorContacts
|