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