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