1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    *
5    *
6    *
7    * The contents of this file are subject to the terms of the Liferay Enterprise
8    * Subscription License ("License"). You may not use this file except in
9    * compliance with the License. You can obtain a copy of the License by
10   * contacting Liferay, Inc. See the License for the specific language governing
11   * permissions and limitations under the License, including but not limited to
12   * distribution rights 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.io.unsync.UnsyncBufferedOutputStream;
35  import com.liferay.portal.kernel.log.Log;
36  import com.liferay.portal.kernel.log.LogFactoryUtil;
37  import com.liferay.portal.kernel.mail.MailMessage;
38  import com.liferay.portal.kernel.search.BooleanClauseOccur;
39  import com.liferay.portal.kernel.search.BooleanQuery;
40  import com.liferay.portal.kernel.search.BooleanQueryFactoryUtil;
41  import com.liferay.portal.kernel.search.Field;
42  import com.liferay.portal.kernel.search.Hits;
43  import com.liferay.portal.kernel.search.SearchEngineUtil;
44  import com.liferay.portal.kernel.search.SearchException;
45  import com.liferay.portal.kernel.util.ArrayUtil;
46  import com.liferay.portal.kernel.util.CalendarFactoryUtil;
47  import com.liferay.portal.kernel.util.CalendarUtil;
48  import com.liferay.portal.kernel.util.FastDateFormatFactoryUtil;
49  import com.liferay.portal.kernel.util.GetterUtil;
50  import com.liferay.portal.kernel.util.LocaleUtil;
51  import com.liferay.portal.kernel.util.ReleaseInfo;
52  import com.liferay.portal.kernel.util.StreamUtil;
53  import com.liferay.portal.kernel.util.StringPool;
54  import com.liferay.portal.kernel.util.StringUtil;
55  import com.liferay.portal.kernel.util.Time;
56  import com.liferay.portal.kernel.util.TimeZoneUtil;
57  import com.liferay.portal.kernel.util.UnmodifiableList;
58  import com.liferay.portal.kernel.util.Validator;
59  import com.liferay.portal.kernel.uuid.PortalUUIDUtil;
60  import com.liferay.portal.model.Company;
61  import com.liferay.portal.model.Contact;
62  import com.liferay.portal.model.Group;
63  import com.liferay.portal.model.ModelHintsUtil;
64  import com.liferay.portal.model.ResourceConstants;
65  import com.liferay.portal.model.User;
66  import com.liferay.portal.service.ServiceContext;
67  import com.liferay.portal.util.PortalUtil;
68  import com.liferay.portal.util.PortletKeys;
69  import com.liferay.portlet.calendar.EventDurationException;
70  import com.liferay.portlet.calendar.EventEndDateException;
71  import com.liferay.portlet.calendar.EventStartDateException;
72  import com.liferay.portlet.calendar.EventTitleException;
73  import com.liferay.portlet.calendar.job.CheckEventJob;
74  import com.liferay.portlet.calendar.model.CalEvent;
75  import com.liferay.portlet.calendar.model.impl.CalEventImpl;
76  import com.liferay.portlet.calendar.service.base.CalEventLocalServiceBaseImpl;
77  import com.liferay.portlet.calendar.social.CalendarActivityKeys;
78  import com.liferay.portlet.calendar.util.CalUtil;
79  import com.liferay.portlet.calendar.util.Indexer;
80  import com.liferay.portlet.expando.model.ExpandoBridge;
81  import com.liferay.util.TimeZoneSensitive;
82  
83  import java.io.File;
84  import java.io.FileOutputStream;
85  import java.io.FileReader;
86  import java.io.IOException;
87  import java.io.OutputStream;
88  
89  import java.text.Format;
90  
91  import java.util.ArrayList;
92  import java.util.Calendar;
93  import java.util.Date;
94  import java.util.Iterator;
95  import java.util.List;
96  import java.util.Locale;
97  import java.util.Map;
98  import java.util.TimeZone;
99  
100 import javax.mail.internet.InternetAddress;
101 
102 import javax.portlet.PortletPreferences;
103 
104 import net.fortuna.ical4j.data.CalendarBuilder;
105 import net.fortuna.ical4j.data.CalendarOutputter;
106 import net.fortuna.ical4j.data.ParserException;
107 import net.fortuna.ical4j.model.Component;
108 import net.fortuna.ical4j.model.DateTime;
109 import net.fortuna.ical4j.model.Dur;
110 import net.fortuna.ical4j.model.Parameter;
111 import net.fortuna.ical4j.model.Property;
112 import net.fortuna.ical4j.model.PropertyList;
113 import net.fortuna.ical4j.model.Recur;
114 import net.fortuna.ical4j.model.WeekDay;
115 import net.fortuna.ical4j.model.component.VEvent;
116 import net.fortuna.ical4j.model.parameter.Value;
117 import net.fortuna.ical4j.model.property.CalScale;
118 import net.fortuna.ical4j.model.property.Comment;
119 import net.fortuna.ical4j.model.property.DateProperty;
120 import net.fortuna.ical4j.model.property.Description;
121 import net.fortuna.ical4j.model.property.DtEnd;
122 import net.fortuna.ical4j.model.property.DtStart;
123 import net.fortuna.ical4j.model.property.Duration;
124 import net.fortuna.ical4j.model.property.Method;
125 import net.fortuna.ical4j.model.property.ProdId;
126 import net.fortuna.ical4j.model.property.RRule;
127 import net.fortuna.ical4j.model.property.Summary;
128 import net.fortuna.ical4j.model.property.Uid;
129 import net.fortuna.ical4j.model.property.Version;
130 
131 /**
132  * <a href="CalEventLocalServiceImpl.java.html"><b><i>View Source</i></b></a>
133  *
134  * @author Brian Wing Shun Chan
135  * @author Bruno Farache
136  * @author Samuel Kong
137  * @author Ganesh Ram
138  * @author Brett Swaim
139  */
140 public class CalEventLocalServiceImpl extends CalEventLocalServiceBaseImpl {
141 
142     public CalEvent addEvent(
143             long userId, String title, String description, int startDateMonth,
144             int startDateDay, int startDateYear, int startDateHour,
145             int startDateMinute, int endDateMonth, int endDateDay,
146             int endDateYear, int durationHour, int durationMinute,
147             boolean allDay, boolean timeZoneSensitive, String type,
148             boolean repeating, TZSRecurrence recurrence, int remindBy,
149             int firstReminder, int secondReminder,
150             ServiceContext serviceContext)
151         throws PortalException, SystemException {
152 
153         return addEvent(
154             null, userId, title, description, startDateMonth, startDateDay,
155             startDateYear, startDateHour, startDateMinute, endDateMonth,
156             endDateDay, endDateYear, durationHour, durationMinute, allDay,
157             timeZoneSensitive, type, repeating, recurrence, remindBy,
158             firstReminder, secondReminder, serviceContext);
159     }
160 
161     public CalEvent addEvent(
162             String uuid, long userId, String title, String description,
163             int startDateMonth, int startDateDay, int startDateYear,
164             int startDateHour, int startDateMinute, int endDateMonth,
165             int endDateDay, int endDateYear, int durationHour,
166             int durationMinute, boolean allDay, boolean timeZoneSensitive,
167             String type, boolean repeating, TZSRecurrence recurrence,
168             int remindBy, int firstReminder, int secondReminder,
169             ServiceContext serviceContext)
170         throws PortalException, SystemException {
171 
172         // Event
173 
174         User user = userPersistence.findByPrimaryKey(userId);
175         long groupId = serviceContext.getScopeGroupId();
176         Date now = new Date();
177 
178         Locale locale = null;
179         TimeZone timeZone = null;
180 
181         if (timeZoneSensitive) {
182             locale = user.getLocale();
183             timeZone = user.getTimeZone();
184         }
185         else {
186             locale = LocaleUtil.getDefault();
187             timeZone = TimeZoneUtil.getDefault();
188         }
189 
190         Calendar startDate = CalendarFactoryUtil.getCalendar(timeZone, locale);
191 
192         startDate.set(Calendar.MONTH, startDateMonth);
193         startDate.set(Calendar.DATE, startDateDay);
194         startDate.set(Calendar.YEAR, startDateYear);
195         startDate.set(Calendar.HOUR_OF_DAY, startDateHour);
196         startDate.set(Calendar.MINUTE, startDateMinute);
197         startDate.set(Calendar.SECOND, 0);
198         startDate.set(Calendar.MILLISECOND, 0);
199 
200         Calendar endDate = CalendarFactoryUtil.getCalendar(timeZone, locale);
201 
202         endDate.set(Calendar.MONTH, endDateMonth);
203         endDate.set(Calendar.DATE, endDateDay);
204         endDate.set(Calendar.YEAR, endDateYear);
205         endDate.set(Calendar.HOUR_OF_DAY, 23);
206         endDate.set(Calendar.MINUTE, 59);
207         endDate.set(Calendar.SECOND, 59);
208         endDate.set(Calendar.MILLISECOND, 999);
209 
210         if (allDay) {
211             startDate.set(Calendar.HOUR_OF_DAY, 0);
212             startDate.set(Calendar.MINUTE, 0);
213 
214             durationHour = 24;
215             durationMinute = 0;
216         }
217 
218         validate(
219             title, startDateMonth, startDateDay, startDateYear, endDateMonth,
220             endDateDay, endDateYear, durationHour, durationMinute, allDay,
221             repeating);
222 
223         long eventId = counterLocalService.increment();
224 
225         CalEvent event = calEventPersistence.create(eventId);
226 
227         event.setUuid(uuid);
228         event.setGroupId(groupId);
229         event.setCompanyId(user.getCompanyId());
230         event.setUserId(user.getUserId());
231         event.setUserName(user.getFullName());
232         event.setCreateDate(now);
233         event.setModifiedDate(now);
234         event.setTitle(title);
235         event.setDescription(description);
236         event.setStartDate(startDate.getTime());
237         event.setEndDate(endDate.getTime());
238         event.setDurationHour(durationHour);
239         event.setDurationMinute(durationMinute);
240         event.setAllDay(allDay);
241         event.setTimeZoneSensitive(timeZoneSensitive);
242         event.setType(type);
243         event.setRepeating(repeating);
244         event.setRecurrenceObj(recurrence);
245         event.setRemindBy(remindBy);
246         event.setFirstReminder(firstReminder);
247         event.setSecondReminder(secondReminder);
248         event.setExpandoBridgeAttributes(serviceContext);
249 
250         calEventPersistence.update(event, false);
251 
252         // Resources
253 
254         if (serviceContext.getAddCommunityPermissions() ||
255             serviceContext.getAddGuestPermissions()) {
256 
257             addEventResources(
258                 event, serviceContext.getAddCommunityPermissions(),
259                 serviceContext.getAddGuestPermissions());
260         }
261         else {
262             addEventResources(
263                 event, serviceContext.getCommunityPermissions(),
264                 serviceContext.getGuestPermissions());
265         }
266 
267         // Social
268 
269         socialActivityLocalService.addActivity(
270             userId, groupId, CalEvent.class.getName(), eventId,
271             CalendarActivityKeys.ADD_EVENT, StringPool.BLANK, 0);
272 
273         // Indexer
274 
275         reIndex(event);
276 
277         // Pool
278 
279         CalEventLocalUtil.clearEventsPool(event.getGroupId());
280 
281         return event;
282     }
283 
284     public void addEventResources(
285             CalEvent event, boolean addCommunityPermissions,
286             boolean addGuestPermissions)
287         throws PortalException, SystemException {
288 
289         resourceLocalService.addResources(
290             event.getCompanyId(), event.getGroupId(), event.getUserId(),
291             CalEvent.class.getName(), event.getEventId(), false,
292             addCommunityPermissions, addGuestPermissions);
293     }
294 
295     public void addEventResources(
296             CalEvent event, String[] communityPermissions,
297             String[] guestPermissions)
298         throws PortalException, SystemException {
299 
300         resourceLocalService.addModelResources(
301             event.getCompanyId(), event.getGroupId(), event.getUserId(),
302             CalEvent.class.getName(), event.getEventId(), communityPermissions,
303             guestPermissions);
304     }
305 
306     public void addEventResources(
307             long eventId, boolean addCommunityPermissions,
308             boolean addGuestPermissions)
309         throws PortalException, SystemException {
310 
311         CalEvent event = calEventPersistence.findByPrimaryKey(eventId);
312 
313         addEventResources(
314             event, addCommunityPermissions, addGuestPermissions);
315     }
316 
317     public void addEventResources(
318             long eventId, String[] communityPermissions,
319             String[] guestPermissions)
320         throws PortalException, SystemException {
321 
322         CalEvent event = calEventPersistence.findByPrimaryKey(eventId);
323 
324         addEventResources(event, communityPermissions, guestPermissions);
325     }
326 
327     public void checkEvents() throws PortalException, SystemException {
328         Iterator<CalEvent> itr = calEventPersistence.findByRemindBy(
329             CalEventImpl.REMIND_BY_NONE).iterator();
330 
331         while (itr.hasNext()) {
332             CalEvent event = itr.next();
333 
334             User user = userPersistence.fetchByPrimaryKey(event.getUserId());
335 
336             if (user == null) {
337                 deleteEvent(event);
338 
339                 continue;
340             }
341 
342             Calendar now = CalendarFactoryUtil.getCalendar(
343                 user.getTimeZone(), user.getLocale());
344 
345             if (!event.isTimeZoneSensitive()) {
346                 Calendar temp = CalendarFactoryUtil.getCalendar();
347 
348                 temp.setTime(Time.getDate(now));
349 
350                 now = temp;
351             }
352 
353             Calendar startDate = null;
354 
355             if (event.isTimeZoneSensitive()) {
356                 startDate = CalendarFactoryUtil.getCalendar(
357                     user.getTimeZone(), user.getLocale());
358             }
359             else {
360                 startDate = CalendarFactoryUtil.getCalendar();
361             }
362 
363             if (event.isRepeating()) {
364                 double daysToCheck = Math.ceil(
365                     CalEventImpl.REMINDERS[CalEventImpl.REMINDERS.length - 1] /
366                     Time.DAY);
367 
368                 Calendar cal = (Calendar)now.clone();
369 
370                 for (int i = 0; i <= daysToCheck; i++) {
371                     Recurrence recurrence = event.getRecurrenceObj();
372 
373                     Calendar tzICal = CalendarFactoryUtil.getCalendar(
374                         cal.get(Calendar.YEAR), cal.get(Calendar.MONTH),
375                         cal.get(Calendar.DATE));
376 
377                     Calendar recurrenceCal = getRecurrenceCal(
378                         cal, tzICal, event);
379 
380                     if (recurrence.isInRecurrence(recurrenceCal)) {
381                         remindUser(event, user, recurrenceCal, now);
382                     }
383 
384                     cal.add(Calendar.DAY_OF_YEAR, 1);
385                 }
386             }
387             else {
388                 startDate.setTime(event.getStartDate());
389 
390                 remindUser(event, user, startDate, now);
391             }
392         }
393     }
394 
395     public void deleteEvent(CalEvent event)
396         throws PortalException, SystemException {
397 
398         // Event
399 
400         calEventPersistence.remove(event);
401 
402         // Resources
403 
404         resourceLocalService.deleteResource(
405             event.getCompanyId(), CalEvent.class.getName(),
406             ResourceConstants.SCOPE_INDIVIDUAL, event.getEventId());
407 
408         // Expando
409 
410         expandoValueLocalService.deleteValues(
411             CalEvent.class.getName(), event.getEventId());
412 
413         // Social
414 
415         socialActivityLocalService.deleteActivities(
416             CalEvent.class.getName(), event.getEventId());
417 
418         // Pool
419 
420         CalEventLocalUtil.clearEventsPool(event.getGroupId());
421     }
422 
423     public void deleteEvent(long eventId)
424         throws PortalException, SystemException {
425 
426         CalEvent event = calEventPersistence.findByPrimaryKey(eventId);
427 
428         deleteEvent(event);
429     }
430 
431     public void deleteEvents(long groupId)
432         throws PortalException, SystemException {
433 
434         Iterator<CalEvent> itr = calEventPersistence.findByGroupId(
435             groupId).iterator();
436 
437         while (itr.hasNext()) {
438             CalEvent event = itr.next();
439 
440             deleteEvent(event);
441         }
442     }
443 
444     public File exportEvent(long userId, long eventId)
445         throws PortalException, SystemException {
446 
447         List<CalEvent> events = new ArrayList<CalEvent>();
448 
449         CalEvent event = calEventPersistence.findByPrimaryKey(eventId);
450 
451         events.add(event);
452 
453         return exportICal4j(toICalCalendar(userId, events), null);
454     }
455 
456     public File exportGroupEvents(long userId, long groupId, String fileName)
457         throws PortalException, SystemException {
458 
459         List<CalEvent> events = calEventPersistence.findByGroupId(groupId);
460 
461         return exportICal4j(toICalCalendar(userId, events), fileName);
462     }
463 
464     public CalEvent getEvent(long eventId)
465         throws PortalException, SystemException {
466 
467         return calEventPersistence.findByPrimaryKey(eventId);
468     }
469 
470     public List<CalEvent> getEvents(long groupId, Calendar cal)
471         throws SystemException {
472 
473         Map<String, List<CalEvent>> eventsPool =
474             CalEventLocalUtil.getEventsPool(groupId);
475 
476         String key = CalUtil.toString(cal);
477 
478         List<CalEvent> events = eventsPool.get(key);
479 
480         if (events == null) {
481 
482             // Time zone sensitive
483 
484             List<CalEvent> events1 = calEventFinder.findByG_SD(
485                 groupId, CalendarUtil.getGTDate(cal),
486                 CalendarUtil.getLTDate(cal), true);
487 
488             // Time zone insensitive
489 
490             Calendar tzICal = CalendarFactoryUtil.getCalendar(
491                 cal.get(Calendar.YEAR), cal.get(Calendar.MONTH),
492                 cal.get(Calendar.DATE));
493 
494             List<CalEvent> events2 = calEventFinder.findByG_SD(
495                 groupId, CalendarUtil.getGTDate(tzICal),
496                 CalendarUtil.getLTDate(tzICal), false);
497 
498             // Create new list
499 
500             events = new ArrayList<CalEvent>();
501 
502             events.addAll(events1);
503             events.addAll(events2);
504 
505             // Add repeating events
506 
507             Iterator<CalEvent> itr = getRepeatingEvents(groupId).iterator();
508 
509             while (itr.hasNext()) {
510                 CalEvent event = itr.next();
511 
512                 TZSRecurrence recurrence = event.getRecurrenceObj();
513 
514                 try {
515 
516                     // LEP-3468
517 
518                     if ((recurrence.getFrequency() !=
519                             Recurrence.NO_RECURRENCE) &&
520                         (recurrence.getInterval() <= 0)) {
521 
522                         recurrence.setInterval(1);
523 
524                         event.setRecurrenceObj(recurrence);
525 
526                         event = calEventPersistence.update(event, false);
527 
528                         recurrence = event.getRecurrenceObj();
529                     }
530 
531                     if (recurrence.isInRecurrence(
532                             getRecurrenceCal(cal, tzICal, event))) {
533 
534                         events.add(event);
535                     }
536                 }
537                 catch (Exception e) {
538                     _log.error(e.getMessage());
539                 }
540             }
541 
542             events = new UnmodifiableList<CalEvent>(events);
543 
544             eventsPool.put(key, events);
545         }
546 
547         return events;
548     }
549 
550     public List<CalEvent> getEvents(long groupId, Calendar cal, String type)
551         throws SystemException {
552 
553         List<CalEvent> events = getEvents(groupId, cal);
554 
555         if (Validator.isNull(type)) {
556             return events;
557         }
558         else {
559             events = new ArrayList<CalEvent>(events);
560 
561             Iterator<CalEvent> itr = events.iterator();
562 
563             while (itr.hasNext()) {
564                 CalEvent event = itr.next();
565 
566                 if (!event.getType().equals(type)) {
567                     itr.remove();
568                 }
569             }
570 
571             return events;
572         }
573     }
574 
575     public List<CalEvent> getEvents(
576             long groupId, String type, int start, int end)
577         throws SystemException {
578 
579         if (Validator.isNull(type)) {
580             return calEventPersistence.findByGroupId(groupId, start, end);
581         }
582         else {
583             return calEventPersistence.findByG_T(groupId, type, start, end);
584         }
585     }
586 
587     public int getEventsCount(long groupId, String type)
588         throws SystemException {
589 
590         if (Validator.isNull(type)) {
591             return calEventPersistence.countByGroupId(groupId);
592         }
593         else {
594             return calEventPersistence.countByG_T(groupId, type);
595         }
596     }
597 
598     public List<CalEvent> getRepeatingEvents(long groupId)
599         throws SystemException {
600 
601         Map<String, List<CalEvent>> eventsPool =
602             CalEventLocalUtil.getEventsPool(groupId);
603 
604         String key = "recurrence";
605 
606         List<CalEvent> events = eventsPool.get(key);
607 
608         if (events == null) {
609             events = calEventPersistence.findByG_R(groupId, true);
610 
611             events = new UnmodifiableList<CalEvent>(events);
612 
613             eventsPool.put(key, events);
614         }
615 
616         return events;
617     }
618 
619     public boolean hasEvents(long groupId, Calendar cal)
620         throws SystemException {
621 
622         return hasEvents(groupId, cal, null);
623     }
624 
625     public boolean hasEvents(long groupId, Calendar cal, String type)
626         throws SystemException {
627 
628         if (getEvents(groupId, cal, type).size() > 0) {
629             return true;
630         }
631         else {
632             return false;
633         }
634     }
635 
636     public void importICal4j(long userId, long groupId, File file)
637         throws PortalException, SystemException {
638 
639         FileReader fileReader = null;
640 
641         try {
642             fileReader = new FileReader(file);
643 
644             CalendarBuilder builder = new CalendarBuilder();
645 
646             net.fortuna.ical4j.model.Calendar calendar = builder.build(
647                 fileReader);
648 
649             Iterator<VEvent> itr = calendar.getComponents(
650                 Component.VEVENT).iterator();
651 
652             while (itr.hasNext()) {
653                 VEvent vEvent = itr.next();
654 
655                 importICal4j(userId, groupId, vEvent);
656             }
657         }
658         catch (IOException ioe) {
659             throw new SystemException(ioe.getMessage());
660         }
661         catch (ParserException pe) {
662             throw new SystemException(pe.getMessage());
663         }
664         finally {
665             try {
666                 fileReader.close();
667             }
668             catch (IOException ioe) {
669                 _log.error(ioe);
670             }
671         }
672     }
673 
674     public void reIndex(CalEvent event) throws SystemException {
675         long companyId = event.getCompanyId();
676         long groupId = event.getGroupId();
677         long userId = event.getUserId();
678         long eventId = event.getEventId();
679         String userName = event.getUserName();
680         String title = event.getTitle();
681         String description = event.getDescription();
682         Date modifiedDate = event.getModifiedDate();
683 
684         String[] tagsEntries = tagsEntryLocalService.getEntryNames(
685             CalEvent.class.getName(), eventId);
686 
687         ExpandoBridge expandoBridge = event.getExpandoBridge();
688 
689         try {
690             Indexer.updateEvent(
691                 companyId, groupId, userId, userName, eventId, title,
692                 description, modifiedDate, tagsEntries, expandoBridge);
693         }
694         catch (SearchException se) {
695             _log.error("Reindexing " + eventId, se);
696         }
697     }
698 
699     public void reIndex(long eventId) throws SystemException {
700         if (SearchEngineUtil.isIndexReadOnly()) {
701             return;
702         }
703 
704         CalEvent event = calEventPersistence.fetchByPrimaryKey(eventId);
705 
706         if (event == null) {
707             return;
708         }
709 
710         reIndex(event);
711     }
712 
713     public void reIndex(String[] ids) throws SystemException {
714         if (SearchEngineUtil.isIndexReadOnly()) {
715             return;
716         }
717 
718         long companyId = GetterUtil.getLong(ids[0]);
719 
720         try {
721             reIndexEvents(companyId);
722         }
723         catch (SystemException se) {
724             throw se;
725         }
726         catch (Exception e) {
727             throw new SystemException(e);
728         }
729     }
730 
731     public Hits search(
732             long companyId, long groupId, long userId, long ownerUserId,
733             String keywords, int start, int end)
734         throws SystemException {
735 
736         try {
737             BooleanQuery contextQuery = BooleanQueryFactoryUtil.create();
738 
739             contextQuery.addRequiredTerm(Field.PORTLET_ID, Indexer.PORTLET_ID);
740 
741             if (groupId > 0) {
742                 Group group = groupLocalService.getGroup(groupId);
743 
744                 if (group.isLayout()) {
745                     contextQuery.addRequiredTerm(Field.SCOPE_GROUP_ID, groupId);
746 
747                     groupId = group.getParentGroupId();
748                 }
749 
750                 contextQuery.addRequiredTerm(Field.GROUP_ID, groupId);
751             }
752 
753             if (ownerUserId > 0) {
754                 contextQuery.addRequiredTerm(Field.USER_ID, ownerUserId);
755             }
756 
757             BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
758 
759             if (Validator.isNotNull(keywords)) {
760                 searchQuery.addTerm(Field.USER_NAME, keywords);
761                 searchQuery.addTerm(Field.TITLE, keywords);
762                 searchQuery.addTerm(Field.DESCRIPTION, keywords);
763                 searchQuery.addTerm(Field.TAGS_ENTRIES, keywords, true);
764             }
765 
766             BooleanQuery fullQuery = BooleanQueryFactoryUtil.create();
767 
768             fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
769 
770             if (searchQuery.clauses().size() > 0) {
771                 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
772             }
773 
774             return SearchEngineUtil.search(
775                 companyId, groupId, userId, CalEvent.class.getName(), fullQuery,
776                 start, end);
777         }
778         catch (Exception e) {
779             throw new SystemException(e);
780         }
781     }
782 
783     public CalEvent updateEvent(
784             long userId, long eventId, String title, String description,
785             int startDateMonth, int startDateDay, int startDateYear,
786             int startDateHour, int startDateMinute, int endDateMonth,
787             int endDateDay, int endDateYear, int durationHour,
788             int durationMinute, boolean allDay, boolean timeZoneSensitive,
789             String type, boolean repeating, TZSRecurrence recurrence,
790             int remindBy, int firstReminder, int secondReminder,
791             ServiceContext serviceContext)
792         throws PortalException, SystemException {
793 
794         // Event
795 
796         User user = userPersistence.findByPrimaryKey(userId);
797 
798         Locale locale = null;
799         TimeZone timeZone = null;
800 
801         if (timeZoneSensitive) {
802             locale = user.getLocale();
803             timeZone = user.getTimeZone();
804         }
805         else {
806             locale = LocaleUtil.getDefault();
807             timeZone = TimeZoneUtil.getDefault();
808         }
809 
810         Calendar startDate = CalendarFactoryUtil.getCalendar(timeZone, locale);
811 
812         startDate.set(Calendar.MONTH, startDateMonth);
813         startDate.set(Calendar.DATE, startDateDay);
814         startDate.set(Calendar.YEAR, startDateYear);
815         startDate.set(Calendar.HOUR_OF_DAY, startDateHour);
816         startDate.set(Calendar.MINUTE, startDateMinute);
817         startDate.set(Calendar.SECOND, 0);
818         startDate.set(Calendar.MILLISECOND, 0);
819 
820         Calendar endDate = CalendarFactoryUtil.getCalendar(timeZone, locale);
821 
822         endDate.set(Calendar.MONTH, endDateMonth);
823         endDate.set(Calendar.DATE, endDateDay);
824         endDate.set(Calendar.YEAR, endDateYear);
825         endDate.set(Calendar.HOUR_OF_DAY, 23);
826         endDate.set(Calendar.MINUTE, 59);
827         endDate.set(Calendar.SECOND, 59);
828         endDate.set(Calendar.MILLISECOND, 999);
829 
830         if (allDay) {
831             startDate.set(Calendar.HOUR_OF_DAY, 0);
832             startDate.set(Calendar.MINUTE, 0);
833 
834             durationHour = 24;
835             durationMinute = 0;
836         }
837 
838         validate(
839             title, startDateMonth, startDateDay, startDateYear, endDateMonth,
840             endDateDay, endDateYear, durationHour, durationMinute, allDay,
841             repeating);
842 
843         CalEvent event = calEventPersistence.findByPrimaryKey(eventId);
844 
845         event.setModifiedDate(new Date());
846         event.setTitle(title);
847         event.setDescription(description);
848         event.setStartDate(startDate.getTime());
849         event.setEndDate(endDate.getTime());
850         event.setDurationHour(durationHour);
851         event.setDurationMinute(durationMinute);
852         event.setAllDay(allDay);
853         event.setTimeZoneSensitive(timeZoneSensitive);
854         event.setType(type);
855         event.setRepeating(repeating);
856         event.setRecurrenceObj(recurrence);
857         event.setRemindBy(remindBy);
858         event.setFirstReminder(firstReminder);
859         event.setSecondReminder(secondReminder);
860         event.setExpandoBridgeAttributes(serviceContext);
861 
862         calEventPersistence.update(event, false);
863 
864         // Social
865 
866         socialActivityLocalService.addActivity(
867             userId, event.getGroupId(), CalEvent.class.getName(), eventId,
868             CalendarActivityKeys.UPDATE_EVENT, StringPool.BLANK, 0);
869 
870         // Indexer
871 
872         reIndex(event);
873 
874         // Pool
875 
876         CalEventLocalUtil.clearEventsPool(event.getGroupId());
877 
878         return event;
879     }
880 
881     protected File exportICal4j(
882             net.fortuna.ical4j.model.Calendar cal, String fileName)
883         throws SystemException {
884 
885         OutputStream os = null;
886 
887         try {
888             String extension = ".ics";
889 
890             if (Validator.isNull(fileName)) {
891                 fileName = "liferay.";
892             }
893             else {
894                 int pos = fileName.lastIndexOf(StringPool.PERIOD);
895 
896                 if (pos != -1) {
897                     extension = fileName.substring(pos);
898                     fileName = fileName.substring(0, pos);
899                 }
900             }
901 
902             File file = File.createTempFile(fileName, extension);
903 
904             os = new UnsyncBufferedOutputStream(
905                 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             StreamUtil.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            Format dateFormatDateTime = FastDateFormatFactoryUtil.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        // LPS-6058
1385
1386        props.add(Method.PUBLISH);
1387
1388        User user = userPersistence.findByPrimaryKey(userId);
1389        TimeZone timeZone = user.getTimeZone();
1390
1391        List<VEvent> components = iCal.getComponents();
1392
1393        Iterator<CalEvent> itr = events.iterator();
1394
1395        while (itr.hasNext()) {
1396            CalEvent event = itr.next();
1397
1398            components.add(toICalVEvent(event, timeZone));
1399        }
1400
1401        return iCal;
1402    }
1403
1404    protected Recur toICalRecurrence(TZSRecurrence recurrence) {
1405        Recur recur = null;
1406
1407        int recurrenceType = recurrence.getFrequency();
1408
1409        int interval = recurrence.getInterval();
1410
1411        if (recurrenceType == Recurrence.DAILY) {
1412            recur = new Recur(Recur.DAILY, -1);
1413
1414            if (interval >= 1) {
1415                recur.setInterval(interval);
1416            }
1417
1418            DayAndPosition[] byDay = recurrence.getByDay();
1419
1420            if (byDay != null) {
1421                for (int i = 0; i < byDay.length; i++) {
1422                    WeekDay weekDay = toICalWeekDay(byDay[i].getDayOfWeek());
1423
1424                    recur.getDayList().add(weekDay);
1425                }
1426            }
1427
1428        }
1429        else if (recurrenceType == Recurrence.WEEKLY) {
1430            recur = new Recur(Recur.WEEKLY, -1);
1431
1432            recur.setInterval(interval);
1433
1434            DayAndPosition[] byDay = recurrence.getByDay();
1435
1436            if (byDay != null) {
1437                for (int i = 0; i < byDay.length; i++) {
1438                    WeekDay weekDay = toICalWeekDay(byDay[i].getDayOfWeek());
1439
1440                    recur.getDayList().add(weekDay);
1441                }
1442            }
1443        }
1444        else if (recurrenceType == Recurrence.MONTHLY) {
1445            recur = new Recur(Recur.MONTHLY, -1);
1446
1447            recur.setInterval(interval);
1448
1449            int[] byMonthDay = recurrence.getByMonthDay();
1450
1451            if (byMonthDay != null) {
1452                Integer monthDay = new Integer(byMonthDay[0]);
1453
1454                recur.getMonthDayList().add(monthDay);
1455            }
1456            else if (recurrence.getByDay() != null) {
1457                DayAndPosition[] byDay = recurrence.getByDay();
1458
1459                WeekDay weekDay = toICalWeekDay(byDay[0].getDayOfWeek());
1460
1461                recur.getDayList().add(weekDay);
1462
1463                Integer position = new Integer(byDay[0].getDayPosition());
1464
1465                recur.getSetPosList().add(position);
1466            }
1467        }
1468        else if (recurrenceType == Recurrence.YEARLY) {
1469            recur = new Recur(Recur.YEARLY, -1);
1470
1471            recur.setInterval(interval);
1472        }
1473
1474        Calendar until = recurrence.getUntil();
1475
1476        if (until != null) {
1477            DateTime dateTime = new DateTime(until.getTime());
1478
1479            recur.setUntil(dateTime);
1480        }
1481
1482        return recur;
1483    }
1484
1485    protected VEvent toICalVEvent(CalEvent event, TimeZone timeZone) {
1486        VEvent vEvent = new VEvent();
1487
1488        PropertyList eventProps = vEvent.getProperties();
1489
1490        // UID
1491
1492        Uid uid = new Uid(PortalUUIDUtil.generate());
1493
1494        eventProps.add(uid);
1495
1496        if (event.isAllDay()) {
1497
1498            // Start date
1499
1500            DtStart dtStart = new DtStart(
1501                new net.fortuna.ical4j.model.Date(event.getStartDate()));
1502
1503            eventProps.add(dtStart);
1504
1505            Property dtStartProperty = eventProps.getProperty(Property.DTSTART);
1506
1507            dtStartProperty.getParameters().add(Value.DATE);
1508        }
1509        else {
1510
1511            // Start date
1512
1513            DtStart dtStart = new DtStart(new DateTime(event.getStartDate()));
1514
1515            eventProps.add(dtStart);
1516
1517            // Duration
1518
1519            Duration duration = new Duration(
1520                new Dur(
1521                    0, event.getDurationHour(), event.getDurationMinute(), 0));
1522
1523            eventProps.add(duration);
1524        }
1525
1526        // Summary
1527
1528        Summary summary = new Summary(event.getTitle());
1529
1530        eventProps.add(summary);
1531
1532        // Description
1533
1534        Description description = new Description(event.getDescription());
1535
1536        eventProps.add(description);
1537
1538        // Comment
1539
1540        Comment comment = new Comment(event.getType());
1541
1542        eventProps.add(comment);
1543
1544        // Recurrence rule
1545
1546        if (event.isRepeating()) {
1547            Recur recur = toICalRecurrence(event.getRecurrenceObj());
1548
1549            RRule rRule = new RRule(recur);
1550
1551            eventProps.add(rRule);
1552        }
1553
1554        // Time zone sensitive
1555
1556        if (!event.getTimeZoneSensitive()) {
1557            eventProps.add(new TimeZoneSensitive("FALSE"));
1558        }
1559
1560        return vEvent;
1561    }
1562
1563    protected WeekDay toICalWeekDay(int dayOfWeek) {
1564        WeekDay weekDay = null;
1565
1566        if (dayOfWeek == Calendar.SUNDAY) {
1567            weekDay = WeekDay.SU;
1568        }
1569        else if (dayOfWeek == Calendar.MONDAY) {
1570            weekDay = WeekDay.MO;
1571        }
1572        else if (dayOfWeek == Calendar.TUESDAY) {
1573            weekDay = WeekDay.TU;
1574        }
1575        else if (dayOfWeek == Calendar.WEDNESDAY) {
1576            weekDay = WeekDay.WE;
1577        }
1578        else if (dayOfWeek == Calendar.THURSDAY) {
1579            weekDay = WeekDay.TH;
1580        }
1581        else if (dayOfWeek == Calendar.FRIDAY) {
1582            weekDay = WeekDay.FR;
1583        }
1584        else if (dayOfWeek == Calendar.SATURDAY) {
1585            weekDay = WeekDay.SA;
1586        }
1587
1588        return weekDay;
1589    }
1590
1591    protected TZSRecurrence toRecurrence(
1592        RRule rRule, TimeZone timeZone, Calendar startDate) {
1593
1594        Recur recur = rRule.getRecur();
1595
1596        Calendar recStartCal = CalendarFactoryUtil.getCalendar(timeZone);
1597
1598        recStartCal.setTime(startDate.getTime());
1599
1600        TZSRecurrence recurrence = new TZSRecurrence(
1601            recStartCal,
1602            new com.liferay.portal.kernel.cal.Duration(1, 0, 0, 0));
1603
1604        recurrence.setWeekStart(Calendar.SUNDAY);
1605
1606        if (recur.getInterval() > 1) {
1607            recurrence.setInterval(recur.getInterval());
1608        }
1609
1610        Calendar until = Calendar.getInstance(timeZone);
1611
1612        String frequency = recur.getFrequency();
1613
1614        if (Validator.isNotNull(recur.getUntil())) {
1615            until.setTime(recur.getUntil());
1616
1617            recurrence.setUntil(until);
1618        }
1619        else if (rRule.getValue().indexOf("COUNT") >= 0) {
1620            until.setTimeInMillis(startDate.getTimeInMillis());
1621
1622            int addField = 0;
1623
1624            if (Recur.DAILY.equals(frequency)) {
1625                addField = Calendar.DAY_OF_YEAR;
1626            }
1627            else if (Recur.WEEKLY.equals(frequency)) {
1628                addField = Calendar.WEEK_OF_YEAR;
1629            }
1630            else if (Recur.MONTHLY.equals(frequency)) {
1631                addField = Calendar.MONTH;
1632            }
1633            else if (Recur.YEARLY.equals(frequency)) {
1634                addField = Calendar.YEAR;
1635            }
1636
1637            int addAmount = recurrence.getInterval() * recur.getCount();
1638
1639            until.add(addField, addAmount);
1640            until.add(Calendar.DAY_OF_YEAR, -1);
1641
1642            recurrence.setUntil(until);
1643        }
1644
1645        if (Recur.DAILY.equals(frequency)) {
1646            recurrence.setFrequency(Recurrence.DAILY);
1647
1648            List<DayAndPosition> dayPosList = new ArrayList<DayAndPosition>();
1649
1650            Iterator<WeekDay> itr = recur.getDayList().iterator();
1651
1652            while (itr.hasNext()) {
1653                WeekDay weekDay = itr.next();
1654
1655                dayPosList.add(
1656                    new DayAndPosition(toCalendarWeekDay(weekDay), 0));
1657            }
1658
1659            if (!dayPosList.isEmpty()) {
1660                recurrence.setByDay(
1661                    dayPosList.toArray(new DayAndPosition[dayPosList.size()]));
1662            }
1663        }
1664        else if (Recur.WEEKLY.equals(frequency)) {
1665            recurrence.setFrequency(Recurrence.WEEKLY);
1666
1667            List<DayAndPosition> dayPosList = new ArrayList<DayAndPosition>();
1668
1669            Iterator<WeekDay> itr = recur.getDayList().iterator();
1670
1671            while (itr.hasNext()) {
1672                WeekDay weekDay = itr.next();
1673
1674                dayPosList.add(
1675                    new DayAndPosition(toCalendarWeekDay(weekDay), 0));
1676            }
1677
1678            if (!dayPosList.isEmpty()) {
1679                recurrence.setByDay(
1680                    dayPosList.toArray(new DayAndPosition[dayPosList.size()]));
1681            }
1682        }
1683        else if (Recur.MONTHLY.equals(frequency)) {
1684            recurrence.setFrequency(Recurrence.MONTHLY);
1685
1686            Iterator<Integer> monthDayListItr =
1687                recur.getMonthDayList().iterator();
1688
1689            if (monthDayListItr.hasNext()) {
1690                Integer monthDay = monthDayListItr.next();
1691
1692                recurrence.setByMonthDay(new int[] {monthDay.intValue()});
1693            }
1694
1695            Iterator<WeekDay> dayListItr = recur.getDayList().iterator();
1696
1697            if (dayListItr.hasNext()) {
1698                WeekDay weekDay = dayListItr.next();
1699
1700                DayAndPosition[] dayPos = {
1701                    new DayAndPosition(toCalendarWeekDay(weekDay),
1702                    weekDay.getOffset())
1703                };
1704
1705                recurrence.setByDay(dayPos);
1706            }
1707        }
1708        else if (Recur.YEARLY.equals(frequency)) {
1709            recurrence.setFrequency(Recurrence.YEARLY);
1710        }
1711
1712        return recurrence;
1713    }
1714
1715    protected void validate(
1716            String title, int startDateMonth, int startDateDay,
1717            int startDateYear, int endDateMonth, int endDateDay,
1718            int endDateYear, int durationHour, int durationMinute,
1719            boolean allDay, boolean repeating)
1720        throws PortalException {
1721
1722        if (Validator.isNull(title)) {
1723            throw new EventTitleException();
1724        }
1725        else if (!Validator.isDate(
1726                startDateMonth, startDateDay, startDateYear)) {
1727
1728            throw new EventStartDateException();
1729        }
1730        else if (!Validator.isDate(endDateMonth, endDateDay, endDateYear)) {
1731            throw new EventEndDateException();
1732        }
1733
1734        if (!allDay && durationHour <= 0 && durationMinute <= 0) {
1735            throw new EventDurationException();
1736        }
1737
1738        Calendar startDate = CalendarFactoryUtil.getCalendar(
1739            startDateYear, startDateMonth, startDateDay);
1740
1741        Calendar endDate = CalendarFactoryUtil.getCalendar(
1742            endDateYear, endDateMonth, endDateDay);
1743
1744        if (repeating && startDate.after(endDate)) {
1745            throw new EventEndDateException();
1746        }
1747    }
1748
1749    private static Log _log =
1750        LogFactoryUtil.getLog(CalEventLocalServiceImpl.class);
1751
1752}