View Javadoc
1   /**
2    * Copyright (C) 2003-2007 eXo Platform SAS.
3    *
4    * This program is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Affero General Public License
6    * as published by the Free Software Foundation; either version 3
7    * of the License, or (at your option) any later version.
8    *
9    * This program is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU General Public License
15   * along with this program; if not, see<http://www.gnu.org/licenses/>.
16   **/
17  package org.exoplatform.calendar.service.impl;
18  
19  import java.io.*;
20  import java.text.SimpleDateFormat;
21  import java.util.ArrayList;
22  import java.util.Arrays;
23  import java.util.Date;
24  import java.util.HashMap;
25  import java.util.List;
26  import java.util.Map;
27  
28  import javax.jcr.Node;
29  
30  import org.apache.commons.compress.utils.IOUtils;
31  import org.exoplatform.calendar.service.Attachment;
32  import org.exoplatform.calendar.service.Calendar;
33  import org.exoplatform.calendar.service.CalendarEvent;
34  import org.exoplatform.calendar.service.CalendarImportExport;
35  import org.exoplatform.calendar.service.CalendarService;
36  import org.exoplatform.calendar.service.EventQuery;
37  import org.exoplatform.calendar.service.ImportCalendarJob;
38  import org.exoplatform.calendar.service.ModifiedInputStream;
39  import org.exoplatform.calendar.service.Reminder;
40  import org.exoplatform.calendar.service.Utils;
41  import org.exoplatform.calendar.util.Constants;
42  import org.exoplatform.commons.utils.DateUtils;
43  import org.exoplatform.container.ExoContainerContext;
44  import org.exoplatform.services.log.ExoLogger;
45  import org.exoplatform.services.log.Log;
46  import org.exoplatform.services.scheduler.JobSchedulerService;
47  import org.exoplatform.services.scheduler.impl.JobSchedulerServiceImpl;
48  
49  import org.quartz.JobDetail;
50  import org.quartz.impl.triggers.SimpleTriggerImpl;
51  
52  import net.fortuna.ical4j.data.CalendarBuilder;
53  import net.fortuna.ical4j.data.CalendarOutputter;
54  import net.fortuna.ical4j.data.ParserException;
55  import net.fortuna.ical4j.model.ComponentList;
56  import net.fortuna.ical4j.model.DateTime;
57  import net.fortuna.ical4j.model.Dur;
58  import net.fortuna.ical4j.model.Parameter;
59  import net.fortuna.ical4j.model.ParameterList;
60  import net.fortuna.ical4j.model.Property;
61  import net.fortuna.ical4j.model.PropertyList;
62  import net.fortuna.ical4j.model.Recur;
63  import net.fortuna.ical4j.model.ValidationException;
64  import net.fortuna.ical4j.model.WeekDay;
65  import net.fortuna.ical4j.model.component.CalendarComponent;
66  import net.fortuna.ical4j.model.component.VAlarm;
67  import net.fortuna.ical4j.model.component.VEvent;
68  import net.fortuna.ical4j.model.component.VFreeBusy;
69  import net.fortuna.ical4j.model.component.VToDo;
70  import net.fortuna.ical4j.model.parameter.Encoding;
71  import net.fortuna.ical4j.model.parameter.Value;
72  import net.fortuna.ical4j.model.parameter.XParameter;
73  import net.fortuna.ical4j.model.property.Action;
74  import net.fortuna.ical4j.model.property.Attach;
75  import net.fortuna.ical4j.model.property.Attendee;
76  import net.fortuna.ical4j.model.property.CalScale;
77  import net.fortuna.ical4j.model.property.Categories;
78  import net.fortuna.ical4j.model.property.Clazz;
79  import net.fortuna.ical4j.model.property.Completed;
80  import net.fortuna.ical4j.model.property.Description;
81  import net.fortuna.ical4j.model.property.Due;
82  import net.fortuna.ical4j.model.property.Duration;
83  import net.fortuna.ical4j.model.property.ExDate;
84  import net.fortuna.ical4j.model.property.Location;
85  import net.fortuna.ical4j.model.property.Method;
86  import net.fortuna.ical4j.model.property.Priority;
87  import net.fortuna.ical4j.model.property.ProdId;
88  import net.fortuna.ical4j.model.property.RRule;
89  import net.fortuna.ical4j.model.property.RecurrenceId;
90  import net.fortuna.ical4j.model.property.Repeat;
91  import net.fortuna.ical4j.model.property.Status;
92  import net.fortuna.ical4j.model.property.Summary;
93  import net.fortuna.ical4j.model.property.Uid;
94  import net.fortuna.ical4j.model.property.Version;
95  import net.fortuna.ical4j.model.property.XProperty;
96  import net.fortuna.ical4j.util.CompatibilityHints;
97  
98  /**
99   * Created by The eXo Platform SARL
100  * Author : Hung Nguyen
101  *          hung.nguyen@exoplatform.com
102  * Jul 2, 2007  
103  */
104 public class ICalendarImportExport implements CalendarImportExport {
105   
106   private JCRDataStorage      storage_;
107 
108   private static final Log    logger       = ExoLogger.getLogger(ICalendarImportExport.class);
109 
110   public ICalendarImportExport(JCRDataStorage storage) throws Exception {
111     storage_ = storage;
112   }
113 
114   public net.fortuna.ical4j.model.Calendar getCalendarComponent(net.fortuna.ical4j.model.Calendar calendar, CalendarEvent exoEvent, String componentType) throws Exception {
115     Uid id = new Uid(exoEvent.getId());
116     long start = exoEvent.getFromDateTime().getTime();
117     long end = exoEvent.getToDateTime().getTime();
118     String summary = exoEvent.getSummary();
119     CalendarComponent event = null;
120 
121     if (end > 0) {
122       if (CalendarComponent.VEVENT.equals(componentType)) {
123         event = new VEvent(new DateTime(start), new DateTime(end), summary);
124       } else if (CalendarComponent.VTODO.equals(componentType)) {
125         event = new VToDo(new DateTime(start), new DateTime(end), summary);
126       }
127     } else {
128       if (CalendarComponent.VEVENT.equals(componentType)) {
129         event = new VEvent(new DateTime(start), summary);
130       } else if (CalendarComponent.VTODO.equals(componentType)) {
131         event = new VToDo(new DateTime(start), summary);
132       }
133     }
134 
135     if (event == null)
136       return null;
137 
138     event.getProperties().getProperty(Property.DTSTART).getParameters().add(net.fortuna.ical4j.model.parameter.Value.DATE_TIME);
139 
140     event.getProperties().add(new Description(exoEvent.getDescription()));
141     event.getProperties().getProperty(Property.DESCRIPTION).getParameters().add(net.fortuna.ical4j.model.parameter.Value.TEXT);
142 
143     event.getProperties().add(new Location(exoEvent.getLocation()));
144     event.getProperties().getProperty(Property.LOCATION).getParameters().add(net.fortuna.ical4j.model.parameter.Value.TEXT);
145 
146     if (exoEvent.getEventCategoryName() != null) {
147       event.getProperties().add(new Categories(exoEvent.getEventCategoryName()));
148       event.getProperties().getProperty(Property.CATEGORIES).getParameters().add(net.fortuna.ical4j.model.parameter.Value.TEXT);
149     }
150     setPriorityCalEvent(event.getProperties(), exoEvent);
151 
152     if (CalendarComponent.VTODO.equals(componentType)) {
153       if (exoEvent.getCompletedDateTime() != null) {
154         long completed = exoEvent.getCompletedDateTime().getTime();
155         event.getProperties().add(new Completed(new DateTime(completed)));
156         event.getProperties().getProperty(Property.COMPLETED).getParameters().add(net.fortuna.ical4j.model.parameter.Value.DATE_TIME);
157       }
158       event.getProperties().add(new Due(new DateTime(end)));
159       event.getProperties().getProperty(Property.DUE).getParameters().add(net.fortuna.ical4j.model.parameter.Value.DATE_TIME);
160       if (!Utils.isEmpty(exoEvent.getStatus())) {
161         event.getProperties().add(new Status(exoEvent.getStatus()));
162         event.getProperties().getProperty(Property.STATUS).getParameters().add(net.fortuna.ical4j.model.parameter.Value.TEXT);
163       }
164     }
165 
166     if (exoEvent.getAttachment() != null && !exoEvent.getAttachment().isEmpty()) {
167       for (Attachment att : exoEvent.getAttachment()) {
168         byte bytes[] = new byte[att.getInputStream().available()];
169         att.getInputStream().read(bytes);
170         ParameterList plist = new ParameterList();
171         plist.add(new XParameter(Parameter.CN, att.getName()));
172         plist.add(new XParameter(Parameter.FMTTYPE, att.getMimeType()));
173         plist.add(Encoding.BASE64);
174         plist.add(Value.BINARY);
175         Attach attach = new Attach(plist, bytes);
176         event.getProperties().add(attach);
177       }
178     }
179 
180     if (exoEvent.getReminders() != null && !exoEvent.getReminders().isEmpty()) {
181       for (Reminder r : exoEvent.getReminders()) {
182         VAlarm reminder = new VAlarm(new DateTime(r.getFromDateTime()));
183         Long times = new Long(1);
184         if (r.isRepeat())
185           times = (r.getAlarmBefore() / r.getRepeatInterval());
186         reminder.getProperties().add(new Repeat(times.intValue()));
187         reminder.getProperties().add(new Duration(new Dur(new Long(r.getAlarmBefore()).intValue())));
188         if (Reminder.TYPE_POPUP.equals(r.getReminderType())) {
189           for (String n : r.getReminderOwner().split(Utils.COMMA)) {
190             Attendee a = new Attendee(n);
191             reminder.getProperties().add(a);
192           }
193           reminder.getProperties().add(Action.DISPLAY);
194         } else {
195           for (String m : r.getEmailAddress().split(Utils.COMMA)) {
196             Attendee a = new Attendee(m);
197             reminder.getProperties().add(a);
198           }
199           reminder.getProperties().add(Action.EMAIL);
200         }
201         reminder.getProperties().add(new Summary(exoEvent.getSummary()));
202         reminder.getProperties().add(new Description(r.getDescription()));
203         reminder.getProperties().add(id);
204         calendar.getComponents().add(reminder);
205       }
206     }
207     if (exoEvent.isPrivate())
208       event.getProperties().add(new Clazz(Clazz.PRIVATE.getValue()));
209     else
210       event.getProperties().add(new Clazz(Clazz.PUBLIC.getValue()));
211     event.getProperties().getProperty(Property.CLASS).getParameters().add(net.fortuna.ical4j.model.parameter.Value.TEXT);
212     String[] attendees = exoEvent.getInvitation();
213     if (attendees != null && attendees.length > 0) {
214       for (int i = 0; i < attendees.length; i++) {
215         if (attendees[i] != null) {
216           event.getProperties().add(new Attendee(attendees[i]));
217         }
218       }
219       event.getProperties().getProperty(Property.ATTENDEE).getParameters().add(net.fortuna.ical4j.model.parameter.Value.TEXT);
220     }
221     if (!Utils.isEmpty(exoEvent.getRepeatType())) {
222       Recur rc = null;
223       if (CalendarEvent.RP_NOREPEAT.equalsIgnoreCase(exoEvent.getRepeatType())) {
224       } else if (CalendarEvent.RP_WEEKEND.equalsIgnoreCase(exoEvent.getRepeatType())) {
225         rc = new Recur(Recur.WEEKLY, 1);
226         rc.getDayList().add(WeekDay.SU);
227         rc.getDayList().add(WeekDay.SA);
228         rc.setInterval(1);
229       } else if (CalendarEvent.RP_WORKINGDAYS.equalsIgnoreCase(exoEvent.getRepeatType())) {
230         rc = new Recur(Recur.WEEKLY, 1);
231         rc.getDayList().add(WeekDay.MO);
232         rc.getDayList().add(WeekDay.TU);
233         rc.getDayList().add(WeekDay.WE);
234         rc.getDayList().add(WeekDay.TH);
235         rc.getDayList().add(WeekDay.FR);
236         rc.setInterval(1);
237       } else if (CalendarEvent.RP_WEEKLY.equalsIgnoreCase(exoEvent.getRepeatType())) {
238         rc = new Recur(Recur.WEEKLY, 1);
239         rc.getDayList().add(WeekDay.SU);
240         rc.getDayList().add(WeekDay.MO);
241         rc.getDayList().add(WeekDay.TU);
242         rc.getDayList().add(WeekDay.WE);
243         rc.getDayList().add(WeekDay.TH);
244         rc.getDayList().add(WeekDay.FR);
245         rc.getDayList().add(WeekDay.SA);
246         rc.setInterval(1);
247       } else {
248         rc = new Recur(exoEvent.getRepeatType().toUpperCase(), 1);
249         rc.setInterval(1);
250       }
251       if (rc != null) {
252         rc.setWeekStartDay(WeekDay.SU.getDay());
253         RRule r = new RRule(rc);
254         event.getProperties().add(r);
255       }
256     }
257     if (!Utils.isEmpty(exoEvent.getEventState())) {
258       XProperty xProperty = new XProperty(Utils.X_STATUS, exoEvent.getEventState());
259       event.getProperties().add(xProperty);
260     }
261     event.getProperties().add(id);
262     calendar.getComponents().add(event);
263     return calendar;
264   }
265 
266   public OutputStream exportCalendar(String username, List<String> calendarIds, String type, int limited) throws Exception {
267     List<CalendarEvent> events = new ArrayList<CalendarEvent>();
268     if (type.equals(PRIVATE_TYPE)) {
269       if (limited > 0) {
270         EventQuery eventQuery = new EventQuery();
271         eventQuery.setCalendarId(calendarIds.toArray(new String[] {}));
272         eventQuery.setOrderBy(new String[] { Utils.JCR_LASTMODIFIED });
273         eventQuery.setLimitedItems(limited);
274         events = storage_.getEvents(username, eventQuery, null);
275       } else {
276         events = storage_.getUserEventByCalendar(username, calendarIds);
277       }
278     } else if (type.equals(SHARED_TYPE)) {
279       events = storage_.getSharedEventByCalendars(username, calendarIds);
280     } else if (type.equals(PUBLIC_TYPE)) {
281       events = storage_.getGroupEventByCalendar(calendarIds);
282     }
283     if (events.isEmpty())
284       return null;
285     net.fortuna.ical4j.model.Calendar calendar = new net.fortuna.ical4j.model.Calendar();
286     calendar.getProperties().add(new ProdId("-//Ben Fortuna//iCal4j 1.0//EN"));
287     calendar.getProperties().add(Version.VERSION_2_0);
288     calendar.getProperties().add(CalScale.GREGORIAN);
289     calendar.getProperties().add(Method.REQUEST);
290     for (CalendarEvent exoEvent : events) {
291       if (exoEvent.getEventType().equals(CalendarEvent.TYPE_EVENT)) {
292         calendar = getCalendarComponent(calendar, exoEvent, CalendarComponent.VEVENT);
293       } else { // task
294         calendar = getCalendarComponent(calendar, exoEvent, CalendarComponent.VTODO);
295       }
296     }
297     ByteArrayOutputStream bout = new ByteArrayOutputStream();
298     CalendarOutputter output = new CalendarOutputter();
299     try {
300       output.output(calendar, bout);
301     } catch (ValidationException e) {
302       if (logger.isDebugEnabled()) {
303         logger.debug("Validate error", e);
304       }
305       return null;
306     }
307     return bout;
308   }
309 
310   public OutputStream exportEventCalendar(String username, String calendarId, String type, String eventId) throws Exception {
311     List<CalendarEvent> events = new ArrayList<CalendarEvent>();
312     List<String> calendarIds = Arrays.asList(new String[] { calendarId });
313 
314     if (type.equals(PRIVATE_TYPE)) {
315       events = storage_.getUserEventByCalendar(username, calendarIds);
316     } else if (type.equals(SHARED_TYPE)) {
317       events = storage_.getSharedEventByCalendars(username, calendarIds);
318     } else if (type.equals(PUBLIC_TYPE)) {
319       events = storage_.getGroupEventByCalendar(calendarIds);
320     }
321     net.fortuna.ical4j.model.Calendar calendar = new net.fortuna.ical4j.model.Calendar();
322     calendar.getProperties().add(new ProdId("-//Ben Fortuna//iCal4j 1.0//EN"));
323     calendar.getProperties().add(Version.VERSION_2_0);
324     calendar.getProperties().add(CalScale.GREGORIAN);
325     calendar.getProperties().add(Method.REQUEST);
326     for (CalendarEvent exoEvent : events) {
327       if (exoEvent.getId().equals(eventId)) {
328         if (exoEvent.getEventType().equals(CalendarEvent.TYPE_EVENT)) {
329           calendar = getCalendarComponent(calendar, exoEvent, CalendarComponent.VEVENT);
330         } else {
331           calendar = getCalendarComponent(calendar, exoEvent, CalendarComponent.VTODO);
332         }
333         break;
334       }
335     }
336     ByteArrayOutputStream bout = new ByteArrayOutputStream();
337     CalendarOutputter output = new CalendarOutputter();
338     try {
339       output.output(calendar, bout);
340     } catch (ValidationException e) {
341       if (logger.isDebugEnabled()) {
342         logger.debug("Validate error", e);
343       }
344       return null;
345     }
346     return bout;
347   }
348 
349 
350   public List<CalendarEvent> getEventObjects(InputStream icalInputStream) throws Exception {
351     CalendarBuilder calendarBuilder = new CalendarBuilder();
352     net.fortuna.ical4j.model.Calendar iCalendar = calendarBuilder.build(icalInputStream);
353     ComponentList componentList = iCalendar.getComponents();
354     List<CalendarEvent> eventList = new ArrayList<CalendarEvent>();
355     VEvent event;
356     for (Object obj : componentList) {
357       if (obj instanceof VEvent) {
358         CalendarEvent exoEvent = new CalendarEvent();
359         event = (VEvent) obj;
360         if (event.getProperty(Property.UID) != null) {
361           exoEvent.setId(event.getProperty(Property.UID).getValue());
362         }
363         if (event.getProperty(Property.CATEGORIES) != null) {
364           exoEvent.setEventCategoryName(event.getProperty(Property.CATEGORIES).getValue().trim());
365         }
366         if (event.getSummary() != null)
367           exoEvent.setSummary(event.getSummary().getValue());
368         if (event.getDescription() != null)
369           exoEvent.setDescription(event.getDescription().getValue());
370         if (event.getStatus() != null)
371           exoEvent.setStatus(event.getStatus().getValue());
372         exoEvent.setEventType(CalendarEvent.TYPE_EVENT);
373         if (event.getStartDate() != null)
374           exoEvent.setFromDateTime(event.getStartDate().getDate());
375         if (event.getEndDate() != null)
376           exoEvent.setToDateTime(event.getEndDate().getDate());
377         if (event.getLocation() != null)
378           exoEvent.setLocation(event.getLocation().getValue());
379         logger.info(event.getPriority());
380         setPriorityExoEvent(event.getPriority(), exoEvent);
381         try {
382           RRule r = (RRule) event.getProperty(Property.RRULE);
383           if (r != null && r.getRecur() != null) {
384             Recur rc = r.getRecur();
385             rc.getFrequency();
386             if (Recur.WEEKLY.equalsIgnoreCase(rc.getFrequency())) {
387               if (rc.getDayList().size() == 2) {
388                 exoEvent.setRepeatType(CalendarEvent.RP_WEEKEND);
389               } else if (rc.getDayList().size() == 5) {
390                 exoEvent.setRepeatType(CalendarEvent.RP_WORKINGDAYS);
391               }
392               if (rc.getDayList().size() == 7) {
393                 exoEvent.setRepeatType(CalendarEvent.RP_WEEKLY);
394               }
395             } else {
396               exoEvent.setRepeatType(rc.getFrequency().toLowerCase());
397             }
398           }
399         } catch (Exception e) {
400           if (logger.isDebugEnabled()) {
401             logger.debug("Exception in method getEventObjects", e);
402           }
403         }
404         exoEvent.setPrivate(true);
405         PropertyList attendees = event.getProperties(Property.ATTENDEE);
406         if (attendees.size() < 1) {
407           exoEvent.setInvitation(new String[] {});
408         } else {
409           String[] invitation = new String[attendees.size()];
410           for (int i = 0; i < attendees.size(); i++) {
411             invitation[i] = ((Attendee) attendees.get(i)).getValue();
412           }
413           exoEvent.setInvitation(invitation);
414         }
415         eventList.add(exoEvent);
416       }
417     }
418     return eventList;
419   }
420 
421   public boolean isValidate(InputStream icalInputStream) {
422     try {
423       CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_RELAXED_UNFOLDING, true);
424       CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_RELAXED_PARSING, true);
425       CalendarBuilder calendarBuilder = new CalendarBuilder();
426       calendarBuilder.build(icalInputStream);
427       return true;
428     } catch (ParserException pe) {
429       if (logger.isDebugEnabled()) 
430         logger.debug("Can not parsing input stream to calendar under ICal format", pe);
431     } catch (IOException ioe) {
432       if (logger.isDebugEnabled()) 
433         logger.debug("IO Error occurs when parsing input stream to calendar under ICal format", ioe);
434     }
435     return false;
436   }
437 
438   public void importCalendar(String username,
439                               InputStream icalInputStream,
440                               String calendarId,
441                               String calendarName,
442                               java.util.Calendar from,
443                               java.util.Calendar to,
444                               boolean isNew) throws Exception {
445     CalendarBuilder calendarBuilder = new CalendarBuilder();
446     CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_RELAXED_UNFOLDING, true);
447     CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_RELAXED_PARSING, true);
448     net.fortuna.ical4j.model.Calendar iCalendar;
449     try {
450       InputStream modStream = ModifiedInputStream.getIcsModifiedStream(icalInputStream);
451       iCalendar = calendarBuilder.build(modStream);
452     } catch (ParserException e) {
453       if (logger.isDebugEnabled()) {
454         logger.debug("ParserException occurs when building iCalendar object", e);
455       }
456       throw new ParserException("Cannot parsed the input stream to iCalendar object", e.getLineNo());
457     } catch (IOException e) {
458       if (logger.isDebugEnabled()) {
459         logger.debug("IOException occurs when building iCalendar object", e);
460       }
461       throw new IOException("IOException when parsing input stream to iCalendar object");
462     } finally {
463       icalInputStream.close();
464     }
465 
466     CalendarService calService = (CalendarService) ExoContainerContext.getCurrentContainer().getComponentInstanceOfType(CalendarService.class);
467 
468 
469     if (isNew) {
470       Calendar exoCalendar = new Calendar();
471       exoCalendar.setName(calendarName);
472       exoCalendar.setCalendarColor(Constants.COLORS[0]);
473       exoCalendar.setDescription(iCalendar.getProductId().getValue());
474       exoCalendar.setPublic(false);
475       exoCalendar.setCalendarOwner(username);
476       calService.saveUserCalendar(username, exoCalendar, true);
477       calendarId = exoCalendar.getId();
478     }
479     CalendarEvent exoEvent;
480     ComponentList componentList = iCalendar.getComponents();
481 
482     Map<String, VFreeBusy> vFreeBusyData = new HashMap<String, VFreeBusy>();
483     Map<String, VAlarm> vAlarmData = new HashMap<String, VAlarm>();
484 
485     Map<String, String> originalRecurrenceEvents = new HashMap<String, String>();
486     Map<String, List<CalendarEvent>> exceptionOccurrences = new HashMap<String, List<CalendarEvent>>();
487 
488     SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
489     format.setTimeZone(DateUtils.getTimeZone("GMT"));
490     int calType = storage_.getTypeOfCalendar(username, calendarId);
491 
492     for (Object obj : componentList) {
493       if (obj instanceof VEvent) {
494         VEvent v = (VEvent) obj;
495         if (!v.getAlarms().isEmpty()) {
496           for (Object o : v.getAlarms()) {
497             if (o instanceof VAlarm) {
498               VAlarm va = (VAlarm) o;
499               vAlarmData.put(v.getUid().getValue() + ":" + va.getProperty(Property.ACTION).getName(), va);
500             }
501           }
502         }
503       }
504       if (obj instanceof VFreeBusy)
505         vFreeBusyData.put(((VFreeBusy) obj).getUid().getValue(), (VFreeBusy) obj);
506     }
507 
508     for (Object obj : componentList) {
509       if (obj instanceof VEvent) {
510         VEvent event = (VEvent) obj;
511         exoEvent = new CalendarEvent();
512         try {
513           exoEvent = RemoteCalendarServiceImpl.generateEvent(event, exoEvent, username, calendarId);
514 
515           String sValue = Utils.EMPTY_STR;
516           String eValue = Utils.EMPTY_STR;
517           if (event.getStartDate() != null) {
518             if (to != null && event.getStartDate().getDate().getTime() > to.getTimeInMillis()) {
519               continue;
520             }
521             sValue = event.getStartDate().getValue();
522             exoEvent.setFromDateTime(event.getStartDate().getDate());
523           }
524           if (event.getEndDate() != null) {
525             if (from != null && event.getEndDate().getDate().getTime() < from.getTimeInMillis()) {
526               continue;
527             }
528             eValue = event.getEndDate().getValue();
529             exoEvent.setToDateTime(event.getEndDate().getDate());
530           }
531           if (sValue.length() == 8 && eValue.length() == 8) {
532             exoEvent.setToDateTime(new Date(event.getEndDate().getDate().getTime() - 1));
533           }
534           if (vFreeBusyData.get(event.getUid().getValue()) != null) {
535             exoEvent.setEventState(CalendarEvent.ST_BUSY);
536           }
537           exoEvent = RemoteCalendarServiceImpl.setEventAttachment(event, exoEvent,eValue,sValue);
538           exoEvent.setRepeatType(CalendarEvent.RP_NOREPEAT);
539           if (event.getProperty(Property.RECURRENCE_ID) != null) {
540             RecurrenceId recurId = (RecurrenceId) event.getProperty(Property.RECURRENCE_ID);
541             exoEvent.setRecurrenceId(format.format(new Date(recurId.getDate().getTime())));
542             String originalId = originalRecurrenceEvents.get(event.getUid().getValue());
543             if (originalId != null) {
544               Node originalNode = storage_.getCalendarEventNode(username, String.valueOf(calType), calendarId, originalId);
545               CalendarEvent original = storage_.getEvent(originalNode);
546               String uuid = originalNode.getUUID();
547               exoEvent.setOriginalReference(uuid);
548 
549               List<String> excludeId;
550               if (original.getExcludeId() != null && original.getExcludeId().length > 0) {
551                 excludeId = new ArrayList<String>(Arrays.asList(original.getExcludeId()));
552               } else {
553                 excludeId = new ArrayList<String>();
554               }
555               excludeId.add(exoEvent.getRecurrenceId());
556               original.setExcludeId(excludeId.toArray(new String[0]));
557               if (calType == Calendar.TYPE_PRIVATE)
558                 storage_.saveUserEvent(username, calendarId, original, false);
559               else if (calType == Calendar.TYPE_PUBLIC)
560                 storage_.savePublicEvent(calendarId, original, false);
561               else if (calType == Calendar.TYPE_SHARED)
562                 storage_.saveEventToSharedCalendar(username, calendarId, original, false);
563 
564             } else {
565               if (exceptionOccurrences.get(event.getUid().getValue()) == null) {
566                 List<CalendarEvent> exceptions = new ArrayList<CalendarEvent>();
567                 exceptions.add(exoEvent);
568                 exceptionOccurrences.put(event.getUid().getValue(), exceptions);
569               } else {
570                 exceptionOccurrences.get(event.getUid().getValue()).add(exoEvent);
571               }
572             }
573             storage_.saveOccurrenceEvent(username, calendarId, exoEvent, true);
574           } else {
575             if (event.getProperty(Property.RRULE) != null && event.getProperty(Property.RECURRENCE_ID) == null) {
576               exoEvent = RemoteCalendarServiceImpl.calculateEvent(event, exoEvent);
577 
578               originalRecurrenceEvents.put(event.getUid().getValue(), exoEvent.getId());
579 
580               List<String> excludeIds = new ArrayList<String>();
581               PropertyList exdates = event.getProperties(Property.EXDATE);
582               if (exdates != null && exdates.size() > 0) {
583                 for (Object exdate : exdates) {
584                   for (Object date : ((ExDate) exdate).getDates()) {
585                     excludeIds.add(format.format(new Date(((net.fortuna.ical4j.model.DateTime) date).getTime())));
586                   }
587                 }
588               }
589 
590               List<CalendarEvent> exceptions = exceptionOccurrences.get(event.getUid().getValue());
591               if (exceptions != null && exceptions.size() > 0) {
592                 for (CalendarEvent exception : exceptions) {
593                   excludeIds.add(exception.getRecurrenceId());
594                 }
595               }
596               exoEvent.setExcludeId(excludeIds.toArray(new String[0]));
597 
598               if (calType == Utils.PRIVATE_TYPE)
599                 storage_.saveUserEvent(username, calendarId, exoEvent, true);
600               else if (calType == Utils.SHARED_TYPE)
601                 storage_.saveEventToSharedCalendar(username, calendarId, exoEvent, true);
602               else if (calType == Utils.PUBLIC_TYPE)
603                 storage_.savePublicEvent(calendarId, exoEvent, true);
604 
605               Node originalNode = storage_.getCalendarEventNode(username, String.valueOf(calType), calendarId, exoEvent.getId());
606               String uuid = originalNode.getUUID();
607               if (exceptions != null && exceptions.size() > 0) {
608                 for (CalendarEvent exception : exceptions) {
609                   exception.setOriginalReference(uuid);
610                   storage_.saveOccurrenceEvent(username, calendarId, exception, false);
611                 }
612               }
613             } else {
614               if (calType == Utils.PRIVATE_TYPE)
615                 storage_.saveUserEvent(username, calendarId, exoEvent, true);
616               else if (calType == Utils.SHARED_TYPE)
617                 storage_.saveEventToSharedCalendar(username, calendarId, exoEvent, true);
618               else if (calType == Utils.PUBLIC_TYPE)
619                 storage_.savePublicEvent(calendarId, exoEvent, true);
620             }
621           }
622         } catch (Exception e) {
623           if (logger.isDebugEnabled()) {
624             logger.debug("Exception occurs when importing iCalendar component: " + event.getUid().getValue() + ". Skip this component.", e);
625           }
626           continue;
627         }
628       }
629 
630       else if (obj instanceof VToDo) {
631         VToDo event = (VToDo) obj;
632         exoEvent = new CalendarEvent();
633         try {
634           exoEvent = RemoteCalendarServiceImpl.setTaskAttachment(event, exoEvent,username,calendarId,vFreeBusyData);
635           switch (storage_.getTypeOfCalendar(username, calendarId)) {
636           case Utils.PRIVATE_TYPE:
637             calService.saveUserEvent(username, calendarId, exoEvent, true);
638             break;
639           case Utils.SHARED_TYPE:
640             calService.saveEventToSharedCalendar(username, calendarId, exoEvent, true);
641             break;
642           case Utils.PUBLIC_TYPE:
643             calService.savePublicEvent(calendarId, exoEvent, true);
644             break;
645           }
646         } catch (Exception e) {
647           if (logger.isDebugEnabled()) {
648             logger.debug("Exception occurs when importing iCalendar VTODO component: " + event.getUid().getValue() + ". Skip this component.", e);
649           }
650           continue;
651         }
652       }
653     }
654 
655   }
656 
657   @Override
658   public ByteArrayOutputStream exportEventCalendar(CalendarEvent exoEvent) throws Exception {
659     net.fortuna.ical4j.model.Calendar calendar = new net.fortuna.ical4j.model.Calendar();
660     calendar.getProperties().add(new ProdId("-//Ben Fortuna//iCal4j 1.0//EN"));
661     calendar.getProperties().add(Version.VERSION_2_0);
662     calendar.getProperties().add(CalScale.GREGORIAN);
663     calendar.getProperties().add(Method.REQUEST);
664     if (exoEvent.getEventType().equals(CalendarEvent.TYPE_EVENT)) {
665       calendar = getCalendarComponent(calendar, exoEvent, CalendarComponent.VEVENT);
666     } else {
667       calendar = getCalendarComponent(calendar, exoEvent, CalendarComponent.VTODO);
668     }
669     ByteArrayOutputStream bout = new ByteArrayOutputStream();
670     CalendarOutputter output = new CalendarOutputter();
671     try {
672       output.output(calendar, bout);
673     } catch (ValidationException e) {
674       if (logger.isDebugEnabled()) {
675         logger.debug("Validate error", e);
676       }
677       return null;
678     }
679     return bout;
680   }
681   
682   public static void setPriorityCalEvent(PropertyList propertyList, CalendarEvent exoEvent) {
683     if (exoEvent.getPriority() != null) {
684       int priority = 0;
685       for (int i = 0; i < CalendarEvent.PRIORITY.length; i++) {
686         if (exoEvent.getPriority().equalsIgnoreCase(CalendarEvent.PRIORITY[i])) {
687           if (i == CalendarEvent.PRI_MEDIUM) {
688             priority = 5;
689           } else if (i == CalendarEvent.PRI_LOW) {
690             priority = 6;
691           } else {
692             priority = i;
693           }
694           propertyList.add(new Priority(priority));
695           propertyList.getProperty(Property.PRIORITY).getParameters()
696                       .add(net.fortuna.ical4j.model.parameter.Value.INTEGER);
697           break;
698         }
699       }
700     }
701   }
702 
703   public static void setPriorityExoEvent(Priority priority, CalendarEvent exoEvent) {
704     if (priority != null) {
705       if (priority.getValue() != null) {
706         int priorityVl = 0;
707         try {
708           priorityVl = Integer.parseInt(priority.getValue());
709           if (1 < priorityVl && priorityVl <= 4) {
710             priorityVl = CalendarEvent.PRI_HIGH;
711           } else if (priorityVl == 5) {
712             priorityVl = CalendarEvent.PRI_MEDIUM;
713           } else if (priorityVl > 5) {
714             priorityVl = CalendarEvent.PRI_LOW;
715           }
716           exoEvent.setPriority(CalendarEvent.PRIORITY[priorityVl]);
717         } catch (NumberFormatException e) {
718           logger.warn("Can not set the priority of this event");
719         }
720       }
721     }
722   }
723   
724   public void importCalendarByJob(String username,
725                                   InputStream icalInputStream,
726                                   String calendarId, String calendarName,
727                                   java.util.Calendar from, java.util.Calendar to,
728                                   boolean isNew) throws Exception {
729     JobSchedulerServiceImpl  schedulerService = (JobSchedulerServiceImpl)ExoContainerContext.getCurrentContainer().
730         getComponentInstance(JobSchedulerService.class) ;
731 
732     JobDetail job = findImportJob(schedulerService, calendarId);
733 
734     if(job == null) {
735       byte[] icalInput = IOUtils.toByteArray(icalInputStream);
736       job = ImportCalendarJob.getImportICSFileJobDetail(username, calendarId, calendarName, icalInput, from, to, isNew);
737     }
738 
739     SimpleTriggerImpl trigger = new SimpleTriggerImpl();
740     trigger.setName(calendarId);
741     trigger.setGroup(ImportCalendarJob.IMPORT_CALENDAR_JOB_GROUP_NAME);
742     trigger.setStartTime(new Date());
743 
744     schedulerService.addJob(job, trigger);  
745   }
746 
747   public JobDetail findImportJob(JobSchedulerService schedulerService, String calendarId) throws Exception {
748     List<JobDetail> listJobs = schedulerService.getAllJobs();
749     for(JobDetail job : listJobs) {
750       if(job.getKey().getName().equals(calendarId)) {
751         return job;
752       }
753     }
754     return null;
755   }
756 }