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