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