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