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