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