001: /**
002: * $Id: CalendarBaseModel.java,v 1.5 2005/09/21 11:02:49 dg154973 Exp $
003: * Copyright 2002 Sun Microsystems, Inc. All
004: * rights reserved. Use of this product is subject
005: * to license terms. Federal Acquisitions:
006: * Commercial Software -- Government Users
007: * Subject to Standard License Terms and
008: * Conditions.
009: *
010: * Sun, Sun Microsystems, the Sun logo, and Sun ONE
011: * are trademarks or registered trademarks of Sun Microsystems,
012: * Inc. in the United States and other countries.
013: *
014: */package com.sun.portal.app.sharedevents.models;
015:
016: import java.util.*;
017: import java.util.logging.*;
018:
019: import com.sun.portal.app.sharedevents.util.CalUserHelper;
020: import com.sun.portal.app.sharedevents.util.SharedConstants;
021:
022: import com.sun.comclient.calendar.*;
023: import com.sun.comclient.calendar.socs.SOCSCalendar;
024: import com.sun.portal.log.common.PortalLogger;
025:
026: /**
027: * CalendarBaseModel class provides an interface to get<b>/</b>set
028: * the user's calendar data from calendar server.
029: * It provides many convenient methods to access/modify user's calendar
030: * data with appropriate data types as input/output.
031: * This should be the only interface to WCAP of Calendar Server.
032: * A Single instance of this object per request needs to be used.
033: *
034: * @author Sai
035: *
036: */
037:
038: public final class CalendarBaseModel {
039:
040: private ArrayList typeEvents = null;
041: private ArrayList typeTodos = null;
042: private ArrayList calids = null;
043: private String componentSearchFilter = null;
044: private int componentSearchOption = -1;
045: private String componentUid = null;
046: private String componentRid = null;
047: private String _userId = null;
048: private String eventsFilter = null;
049: private ArrayList allEvents = null;
050: private ArrayList allTodos = null;
051: private HashMap calendars = null;
052: private DateTime start = null;
053: private DateTime end = null;
054: private DateTime contextDate = null;
055: private DateTime currentDate = null;
056: private TimeZone timezone = null;
057:
058: private String CLASS_NAME = "CalendarBaseModel";
059:
060: private static Logger logger = PortalLogger
061: .getLogger(CalendarBaseModel.class);
062:
063: public CalendarBaseModel() {
064: super ();
065: }
066:
067: public CalendarBaseModel(String name) {
068:
069: }
070:
071: /* Gets the Start date.
072: * Used while fetching Events/ Todos/ FreeBusy
073: */
074:
075: public DateTime getStartTime() {
076: return start;
077: }
078:
079: /* Sets the Start date.
080: * Used while fetching Events/ Todos/ FreeBusy
081: * @param curDate DateTime Object
082: */
083:
084: public void setStartTime(DateTime starttime) {
085: start = starttime;
086: }
087:
088: /* gets the End date.
089: * Used while fetching Events/ Todos/ FreeBusy
090: */
091:
092: public DateTime getEndTime() {
093: return end;
094: }
095:
096: /* Sets the End date.
097: * Used while fetching Events/ Todos/ FreeBusy
098: * @param curDate DateTime Object
099: */
100:
101: public void setEndTime(DateTime endtime) {
102: end = endtime;
103: }
104:
105: /* Sets the ComponentUid.
106: * Used when the request context is Fetch_Component_by_Uid.
107: * @param uid String.
108: */
109:
110: public void setComponentUID(String uid) {
111: componentUid = uid;
112: }
113:
114: /* Sets the ComponentRid.
115: * Used when the request context is Fetch_Component_by_Uid.
116: * @param rid String.
117: */
118:
119: public void setComponentRID(String rid) {
120: componentRid = rid;
121: }
122:
123: /* Sets the componentSearchFilter String.
124: * Used when the request context is Search_Events or Search_Todos.
125: * @param filter String.
126: */
127:
128: public void setComponentSearchFilter(String filter) {
129: componentSearchFilter = filter;
130: }
131:
132: /* Sets the componentSearch options int
133: * Used when the request context is Search_Events or Search_Todos.
134: * @param filter String.
135: */
136:
137: public void setComponentSearchOption(int searchOpt) {
138: componentSearchOption = searchOpt;
139: }
140:
141: /* gets the List of VEvent Objects.
142: * These objects may be result of previous execute/retrive contexts
143: * @return allEvents ArrayList of VEvent objects
144: */
145:
146: public ArrayList getAllEvents() {
147: return allEvents;
148: }
149:
150: /* gets the List of VTodos Objects.
151: * These objects may be result of previous execute/retrive contexts
152: * @return allTodos ArrayList of VTodos objects
153: */
154:
155: public ArrayList getAllTodos() {
156: return allTodos;
157: }
158:
159: /**
160: * Returns the timezone that has been used while fetching
161: * events and todos in the recent fetch context.
162: * <p>
163: *
164: */
165: public TimeZone getTimeZone() {
166: return timezone;
167: }
168:
169: public void loadCalendar() throws Exception {
170:
171: if (calids == null)
172: throw new Exception("calids list is empty!");
173:
174: CalendarStore calstore = CalUserHelper.getCalStore(true);
175:
176: ICalendar cal = null;
177:
178: int length = calids.size();
179:
180: if (calendars == null)
181: calendars = new HashMap();
182:
183: for (int i = 0; i < length; i++) {
184: try {
185:
186: // get ICalendar Object
187: cal = calstore.openCalendar((String) calids.get(i));
188: // load calendar properties
189: cal.getCalProps();
190:
191: // put the calendar object into calendar bucket
192: calendars.put(calids.get(i), cal);
193: } catch (CalendarStoreException cse) {
194: logger
195: .log(
196: Level.SEVERE,
197: "loadCalendar Failed with CalendarStoreException: Unable to get ICalendar object: "
198: + cse);
199: calendars.put(calids.get(i), null);
200: } catch (OperationNotSupportedException onse) {
201: logger.log(Level.SEVERE,
202: "loadCalendar Failed with OperationNotSupportedException: "
203: + onse);
204: calendars.put(calids.get(i), null);
205: } catch (CalendarException ce) {
206: logger.log(Level.SEVERE,
207: "loadCalendar Failed with CalendarException: "
208: + ce);
209: calendars.put(calids.get(i), null);
210: }
211: }
212: }
213:
214: /* add calid to list. This is the list of calids used during execution contexts.
215: * @param newcalid String
216: */
217:
218: public void addCalid(String newcalid) {
219: if (calids == null) {
220: calids = new ArrayList();
221:
222: }
223: calids.add(newcalid);
224: }
225:
226: public void addCalid(ArrayList calIdList) {
227: if (calids == null) {
228: calids = new ArrayList();
229: }
230: calids.addAll(calIdList);
231: }
232:
233: /* remove calid from the list of calids. This list of calids is used during execution contexts.
234: * @param calid String
235: */
236:
237: public void removeCalid(String calid) {
238: if (calids == null) {
239: return;
240: }
241: int length = calids.size();
242: for (int i = 0; i < length; i++) {
243: if (calid.equals((String) calids.get(i))) {
244: calids.remove(i);
245: length--;
246: break;
247: }
248: }
249: if (length == 0) {
250: calids = null;
251: }
252: }
253:
254: public void removeAllCalids() {
255: if (calids != null) {
256: calids.clear();
257: }
258: }
259:
260: public void execute(String context) throws Exception {
261: String operationName = null;
262:
263: if (context != null) {
264: operationName = context;
265: } else {
266: operationName = SharedConstants.FETCH_EVENTS_CONTEXT;
267:
268: }
269:
270: if (operationName.equals(SharedConstants.FETCH_EVENTS_CONTEXT)) {
271:
272: /* Events Model is expected to set the start and end Date
273: * executeFetchEvents gets events from the start to end
274: */
275:
276: if (allEvents == null) {
277: allEvents = new ArrayList();
278: }
279:
280: executeFetchEvents();
281: } else if (operationName
282: .equals(SharedConstants.FETCH_EVENT_BY_ID_CONTEXT)) {
283:
284: /* Events Model is expected to set the copmponentUid
285: * executeFetchEventById gets events/todos given the uid
286: */
287:
288: if (allEvents == null) {
289: allEvents = new ArrayList();
290: }
291: executeFetchEventById(componentUid, componentRid);
292: }
293:
294: else if (operationName
295: .equals(SharedConstants.SEARCH_EVENTS_CONTEXT)) {
296:
297: if (allEvents == null) {
298: allEvents = new ArrayList();
299: }
300:
301: executeSearchEvents();
302: }
303:
304: }
305:
306: /* Interface to add a event. The calendarId of the calendar to which this
307: *event is added is the first entry from the calids list
308: *
309: * @param newevent VEvent
310: * @param notify Boolean
311: * @throws Exception
312: */
313:
314: public void addEvent(VEvent newevent, boolean notify)
315: throws Exception {
316:
317: try {
318:
319: // get the calendar store
320:
321: CalendarStore calstore = null;
322: try {
323: calstore = CalUserHelper.getCalStore(false);
324: } catch (Exception e1) {
325: logger.log(Level.SEVERE,
326: "Failed to obtain CalendarStore: "
327: + e1.getMessage());
328: throw e1;
329: }
330:
331: // check if the calids list is empty
332:
333: ICalendar cal = null;
334:
335: if (!calids.isEmpty()) {
336: cal = calstore.openCalendar((String) calids.get(0));
337: } else {
338: throw new Exception("Empty calid list");
339: }
340:
341: cal.addEvent(newevent, notify);
342:
343: }
344:
345: catch (CalendarException ce) {
346: if (40 == ce.getError()) {
347: String msg = "Add Event Failed with CalendarException(DOUBLE_BOOKED_ERROR";
348: logger.log(Level.SEVERE, msg + ": Error Number: "
349: + ce.getError());
350: throw new Exception(msg);
351: } else {
352: String msg = "Add Event Failed with CalendarException";
353: logger.log(Level.SEVERE, msg + ": Error Number: "
354: + ce.getError());
355: throw new Exception(msg);
356: }
357: } catch (CalendarStoreException cse) {
358: String msg = "Add Event Failed with CalendarStoreException: Unable to get ICalendar object";
359: logger.log(Level.SEVERE, msg + ": Error Number: "
360: + cse.getError());
361: throw new Exception(msg);
362: } catch (Exception e1) {
363: String msg = "Add Event Failed with Exception";
364: logger.log(Level.SEVERE, msg + ": " + e1);
365: //e1.printStackTrace();
366: throw new Exception(msg);
367: }
368:
369: }
370:
371: /* Interface to modify a event. The calendarId of the calendar to which this
372: *event is modify is the first entry from the calids list
373: *
374: * @param event VEvent
375: * @param modifier String
376: * @param notify Boolean
377: * @throws Exception
378: */
379:
380: public void modifyEvent(VEvent event, String modifier,
381: boolean notify) throws Exception {
382: try {
383:
384: // get the calendar store
385:
386: CalendarStore calstore = null;
387: calstore = CalUserHelper.getCalStore(false);
388:
389: // check if the calids list is empty
390:
391: ICalendar cal = null;
392:
393: if (!calids.isEmpty()) {
394: cal = calstore.openCalendar((String) calids.get(0));
395: } else {
396: throw new Exception("Empty calid list");
397: }
398: cal.modifyEvent(event, modifier, false);
399: }
400:
401: catch (CalendarException ce) {
402: if (40 == ce.getError()) {
403: String msg = "Add Event Failed with CalendarException(DOUBLE_BOOKED_ERROR";
404: logger.log(Level.SEVERE, msg + ": " + ce);
405: throw new Exception(msg);
406: } else {
407: String msg = "Add Event Failed with CalendarException";
408: logger.log(Level.SEVERE, msg + ": " + ce);
409: throw new Exception(msg);
410: }
411: } catch (CalendarStoreException cse) {
412: String msg = "Add Event Failed with CalendarStoreException: Unable to get ICalendar object";
413: logger.log(Level.SEVERE, msg + ": " + cse);
414: throw new Exception(msg);
415: } catch (Exception e1) {
416: String msg = "Add Event Failed with Exception";
417: logger.log(Level.SEVERE, msg + ": " + e1);
418: //e1.printStackTrace();
419: throw new Exception(msg);
420: }
421:
422: }
423:
424: /* Interface to delete an event. The calendarId of the calendar from which this
425: *event is deleted is the first entry from the calids list
426: *
427: * @param event VEvent
428: * @param modifier String
429: * @param notify Boolean
430: * @throws Exception
431: */
432:
433: public void deleteEvent(VEvent event, String modifier,
434: boolean notify) throws Exception {
435: try {
436:
437: // get the calendar store
438:
439: CalendarStore calstore = CalUserHelper.getCalStore(false);
440:
441: // check if the calids list is empty
442:
443: ICalendar cal = null;
444:
445: if (!calids.isEmpty()) {
446: cal = calstore.openCalendar((String) calids.get(0));
447: } else {
448: throw new Exception("Calid List is empty!");
449:
450: }
451: cal.deleteEvent(event, modifier, notify);
452: }
453:
454: catch (CalendarException ce) {
455: logger
456: .log(Level.SEVERE,
457: "Delete Event Failed with CalendarException: "
458: + ce);
459: throw new Exception("Event Deleteion Failed!");
460: } catch (CalendarStoreException cse) {
461: logger
462: .log(
463: Level.SEVERE,
464: "Delete Event Failed with CalendarStoreException: Unable to get ICalendar object: "
465: + cse);
466: throw new Exception(
467: "Event Deletion Failed. Invalid Calendar!");
468: }
469:
470: }
471:
472: public void setTimeZone(TimeZone TZ) {
473: this .timezone = TZ;
474: }
475:
476: /* Fetches the component based on component uid*/
477:
478: private void executeFetchEventById(String uid, String rid)
479: throws Exception {
480:
481: int i;
482: VEvent[] events;
483: Properties parsingProperties = new Properties();
484:
485: try {
486:
487: // get the calendar store
488: CalendarStore calstore = CalUserHelper.getCalStore(false);
489: ICalendar cal = null;
490:
491: // Empty the existing calendar data. if any
492: removeCalendarData();
493:
494: // check if the calids list is empty
495:
496: if (!calids.isEmpty()) {
497:
498: if (loadViewContextCalendar(calstore, (String) calids
499: .get(0))) {
500: cal = (ICalendar) calendars.get((String) calids
501: .get(0));
502: }
503:
504: // SOCS-specific feature
505:
506: // While fetching a recurring event, if UID and RID is passed, the server
507: // returns just that instance. But, we need to know the Recurrence Pattern
508: // for that event in order to show that in the UI for modification etc.
509: // Sun Calendar server provides a mechanism to retrieve that info along with the
510: // instance of the event.
511: // By specifying the following extra property to JCAPI, the server returns
512: // RRULE (Recurrence Pattern) as part of the event returned
513:
514: // NOTE: Thos functionality may not be available in other back-end servers
515:
516: parsingProperties.put("cal.socs.compressed", "true");
517:
518: if (cal != null) {
519: events = ((SOCSCalendar) cal).fetchEvents(uid, rid,
520: RecurrencePattern.THIS_INSTANCE,
521: parsingProperties);
522: //events= cal.fetchEvents(uid, rid, RecurrencePattern.THIS_INSTANCE);
523: allEvents.add(events[0]);
524: calstore.closeCalendar(cal);
525: }
526: } else {
527: logger.log(Level.SEVERE, "CalId is not set");
528: throw new Exception("No calid is set!");
529: }
530: } catch (CalendarStoreException cse) {
531: logger
532: .log(
533: Level.SEVERE,
534: "executeFetchEventById Failed with CalendarStoreException: Unable to get ICalendar object: "
535: + cse);
536: throw new Exception("Invalid calid");
537: } catch (CalendarException ce) {
538: logger.log(Level.SEVERE, "Calendar Exception: " + ce);
539: throw new Exception("Fetch Event Failed!");
540: } catch (OperationNotSupportedException onse) {
541: logger.log(Level.SEVERE, "OperationNotSupported Exception");
542: throw new Exception("OperationNotSupported Exception: "
543: + onse.getMessage());
544: } catch (Exception e) {
545: logger
546: .log(Level.SEVERE, "Unable to get Store object: "
547: + e);
548: throw new Exception(e.getMessage());
549: }
550: }
551:
552: private boolean loadViewContextCalendar(CalendarStore calstore,
553: String calid) {
554: if (null == calid) {
555: return false;
556: }
557: if (calendars == null)
558: calendars = new HashMap();
559:
560: boolean calendarLoaded = false;
561:
562: if (!calendarLoaded) {
563: try {
564: // get ICalendar Object
565: if (logger.isLoggable(Level.FINE)) {
566: logger.fine("Loading calendar: " + calid);
567: }
568: ICalendar cal = calstore.openCalendar(calid);
569:
570: // load calendar properties
571: cal.getCalProps();
572:
573: // put the calendar object into calendar bucket
574: calendars.put(calid, cal);
575: calendarLoaded = true;
576: calstore.closeCalendar(calid);
577: } catch (CalendarStoreException cse) {
578: logger
579: .log(
580: Level.SEVERE,
581: "loadViewContextCalendar Failed with CalendarStoreException: Unable to get ICalendar object: "
582: + cse);
583: calendars.put(calid, null);
584: calendarLoaded = false;
585: } catch (OperationNotSupportedException onse) {
586: logger.log(Level.SEVERE,
587: "loadViewContextCalendar Failed with OperationNotSupportedException: "
588: + onse);
589: calendars.put(calid, null);
590: calendarLoaded = false;
591:
592: } catch (CalendarException ce) {
593: logger.log(Level.SEVERE,
594: "loadViewContextCalendar Failed with CalendarException: "
595: + ce);
596: calendars.put(calid, null);
597: calendarLoaded = false;
598: } catch (Exception uwce) {
599: logger.log(Level.SEVERE,
600: "loadViewContextCalendar Failed with Exception: "
601: + uwce);
602: calendars.put(calid, null);
603: calendarLoaded = false;
604: }
605:
606: if (logger.isLoggable(Level.FINE)) {
607: logger.fine("Loaded Calendar: " + calid);
608: }
609: return calendarLoaded;
610: }
611: return calendarLoaded;
612:
613: }
614:
615: /* Fetches the events based on start and end date for the calids in the list*/
616: private void executeFetchEvents() throws Exception {
617:
618: try {
619: int i;
620: CalendarComponent[] calcomponents;
621: Properties parsingProperties = new Properties();
622:
623: // Empty the existing calendar data. if any
624: removeCalendarData();
625:
626: // get the calendar store
627: CalendarStore calstore = CalUserHelper.getCalStore(false);
628:
629: if (logger.isLoggable(Level.FINE)) {
630: CalendarSession calSess = calstore.getSession();
631: logger.fine("CalendarStore created for: "
632: + calSess.toString());
633: }
634:
635: // Get Events for each of the calendars in ArrayList calids */
636:
637: ICalendar cal = null;
638: // Load the calendars
639: if (!calids.isEmpty()) {
640: // calids list is not empty, fetch events/todos for each calendar in the list
641: for (i = 0; i < calids.size(); i++) {
642: if (loadViewContextCalendar(calstore,
643: (String) calids.get(i))) {
644: //logger.fine("loaded Calendar.." + (String)calids.get(i));
645: }
646: }
647: }
648:
649: // check if the calids list is empty
650:
651: if (calids != null && !calids.isEmpty()) {
652:
653: // calids list is not empty, fetch events for each calendar in the list
654: for (i = 0; i < calids.size(); i++) {
655: cal = null;
656: calcomponents = null;
657:
658: cal = (ICalendar) calendars.get((String) calids
659: .get(i));
660:
661: //parsingProperties = new Properties();
662:
663: if (cal != null) {
664: if (logger.isLoggable(Level.FINE)) {
665: logger
666: .fine("Fetching Events from calendar: "
667: + cal.getCalID());
668: }
669: //calcomponents = cal.fetchComponents(start, end,parsingProperties, ICalendar.VEVENT);
670: calcomponents = cal.fetchComponents(start, end,
671: ICalendar.VEVENT);
672: if (calcomponents != null) {
673: for (int j = 0; j < calcomponents.length; j++) {
674: allEvents.add(calcomponents[j]);
675: }
676: }
677:
678: //Note: Not closing the calendar here. Reasons:
679: // If the calendar is closed, then every openCalendar call is a
680: // network request. If it is not closed, then JCAPI will return the
681: // calendar object from its cache.
682: // Since we use only single, community-cal (kinda private), and the operations
683: // (viewing different contexts, pagination, etc) are more frequent,
684: // we could avoid multiple, unnecessary n/w calls.
685:
686: //calstore.closeCalendar(cal);
687: }
688: }
689: } else {
690:
691: // calids list is empty
692: logger.log(Level.SEVERE, "CalId is not set");
693: throw new Exception("Empty calid list!");
694: }
695:
696: } catch (CalendarStoreException cse) {
697: logger
698: .log(
699: Level.SEVERE,
700: "executeFetchEvents Failed with CalendarStoreException: Unable to get ICalendar object: "
701: + cse.getMessage());
702: throw new Exception(cse.getMessage());
703: } catch (CalendarException ce) {
704: logger.log(Level.SEVERE, "Calendar Exception: "
705: + ce.getMessage());
706: throw new Exception("Fetch Failed: " + ce.getMessage());
707: } catch (Exception uwce) {
708: logger.log(Level.SEVERE, "Unable to get Store object: "
709: + uwce.getMessage());
710: throw new Exception(uwce.getMessage());
711: }
712:
713: }
714:
715: private void removeCalendarData() {
716: if (allEvents != null) {
717: allEvents.clear();
718:
719: }
720:
721: if (allTodos != null) {
722: allTodos.clear();
723: }
724:
725: if (calendars != null) {
726: calendars.clear();
727: }
728:
729: }
730:
731: /* searches the calendar for events based on componentSearchFilter*/
732:
733: private void executeSearchEvents() throws Exception {
734:
735: try {
736: int i;
737: CalendarComponent[] calcomponents;
738: Properties parsingProperties = new Properties();
739:
740: // Empty the existing calendar data. if any
741: removeCalendarData();
742:
743: // get the calendar store
744:
745: CalendarStore calstore = CalUserHelper.getCalStore(false);
746:
747: // Get Events for each of the calendars in ArrayList calids */
748: SOCSCalendar cal = null;
749:
750: // Load the calendars
751: if (!calids.isEmpty()) {
752: // calids list is not empty, fetch events for each calendar in the list
753: for (i = 0; i < calids.size(); i++) {
754: if (loadViewContextCalendar(calstore,
755: (String) calids.get(i))) {
756: //logger.fine("loaded Calendar.." + (String)calids.get(i))
757: }
758: }
759: }
760:
761: // SOCS-specific
762: // Note: We are using a Sun Calendar specific functionality here. i.e searching of events.
763: // There is no abstraction in JCAPI that can be used which provides an adaptor based
764: // implementation beneath.
765: // If a support for other backend calendars is needed, then this processing needs to be
766: // changed. Ex: fetch all the events and perform a search based on the search filter on the
767: // client side.
768: // This implemetation relies on the search done by Sun Calendar server.
769:
770: if (calids != null && !calids.isEmpty()) {
771: // calids list is not empty, fetch events for each calendar in the list
772: for (i = 0; i < calids.size(); i++) {
773: cal = null;
774: calcomponents = null;
775: cal = (SOCSCalendar) calendars.get((String) calids
776: .get(i));
777:
778: if (cal != null) {
779: calcomponents = cal.searchEvents(start, end,
780: componentSearchFilter,
781: componentSearchOption,
782: parsingProperties);
783: if (calcomponents != null) {
784: for (int j = 0; j < calcomponents.length; j++) {
785: allEvents.add(calcomponents[j]);
786: }
787: }
788: calstore.closeCalendar(cal);
789: }
790: }
791: } else { // calids list is empty
792: logger.log(Level.SEVERE, "CalId is not set");
793: throw new Exception("No Calendar specified!");
794: }
795: } catch (CalendarStoreException cse) {
796: logger
797: .log(
798: Level.SEVERE,
799: "executeFetchEvents Failed with CalendarStoreException: Unable to get ICalendar object: "
800: + cse);
801: throw new Exception("Invalid Calendar Specified! "
802: + cse.getMessage());
803: } catch (OperationNotSupportedException onse) {
804: logger.log(Level.SEVERE,
805: "OperationNotSupported Exception: " + onse);
806: throw new Exception("Fetch Failed: " + onse.getMessage());
807: } catch (CalendarException ce) {
808: logger.log(Level.SEVERE, "Calendar Exception: " + ce);
809: throw new Exception("Fetch Failed: " + ce.getMessage());
810: } catch (Exception e) {
811: logger
812: .log(Level.SEVERE, "Unable to get Store object: "
813: + e);
814: throw new Exception(e.getMessage());
815: }
816:
817: }
818:
819: }
|