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