1   /**
2    * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portlet.calendar.service.impl;
24  
25  import com.liferay.portal.NoSuchUserException;
26  import com.liferay.portal.PortalException;
27  import com.liferay.portal.SystemException;
28  import com.liferay.portal.im.AIMConnector;
29  import com.liferay.portal.im.ICQConnector;
30  import com.liferay.portal.im.MSNConnector;
31  import com.liferay.portal.im.YMConnector;
32  import com.liferay.portal.kernel.cal.DayAndPosition;
33  import com.liferay.portal.kernel.cal.Recurrence;
34  import com.liferay.portal.kernel.mail.MailMessage;
35  import com.liferay.portal.kernel.util.Base64;
36  import com.liferay.portal.kernel.util.CalendarFactoryUtil;
37  import com.liferay.portal.kernel.util.LocaleUtil;
38  import com.liferay.portal.kernel.util.ReleaseInfo;
39  import com.liferay.portal.kernel.util.StringPool;
40  import com.liferay.portal.kernel.util.StringUtil;
41  import com.liferay.portal.kernel.util.TimeZoneUtil;
42  import com.liferay.portal.kernel.util.Validator;
43  import com.liferay.portal.kernel.uuid.PortalUUIDUtil;
44  import com.liferay.portal.model.Company;
45  import com.liferay.portal.model.Contact;
46  import com.liferay.portal.model.User;
47  import com.liferay.portal.model.impl.ResourceImpl;
48  import com.liferay.portal.util.DateFormats;
49  import com.liferay.portal.util.PortalUtil;
50  import com.liferay.portal.util.PortletKeys;
51  import com.liferay.portlet.calendar.EventDurationException;
52  import com.liferay.portlet.calendar.EventEndDateException;
53  import com.liferay.portlet.calendar.EventStartDateException;
54  import com.liferay.portlet.calendar.EventTitleException;
55  import com.liferay.portlet.calendar.model.CalEvent;
56  import com.liferay.portlet.calendar.model.impl.CalEventImpl;
57  import com.liferay.portlet.calendar.service.base.CalEventLocalServiceBaseImpl;
58  import com.liferay.portlet.calendar.util.CalUtil;
59  import com.liferay.util.Time;
60  import com.liferay.util.cal.CalendarUtil;
61  import com.liferay.util.servlet.ServletResponseUtil;
62  
63  import java.io.BufferedOutputStream;
64  import java.io.File;
65  import java.io.FileOutputStream;
66  import java.io.FileReader;
67  import java.io.IOException;
68  import java.io.OutputStream;
69  
70  import java.text.DateFormat;
71  
72  import java.util.ArrayList;
73  import java.util.Calendar;
74  import java.util.Collection;
75  import java.util.Date;
76  import java.util.Iterator;
77  import java.util.List;
78  import java.util.Locale;
79  import java.util.Map;
80  import java.util.TimeZone;
81  
82  import javax.mail.internet.InternetAddress;
83  
84  import javax.portlet.PortletPreferences;
85  
86  import net.fortuna.ical4j.data.CalendarBuilder;
87  import net.fortuna.ical4j.data.CalendarOutputter;
88  import net.fortuna.ical4j.data.ParserException;
89  import net.fortuna.ical4j.model.Component;
90  import net.fortuna.ical4j.model.DateTime;
91  import net.fortuna.ical4j.model.Parameter;
92  import net.fortuna.ical4j.model.Property;
93  import net.fortuna.ical4j.model.PropertyList;
94  import net.fortuna.ical4j.model.Recur;
95  import net.fortuna.ical4j.model.WeekDay;
96  import net.fortuna.ical4j.model.component.VEvent;
97  import net.fortuna.ical4j.model.component.VTimeZone;
98  import net.fortuna.ical4j.model.property.CalScale;
99  import net.fortuna.ical4j.model.property.Comment;
100 import net.fortuna.ical4j.model.property.Description;
101 import net.fortuna.ical4j.model.property.DtStart;
102 import net.fortuna.ical4j.model.property.Duration;
103 import net.fortuna.ical4j.model.property.ProdId;
104 import net.fortuna.ical4j.model.property.RRule;
105 import net.fortuna.ical4j.model.property.Summary;
106 import net.fortuna.ical4j.model.property.Uid;
107 import net.fortuna.ical4j.model.property.Version;
108 
109 import org.apache.commons.logging.Log;
110 import org.apache.commons.logging.LogFactory;
111 
112 /**
113  * <a href="CalEventLocalServiceImpl.java.html"><b><i>View Source</i></b></a>
114  *
115  * @author Brian Wing Shun Chan
116  * @author Bruno Farache
117  *
118  */
119 public class CalEventLocalServiceImpl extends CalEventLocalServiceBaseImpl {
120 
121     public CalEvent addEvent(
122             long userId, long plid, String title, String description,
123             int startDateMonth, int startDateDay, int startDateYear,
124             int startDateHour, int startDateMinute, int endDateMonth,
125             int endDateDay, int endDateYear, int durationHour,
126             int durationMinute, boolean allDay, boolean timeZoneSensitive,
127             String type, boolean repeating, Recurrence recurrence,
128             String remindBy, int firstReminder, int secondReminder,
129             boolean addCommunityPermissions, boolean addGuestPermissions)
130         throws PortalException, SystemException {
131 
132         return addEvent(
133             null, userId, plid, title, description, startDateMonth,
134             startDateDay, startDateYear, startDateHour, startDateMinute,
135             endDateMonth, endDateDay, endDateYear, durationHour, durationMinute,
136             allDay, timeZoneSensitive, type, repeating, recurrence, remindBy,
137             firstReminder, secondReminder,
138             Boolean.valueOf(addCommunityPermissions),
139             Boolean.valueOf(addGuestPermissions), null, null);
140     }
141 
142     public CalEvent addEvent(
143             String uuid, long userId, long plid, String title,
144             String description, int startDateMonth, int startDateDay,
145             int startDateYear, int startDateHour, int startDateMinute,
146             int endDateMonth, int endDateDay, int endDateYear, int durationHour,
147             int durationMinute, boolean allDay, boolean timeZoneSensitive,
148             String type, boolean repeating, Recurrence recurrence,
149             String remindBy, int firstReminder, int secondReminder,
150             boolean addCommunityPermissions, boolean addGuestPermissions)
151         throws PortalException, SystemException {
152 
153         return addEvent(
154             uuid, userId, plid, title, description, startDateMonth,
155             startDateDay, startDateYear, startDateHour, startDateMinute,
156             endDateMonth, endDateDay, endDateYear, durationHour, durationMinute,
157             allDay, timeZoneSensitive, type, repeating, recurrence, remindBy,
158             firstReminder, secondReminder, new Boolean(addCommunityPermissions),
159             new Boolean(addGuestPermissions), null, null);
160     }
161 
162     public CalEvent addEvent(
163             long userId, long plid, String title, String description,
164             int startDateMonth, int startDateDay, int startDateYear,
165             int startDateHour, int startDateMinute, int endDateMonth,
166             int endDateDay, int endDateYear, int durationHour,
167             int durationMinute, boolean allDay, boolean timeZoneSensitive,
168             String type, boolean repeating, Recurrence recurrence,
169             String remindBy, int firstReminder, int secondReminder,
170             String[] communityPermissions, String[] guestPermissions)
171         throws PortalException, SystemException {
172 
173         return addEvent(
174             null, userId, plid, title, description, startDateMonth,
175             startDateDay, startDateYear, startDateHour, startDateMinute,
176             endDateMonth, endDateDay, endDateYear, durationHour, durationMinute,
177             allDay, timeZoneSensitive, type, repeating, recurrence, remindBy,
178             firstReminder, secondReminder, null, null, communityPermissions,
179             guestPermissions);
180     }
181 
182     public CalEvent addEvent(
183             String uuid, long userId, long plid, String title,
184             String description, int startDateMonth, int startDateDay,
185             int startDateYear, int startDateHour, int startDateMinute,
186             int endDateMonth, int endDateDay, int endDateYear, int durationHour,
187             int durationMinute, boolean allDay, boolean timeZoneSensitive,
188             String type, boolean repeating, Recurrence recurrence,
189             String remindBy, int firstReminder, int secondReminder,
190             Boolean addCommunityPermissions, Boolean addGuestPermissions,
191             String[] communityPermissions, String[] guestPermissions)
192         throws PortalException, SystemException {
193 
194         // Event
195 
196         User user = userPersistence.findByPrimaryKey(userId);
197         long groupId = PortalUtil.getPortletGroupId(plid);
198         Date now = new Date();
199 
200         Locale locale = null;
201         TimeZone timeZone = null;
202 
203         if (timeZoneSensitive) {
204             locale = user.getLocale();
205             timeZone = user.getTimeZone();
206         }
207         else {
208             locale = LocaleUtil.getDefault();
209             timeZone = TimeZoneUtil.getDefault();
210         }
211 
212         Calendar startDate = CalendarFactoryUtil.getCalendar(timeZone, locale);
213 
214         startDate.set(Calendar.MONTH, startDateMonth);
215         startDate.set(Calendar.DATE, startDateDay);
216         startDate.set(Calendar.YEAR, startDateYear);
217         startDate.set(Calendar.HOUR_OF_DAY, startDateHour);
218         startDate.set(Calendar.MINUTE, startDateMinute);
219         startDate.set(Calendar.SECOND, 0);
220         startDate.set(Calendar.MILLISECOND, 0);
221 
222         Calendar endDate = CalendarFactoryUtil.getCalendar(timeZone, locale);
223 
224         endDate.set(Calendar.MONTH, endDateMonth);
225         endDate.set(Calendar.DATE, endDateDay);
226         endDate.set(Calendar.YEAR, endDateYear);
227         endDate.set(Calendar.HOUR_OF_DAY, 23);
228         endDate.set(Calendar.MINUTE, 59);
229         endDate.set(Calendar.SECOND, 59);
230         endDate.set(Calendar.MILLISECOND, 999);
231 
232         if (allDay) {
233             startDate.set(Calendar.HOUR_OF_DAY, 0);
234             startDate.set(Calendar.MINUTE, 0);
235 
236             durationHour = 24;
237             durationMinute = 0;
238         }
239 
240         validate(
241             title, startDateMonth, startDateDay, startDateYear, endDateMonth,
242             endDateDay, endDateYear, durationHour, durationMinute, allDay);
243 
244         long eventId = counterLocalService.increment();
245 
246         CalEvent event = calEventPersistence.create(eventId);
247 
248         event.setUuid(uuid);
249         event.setGroupId(groupId);
250         event.setCompanyId(user.getCompanyId());
251         event.setUserId(user.getUserId());
252         event.setUserName(user.getFullName());
253         event.setCreateDate(now);
254         event.setModifiedDate(now);
255         event.setTitle(title);
256         event.setDescription(description);
257         event.setStartDate(startDate.getTime());
258         event.setEndDate(endDate.getTime());
259         event.setDurationHour(durationHour);
260         event.setDurationMinute(durationMinute);
261         event.setAllDay(allDay);
262         event.setTimeZoneSensitive(timeZoneSensitive);
263         event.setType(type);
264         event.setRepeating(repeating);
265         event.setRecurrence(Base64.objectToString(recurrence));
266         event.setRemindBy(remindBy);
267         event.setFirstReminder(firstReminder);
268         event.setSecondReminder(secondReminder);
269 
270         calEventPersistence.update(event);
271 
272         // Resources
273 
274         if ((addCommunityPermissions != null) &&
275             (addGuestPermissions != null)) {
276 
277             addEventResources(
278                 event, addCommunityPermissions.booleanValue(),
279                 addGuestPermissions.booleanValue());
280         }
281         else {
282             addEventResources(event, communityPermissions, guestPermissions);
283         }
284 
285         // Pool
286 
287         CalEventLocalUtil.clearEventsPool(event.getGroupId());
288 
289         return event;
290     }
291 
292     public void addEventResources(
293             long eventId, boolean addCommunityPermissions,
294             boolean addGuestPermissions)
295         throws PortalException, SystemException {
296 
297         CalEvent event = calEventPersistence.findByPrimaryKey(eventId);
298 
299         addEventResources(
300             event, addCommunityPermissions, addGuestPermissions);
301     }
302 
303     public void addEventResources(
304             CalEvent event, boolean addCommunityPermissions,
305             boolean addGuestPermissions)
306         throws PortalException, SystemException {
307 
308         resourceLocalService.addResources(
309             event.getCompanyId(), event.getGroupId(), event.getUserId(),
310             CalEvent.class.getName(), event.getEventId(), false,
311             addCommunityPermissions, addGuestPermissions);
312     }
313 
314     public void addEventResources(
315             long eventId, String[] communityPermissions,
316             String[] guestPermissions)
317         throws PortalException, SystemException {
318 
319         CalEvent event = calEventPersistence.findByPrimaryKey(eventId);
320 
321         addEventResources(event, communityPermissions, guestPermissions);
322     }
323 
324     public void addEventResources(
325             CalEvent event, String[] communityPermissions,
326             String[] guestPermissions)
327         throws PortalException, SystemException {
328 
329         resourceLocalService.addModelResources(
330             event.getCompanyId(), event.getGroupId(), event.getUserId(),
331             CalEvent.class.getName(), event.getEventId(), communityPermissions,
332             guestPermissions);
333     }
334 
335     public void checkEvents() throws PortalException, SystemException {
336         Iterator itr = calEventFinder.findByRemindBy().iterator();
337 
338         while (itr.hasNext()) {
339             CalEvent event = (CalEvent)itr.next();
340 
341             User user = userPersistence.findByPrimaryKey(event.getUserId());
342 
343             Calendar now = CalendarFactoryUtil.getCalendar(
344                 user.getTimeZone(), user.getLocale());
345 
346             if (!event.isTimeZoneSensitive()) {
347                 Calendar temp = CalendarFactoryUtil.getCalendar();
348 
349                 temp.setTime(Time.getDate(now));
350 
351                 now = temp;
352             }
353 
354             Calendar startDate = null;
355 
356             if (event.isTimeZoneSensitive()) {
357                 startDate = CalendarFactoryUtil.getCalendar(
358                     user.getTimeZone(), user.getLocale());
359             }
360             else {
361                 startDate = CalendarFactoryUtil.getCalendar();
362             }
363 
364             startDate.setTime(event.getStartDate());
365 
366             long diff =
367                 (startDate.getTime().getTime() - now.getTime().getTime()) /
368                 Time.MINUTE;
369 
370             if ((diff == (event.getFirstReminder() / Time.MINUTE)) ||
371                 (diff == (event.getSecondReminder() / Time.MINUTE))) {
372 
373                 remindUser(event, user);
374             }
375         }
376     }
377 
378     public void deleteEvent(long eventId)
379         throws PortalException, SystemException {
380 
381         CalEvent event = calEventPersistence.findByPrimaryKey(eventId);
382 
383         deleteEvent(event);
384     }
385 
386     public void deleteEvent(CalEvent event)
387         throws PortalException, SystemException {
388 
389         // Pool
390 
391         CalEventLocalUtil.clearEventsPool(event.getGroupId());
392 
393         // Resources
394 
395         resourceLocalService.deleteResource(
396             event.getCompanyId(), CalEvent.class.getName(),
397             ResourceImpl.SCOPE_INDIVIDUAL, event.getEventId());
398 
399         // Event
400 
401         calEventPersistence.remove(event.getEventId());
402     }
403 
404     public void deleteEvents(long groupId)
405         throws PortalException, SystemException {
406 
407         Iterator itr = calEventPersistence.findByGroupId(groupId).iterator();
408 
409         while (itr.hasNext()) {
410             CalEvent event = (CalEvent)itr.next();
411 
412             deleteEvent(event);
413         }
414     }
415 
416     public File exportEvent(long userId, long eventId)
417         throws PortalException, SystemException {
418 
419         List events = new ArrayList();
420 
421         CalEvent event = calEventPersistence.findByPrimaryKey(eventId);
422 
423         events.add(event);
424 
425         return exportICal4j(toICalCalendar(userId, events), null);
426     }
427 
428     public File exportGroupEvents(long userId, long plid, String fileName)
429         throws PortalException, SystemException {
430 
431         long groupId = PortalUtil.getPortletGroupId(plid);
432 
433         List events = calEventPersistence.findByGroupId(groupId);
434 
435         return exportICal4j(toICalCalendar(userId, events), fileName);
436     }
437 
438     public CalEvent getEvent(long eventId)
439         throws PortalException, SystemException {
440 
441         return calEventPersistence.findByPrimaryKey(eventId);
442     }
443 
444     public List getEvents(long groupId, String type, int begin, int end)
445         throws SystemException {
446 
447         if (Validator.isNull(type)) {
448             return calEventPersistence.findByGroupId(groupId, begin, end);
449         }
450         else {
451             return calEventPersistence.findByG_T(groupId, type, begin, end);
452         }
453     }
454 
455     public List getEvents(long groupId, Calendar cal) throws SystemException {
456         Map eventsPool = CalEventLocalUtil.getEventsPool(groupId);
457 
458         String key = CalUtil.toString(cal);
459 
460         List events = (List)eventsPool.get(key);
461 
462         if (events == null) {
463 
464             // Time zone sensitive
465 
466             Collection eventsCol1 = calEventFinder.findByG_SD(
467                 groupId, CalendarUtil.getGTDate(cal),
468                 CalendarUtil.getLTDate(cal), true);
469 
470             // Time zone insensitive
471 
472             Calendar tzICal = CalendarFactoryUtil.getCalendar(
473                 cal.get(Calendar.YEAR),
474                 cal.get(Calendar.MONTH),
475                 cal.get(Calendar.DATE));
476 
477             Collection eventsCol2 = calEventFinder.findByG_SD(
478                 groupId, CalendarUtil.getGTDate(tzICal),
479                 CalendarUtil.getLTDate(tzICal), false);
480 
481             // Create new list
482 
483             events = new ArrayList();
484             events.addAll(eventsCol1);
485             events.addAll(eventsCol2);
486 
487             // Add repeating events
488 
489             Iterator itr = getRepeatingEvents(groupId).iterator();
490 
491             while (itr.hasNext()) {
492                 CalEvent event = (CalEvent)itr.next();
493 
494                 Recurrence recurrence = event.getRecurrenceObj();
495 
496                 try {
497 
498                     // LEP-3468
499 
500                     if ((recurrence.getFrequency() == Recurrence.DAILY) &&
501                         (recurrence.getInterval() <= 0)) {
502 
503                         recurrence.setInterval(1);
504 
505                         event.setRecurrence(Base64.objectToString(recurrence));
506 
507                         event = calEventPersistence.update(event);
508 
509                         recurrence = event.getRecurrenceObj();
510                     }
511 
512                     if (recurrence.isInRecurrence(
513                             getRecurrenceCal(cal, tzICal, event))) {
514 
515                         events.add(event);
516                     }
517                 }
518                 catch (Exception e) {
519                     _log.error(e.getMessage());
520                 }
521             }
522 
523             eventsPool.put(key, events);
524         }
525 
526         return events;
527     }
528 
529     public List getEvents(long groupId, Calendar cal, String type)
530         throws SystemException {
531 
532         List events = getEvents(groupId, cal);
533 
534         if (Validator.isNull(type)) {
535             return events;
536         }
537         else {
538             events = new ArrayList(events);
539 
540             Iterator itr = events.iterator();
541 
542             while (itr.hasNext()) {
543                 CalEvent event = (CalEvent)itr.next();
544 
545                 if (!event.getType().equals(type)) {
546                     itr.remove();
547                 }
548             }
549 
550             return events;
551         }
552     }
553 
554     public int getEventsCount(long groupId, String type)
555         throws SystemException {
556 
557         if (Validator.isNull(type)) {
558             return calEventPersistence.countByGroupId(groupId);
559         }
560         else {
561             return calEventPersistence.countByG_T(groupId, type);
562         }
563     }
564 
565     public List getRepeatingEvents(long groupId) throws SystemException {
566         Map eventsPool = CalEventLocalUtil.getEventsPool(groupId);
567 
568         String key = "recurrence";
569 
570         List events = (List)eventsPool.get(key);
571 
572         if (events == null) {
573             events = calEventPersistence.findByG_R(groupId, true);
574 
575             eventsPool.put(key, events);
576         }
577 
578         return events;
579     }
580 
581     public boolean hasEvents(long groupId, Calendar cal)
582         throws SystemException {
583 
584         return hasEvents(groupId, cal, null);
585     }
586 
587     public boolean hasEvents(long groupId, Calendar cal, String type)
588         throws SystemException {
589 
590         if (getEvents(groupId, cal, type).size() > 0) {
591             return true;
592         }
593         else {
594             return false;
595         }
596     }
597 
598     public void importICal4j(long userId, long plid, File file)
599         throws PortalException, SystemException {
600 
601         try {
602             CalendarBuilder builder = new CalendarBuilder();
603 
604             net.fortuna.ical4j.model.Calendar calendar = builder.build(
605                 new FileReader(file));
606 
607             TimeZone timeZone = toTimeZone(
608                 userId, (VTimeZone)calendar.getComponent(Component.VTIMEZONE));
609 
610             Iterator itr = calendar.getComponents(Component.VEVENT).iterator();
611 
612             while (itr.hasNext()) {
613                 VEvent vEvent = (VEvent)itr.next();
614 
615                 importICal4j(userId, plid, vEvent, timeZone);
616             }
617         }
618         catch (IOException ioe) {
619             throw new SystemException(ioe.getMessage());
620         }
621         catch (ParserException pe) {
622             throw new SystemException(pe.getMessage());
623         }
624     }
625 
626     public CalEvent updateEvent(
627             long userId, long eventId, String title, String description,
628             int startDateMonth, int startDateDay, int startDateYear,
629             int startDateHour, int startDateMinute, int endDateMonth,
630             int endDateDay, int endDateYear, int durationHour,
631             int durationMinute, boolean allDay, boolean timeZoneSensitive,
632             String type, boolean repeating, Recurrence recurrence,
633             String remindBy, int firstReminder, int secondReminder)
634         throws PortalException, SystemException {
635 
636         User user = userPersistence.findByPrimaryKey(userId);
637 
638         Locale locale = null;
639         TimeZone timeZone = null;
640 
641         if (timeZoneSensitive) {
642             locale = user.getLocale();
643             timeZone = user.getTimeZone();
644         }
645         else {
646             locale = LocaleUtil.getDefault();
647             timeZone = TimeZoneUtil.getDefault();
648         }
649 
650         Calendar startDate = CalendarFactoryUtil.getCalendar(timeZone, locale);
651 
652         startDate.set(Calendar.MONTH, startDateMonth);
653         startDate.set(Calendar.DATE, startDateDay);
654         startDate.set(Calendar.YEAR, startDateYear);
655         startDate.set(Calendar.HOUR_OF_DAY, startDateHour);
656         startDate.set(Calendar.MINUTE, startDateMinute);
657         startDate.set(Calendar.SECOND, 0);
658         startDate.set(Calendar.MILLISECOND, 0);
659 
660         Calendar endDate = CalendarFactoryUtil.getCalendar(timeZone, locale);
661 
662         endDate.set(Calendar.MONTH, endDateMonth);
663         endDate.set(Calendar.DATE, endDateDay);
664         endDate.set(Calendar.YEAR, endDateYear);
665         endDate.set(Calendar.HOUR_OF_DAY, 23);
666         endDate.set(Calendar.MINUTE, 59);
667         endDate.set(Calendar.SECOND, 59);
668         endDate.set(Calendar.MILLISECOND, 999);
669 
670         if (allDay) {
671             startDate.set(Calendar.HOUR_OF_DAY, 0);
672             startDate.set(Calendar.MINUTE, 0);
673 
674             durationHour = 24;
675             durationMinute = 0;
676         }
677 
678         validate(
679             title, startDateMonth, startDateDay, startDateYear, endDateMonth,
680             endDateDay, endDateYear, durationHour, durationMinute, allDay);
681 
682         CalEvent event = calEventPersistence.findByPrimaryKey(eventId);
683 
684         event.setModifiedDate(new Date());
685         event.setTitle(title);
686         event.setDescription(description);
687         event.setStartDate(startDate.getTime());
688         event.setEndDate(endDate.getTime());
689         event.setDurationHour(durationHour);
690         event.setDurationMinute(durationMinute);
691         event.setAllDay(allDay);
692         event.setTimeZoneSensitive(timeZoneSensitive);
693         event.setType(type);
694         event.setRepeating(repeating);
695         event.setRecurrence(Base64.objectToString(recurrence));
696         event.setRemindBy(remindBy);
697         event.setFirstReminder(firstReminder);
698         event.setSecondReminder(secondReminder);
699 
700         calEventPersistence.update(event);
701 
702         CalEventLocalUtil.clearEventsPool(event.getGroupId());
703 
704         return event;
705     }
706 
707     protected File exportICal4j(
708             net.fortuna.ical4j.model.Calendar cal, String fileName)
709         throws SystemException {
710 
711         OutputStream os = null;
712 
713         try {
714             String extension = ".ics";
715 
716             if (Validator.isNull(fileName)) {
717                 fileName = "liferay.";
718             }
719             else {
720                 int pos = fileName.lastIndexOf(StringPool.PERIOD);
721 
722                 if (pos != -1) {
723                     extension = fileName.substring(pos);
724                     fileName = fileName.substring(0, pos);
725                 }
726             }
727 
728             File file = File.createTempFile(fileName, extension);
729 
730             os = new BufferedOutputStream(new FileOutputStream(file.getPath()));
731 
732             CalendarOutputter calOutput = new CalendarOutputter();
733 
734             calOutput.output(cal, os);
735 
736             return file;
737         }
738         catch (Exception e) {
739             _log.error(e, e);
740 
741             throw new SystemException(e);
742         }
743         finally {
744             ServletResponseUtil.cleanUp(os);
745         }
746     }
747 
748     protected Calendar getRecurrenceCal(
749         Calendar cal, Calendar tzICal, CalEvent event) {
750 
751         Calendar eventCal = CalendarFactoryUtil.getCalendar();
752         eventCal.setTime(event.getStartDate());
753 
754         Calendar recurrenceCal = (Calendar)tzICal.clone();
755         recurrenceCal.set(
756             Calendar.HOUR_OF_DAY, eventCal.get(Calendar.HOUR_OF_DAY));
757         recurrenceCal.set(
758             Calendar.MINUTE, eventCal.get(Calendar.MINUTE));
759         recurrenceCal.set(Calendar.SECOND, 0);
760         recurrenceCal.set(Calendar.MILLISECOND, 0);
761 
762         if (event.isTimeZoneSensitive()) {
763             int gmtDate = eventCal.get(Calendar.DATE);
764             long gmtMills = eventCal.getTimeInMillis();
765 
766             eventCal.setTimeZone(cal.getTimeZone());
767 
768             int tziDate = eventCal.get(Calendar.DATE);
769             long tziMills = Time.getDate(eventCal).getTime();
770 
771             if (gmtDate != tziDate) {
772                 int diffDate = 0;
773 
774                 if (gmtMills > tziMills) {
775                     diffDate = (int)Math.ceil(
776                         (double)(gmtMills - tziMills) / Time.DAY);
777                 }
778                 else {
779                     diffDate = (int)Math.floor(
780                         (double)(gmtMills - tziMills) / Time.DAY);
781                 }
782 
783                 recurrenceCal.add(Calendar.DATE, diffDate);
784             }
785         }
786 
787         return recurrenceCal;
788     }
789 
790     protected void importICal4j(
791             long userId, long plid, VEvent event, TimeZone timeZone)
792         throws PortalException, SystemException {
793 
794         String title = StringPool.BLANK;
795 
796         if (event.getSummary() != null) {
797             title = event.getSummary().getValue();
798         }
799 
800         String description = StringPool.BLANK;
801 
802         if (event.getDescription() != null) {
803             description = event.getDescription().getValue();
804         }
805 
806         Calendar startDate = Calendar.getInstance(timeZone);
807 
808         startDate.setTime(event.getStartDate().getDate());
809 
810         Calendar endDate = Calendar.getInstance(timeZone);
811 
812         endDate.setTime(event.getEndDate().getDate());
813 
814         long diffMillis =
815             endDate.getTimeInMillis() - startDate.getTimeInMillis();
816         long durationHours = diffMillis / (60 * 60 * 1000);
817         long durationMins =
818             (diffMillis / (60 * 1000)) - (durationHours * 60);
819         boolean allDay = false;
820 
821         if (event.getProperty(Property.DTSTART).getParameter(
822                 Parameter.TZID) == null){
823 
824             Calendar startDateWithoutTimeZone = Calendar.getInstance();
825 
826             startDateWithoutTimeZone.setTime(
827                 event.getStartDate().getDate());
828 
829             startDate.set(
830                 Calendar.DAY_OF_MONTH,
831                 startDateWithoutTimeZone.get(Calendar.DAY_OF_MONTH));
832             startDate.set(Calendar.HOUR_OF_DAY, 0);
833             startDate.set(Calendar.MINUTE, 0);
834             startDate.set(Calendar.SECOND, 0);
835             startDate.set(Calendar.MILLISECOND, 0);
836 
837             durationHours = 24;
838             durationMins = 0;
839             allDay = true;
840         }
841 
842         boolean timeZoneSensitive = false;
843         String type = StringPool.BLANK;
844         boolean repeating = false;
845         Recurrence recurrence = null;
846 
847         RRule rrule = (RRule)event.getProperty(Property.RRULE);
848 
849         if (rrule != null) {
850             repeating = true;
851             recurrence = toRecurrence(
852                 rrule.getRecur(), timeZone, startDate);
853 
854             if (recurrence.getUntil() != null) {
855                 endDate = recurrence.getUntil();
856             }
857         }
858 
859         String remindBy = "none";
860         int firstReminder = 300000;
861         int secondReminder = 300000;
862 
863         boolean addCommunityPermissions = false;
864         boolean addGuestPermissions = false;
865 
866         addEvent(
867             userId, plid, title, description, startDate.get(Calendar.MONTH),
868             startDate.get(Calendar.DAY_OF_MONTH),
869             startDate.get(Calendar.YEAR),
870             startDate.get(Calendar.HOUR_OF_DAY),
871             startDate.get(Calendar.MINUTE), endDate.get(Calendar.MONTH),
872             endDate.get(Calendar.DAY_OF_MONTH), endDate.get(Calendar.YEAR),
873             (int)durationHours, (int)durationMins, allDay,
874             timeZoneSensitive, type, repeating, recurrence, remindBy,
875             firstReminder, secondReminder, addCommunityPermissions,
876             addGuestPermissions);
877 
878     }
879 
880     protected void remindUser(CalEvent event, User user) {
881         String remindBy = event.getRemindBy();
882 
883         if (remindBy.equals(CalEventImpl.REMIND_BY_NONE)) {
884             return;
885         }
886 
887         try {
888             long ownerId = event.getGroupId();
889             int ownerType = PortletKeys.PREFS_OWNER_TYPE_GROUP;
890             long plid = PortletKeys.PREFS_PLID_SHARED;
891             String portletId = PortletKeys.CALENDAR;
892 
893             PortletPreferences prefs =
894                 portletPreferencesLocalService.getPreferences(
895                     event.getCompanyId(), ownerId, ownerType, plid, portletId);
896 
897             Company company = companyPersistence.findByPrimaryKey(
898                 user.getCompanyId());
899 
900             Contact contact = user.getContact();
901 
902             String portletName = PortalUtil.getPortletTitle(
903                 PortletKeys.CALENDAR, user);
904 
905             String fromName = CalUtil.getEmailFromName(prefs);
906             String fromAddress = CalUtil.getEmailFromAddress(prefs);
907 
908             String toName = user.getFullName();
909             String toAddress = user.getEmailAddress();
910 
911             if (remindBy.equals(CalEventImpl.REMIND_BY_SMS)) {
912                 toAddress = contact.getSmsSn();
913             }
914 
915             String subject = CalUtil.getEmailEventReminderSubject(prefs);
916             String body = CalUtil.getEmailEventReminderBody(prefs);
917 
918             DateFormat dateFormatDateTime = DateFormats.getDateTime(
919                 user.getLocale(), user.getTimeZone());
920 
921             subject = StringUtil.replace(
922                 subject,
923                 new String[] {
924                     "[$EVENT_START_DATE$]",
925                     "[$EVENT_TITLE$]",
926                     "[$FROM_ADDRESS$]",
927                     "[$FROM_NAME$]",
928                     "[$PORTAL_URL$]",
929                     "[$PORTLET_NAME$]",
930                     "[$TO_ADDRESS$]",
931                     "[$TO_NAME$]"
932                 },
933                 new String[] {
934                     dateFormatDateTime.format(event.getStartDate()),
935                     event.getTitle(),
936                     fromAddress,
937                     fromName,
938                     company.getVirtualHost(),
939                     portletName,
940                     toAddress,
941                     toName,
942                 });
943 
944             body = StringUtil.replace(
945                 body,
946                 new String[] {
947                     "[$EVENT_START_DATE$]",
948                     "[$EVENT_TITLE$]",
949                     "[$FROM_ADDRESS$]",
950                     "[$FROM_NAME$]",
951                     "[$PORTAL_URL$]",
952                     "[$PORTLET_NAME$]",
953                     "[$TO_ADDRESS$]",
954                     "[$TO_NAME$]"
955                 },
956                 new String[] {
957                     dateFormatDateTime.format(event.getStartDate()),
958                     event.getTitle(),
959                     fromAddress,
960                     fromName,
961                     company.getVirtualHost(),
962                     portletName,
963                     toAddress,
964                     toName,
965                 });
966 
967             if (remindBy.equals(CalEventImpl.REMIND_BY_EMAIL) ||
968                 remindBy.equals(CalEventImpl.REMIND_BY_SMS)) {
969 
970                 InternetAddress from = new InternetAddress(
971                     fromAddress, fromName);
972 
973                 InternetAddress to = new InternetAddress(toAddress, toName);
974 
975                 MailMessage message = new MailMessage(
976                     from, to, subject, body, true);
977 
978                 mailService.sendEmail(message);
979             }
980             else if (remindBy.equals(CalEventImpl.REMIND_BY_AIM) &&
981                      Validator.isNotNull(contact.getAimSn())) {
982 
983                 AIMConnector.send(contact.getAimSn(), body);
984             }
985             else if (remindBy.equals(CalEventImpl.REMIND_BY_ICQ) &&
986                      Validator.isNotNull(contact.getIcqSn())) {
987 
988                 ICQConnector.send(contact.getIcqSn(), body);
989             }
990             else if (remindBy.equals(CalEventImpl.REMIND_BY_MSN) &&
991                      Validator.isNotNull(contact.getMsnSn())) {
992 
993                 MSNConnector.send(contact.getMsnSn(), body);
994             }
995             else if (remindBy.equals(CalEventImpl.REMIND_BY_YM) &&
996                      Validator.isNotNull(contact.getYmSn())) {
997 
998                 YMConnector.send(contact.getYmSn(), body);
999             }
1000        }
1001        catch (Exception e) {
1002            _log.error(e);
1003        }
1004    }
1005
1006    protected int toCalendarWeekDay(WeekDay weekDay) {
1007        int dayOfWeeek = 0;
1008
1009        if (weekDay.getDay().equals(WeekDay.SU.getDay())) {
1010            dayOfWeeek = Calendar.SUNDAY;
1011        }
1012        else if (weekDay.getDay().equals(WeekDay.MO.getDay())) {
1013            dayOfWeeek = Calendar.MONDAY;
1014        }
1015        else if (weekDay.getDay().equals(WeekDay.TU.getDay())) {
1016            dayOfWeeek = Calendar.TUESDAY;
1017        }
1018        else if (weekDay.getDay().equals(WeekDay.WE.getDay())) {
1019            dayOfWeeek = Calendar.WEDNESDAY;
1020        }
1021        else if (weekDay.getDay().equals(WeekDay.TH.getDay())) {
1022            dayOfWeeek = Calendar.THURSDAY;
1023        }
1024        else if (weekDay.getDay().equals(WeekDay.FR.getDay())) {
1025            dayOfWeeek = Calendar.FRIDAY;
1026        }
1027        else if (weekDay.getDay().equals(WeekDay.SA.getDay())) {
1028            dayOfWeeek = Calendar.SATURDAY;
1029        }
1030
1031        return dayOfWeeek;
1032    }
1033
1034    protected net.fortuna.ical4j.model.Calendar toICalCalendar(
1035        long userId, List events)
1036        throws PortalException, SystemException {
1037
1038        net.fortuna.ical4j.model.Calendar iCal =
1039            new net.fortuna.ical4j.model.Calendar();
1040
1041        ProdId prodId = new ProdId(
1042            "-//Liferay Inc//Liferay Portal " + ReleaseInfo.getVersion() +
1043            "//EN");
1044
1045        PropertyList props = iCal.getProperties();
1046
1047        props.add(prodId);
1048        props.add(Version.VERSION_2_0);
1049        props.add(CalScale.GREGORIAN);
1050
1051        User user = userPersistence.findByPrimaryKey(userId);
1052        TimeZone timeZone = user.getTimeZone();
1053
1054        List components = iCal.getComponents();
1055
1056        Iterator itr = events.iterator();
1057
1058        while (itr.hasNext()) {
1059            CalEvent event = (CalEvent)itr.next();
1060
1061            components.add(toICalVEvent(event, timeZone));
1062        }
1063
1064        return iCal;
1065    }
1066
1067    protected Recur toICalRecurrence(Recurrence recurrence) {
1068        Recur recur = null;
1069
1070        int recurrenceType = recurrence.getFrequency();
1071
1072        int interval = recurrence.getInterval();
1073
1074        if (recurrenceType == Recurrence.DAILY) {
1075            recur = new Recur(Recur.DAILY, -1);
1076
1077            if (interval >= 1) {
1078                recur.setInterval(interval);
1079            }
1080
1081            DayAndPosition[] byDay = recurrence.getByDay();
1082
1083            if (byDay != null) {
1084                for (int i = 0; i < byDay.length; i++) {
1085                    WeekDay weekDay = toICalWeekDay(byDay[i].getDayOfWeek());
1086
1087                    recur.getDayList().add(weekDay);
1088                }
1089            }
1090
1091        }
1092        else if (recurrenceType == Recurrence.WEEKLY) {
1093            recur = new Recur(Recur.WEEKLY, -1);
1094
1095            recur.setInterval(interval);
1096
1097            DayAndPosition[] byDay = recurrence.getByDay();
1098
1099            if (byDay != null) {
1100                for (int i = 0; i < byDay.length; i++) {
1101                    WeekDay weekDay = toICalWeekDay(byDay[i].getDayOfWeek());
1102
1103                    recur.getDayList().add(weekDay);
1104                }
1105            }
1106        }
1107        else if (recurrenceType == Recurrence.MONTHLY) {
1108            recur = new Recur(Recur.MONTHLY, -1);
1109
1110            recur.setInterval(interval);
1111
1112            int[] byMonthDay = recurrence.getByMonthDay();
1113
1114            if (byMonthDay != null) {
1115                Integer monthDay = new Integer(byMonthDay[0]);
1116
1117                recur.getMonthDayList().add(monthDay);
1118            }
1119            else if (recurrence.getByDay() != null){
1120                DayAndPosition[] byDay = recurrence.getByDay();
1121
1122                WeekDay weekDay = toICalWeekDay(byDay[0].getDayOfWeek());
1123
1124                recur.getDayList().add(weekDay);
1125
1126                Integer position = new Integer(byDay[0].getDayPosition());
1127
1128                recur.getSetPosList().add(position);
1129            }
1130        }
1131        else if (recurrenceType == Recurrence.YEARLY) {
1132            recur = new Recur(Recur.YEARLY, -1);
1133
1134            recur.setInterval(interval);
1135        }
1136
1137        Calendar until = recurrence.getUntil();
1138
1139        if (until != null) {
1140            DateTime dateTime = new DateTime(until.getTime());
1141
1142            recur.setUntil(dateTime);
1143        }
1144
1145        return recur;
1146    }
1147
1148    protected VEvent toICalVEvent(CalEvent event, TimeZone timeZone){
1149        VEvent vEvent = new VEvent();
1150
1151        PropertyList eventProps = vEvent.getProperties();
1152
1153        // UID
1154
1155        Uid uid = new Uid(PortalUUIDUtil.generate());
1156
1157        eventProps.add(uid);
1158
1159        DtStart dtStart = new DtStart(new DateTime(event.getStartDate()));
1160
1161        eventProps.add(dtStart);
1162
1163        // Duration
1164
1165        Calendar cal = Calendar.getInstance();
1166
1167        Date start = cal.getTime();
1168
1169        cal.add(Calendar.HOUR, event.getDurationHour());
1170        cal.add(Calendar.MINUTE, event.getDurationHour());
1171
1172        Date end = cal.getTime();
1173
1174        Duration duration = new Duration(start, end);
1175
1176        eventProps.add(duration);
1177
1178        // Summary
1179
1180        Summary summary = new Summary(event.getTitle());
1181
1182        eventProps.add(summary);
1183
1184        // Description
1185
1186        Description description = new Description(event.getDescription());
1187
1188        eventProps.add(description);
1189
1190        // Comment
1191
1192        Comment comment = new Comment(event.getType());
1193
1194        eventProps.add(comment);
1195
1196        // Recurrence rule
1197
1198        if (event.isRepeating()) {
1199            Recur recur = toICalRecurrence(event.getRecurrenceObj());
1200
1201            RRule rRule = new RRule(recur);
1202
1203            eventProps.add(rRule);
1204        }
1205
1206        return vEvent;
1207    }
1208
1209    protected WeekDay toICalWeekDay(int dayOfWeek) {
1210        WeekDay weekDay = null;
1211
1212        if (dayOfWeek == Calendar.SUNDAY) {
1213            weekDay = WeekDay.SU;
1214        }
1215        else if (dayOfWeek == Calendar.MONDAY) {
1216            weekDay = WeekDay.MO;
1217        }
1218        else if (dayOfWeek == Calendar.TUESDAY) {
1219            weekDay = WeekDay.TU;
1220        }
1221        else if (dayOfWeek == Calendar.WEDNESDAY) {
1222            weekDay = WeekDay.WE;
1223        }
1224        else if (dayOfWeek == Calendar.THURSDAY) {
1225            weekDay = WeekDay.TH;
1226        }
1227        else if (dayOfWeek == Calendar.FRIDAY) {
1228            weekDay = WeekDay.FR;
1229        }
1230        else if (dayOfWeek == Calendar.SATURDAY) {
1231            weekDay = WeekDay.SA;
1232        }
1233
1234        return weekDay;
1235    }
1236
1237    protected TimeZone toTimeZone(long userId, VTimeZone vTimeZone)
1238        throws SystemException, NoSuchUserException {
1239
1240        User user = userPersistence.findByPrimaryKey(userId);
1241
1242        TimeZone timeZone = user.getTimeZone();
1243
1244        timeZone = TimeZone.getTimeZone(
1245            vTimeZone.getTimeZoneId().getValue());
1246
1247        return timeZone;
1248    }
1249
1250    protected Recurrence toRecurrence(
1251        Recur recur, TimeZone timeZone, Calendar startDate) {
1252
1253        Calendar recStartCal = CalendarFactoryUtil.getCalendar(timeZone);
1254
1255        recStartCal.setTime(startDate.getTime());
1256
1257        Recurrence recurrence = new Recurrence(
1258            recStartCal,
1259            new com.liferay.portal.kernel.cal.Duration(1, 0, 0, 0));
1260
1261        recurrence.setWeekStart(Calendar.SUNDAY);
1262
1263        if (recur.getInterval() > 1){
1264            recurrence.setInterval(recur.getInterval());
1265        }
1266
1267        Calendar until = Calendar.getInstance(timeZone);
1268
1269        if (recur.getUntil() != null) {
1270            until.setTime(recur.getUntil());
1271
1272            recurrence.setUntil(until);
1273        }
1274
1275        String frequency = recur.getFrequency();
1276
1277        if (Recur.DAILY.equals(frequency)) {
1278            recurrence.setFrequency(Recurrence.DAILY);
1279
1280            List dayPosList = new ArrayList();
1281
1282            Iterator itr = recur.getDayList().iterator();
1283
1284            while (itr.hasNext()) {
1285                WeekDay weekDay = (WeekDay)itr.next();
1286
1287                dayPosList.add(
1288                    new DayAndPosition(toCalendarWeekDay(weekDay), 0));
1289            }
1290
1291            if (!dayPosList.isEmpty()) {
1292                recurrence.setByDay(
1293                    (DayAndPosition[])dayPosList.toArray(
1294                        new DayAndPosition[0]));
1295            }
1296        }
1297        else if (Recur.WEEKLY.equals(frequency)) {
1298            recurrence.setFrequency(Recurrence.WEEKLY);
1299
1300            List dayPosList = new ArrayList();
1301
1302            Iterator itr = recur.getDayList().iterator();
1303
1304            while (itr.hasNext()) {
1305                WeekDay weekDay = (WeekDay)itr.next();
1306
1307                dayPosList.add(
1308                    new DayAndPosition(toCalendarWeekDay(weekDay), 0));
1309            }
1310
1311            if (!dayPosList.isEmpty()) {
1312                recurrence.setByDay(
1313                    (DayAndPosition[])dayPosList.toArray(
1314                        new DayAndPosition[0]));
1315            }
1316        }
1317        else if (Recur.MONTHLY.equals(frequency)) {
1318            recurrence.setFrequency(Recurrence.MONTHLY);
1319
1320            Iterator itr = recur.getMonthDayList().iterator();
1321
1322            if (itr.hasNext()) {
1323                Integer monthDay = (Integer)itr.next();
1324
1325                recurrence.setByMonthDay(new int[] {monthDay.intValue()});
1326            }
1327
1328            itr = recur.getDayList().iterator();
1329
1330            if (itr.hasNext()) {
1331                WeekDay weekDay = (WeekDay)itr.next();
1332
1333                DayAndPosition[] dayPos = {
1334                    new DayAndPosition(toCalendarWeekDay(weekDay),
1335                    weekDay.getOffset())
1336                };
1337
1338                recurrence.setByDay(dayPos);
1339            }
1340        }
1341        else if (Recur.YEARLY.equals(frequency)) {
1342            recurrence.setFrequency(Recurrence.YEARLY);
1343        }
1344
1345        return recurrence;
1346    }
1347
1348    protected void validate(
1349            String title, int startDateMonth, int startDateDay,
1350            int startDateYear, int endDateMonth, int endDateDay,
1351            int endDateYear, int durationHour, int durationMinute,
1352            boolean allDay)
1353        throws PortalException, SystemException {
1354
1355        if (Validator.isNull(title)) {
1356            throw new EventTitleException();
1357        }
1358        else if (!Validator.isDate(
1359                startDateMonth, startDateDay, startDateYear)) {
1360
1361            throw new EventStartDateException();
1362        }
1363        else if (!Validator.isDate(endDateMonth, endDateDay, endDateYear)) {
1364            throw new EventEndDateException();
1365        }
1366
1367        if (!allDay && durationHour <= 0 && durationMinute <= 0) {
1368            throw new EventDurationException();
1369        }
1370
1371        Calendar startDate = CalendarFactoryUtil.getCalendar(
1372            startDateYear, startDateMonth, startDateDay);
1373
1374        Calendar endDate = CalendarFactoryUtil.getCalendar(
1375            endDateYear, endDateMonth, endDateDay);
1376
1377        if (startDate.after(endDate)) {
1378            throw new EventEndDateException();
1379        }
1380    }
1381
1382    private static Log _log = LogFactory.getLog(CalEventLocalServiceImpl.class);
1383
1384}