1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portlet.calendar.service.impl;
16  
17  import com.liferay.portal.im.AIMConnector;
18  import com.liferay.portal.im.ICQConnector;
19  import com.liferay.portal.im.MSNConnector;
20  import com.liferay.portal.im.YMConnector;
21  import com.liferay.portal.kernel.cal.DayAndPosition;
22  import com.liferay.portal.kernel.cal.Recurrence;
23  import com.liferay.portal.kernel.cal.TZSRecurrence;
24  import com.liferay.portal.kernel.exception.PortalException;
25  import com.liferay.portal.kernel.exception.SystemException;
26  import com.liferay.portal.kernel.io.unsync.UnsyncBufferedOutputStream;
27  import com.liferay.portal.kernel.log.Log;
28  import com.liferay.portal.kernel.log.LogFactoryUtil;
29  import com.liferay.portal.kernel.mail.MailMessage;
30  import com.liferay.portal.kernel.search.Indexer;
31  import com.liferay.portal.kernel.search.IndexerRegistryUtil;
32  import com.liferay.portal.kernel.util.ArrayUtil;
33  import com.liferay.portal.kernel.util.CalendarFactoryUtil;
34  import com.liferay.portal.kernel.util.CalendarUtil;
35  import com.liferay.portal.kernel.util.ContentTypes;
36  import com.liferay.portal.kernel.util.FastDateFormatFactoryUtil;
37  import com.liferay.portal.kernel.util.LocaleUtil;
38  import com.liferay.portal.kernel.util.ReleaseInfo;
39  import com.liferay.portal.kernel.util.StreamUtil;
40  import com.liferay.portal.kernel.util.StringPool;
41  import com.liferay.portal.kernel.util.StringUtil;
42  import com.liferay.portal.kernel.util.Time;
43  import com.liferay.portal.kernel.util.TimeZoneUtil;
44  import com.liferay.portal.kernel.util.UnmodifiableList;
45  import com.liferay.portal.kernel.util.Validator;
46  import com.liferay.portal.kernel.uuid.PortalUUIDUtil;
47  import com.liferay.portal.model.Company;
48  import com.liferay.portal.model.Contact;
49  import com.liferay.portal.model.ModelHintsUtil;
50  import com.liferay.portal.model.ResourceConstants;
51  import com.liferay.portal.model.User;
52  import com.liferay.portal.service.ServiceContext;
53  import com.liferay.portal.util.PortalUtil;
54  import com.liferay.portal.util.PortletKeys;
55  import com.liferay.portal.util.PropsValues;
56  import com.liferay.portlet.calendar.EventDurationException;
57  import com.liferay.portlet.calendar.EventEndDateException;
58  import com.liferay.portlet.calendar.EventStartDateException;
59  import com.liferay.portlet.calendar.EventTitleException;
60  import com.liferay.portlet.calendar.model.CalEvent;
61  import com.liferay.portlet.calendar.model.CalEventConstants;
62  import com.liferay.portlet.calendar.service.base.CalEventLocalServiceBaseImpl;
63  import com.liferay.portlet.calendar.social.CalendarActivityKeys;
64  import com.liferay.portlet.calendar.util.CalUtil;
65  import com.liferay.util.TimeZoneSensitive;
66  
67  import java.io.File;
68  import java.io.FileOutputStream;
69  import java.io.FileReader;
70  import java.io.IOException;
71  import java.io.OutputStream;
72  
73  import java.text.Format;
74  
75  import java.util.ArrayList;
76  import java.util.Calendar;
77  import java.util.Date;
78  import java.util.Iterator;
79  import java.util.List;
80  import java.util.Locale;
81  import java.util.Map;
82  import java.util.TimeZone;
83  
84  import javax.mail.internet.InternetAddress;
85  
86  import javax.portlet.PortletPreferences;
87  
88  import net.fortuna.ical4j.data.CalendarBuilder;
89  import net.fortuna.ical4j.data.CalendarOutputter;
90  import net.fortuna.ical4j.data.ParserException;
91  import net.fortuna.ical4j.model.Component;
92  import net.fortuna.ical4j.model.DateTime;
93  import net.fortuna.ical4j.model.Dur;
94  import net.fortuna.ical4j.model.Parameter;
95  import net.fortuna.ical4j.model.Property;
96  import net.fortuna.ical4j.model.PropertyList;
97  import net.fortuna.ical4j.model.Recur;
98  import net.fortuna.ical4j.model.WeekDay;
99  import net.fortuna.ical4j.model.component.VEvent;
100 import net.fortuna.ical4j.model.parameter.Value;
101 import net.fortuna.ical4j.model.property.CalScale;
102 import net.fortuna.ical4j.model.property.Comment;
103 import net.fortuna.ical4j.model.property.DateProperty;
104 import net.fortuna.ical4j.model.property.Description;
105 import net.fortuna.ical4j.model.property.DtEnd;
106 import net.fortuna.ical4j.model.property.DtStart;
107 import net.fortuna.ical4j.model.property.Duration;
108 import net.fortuna.ical4j.model.property.Method;
109 import net.fortuna.ical4j.model.property.ProdId;
110 import net.fortuna.ical4j.model.property.RRule;
111 import net.fortuna.ical4j.model.property.Summary;
112 import net.fortuna.ical4j.model.property.Uid;
113 import net.fortuna.ical4j.model.property.Version;
114 
115 /**
116  * <a href="CalEventLocalServiceImpl.java.html"><b><i>View Source</i></b></a>
117  *
118  * @author Brian Wing Shun Chan
119  * @author Bruno Farache
120  * @author Samuel Kong
121  * @author Ganesh Ram
122  * @author Brett Swaim
123  */
124 public class CalEventLocalServiceImpl extends CalEventLocalServiceBaseImpl {
125 
126     public CalEvent addEvent(
127             String uuid, long userId, String title, String description,
128             int startDateMonth, int startDateDay, int startDateYear,
129             int startDateHour, int startDateMinute, int endDateMonth,
130             int endDateDay, int endDateYear, int durationHour,
131             int durationMinute, boolean allDay, boolean timeZoneSensitive,
132             String type, boolean repeating, TZSRecurrence recurrence,
133             int remindBy, int firstReminder, int secondReminder,
134             ServiceContext serviceContext)
135         throws PortalException, SystemException {
136 
137         // Event
138 
139         User user = userPersistence.findByPrimaryKey(userId);
140         long groupId = serviceContext.getScopeGroupId();
141         Date now = new Date();
142 
143         Locale locale = null;
144         TimeZone timeZone = null;
145 
146         if (timeZoneSensitive) {
147             locale = user.getLocale();
148             timeZone = user.getTimeZone();
149         }
150         else {
151             locale = LocaleUtil.getDefault();
152             timeZone = TimeZoneUtil.getDefault();
153         }
154 
155         Calendar startDate = CalendarFactoryUtil.getCalendar(timeZone, locale);
156 
157         startDate.set(Calendar.MONTH, startDateMonth);
158         startDate.set(Calendar.DATE, startDateDay);
159         startDate.set(Calendar.YEAR, startDateYear);
160         startDate.set(Calendar.HOUR_OF_DAY, startDateHour);
161         startDate.set(Calendar.MINUTE, startDateMinute);
162         startDate.set(Calendar.SECOND, 0);
163         startDate.set(Calendar.MILLISECOND, 0);
164 
165         Calendar endDate = CalendarFactoryUtil.getCalendar(timeZone, locale);
166 
167         endDate.set(Calendar.MONTH, endDateMonth);
168         endDate.set(Calendar.DATE, endDateDay);
169         endDate.set(Calendar.YEAR, endDateYear);
170         endDate.set(Calendar.HOUR_OF_DAY, 23);
171         endDate.set(Calendar.MINUTE, 59);
172         endDate.set(Calendar.SECOND, 59);
173         endDate.set(Calendar.MILLISECOND, 990);
174 
175         if (allDay) {
176             startDate.set(Calendar.HOUR_OF_DAY, 0);
177             startDate.set(Calendar.MINUTE, 0);
178 
179             durationHour = 24;
180             durationMinute = 0;
181         }
182 
183         validate(
184             title, startDateMonth, startDateDay, startDateYear, endDateMonth,
185             endDateDay, endDateYear, durationHour, durationMinute, allDay,
186             repeating, recurrence);
187 
188         long eventId = counterLocalService.increment();
189 
190         CalEvent event = calEventPersistence.create(eventId);
191 
192         event.setUuid(uuid);
193         event.setGroupId(groupId);
194         event.setCompanyId(user.getCompanyId());
195         event.setUserId(user.getUserId());
196         event.setUserName(user.getFullName());
197         event.setCreateDate(serviceContext.getCreateDate(now));
198         event.setModifiedDate(serviceContext.getModifiedDate(now));
199         event.setTitle(title);
200         event.setDescription(description);
201         event.setStartDate(startDate.getTime());
202         event.setEndDate(endDate.getTime());
203         event.setDurationHour(durationHour);
204         event.setDurationMinute(durationMinute);
205         event.setAllDay(allDay);
206         event.setTimeZoneSensitive(timeZoneSensitive);
207         event.setType(type);
208         event.setRepeating(repeating);
209         event.setRecurrenceObj(recurrence);
210         event.setRemindBy(remindBy);
211         event.setFirstReminder(firstReminder);
212         event.setSecondReminder(secondReminder);
213         event.setExpandoBridgeAttributes(serviceContext);
214 
215         calEventPersistence.update(event, false);
216 
217         // Resources
218 
219         if (serviceContext.getAddCommunityPermissions() ||
220             serviceContext.getAddGuestPermissions()) {
221 
222             addEventResources(
223                 event, serviceContext.getAddCommunityPermissions(),
224                 serviceContext.getAddGuestPermissions());
225         }
226         else {
227             addEventResources(
228                 event, serviceContext.getCommunityPermissions(),
229                 serviceContext.getGuestPermissions());
230         }
231 
232         // Asset
233 
234         updateAsset(
235             userId, event, serviceContext.getAssetCategoryIds(),
236             serviceContext.getAssetTagNames());
237 
238         // Social
239 
240         socialActivityLocalService.addActivity(
241             userId, groupId, CalEvent.class.getName(), eventId,
242             CalendarActivityKeys.ADD_EVENT, StringPool.BLANK, 0);
243 
244         // Indexer
245 
246         Indexer indexer = IndexerRegistryUtil.getIndexer(CalEvent.class);
247 
248         indexer.reindex(event);
249 
250         // Pool
251 
252         CalEventLocalUtil.clearEventsPool(event.getGroupId());
253 
254         return event;
255     }
256 
257     public void addEventResources(
258             CalEvent event, boolean addCommunityPermissions,
259             boolean addGuestPermissions)
260         throws PortalException, SystemException {
261 
262         resourceLocalService.addResources(
263             event.getCompanyId(), event.getGroupId(), event.getUserId(),
264             CalEvent.class.getName(), event.getEventId(), false,
265             addCommunityPermissions, addGuestPermissions);
266     }
267 
268     public void addEventResources(
269             CalEvent event, String[] communityPermissions,
270             String[] guestPermissions)
271         throws PortalException, SystemException {
272 
273         resourceLocalService.addModelResources(
274             event.getCompanyId(), event.getGroupId(), event.getUserId(),
275             CalEvent.class.getName(), event.getEventId(), communityPermissions,
276             guestPermissions);
277     }
278 
279     public void addEventResources(
280             long eventId, boolean addCommunityPermissions,
281             boolean addGuestPermissions)
282         throws PortalException, SystemException {
283 
284         CalEvent event = calEventPersistence.findByPrimaryKey(eventId);
285 
286         addEventResources(
287             event, addCommunityPermissions, addGuestPermissions);
288     }
289 
290     public void addEventResources(
291             long eventId, String[] communityPermissions,
292             String[] guestPermissions)
293         throws PortalException, SystemException {
294 
295         CalEvent event = calEventPersistence.findByPrimaryKey(eventId);
296 
297         addEventResources(event, communityPermissions, guestPermissions);
298     }
299 
300     public void checkEvents() throws PortalException, SystemException {
301         Iterator<CalEvent> itr = calEventPersistence.findByRemindBy(
302             CalEventConstants.REMIND_BY_NONE).iterator();
303 
304         while (itr.hasNext()) {
305             CalEvent event = itr.next();
306 
307             User user = userPersistence.fetchByPrimaryKey(event.getUserId());
308 
309             if (user == null) {
310                 deleteEvent(event);
311 
312                 continue;
313             }
314 
315             Calendar now = CalendarFactoryUtil.getCalendar(
316                 user.getTimeZone(), user.getLocale());
317 
318             if (!event.isTimeZoneSensitive()) {
319                 Calendar temp = CalendarFactoryUtil.getCalendar();
320 
321                 temp.setTime(Time.getDate(now));
322 
323                 now = temp;
324             }
325 
326             Calendar startDate = null;
327 
328             if (event.isTimeZoneSensitive()) {
329                 startDate = CalendarFactoryUtil.getCalendar(
330                     user.getTimeZone(), user.getLocale());
331             }
332             else {
333                 startDate = CalendarFactoryUtil.getCalendar();
334             }
335 
336             if (event.isRepeating()) {
337                 double daysToCheck = Math.ceil(
338                     CalEventConstants.REMINDERS[
339                         CalEventConstants.REMINDERS.length - 1] /
340                     Time.DAY);
341 
342                 Calendar cal = (Calendar)now.clone();
343 
344                 for (int i = 0; i <= daysToCheck; i++) {
345                     Recurrence recurrence = event.getRecurrenceObj();
346 
347                     Calendar tzICal = CalendarFactoryUtil.getCalendar(
348                         cal.get(Calendar.YEAR), cal.get(Calendar.MONTH),
349                         cal.get(Calendar.DATE));
350 
351                     Calendar recurrenceCal = getRecurrenceCal(
352                         cal, tzICal, event);
353 
354                     if (recurrence.isInRecurrence(recurrenceCal)) {
355                         remindUser(event, user, recurrenceCal, now);
356                     }
357 
358                     cal.add(Calendar.DAY_OF_YEAR, 1);
359                 }
360             }
361             else {
362                 startDate.setTime(event.getStartDate());
363 
364                 remindUser(event, user, startDate, now);
365             }
366         }
367     }
368 
369     public void deleteEvent(CalEvent event)
370         throws PortalException, SystemException {
371 
372         // Event
373 
374         calEventPersistence.remove(event);
375 
376         // Resources
377 
378         resourceLocalService.deleteResource(
379             event.getCompanyId(), CalEvent.class.getName(),
380             ResourceConstants.SCOPE_INDIVIDUAL, event.getEventId());
381 
382         // Asset
383 
384         assetEntryLocalService.deleteEntry(
385             CalEvent.class.getName(), event.getEventId());
386 
387         // Expando
388 
389         expandoValueLocalService.deleteValues(
390             CalEvent.class.getName(), event.getEventId());
391 
392         // Social
393 
394         socialActivityLocalService.deleteActivities(
395             CalEvent.class.getName(), event.getEventId());
396 
397         // Indexer
398 
399         Indexer indexer = IndexerRegistryUtil.getIndexer(CalEvent.class);
400 
401         indexer.delete(event);
402 
403         // Pool
404 
405         CalEventLocalUtil.clearEventsPool(event.getGroupId());
406     }
407 
408     public void deleteEvent(long eventId)
409         throws PortalException, SystemException {
410 
411         CalEvent event = calEventPersistence.findByPrimaryKey(eventId);
412 
413         deleteEvent(event);
414     }
415 
416     public void deleteEvents(long groupId)
417         throws PortalException, SystemException {
418 
419         Iterator<CalEvent> itr = calEventPersistence.findByGroupId(
420             groupId).iterator();
421 
422         while (itr.hasNext()) {
423             CalEvent event = itr.next();
424 
425             deleteEvent(event);
426         }
427     }
428 
429     public File exportEvent(long userId, long eventId)
430         throws PortalException, SystemException {
431 
432         List<CalEvent> events = new ArrayList<CalEvent>();
433 
434         CalEvent event = calEventPersistence.findByPrimaryKey(eventId);
435 
436         events.add(event);
437 
438         return exportICal4j(toICalCalendar(userId, events), null);
439     }
440 
441     public File exportGroupEvents(long userId, long groupId, String fileName)
442         throws PortalException, SystemException {
443 
444         List<CalEvent> events = calEventPersistence.findByGroupId(groupId);
445 
446         return exportICal4j(toICalCalendar(userId, events), fileName);
447     }
448 
449     public List<CalEvent> getCompanyEvents(long companyId, int start, int end)
450         throws SystemException {
451 
452         return calEventPersistence.findByCompanyId(companyId, start, end);
453     }
454 
455     public int getCompanyEventsCount(long companyId) throws SystemException {
456         return calEventPersistence.countByCompanyId(companyId);
457     }
458 
459     public CalEvent getEvent(long eventId)
460         throws PortalException, SystemException {
461 
462         return calEventPersistence.findByPrimaryKey(eventId);
463     }
464 
465     public List<CalEvent> getEvents(long groupId, Calendar cal)
466         throws SystemException {
467 
468         Map<String, List<CalEvent>> eventsPool =
469             CalEventLocalUtil.getEventsPool(groupId);
470 
471         String key = CalUtil.toString(cal);
472 
473         List<CalEvent> events = eventsPool.get(key);
474 
475         if (events == null) {
476 
477             // Time zone sensitive
478 
479             List<CalEvent> events1 = calEventFinder.findByG_SD(
480                 groupId, CalendarUtil.getGTDate(cal),
481                 CalendarUtil.getLTDate(cal), true);
482 
483             // Time zone insensitive
484 
485             Calendar tzICal = CalendarFactoryUtil.getCalendar(
486                 cal.get(Calendar.YEAR), cal.get(Calendar.MONTH),
487                 cal.get(Calendar.DATE));
488 
489             List<CalEvent> events2 = calEventFinder.findByG_SD(
490                 groupId, CalendarUtil.getGTDate(tzICal),
491                 CalendarUtil.getLTDate(tzICal), false);
492 
493             // Create new list
494 
495             events = new ArrayList<CalEvent>();
496 
497             events.addAll(events1);
498             events.addAll(events2);
499 
500             // Add repeating events
501 
502             Iterator<CalEvent> itr = getRepeatingEvents(groupId).iterator();
503 
504             while (itr.hasNext()) {
505                 CalEvent event = itr.next();
506 
507                 TZSRecurrence recurrence = event.getRecurrenceObj();
508 
509                 try {
510 
511                     // LEP-3468
512 
513                     if ((recurrence.getFrequency() !=
514                             Recurrence.NO_RECURRENCE) &&
515                         (recurrence.getInterval() <= 0)) {
516 
517                         recurrence.setInterval(1);
518 
519                         event.setRecurrenceObj(recurrence);
520 
521                         event = calEventPersistence.update(event, false);
522 
523                         recurrence = event.getRecurrenceObj();
524                     }
525 
526                     if (recurrence.isInRecurrence(
527                             getRecurrenceCal(cal, tzICal, event))) {
528 
529                         events.add(event);
530                     }
531                 }
532                 catch (Exception e) {
533                     _log.error(e.getMessage());
534                 }
535             }
536 
537             events = new UnmodifiableList<CalEvent>(events);
538 
539             eventsPool.put(key, events);
540         }
541 
542         return events;
543     }
544 
545     public List<CalEvent> getEvents(long groupId, Calendar cal, String type)
546         throws SystemException {
547 
548         List<CalEvent> events = getEvents(groupId, cal);
549 
550         if (Validator.isNull(type)) {
551             return events;
552         }
553         else {
554             events = new ArrayList<CalEvent>(events);
555 
556             Iterator<CalEvent> itr = events.iterator();
557 
558             while (itr.hasNext()) {
559                 CalEvent event = itr.next();
560 
561                 if (!event.getType().equals(type)) {
562                     itr.remove();
563                 }
564             }
565 
566             return events;
567         }
568     }
569 
570     public List<CalEvent> getEvents(
571             long groupId, String type, int start, int end)
572         throws SystemException {
573 
574         if (Validator.isNull(type)) {
575             return calEventPersistence.findByGroupId(groupId, start, end);
576         }
577         else {
578             return calEventPersistence.findByG_T(groupId, type, start, end);
579         }
580     }
581 
582     public int getEventsCount(long groupId, String type)
583         throws SystemException {
584 
585         if (Validator.isNull(type)) {
586             return calEventPersistence.countByGroupId(groupId);
587         }
588         else {
589             return calEventPersistence.countByG_T(groupId, type);
590         }
591     }
592 
593     public List<CalEvent> getNoAssetEvents() throws SystemException {
594         return calEventFinder.findByNoAssets();
595     }
596 
597     public List<CalEvent> getRepeatingEvents(long groupId)
598         throws SystemException {
599 
600         Map<String, List<CalEvent>> eventsPool =
601             CalEventLocalUtil.getEventsPool(groupId);
602 
603         String key = "recurrence";
604 
605         List<CalEvent> events = eventsPool.get(key);
606 
607         if (events == null) {
608             events = calEventPersistence.findByG_R(groupId, true);
609 
610             events = new UnmodifiableList<CalEvent>(events);
611 
612             eventsPool.put(key, events);
613         }
614 
615         return events;
616     }
617 
618     public boolean hasEvents(long groupId, Calendar cal)
619         throws SystemException {
620 
621         return hasEvents(groupId, cal, null);
622     }
623 
624     public boolean hasEvents(long groupId, Calendar cal, String type)
625         throws SystemException {
626 
627         if (getEvents(groupId, cal, type).size() > 0) {
628             return true;
629         }
630         else {
631             return false;
632         }
633     }
634 
635     public void importICal4j(long userId, long groupId, File file)
636         throws PortalException, SystemException {
637 
638         FileReader fileReader = null;
639 
640         try {
641             fileReader = new FileReader(file);
642 
643             CalendarBuilder builder = new CalendarBuilder();
644 
645             net.fortuna.ical4j.model.Calendar calendar = builder.build(
646                 fileReader);
647 
648             Iterator<VEvent> itr = calendar.getComponents(
649                 Component.VEVENT).iterator();
650 
651             while (itr.hasNext()) {
652                 VEvent vEvent = itr.next();
653 
654                 importICal4j(userId, groupId, vEvent);
655             }
656         }
657         catch (IOException ioe) {
658             throw new SystemException(ioe.getMessage());
659         }
660         catch (ParserException pe) {
661             throw new SystemException(pe.getMessage());
662         }
663         finally {
664             try {
665                 if (fileReader != null) {
666                     fileReader.close();
667                 }
668             }
669             catch (IOException ioe) {
670                 _log.error(ioe);
671             }
672         }
673     }
674 
675     public void updateAsset(
676             long userId, CalEvent event, long[] assetCategoryIds,
677             String[] assetTagNames)
678         throws PortalException, SystemException {
679 
680         assetEntryLocalService.updateEntry(
681             userId, event.getGroupId(), CalEvent.class.getName(),
682             event.getEventId(), assetCategoryIds, assetTagNames, true, null,
683             null, null, null, ContentTypes.TEXT_HTML, event.getTitle(),
684             event.getDescription(), null, null, 0, 0, null, false);
685     }
686 
687     public CalEvent updateEvent(
688             long userId, long eventId, String title, String description,
689             int startDateMonth, int startDateDay, int startDateYear,
690             int startDateHour, int startDateMinute, int endDateMonth,
691             int endDateDay, int endDateYear, int durationHour,
692             int durationMinute, boolean allDay, boolean timeZoneSensitive,
693             String type, boolean repeating, TZSRecurrence recurrence,
694             int remindBy, int firstReminder, int secondReminder,
695             ServiceContext serviceContext)
696         throws PortalException, SystemException {
697 
698         // Event
699 
700         User user = userPersistence.findByPrimaryKey(userId);
701 
702         Locale locale = null;
703         TimeZone timeZone = null;
704 
705         if (timeZoneSensitive) {
706             locale = user.getLocale();
707             timeZone = user.getTimeZone();
708         }
709         else {
710             locale = LocaleUtil.getDefault();
711             timeZone = TimeZoneUtil.getDefault();
712         }
713 
714         Calendar startDate = CalendarFactoryUtil.getCalendar(timeZone, locale);
715 
716         startDate.set(Calendar.MONTH, startDateMonth);
717         startDate.set(Calendar.DATE, startDateDay);
718         startDate.set(Calendar.YEAR, startDateYear);
719         startDate.set(Calendar.HOUR_OF_DAY, startDateHour);
720         startDate.set(Calendar.MINUTE, startDateMinute);
721         startDate.set(Calendar.SECOND, 0);
722         startDate.set(Calendar.MILLISECOND, 0);
723 
724         Calendar endDate = CalendarFactoryUtil.getCalendar(timeZone, locale);
725 
726         endDate.set(Calendar.MONTH, endDateMonth);
727         endDate.set(Calendar.DATE, endDateDay);
728         endDate.set(Calendar.YEAR, endDateYear);
729         endDate.set(Calendar.HOUR_OF_DAY, 23);
730         endDate.set(Calendar.MINUTE, 59);
731         endDate.set(Calendar.SECOND, 59);
732         endDate.set(Calendar.MILLISECOND, 990);
733 
734         if (allDay) {
735             startDate.set(Calendar.HOUR_OF_DAY, 0);
736             startDate.set(Calendar.MINUTE, 0);
737 
738             durationHour = 24;
739             durationMinute = 0;
740         }
741 
742         validate(
743             title, startDateMonth, startDateDay, startDateYear, endDateMonth,
744             endDateDay, endDateYear, durationHour, durationMinute, allDay,
745             repeating, recurrence);
746 
747         CalEvent event = calEventPersistence.findByPrimaryKey(eventId);
748 
749         event.setModifiedDate(serviceContext.getModifiedDate(null));
750         event.setTitle(title);
751         event.setDescription(description);
752         event.setStartDate(startDate.getTime());
753         event.setEndDate(endDate.getTime());
754         event.setDurationHour(durationHour);
755         event.setDurationMinute(durationMinute);
756         event.setAllDay(allDay);
757         event.setTimeZoneSensitive(timeZoneSensitive);
758         event.setType(type);
759         event.setRepeating(repeating);
760         event.setRecurrenceObj(recurrence);
761         event.setRemindBy(remindBy);
762         event.setFirstReminder(firstReminder);
763         event.setSecondReminder(secondReminder);
764         event.setExpandoBridgeAttributes(serviceContext);
765 
766         calEventPersistence.update(event, false);
767 
768         // Asset
769 
770         updateAsset(
771             userId, event, serviceContext.getAssetCategoryIds(),
772             serviceContext.getAssetTagNames());
773 
774         // Social
775 
776         socialActivityLocalService.addActivity(
777             userId, event.getGroupId(), CalEvent.class.getName(), eventId,
778             CalendarActivityKeys.UPDATE_EVENT, StringPool.BLANK, 0);
779 
780         // Indexer
781 
782         Indexer indexer = IndexerRegistryUtil.getIndexer(CalEvent.class);
783 
784         indexer.reindex(event);
785 
786         // Pool
787 
788         CalEventLocalUtil.clearEventsPool(event.getGroupId());
789 
790         return event;
791     }
792 
793     protected File exportICal4j(
794             net.fortuna.ical4j.model.Calendar cal, String fileName)
795         throws SystemException {
796 
797         OutputStream os = null;
798 
799         try {
800             String extension = ".ics";
801 
802             if (Validator.isNull(fileName)) {
803                 fileName = "liferay.";
804             }
805             else {
806                 int pos = fileName.lastIndexOf(StringPool.PERIOD);
807 
808                 if (pos != -1) {
809                     extension = fileName.substring(pos);
810                     fileName = fileName.substring(0, pos);
811                 }
812             }
813 
814             File file = File.createTempFile(fileName, extension);
815 
816             os = new UnsyncBufferedOutputStream(
817                 new FileOutputStream(file.getPath()));
818 
819             CalendarOutputter calOutput = new CalendarOutputter();
820 
821             if (cal.getComponents().isEmpty()) {
822                 calOutput.setValidating(false);
823             }
824 
825             calOutput.output(cal, os);
826 
827             return file;
828         }
829         catch (Exception e) {
830             _log.error(e, e);
831 
832             throw new SystemException(e);
833         }
834         finally {
835             StreamUtil.cleanUp(os);
836         }
837     }
838 
839     protected Calendar getRecurrenceCal(
840         Calendar cal, Calendar tzICal, CalEvent event) {
841 
842         Calendar eventCal = CalendarFactoryUtil.getCalendar();
843         eventCal.setTime(event.getStartDate());
844 
845         Calendar recurrenceCal = (Calendar)tzICal.clone();
846         recurrenceCal.set(
847             Calendar.HOUR_OF_DAY, eventCal.get(Calendar.HOUR_OF_DAY));
848         recurrenceCal.set(
849             Calendar.MINUTE, eventCal.get(Calendar.MINUTE));
850         recurrenceCal.set(Calendar.SECOND, 0);
851         recurrenceCal.set(Calendar.MILLISECOND, 0);
852 
853         if (event.isTimeZoneSensitive()) {
854             int gmtDate = eventCal.get(Calendar.DATE);
855             long gmtMills = eventCal.getTimeInMillis();
856 
857             eventCal.setTimeZone(cal.getTimeZone());
858 
859             int tziDate = eventCal.get(Calendar.DATE);
860             long tziMills = Time.getDate(eventCal).getTime();
861 
862             if (gmtDate != tziDate) {
863                 int diffDate = 0;
864 
865                 if (gmtMills > tziMills) {
866                     diffDate = (int)Math.ceil(
867                         (double)(gmtMills - tziMills) / Time.DAY);
868                 }
869                 else {
870                     diffDate = (int)Math.floor(
871                         (double)(gmtMills - tziMills) / Time.DAY);
872                 }
873 
874                 recurrenceCal.add(Calendar.DATE, diffDate);
875             }
876         }
877 
878         return recurrenceCal;
879     }
880 
881     protected void importICal4j(
882             long userId, long groupId, VEvent event)
883         throws PortalException, SystemException {
884 
885         User user = userPersistence.findByPrimaryKey(userId);
886 
887         TimeZone timeZone = user.getTimeZone();
888 
889         // X iCal property
890 
891         Property timeZoneXProperty = event.getProperty(
892             TimeZoneSensitive.PROPERTY_NAME);
893 
894         boolean timeZoneXPropertyValue = true;
895 
896         if (Validator.isNotNull(timeZoneXProperty) &&
897             timeZoneXProperty.getValue().equals("FALSE")) {
898 
899             timeZoneXPropertyValue = false;
900         }
901 
902         // Title
903 
904         String title = StringPool.BLANK;
905 
906         if (event.getSummary() != null) {
907             title = ModelHintsUtil.trimString(
908                 CalEvent.class.getName(), "title",
909                 event.getSummary().getValue());
910         }
911 
912         // Description
913 
914         String description = StringPool.BLANK;
915 
916         if (event.getDescription() != null) {
917             description = event.getDescription().getValue();
918         }
919 
920         // Start date
921 
922         DtStart dtStart = event.getStartDate();
923 
924         Calendar startDate = toCalendar(
925             dtStart, timeZone, timeZoneXPropertyValue);
926 
927         startDate.setTime(dtStart.getDate());
928 
929         // End date
930 
931         Calendar endDate = null;
932 
933         DtEnd dtEnd = event.getEndDate(true);
934 
935         RRule rrule = (RRule)event.getProperty(Property.RRULE);
936 
937         if (Validator.isNotNull(dtEnd)) {
938             endDate = toCalendar(dtEnd, timeZone, timeZoneXPropertyValue);
939 
940             endDate.setTime(dtEnd.getDate());
941         }
942         else {
943             endDate = (Calendar)startDate.clone();
944             endDate.add(Calendar.DATE, 1);
945         }
946 
947         // Duration
948 
949         long diffMillis = 0;
950         long durationHours = 24;
951         long durationMins = 0;
952         boolean multiDayEvent = false;
953 
954         if (Validator.isNotNull(dtEnd)) {
955             diffMillis =
956                 dtEnd.getDate().getTime() - startDate.getTimeInMillis();
957             durationHours = diffMillis / Time.HOUR;
958             durationMins = (diffMillis / Time.MINUTE) - (durationHours * 60);
959 
960             if ((durationHours > 24) ||
961                 ((durationHours == 24) && (durationMins > 0))) {
962 
963                 durationHours = 24;
964                 durationMins = 0;
965                 multiDayEvent = true;
966             }
967         }
968 
969         // All day
970 
971         boolean allDay = false;
972 
973         if (isICal4jDateOnly(event.getStartDate()) || multiDayEvent) {
974             allDay = true;
975         }
976 
977         // Time zone sensitive
978 
979         boolean timeZoneSensitive = true;
980 
981         if (allDay || !timeZoneXPropertyValue) {
982             timeZoneSensitive = false;
983         }
984 
985         // Type
986 
987         String type = StringPool.BLANK;
988 
989         Property comment = event.getProperty(Property.COMMENT);
990 
991         if (Validator.isNotNull(comment) &&
992             ArrayUtil.contains(CalEventConstants.TYPES, comment.getValue())) {
993 
994             type = comment.getValue();
995         }
996 
997         // Recurrence
998 
999         boolean repeating = false;
1000        TZSRecurrence recurrence = null;
1001
1002        if (multiDayEvent) {
1003            repeating = true;
1004
1005            Calendar recStartCal = CalendarFactoryUtil.getCalendar(timeZone);
1006
1007            recStartCal.setTime(startDate.getTime());
1008
1009            com.liferay.portal.kernel.cal.Duration duration =
1010                new com.liferay.portal.kernel.cal.Duration(1, 0, 0, 0);
1011
1012            recurrence = new TZSRecurrence(
1013                recStartCal, duration, Recurrence.DAILY);
1014
1015            Calendar until = (Calendar) startDate.clone();
1016
1017            until.setTimeInMillis(until.getTimeInMillis() + diffMillis);
1018
1019            recurrence.setUntil(until);
1020
1021            endDate = recurrence.getUntil();
1022        }
1023        else if (rrule != null) {
1024            repeating = true;
1025            recurrence = toRecurrence(rrule, timeZone, startDate);
1026
1027            if (recurrence.getUntil() != null) {
1028                endDate = recurrence.getUntil();
1029            }
1030        }
1031
1032        // Reminder
1033
1034        int remindBy = CalEventConstants.REMIND_BY_NONE;
1035        int firstReminder = 300000;
1036        int secondReminder = 300000;
1037
1038        // Permissions
1039
1040        ServiceContext serviceContext = new ServiceContext();
1041
1042        serviceContext.setAddCommunityPermissions(true);
1043        serviceContext.setAddGuestPermissions(true);
1044        serviceContext.setScopeGroupId(groupId);
1045
1046        addEvent(
1047            null, userId, title, description, startDate.get(Calendar.MONTH),
1048            startDate.get(Calendar.DAY_OF_MONTH), startDate.get(Calendar.YEAR),
1049            startDate.get(Calendar.HOUR_OF_DAY),
1050            startDate.get(Calendar.MINUTE), endDate.get(Calendar.MONTH),
1051            endDate.get(Calendar.DAY_OF_MONTH), endDate.get(Calendar.YEAR),
1052            (int)durationHours, (int)durationMins, allDay,
1053            timeZoneSensitive, type, repeating, recurrence, remindBy,
1054            firstReminder, secondReminder, serviceContext);
1055
1056    }
1057
1058    protected boolean isICal4jDateOnly(DateProperty date) {
1059        if (Validator.isNotNull(date.getParameter(Parameter.VALUE)) &&
1060            date.getParameter(Parameter.VALUE).getValue().equals("DATE")) {
1061
1062            return true;
1063        }
1064
1065        return false;
1066    }
1067
1068    protected void remindUser(CalEvent event, User user, Calendar startDate) {
1069        int remindBy = event.getRemindBy();
1070
1071        if (remindBy == CalEventConstants.REMIND_BY_NONE) {
1072            return;
1073        }
1074
1075        try {
1076            long ownerId = event.getGroupId();
1077            int ownerType = PortletKeys.PREFS_OWNER_TYPE_GROUP;
1078            long plid = PortletKeys.PREFS_PLID_SHARED;
1079            String portletId = PortletKeys.CALENDAR;
1080
1081            PortletPreferences preferences =
1082                portletPreferencesLocalService.getPreferences(
1083                    event.getCompanyId(), ownerId, ownerType, plid, portletId);
1084
1085            Company company = companyPersistence.findByPrimaryKey(
1086                user.getCompanyId());
1087
1088            Contact contact = user.getContact();
1089
1090            String portletName = PortalUtil.getPortletTitle(
1091                PortletKeys.CALENDAR, user);
1092
1093            String fromName = CalUtil.getEmailFromName(preferences);
1094            String fromAddress = CalUtil.getEmailFromAddress(preferences);
1095
1096            String toName = user.getFullName();
1097            String toAddress = user.getEmailAddress();
1098
1099            if (remindBy == CalEventConstants.REMIND_BY_SMS) {
1100                toAddress = contact.getSmsSn();
1101            }
1102
1103            String subject = CalUtil.getEmailEventReminderSubject(preferences);
1104            String body = CalUtil.getEmailEventReminderBody(preferences);
1105
1106            Format dateFormatDateTime = FastDateFormatFactoryUtil.getDateTime(
1107                user.getLocale(), user.getTimeZone());
1108
1109            subject = StringUtil.replace(
1110                subject,
1111                new String[] {
1112                    "[$EVENT_START_DATE$]",
1113                    "[$EVENT_TITLE$]",
1114                    "[$FROM_ADDRESS$]",
1115                    "[$FROM_NAME$]",
1116                    "[$PORTAL_URL$]",
1117                    "[$PORTLET_NAME$]",
1118                    "[$TO_ADDRESS$]",
1119                    "[$TO_NAME$]"
1120                },
1121                new String[] {
1122                    dateFormatDateTime.format(startDate.getTime()),
1123                    event.getTitle(),
1124                    fromAddress,
1125                    fromName,
1126                    company.getVirtualHost(),
1127                    portletName,
1128                    toAddress,
1129                    toName,
1130                });
1131
1132            body = StringUtil.replace(
1133                body,
1134                new String[] {
1135                    "[$EVENT_START_DATE$]",
1136                    "[$EVENT_TITLE$]",
1137                    "[$FROM_ADDRESS$]",
1138                    "[$FROM_NAME$]",
1139                    "[$PORTAL_URL$]",
1140                    "[$PORTLET_NAME$]",
1141                    "[$TO_ADDRESS$]",
1142                    "[$TO_NAME$]"
1143                },
1144                new String[] {
1145                    dateFormatDateTime.format(startDate.getTime()),
1146                    event.getTitle(),
1147                    fromAddress,
1148                    fromName,
1149                    company.getVirtualHost(),
1150                    portletName,
1151                    toAddress,
1152                    toName,
1153                });
1154
1155            if ((remindBy == CalEventConstants.REMIND_BY_EMAIL) ||
1156                (remindBy == CalEventConstants.REMIND_BY_SMS)) {
1157
1158                InternetAddress from = new InternetAddress(
1159                    fromAddress, fromName);
1160
1161                InternetAddress to = new InternetAddress(toAddress, toName);
1162
1163                MailMessage message = new MailMessage(
1164                    from, to, subject, body, true);
1165
1166                mailService.sendEmail(message);
1167            }
1168            else if ((remindBy == CalEventConstants.REMIND_BY_AIM) &&
1169                     (Validator.isNotNull(contact.getAimSn()))) {
1170
1171                AIMConnector.send(contact.getAimSn(), body);
1172            }
1173            else if ((remindBy == CalEventConstants.REMIND_BY_ICQ) &&
1174                     (Validator.isNotNull(contact.getIcqSn()))) {
1175
1176                ICQConnector.send(contact.getIcqSn(), body);
1177            }
1178            else if ((remindBy == CalEventConstants.REMIND_BY_MSN) &&
1179                     (Validator.isNotNull(contact.getMsnSn()))) {
1180
1181                MSNConnector.send(contact.getMsnSn(), body);
1182            }
1183            else if ((remindBy == CalEventConstants.REMIND_BY_YM) &&
1184                     (Validator.isNotNull(contact.getYmSn()))) {
1185
1186                YMConnector.send(contact.getYmSn(), body);
1187            }
1188        }
1189        catch (Exception e) {
1190            _log.error(e);
1191        }
1192    }
1193
1194    protected void remindUser(
1195        CalEvent event, User user, Calendar startDate, Calendar now) {
1196
1197        long diff =
1198            (startDate.getTime().getTime() - now.getTime().getTime()) /
1199                _eventCheckInterval;
1200
1201        if ((diff == (event.getFirstReminder() / _eventCheckInterval)) ||
1202            (diff == (event.getSecondReminder() / _eventCheckInterval))) {
1203
1204            remindUser(event, user, startDate);
1205        }
1206    }
1207
1208    protected Calendar toCalendar(
1209        DateProperty date, TimeZone timeZone, boolean timeZoneSensitive) {
1210
1211        Calendar cal = null;
1212
1213        if (isICal4jDateOnly(date)) {
1214            cal = Calendar.getInstance();
1215        }
1216        else if (!timeZoneSensitive) {
1217            cal = Calendar.getInstance(
1218                TimeZoneUtil.getTimeZone(StringPool.UTC));
1219        }
1220        else {
1221            cal = Calendar.getInstance(timeZone);
1222        }
1223
1224        return cal;
1225    }
1226
1227    protected int toCalendarWeekDay(WeekDay weekDay) {
1228        int dayOfWeeek = 0;
1229
1230        if (weekDay.getDay().equals(WeekDay.SU.getDay())) {
1231            dayOfWeeek = Calendar.SUNDAY;
1232        }
1233        else if (weekDay.getDay().equals(WeekDay.MO.getDay())) {
1234            dayOfWeeek = Calendar.MONDAY;
1235        }
1236        else if (weekDay.getDay().equals(WeekDay.TU.getDay())) {
1237            dayOfWeeek = Calendar.TUESDAY;
1238        }
1239        else if (weekDay.getDay().equals(WeekDay.WE.getDay())) {
1240            dayOfWeeek = Calendar.WEDNESDAY;
1241        }
1242        else if (weekDay.getDay().equals(WeekDay.TH.getDay())) {
1243            dayOfWeeek = Calendar.THURSDAY;
1244        }
1245        else if (weekDay.getDay().equals(WeekDay.FR.getDay())) {
1246            dayOfWeeek = Calendar.FRIDAY;
1247        }
1248        else if (weekDay.getDay().equals(WeekDay.SA.getDay())) {
1249            dayOfWeeek = Calendar.SATURDAY;
1250        }
1251
1252        return dayOfWeeek;
1253    }
1254
1255    protected net.fortuna.ical4j.model.Calendar toICalCalendar(
1256        long userId, List<CalEvent> events)
1257        throws PortalException, SystemException {
1258
1259        net.fortuna.ical4j.model.Calendar iCal =
1260            new net.fortuna.ical4j.model.Calendar();
1261
1262        ProdId prodId = new ProdId(
1263            "-//Liferay Inc//Liferay Portal " + ReleaseInfo.getVersion() +
1264            "//EN");
1265
1266        PropertyList props = iCal.getProperties();
1267
1268        props.add(prodId);
1269        props.add(Version.VERSION_2_0);
1270        props.add(CalScale.GREGORIAN);
1271
1272        // LPS-6058
1273
1274        props.add(Method.PUBLISH);
1275
1276        User user = userPersistence.findByPrimaryKey(userId);
1277        TimeZone timeZone = user.getTimeZone();
1278
1279        List<VEvent> components = iCal.getComponents();
1280
1281        Iterator<CalEvent> itr = events.iterator();
1282
1283        while (itr.hasNext()) {
1284            CalEvent event = itr.next();
1285
1286            components.add(toICalVEvent(event, timeZone));
1287        }
1288
1289        return iCal;
1290    }
1291
1292    protected Recur toICalRecurrence(TZSRecurrence recurrence) {
1293        Recur recur = null;
1294
1295        int recurrenceType = recurrence.getFrequency();
1296
1297        int interval = recurrence.getInterval();
1298
1299        if (recurrenceType == Recurrence.DAILY) {
1300            recur = new Recur(Recur.DAILY, -1);
1301
1302            if (interval >= 1) {
1303                recur.setInterval(interval);
1304            }
1305
1306            DayAndPosition[] byDay = recurrence.getByDay();
1307
1308            if (byDay != null) {
1309                for (int i = 0; i < byDay.length; i++) {
1310                    WeekDay weekDay = toICalWeekDay(byDay[i].getDayOfWeek());
1311
1312                    recur.getDayList().add(weekDay);
1313                }
1314            }
1315
1316        }
1317        else if (recurrenceType == Recurrence.WEEKLY) {
1318            recur = new Recur(Recur.WEEKLY, -1);
1319
1320            recur.setInterval(interval);
1321
1322            DayAndPosition[] byDay = recurrence.getByDay();
1323
1324            if (byDay != null) {
1325                for (int i = 0; i < byDay.length; i++) {
1326                    WeekDay weekDay = toICalWeekDay(byDay[i].getDayOfWeek());
1327
1328                    recur.getDayList().add(weekDay);
1329                }
1330            }
1331        }
1332        else if (recurrenceType == Recurrence.MONTHLY) {
1333            recur = new Recur(Recur.MONTHLY, -1);
1334
1335            recur.setInterval(interval);
1336
1337            int[] byMonthDay = recurrence.getByMonthDay();
1338
1339            if (byMonthDay != null) {
1340                Integer monthDay = new Integer(byMonthDay[0]);
1341
1342                recur.getMonthDayList().add(monthDay);
1343            }
1344            else if (recurrence.getByDay() != null) {
1345                DayAndPosition[] byDay = recurrence.getByDay();
1346
1347                WeekDay weekDay = toICalWeekDay(byDay[0].getDayOfWeek());
1348
1349                recur.getDayList().add(weekDay);
1350
1351                Integer position = new Integer(byDay[0].getDayPosition());
1352
1353                recur.getSetPosList().add(position);
1354            }
1355        }
1356        else if (recurrenceType == Recurrence.YEARLY) {
1357            recur = new Recur(Recur.YEARLY, -1);
1358
1359            recur.setInterval(interval);
1360        }
1361
1362        Calendar until = recurrence.getUntil();
1363
1364        if (until != null) {
1365            DateTime dateTime = new DateTime(until.getTime());
1366
1367            recur.setUntil(dateTime);
1368        }
1369
1370        return recur;
1371    }
1372
1373    protected VEvent toICalVEvent(CalEvent event, TimeZone timeZone) {
1374        VEvent vEvent = new VEvent();
1375
1376        PropertyList eventProps = vEvent.getProperties();
1377
1378        // UID
1379
1380        Uid uid = new Uid(PortalUUIDUtil.generate());
1381
1382        eventProps.add(uid);
1383
1384        if (event.isAllDay()) {
1385
1386            // Start date
1387
1388            DtStart dtStart = new DtStart(
1389                new net.fortuna.ical4j.model.Date(event.getStartDate()));
1390
1391            eventProps.add(dtStart);
1392
1393            Property dtStartProperty = eventProps.getProperty(Property.DTSTART);
1394
1395            dtStartProperty.getParameters().add(Value.DATE);
1396        }
1397        else {
1398
1399            // Start date
1400
1401            DtStart dtStart = new DtStart(new DateTime(event.getStartDate()));
1402
1403            eventProps.add(dtStart);
1404
1405            // Duration
1406
1407            Duration duration = new Duration(
1408                new Dur(
1409                    0, event.getDurationHour(), event.getDurationMinute(), 0));
1410
1411            eventProps.add(duration);
1412        }
1413
1414        // Summary
1415
1416        Summary summary = new Summary(event.getTitle());
1417
1418        eventProps.add(summary);
1419
1420        // Description
1421
1422        Description description = new Description(event.getDescription());
1423
1424        eventProps.add(description);
1425
1426        // Comment
1427
1428        Comment comment = new Comment(event.getType());
1429
1430        eventProps.add(comment);
1431
1432        // Recurrence rule
1433
1434        if (event.isRepeating()) {
1435            Recur recur = toICalRecurrence(event.getRecurrenceObj());
1436
1437            RRule rRule = new RRule(recur);
1438
1439            eventProps.add(rRule);
1440        }
1441
1442        // Time zone sensitive
1443
1444        if (!event.getTimeZoneSensitive()) {
1445            eventProps.add(new TimeZoneSensitive("FALSE"));
1446        }
1447
1448        return vEvent;
1449    }
1450
1451    protected WeekDay toICalWeekDay(int dayOfWeek) {
1452        WeekDay weekDay = null;
1453
1454        if (dayOfWeek == Calendar.SUNDAY) {
1455            weekDay = WeekDay.SU;
1456        }
1457        else if (dayOfWeek == Calendar.MONDAY) {
1458            weekDay = WeekDay.MO;
1459        }
1460        else if (dayOfWeek == Calendar.TUESDAY) {
1461            weekDay = WeekDay.TU;
1462        }
1463        else if (dayOfWeek == Calendar.WEDNESDAY) {
1464            weekDay = WeekDay.WE;
1465        }
1466        else if (dayOfWeek == Calendar.THURSDAY) {
1467            weekDay = WeekDay.TH;
1468        }
1469        else if (dayOfWeek == Calendar.FRIDAY) {
1470            weekDay = WeekDay.FR;
1471        }
1472        else if (dayOfWeek == Calendar.SATURDAY) {
1473            weekDay = WeekDay.SA;
1474        }
1475
1476        return weekDay;
1477    }
1478
1479    protected TZSRecurrence toRecurrence(
1480        RRule rRule, TimeZone timeZone, Calendar startDate) {
1481
1482        Recur recur = rRule.getRecur();
1483
1484        Calendar recStartCal = CalendarFactoryUtil.getCalendar(timeZone);
1485
1486        recStartCal.setTime(startDate.getTime());
1487
1488        TZSRecurrence recurrence = new TZSRecurrence(
1489            recStartCal,
1490            new com.liferay.portal.kernel.cal.Duration(1, 0, 0, 0));
1491
1492        recurrence.setWeekStart(Calendar.SUNDAY);
1493
1494        if (recur.getInterval() > 1) {
1495            recurrence.setInterval(recur.getInterval());
1496        }
1497
1498        Calendar until = Calendar.getInstance(timeZone);
1499
1500        String frequency = recur.getFrequency();
1501
1502        if (Validator.isNotNull(recur.getUntil())) {
1503            until.setTime(recur.getUntil());
1504
1505            recurrence.setUntil(until);
1506        }
1507        else if (rRule.getValue().indexOf("COUNT") >= 0) {
1508            until.setTimeInMillis(startDate.getTimeInMillis());
1509
1510            int addField = 0;
1511
1512            if (Recur.DAILY.equals(frequency)) {
1513                addField = Calendar.DAY_OF_YEAR;
1514            }
1515            else if (Recur.WEEKLY.equals(frequency)) {
1516                addField = Calendar.WEEK_OF_YEAR;
1517            }
1518            else if (Recur.MONTHLY.equals(frequency)) {
1519                addField = Calendar.MONTH;
1520            }
1521            else if (Recur.YEARLY.equals(frequency)) {
1522                addField = Calendar.YEAR;
1523            }
1524
1525            int addAmount = recurrence.getInterval() * recur.getCount();
1526
1527            until.add(addField, addAmount);
1528            until.add(Calendar.DAY_OF_YEAR, -1);
1529
1530            recurrence.setUntil(until);
1531        }
1532
1533        if (Recur.DAILY.equals(frequency)) {
1534            recurrence.setFrequency(Recurrence.DAILY);
1535
1536            List<DayAndPosition> dayPosList = new ArrayList<DayAndPosition>();
1537
1538            Iterator<WeekDay> itr = recur.getDayList().iterator();
1539
1540            while (itr.hasNext()) {
1541                WeekDay weekDay = itr.next();
1542
1543                dayPosList.add(
1544                    new DayAndPosition(toCalendarWeekDay(weekDay), 0));
1545            }
1546
1547            if (!dayPosList.isEmpty()) {
1548                recurrence.setByDay(
1549                    dayPosList.toArray(new DayAndPosition[dayPosList.size()]));
1550            }
1551        }
1552        else if (Recur.WEEKLY.equals(frequency)) {
1553            recurrence.setFrequency(Recurrence.WEEKLY);
1554
1555            List<DayAndPosition> dayPosList = new ArrayList<DayAndPosition>();
1556
1557            Iterator<WeekDay> itr = recur.getDayList().iterator();
1558
1559            while (itr.hasNext()) {
1560                WeekDay weekDay = itr.next();
1561
1562                dayPosList.add(
1563                    new DayAndPosition(toCalendarWeekDay(weekDay), 0));
1564            }
1565
1566            if (!dayPosList.isEmpty()) {
1567                recurrence.setByDay(
1568                    dayPosList.toArray(new DayAndPosition[dayPosList.size()]));
1569            }
1570        }
1571        else if (Recur.MONTHLY.equals(frequency)) {
1572            recurrence.setFrequency(Recurrence.MONTHLY);
1573
1574            Iterator<Integer> monthDayListItr =
1575                recur.getMonthDayList().iterator();
1576
1577            if (monthDayListItr.hasNext()) {
1578                Integer monthDay = monthDayListItr.next();
1579
1580                recurrence.setByMonthDay(new int[] {monthDay.intValue()});
1581            }
1582
1583            Iterator<WeekDay> dayListItr = recur.getDayList().iterator();
1584
1585            if (dayListItr.hasNext()) {
1586                WeekDay weekDay = dayListItr.next();
1587
1588                DayAndPosition[] dayPos = {
1589                    new DayAndPosition(toCalendarWeekDay(weekDay),
1590                    weekDay.getOffset())
1591                };
1592
1593                recurrence.setByDay(dayPos);
1594            }
1595        }
1596        else if (Recur.YEARLY.equals(frequency)) {
1597            recurrence.setFrequency(Recurrence.YEARLY);
1598        }
1599
1600        return recurrence;
1601    }
1602
1603    protected void validate(
1604            String title, int startDateMonth, int startDateDay,
1605            int startDateYear, int endDateMonth, int endDateDay,
1606            int endDateYear, int durationHour, int durationMinute,
1607            boolean allDay, boolean repeating, TZSRecurrence recurrence)
1608        throws PortalException {
1609
1610        if (Validator.isNull(title)) {
1611            throw new EventTitleException();
1612        }
1613        else if (!Validator.isDate(
1614                startDateMonth, startDateDay, startDateYear)) {
1615
1616            throw new EventStartDateException();
1617        }
1618        else if (!Validator.isDate(endDateMonth, endDateDay, endDateYear)) {
1619            throw new EventEndDateException();
1620        }
1621
1622        if (!allDay && durationHour <= 0 && durationMinute <= 0) {
1623            throw new EventDurationException();
1624        }
1625
1626        Calendar startDate = CalendarFactoryUtil.getCalendar(
1627            startDateYear, startDateMonth, startDateDay);
1628
1629        if (repeating) {
1630            Calendar until = recurrence.getUntil();
1631
1632            if (startDate.after(until)) {
1633                throw new EventEndDateException();
1634            }
1635        }
1636    }
1637
1638    private static Log _log = LogFactoryUtil.getLog(
1639        CalEventLocalServiceImpl.class);
1640
1641    private long _eventCheckInterval =
1642        PropsValues.CALENDAR_EVENT_CHECK_INTERVAL * Time.MINUTE;
1643
1644}