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);
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(now);
198         event.setModifiedDate(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);
746 
747         CalEvent event = calEventPersistence.findByPrimaryKey(eventId);
748 
749         event.setModifiedDate(new Date());
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(TimeZone.getTimeZone(StringPool.UTC));
1218        }
1219        else {
1220            cal = Calendar.getInstance(timeZone);
1221        }
1222
1223        return cal;
1224    }
1225
1226    protected int toCalendarWeekDay(WeekDay weekDay) {
1227        int dayOfWeeek = 0;
1228
1229        if (weekDay.getDay().equals(WeekDay.SU.getDay())) {
1230            dayOfWeeek = Calendar.SUNDAY;
1231        }
1232        else if (weekDay.getDay().equals(WeekDay.MO.getDay())) {
1233            dayOfWeeek = Calendar.MONDAY;
1234        }
1235        else if (weekDay.getDay().equals(WeekDay.TU.getDay())) {
1236            dayOfWeeek = Calendar.TUESDAY;
1237        }
1238        else if (weekDay.getDay().equals(WeekDay.WE.getDay())) {
1239            dayOfWeeek = Calendar.WEDNESDAY;
1240        }
1241        else if (weekDay.getDay().equals(WeekDay.TH.getDay())) {
1242            dayOfWeeek = Calendar.THURSDAY;
1243        }
1244        else if (weekDay.getDay().equals(WeekDay.FR.getDay())) {
1245            dayOfWeeek = Calendar.FRIDAY;
1246        }
1247        else if (weekDay.getDay().equals(WeekDay.SA.getDay())) {
1248            dayOfWeeek = Calendar.SATURDAY;
1249        }
1250
1251        return dayOfWeeek;
1252    }
1253
1254    protected net.fortuna.ical4j.model.Calendar toICalCalendar(
1255        long userId, List<CalEvent> events)
1256        throws PortalException, SystemException {
1257
1258        net.fortuna.ical4j.model.Calendar iCal =
1259            new net.fortuna.ical4j.model.Calendar();
1260
1261        ProdId prodId = new ProdId(
1262            "-//Liferay Inc//Liferay Portal " + ReleaseInfo.getVersion() +
1263            "//EN");
1264
1265        PropertyList props = iCal.getProperties();
1266
1267        props.add(prodId);
1268        props.add(Version.VERSION_2_0);
1269        props.add(CalScale.GREGORIAN);
1270
1271        // LPS-6058
1272
1273        props.add(Method.PUBLISH);
1274
1275        User user = userPersistence.findByPrimaryKey(userId);
1276        TimeZone timeZone = user.getTimeZone();
1277
1278        List<VEvent> components = iCal.getComponents();
1279
1280        Iterator<CalEvent> itr = events.iterator();
1281
1282        while (itr.hasNext()) {
1283            CalEvent event = itr.next();
1284
1285            components.add(toICalVEvent(event, timeZone));
1286        }
1287
1288        return iCal;
1289    }
1290
1291    protected Recur toICalRecurrence(TZSRecurrence recurrence) {
1292        Recur recur = null;
1293
1294        int recurrenceType = recurrence.getFrequency();
1295
1296        int interval = recurrence.getInterval();
1297
1298        if (recurrenceType == Recurrence.DAILY) {
1299            recur = new Recur(Recur.DAILY, -1);
1300
1301            if (interval >= 1) {
1302                recur.setInterval(interval);
1303            }
1304
1305            DayAndPosition[] byDay = recurrence.getByDay();
1306
1307            if (byDay != null) {
1308                for (int i = 0; i < byDay.length; i++) {
1309                    WeekDay weekDay = toICalWeekDay(byDay[i].getDayOfWeek());
1310
1311                    recur.getDayList().add(weekDay);
1312                }
1313            }
1314
1315        }
1316        else if (recurrenceType == Recurrence.WEEKLY) {
1317            recur = new Recur(Recur.WEEKLY, -1);
1318
1319            recur.setInterval(interval);
1320
1321            DayAndPosition[] byDay = recurrence.getByDay();
1322
1323            if (byDay != null) {
1324                for (int i = 0; i < byDay.length; i++) {
1325                    WeekDay weekDay = toICalWeekDay(byDay[i].getDayOfWeek());
1326
1327                    recur.getDayList().add(weekDay);
1328                }
1329            }
1330        }
1331        else if (recurrenceType == Recurrence.MONTHLY) {
1332            recur = new Recur(Recur.MONTHLY, -1);
1333
1334            recur.setInterval(interval);
1335
1336            int[] byMonthDay = recurrence.getByMonthDay();
1337
1338            if (byMonthDay != null) {
1339                Integer monthDay = new Integer(byMonthDay[0]);
1340
1341                recur.getMonthDayList().add(monthDay);
1342            }
1343            else if (recurrence.getByDay() != null) {
1344                DayAndPosition[] byDay = recurrence.getByDay();
1345
1346                WeekDay weekDay = toICalWeekDay(byDay[0].getDayOfWeek());
1347
1348                recur.getDayList().add(weekDay);
1349
1350                Integer position = new Integer(byDay[0].getDayPosition());
1351
1352                recur.getSetPosList().add(position);
1353            }
1354        }
1355        else if (recurrenceType == Recurrence.YEARLY) {
1356            recur = new Recur(Recur.YEARLY, -1);
1357
1358            recur.setInterval(interval);
1359        }
1360
1361        Calendar until = recurrence.getUntil();
1362
1363        if (until != null) {
1364            DateTime dateTime = new DateTime(until.getTime());
1365
1366            recur.setUntil(dateTime);
1367        }
1368
1369        return recur;
1370    }
1371
1372    protected VEvent toICalVEvent(CalEvent event, TimeZone timeZone) {
1373        VEvent vEvent = new VEvent();
1374
1375        PropertyList eventProps = vEvent.getProperties();
1376
1377        // UID
1378
1379        Uid uid = new Uid(PortalUUIDUtil.generate());
1380
1381        eventProps.add(uid);
1382
1383        if (event.isAllDay()) {
1384
1385            // Start date
1386
1387            DtStart dtStart = new DtStart(
1388                new net.fortuna.ical4j.model.Date(event.getStartDate()));
1389
1390            eventProps.add(dtStart);
1391
1392            Property dtStartProperty = eventProps.getProperty(Property.DTSTART);
1393
1394            dtStartProperty.getParameters().add(Value.DATE);
1395        }
1396        else {
1397
1398            // Start date
1399
1400            DtStart dtStart = new DtStart(new DateTime(event.getStartDate()));
1401
1402            eventProps.add(dtStart);
1403
1404            // Duration
1405
1406            Duration duration = new Duration(
1407                new Dur(
1408                    0, event.getDurationHour(), event.getDurationMinute(), 0));
1409
1410            eventProps.add(duration);
1411        }
1412
1413        // Summary
1414
1415        Summary summary = new Summary(event.getTitle());
1416
1417        eventProps.add(summary);
1418
1419        // Description
1420
1421        Description description = new Description(event.getDescription());
1422
1423        eventProps.add(description);
1424
1425        // Comment
1426
1427        Comment comment = new Comment(event.getType());
1428
1429        eventProps.add(comment);
1430
1431        // Recurrence rule
1432
1433        if (event.isRepeating()) {
1434            Recur recur = toICalRecurrence(event.getRecurrenceObj());
1435
1436            RRule rRule = new RRule(recur);
1437
1438            eventProps.add(rRule);
1439        }
1440
1441        // Time zone sensitive
1442
1443        if (!event.getTimeZoneSensitive()) {
1444            eventProps.add(new TimeZoneSensitive("FALSE"));
1445        }
1446
1447        return vEvent;
1448    }
1449
1450    protected WeekDay toICalWeekDay(int dayOfWeek) {
1451        WeekDay weekDay = null;
1452
1453        if (dayOfWeek == Calendar.SUNDAY) {
1454            weekDay = WeekDay.SU;
1455        }
1456        else if (dayOfWeek == Calendar.MONDAY) {
1457            weekDay = WeekDay.MO;
1458        }
1459        else if (dayOfWeek == Calendar.TUESDAY) {
1460            weekDay = WeekDay.TU;
1461        }
1462        else if (dayOfWeek == Calendar.WEDNESDAY) {
1463            weekDay = WeekDay.WE;
1464        }
1465        else if (dayOfWeek == Calendar.THURSDAY) {
1466            weekDay = WeekDay.TH;
1467        }
1468        else if (dayOfWeek == Calendar.FRIDAY) {
1469            weekDay = WeekDay.FR;
1470        }
1471        else if (dayOfWeek == Calendar.SATURDAY) {
1472            weekDay = WeekDay.SA;
1473        }
1474
1475        return weekDay;
1476    }
1477
1478    protected TZSRecurrence toRecurrence(
1479        RRule rRule, TimeZone timeZone, Calendar startDate) {
1480
1481        Recur recur = rRule.getRecur();
1482
1483        Calendar recStartCal = CalendarFactoryUtil.getCalendar(timeZone);
1484
1485        recStartCal.setTime(startDate.getTime());
1486
1487        TZSRecurrence recurrence = new TZSRecurrence(
1488            recStartCal,
1489            new com.liferay.portal.kernel.cal.Duration(1, 0, 0, 0));
1490
1491        recurrence.setWeekStart(Calendar.SUNDAY);
1492
1493        if (recur.getInterval() > 1) {
1494            recurrence.setInterval(recur.getInterval());
1495        }
1496
1497        Calendar until = Calendar.getInstance(timeZone);
1498
1499        String frequency = recur.getFrequency();
1500
1501        if (Validator.isNotNull(recur.getUntil())) {
1502            until.setTime(recur.getUntil());
1503
1504            recurrence.setUntil(until);
1505        }
1506        else if (rRule.getValue().indexOf("COUNT") >= 0) {
1507            until.setTimeInMillis(startDate.getTimeInMillis());
1508
1509            int addField = 0;
1510
1511            if (Recur.DAILY.equals(frequency)) {
1512                addField = Calendar.DAY_OF_YEAR;
1513            }
1514            else if (Recur.WEEKLY.equals(frequency)) {
1515                addField = Calendar.WEEK_OF_YEAR;
1516            }
1517            else if (Recur.MONTHLY.equals(frequency)) {
1518                addField = Calendar.MONTH;
1519            }
1520            else if (Recur.YEARLY.equals(frequency)) {
1521                addField = Calendar.YEAR;
1522            }
1523
1524            int addAmount = recurrence.getInterval() * recur.getCount();
1525
1526            until.add(addField, addAmount);
1527            until.add(Calendar.DAY_OF_YEAR, -1);
1528
1529            recurrence.setUntil(until);
1530        }
1531
1532        if (Recur.DAILY.equals(frequency)) {
1533            recurrence.setFrequency(Recurrence.DAILY);
1534
1535            List<DayAndPosition> dayPosList = new ArrayList<DayAndPosition>();
1536
1537            Iterator<WeekDay> itr = recur.getDayList().iterator();
1538
1539            while (itr.hasNext()) {
1540                WeekDay weekDay = itr.next();
1541
1542                dayPosList.add(
1543                    new DayAndPosition(toCalendarWeekDay(weekDay), 0));
1544            }
1545
1546            if (!dayPosList.isEmpty()) {
1547                recurrence.setByDay(
1548                    dayPosList.toArray(new DayAndPosition[dayPosList.size()]));
1549            }
1550        }
1551        else if (Recur.WEEKLY.equals(frequency)) {
1552            recurrence.setFrequency(Recurrence.WEEKLY);
1553
1554            List<DayAndPosition> dayPosList = new ArrayList<DayAndPosition>();
1555
1556            Iterator<WeekDay> itr = recur.getDayList().iterator();
1557
1558            while (itr.hasNext()) {
1559                WeekDay weekDay = itr.next();
1560
1561                dayPosList.add(
1562                    new DayAndPosition(toCalendarWeekDay(weekDay), 0));
1563            }
1564
1565            if (!dayPosList.isEmpty()) {
1566                recurrence.setByDay(
1567                    dayPosList.toArray(new DayAndPosition[dayPosList.size()]));
1568            }
1569        }
1570        else if (Recur.MONTHLY.equals(frequency)) {
1571            recurrence.setFrequency(Recurrence.MONTHLY);
1572
1573            Iterator<Integer> monthDayListItr =
1574                recur.getMonthDayList().iterator();
1575
1576            if (monthDayListItr.hasNext()) {
1577                Integer monthDay = monthDayListItr.next();
1578
1579                recurrence.setByMonthDay(new int[] {monthDay.intValue()});
1580            }
1581
1582            Iterator<WeekDay> dayListItr = recur.getDayList().iterator();
1583
1584            if (dayListItr.hasNext()) {
1585                WeekDay weekDay = dayListItr.next();
1586
1587                DayAndPosition[] dayPos = {
1588                    new DayAndPosition(toCalendarWeekDay(weekDay),
1589                    weekDay.getOffset())
1590                };
1591
1592                recurrence.setByDay(dayPos);
1593            }
1594        }
1595        else if (Recur.YEARLY.equals(frequency)) {
1596            recurrence.setFrequency(Recurrence.YEARLY);
1597        }
1598
1599        return recurrence;
1600    }
1601
1602    protected void validate(
1603            String title, int startDateMonth, int startDateDay,
1604            int startDateYear, int endDateMonth, int endDateDay,
1605            int endDateYear, int durationHour, int durationMinute,
1606            boolean allDay, boolean repeating)
1607        throws PortalException {
1608
1609        if (Validator.isNull(title)) {
1610            throw new EventTitleException();
1611        }
1612        else if (!Validator.isDate(
1613                startDateMonth, startDateDay, startDateYear)) {
1614
1615            throw new EventStartDateException();
1616        }
1617        else if (!Validator.isDate(endDateMonth, endDateDay, endDateYear)) {
1618            throw new EventEndDateException();
1619        }
1620
1621        if (!allDay && durationHour <= 0 && durationMinute <= 0) {
1622            throw new EventDurationException();
1623        }
1624
1625        Calendar startDate = CalendarFactoryUtil.getCalendar(
1626            startDateYear, startDateMonth, startDateDay);
1627
1628        Calendar endDate = CalendarFactoryUtil.getCalendar(
1629            endDateYear, endDateMonth, endDateDay);
1630
1631        if (repeating && startDate.after(endDate)) {
1632            throw new EventEndDateException();
1633        }
1634    }
1635
1636    private static Log _log = LogFactoryUtil.getLog(
1637        CalEventLocalServiceImpl.class);
1638
1639    private long _eventCheckInterval =
1640        PropsValues.CALENDAR_EVENT_CHECK_INTERVAL * Time.MINUTE;
1641
1642}