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