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