Remove unneccesary imports
[funambol-groupdav-connector.git] / src / main / java / net / bionicmessage / funambol / datakit / funambol2ical4j.java
blob8c98d9a314554f52ee74d8e6ba324adee73c145e
1 /* GroupDAV connector for Funambol v6.5
2 * Copyright (C) 2007 Mathew McBride
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License as
6 * published by the Free Software Foundation, either version 3 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Affero General Public License for more details.
14 * You should have received a copy of the GNU Affero General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 /**
18 * Converts Funambol calendar instances to ical4j
19 * @author matt
21 package net.bionicmessage.funambol.datakit;
23 import com.funambol.common.pim.utility.TimeUtils;
24 import com.funambol.framework.engine.source.SyncContext;
25 import java.net.URISyntaxException;
26 import java.text.ParseException;
27 import java.text.SimpleDateFormat;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Properties;
31 import java.util.TimeZone;
32 import java.util.logging.Level;
33 import java.util.logging.Logger;
34 import net.bionicmessage.funambol.framework.Constants;
35 import net.bionicmessage.funambol.framework.ObjectTransformationException;
36 import net.fortuna.ical4j.model.Calendar;
37 import net.fortuna.ical4j.model.component.VToDo;
39 public class funambol2ical4j {
41 public static Logger log = Logger.getLogger("groupdav.fnblical");
43 public static net.fortuna.ical4j.model.Calendar convertFunambolEvent2ical4jEvent(
44 com.funambol.common.pim.calendar.Calendar fnblcal,
45 Properties props,
46 SyncContext ctx) throws ObjectTransformationException {
47 /* Do the same thing here as we did in ical4j2funambol. Pick out each
48 * property we want and process it one by one */
49 net.fortuna.ical4j.model.Calendar ical4jcal =
50 new net.fortuna.ical4j.model.Calendar();
51 net.fortuna.ical4j.model.component.CalendarComponent cc = null;
52 if (fnblcal.getCalendarContent() instanceof com.funambol.common.pim.calendar.Event) {
53 cc = new net.fortuna.ical4j.model.component.VEvent();
54 } else if (fnblcal.getCalendarContent() instanceof com.funambol.common.pim.calendar.Task) {
55 cc = new net.fortuna.ical4j.model.component.VToDo();
58 ical4jcal.getComponents().add(cc);
59 /* if (props != null && props.getProperty("connector.timezone") != null)
60 tid = attachVTimeZone(
61 props.getProperty("connector.timezone"),
62 ical4jcal); */
63 String tz = null;
64 if (ctx.getPrincipal().getDevice().getConvertDatePolicy() == 0) {
65 tz = ctx.getPrincipal().getDevice().getTimeZone();
67 net.fortuna.ical4j.model.property.DtStart dts = null;
68 net.fortuna.ical4j.model.property.DtEnd dte = null;
69 com.funambol.common.pim.calendar.CalendarContent calcontent = fnblcal.getCalendarContent();
70 com.funambol.common.pim.common.Property uid = calcontent.getUid();
71 net.fortuna.ical4j.model.property.ProdId pri = new net.fortuna.ical4j.model.property.ProdId("-//BionicMessage Funambol Connector//funambol2ical4jconvert//EN");
72 ical4jcal.getProperties().add(pri);
73 ical4jcal.getProperties().add(net.fortuna.ical4j.model.property.Version.VERSION_2_0);
74 if (uid != null && uid.getPropertyValueAsString() != null) {
75 net.fortuna.ical4j.model.property.Uid ical4juid = new net.fortuna.ical4j.model.property.Uid(uid.getPropertyValueAsString());
76 cc.getProperties().add(ical4juid);
78 com.funambol.common.pim.common.Property dtstart = calcontent.getDtStart();
79 com.funambol.common.pim.common.Property dtend = calcontent.getDtEnd();
81 /* com.funambol.common.pim.common.Property clazz = fnblevent.getClassEvent();
82 if (clazz.getPropertyValue() != null) {
83 net.fortuna.ical4j.model.property.Clazz ical4jclazz =
84 new net.fortuna.ical4j.model.property.Clazz(clazz.getPropertyValueAsString());
85 ical4jevent.getProperties().add(ical4jclazz);
86 } */
88 if (hasValue(dtstart)) {
89 try {
90 String dtstartdate = dtstart.getPropertyValueAsString();
91 if (dtstartdate.length() == com.funambol.common.pim.utility.TimeUtils.PATTERN_YYYY_MM_DD_LENGTH) {
92 if (props.getProperty(Constants.UTC_RELATIVE_ALLDAY) == null) {
93 dts = new net.fortuna.ical4j.model.property.DtStart();
94 dts.getParameters().add(net.fortuna.ical4j.model.parameter.Value.DATE);
95 String formatted = dtstartdate.replace("-", "");
96 dts.setValue(formatted);
97 } else {
98 net.fortuna.ical4j.model.DateTime deds = createOGo1AllDayDtStart(dtstartdate,
99 ctx.getPrincipal().getDevice().getTimeZone());
100 dts = new net.fortuna.ical4j.model.property.DtStart(deds);
102 } else {
103 net.fortuna.ical4j.model.DateTime dtdt = parseIntoDateTime(dtstartdate, tz);
104 dts = new net.fortuna.ical4j.model.property.DtStart(dtdt);
107 cc.getProperties().add(dts);
108 } catch (Exception ex) {
109 log.severe("Error thrown in dtstart conversion: " + ex.getMessage());
110 throw new ObjectTransformationException("Error in DTSTART conversion", ex);
114 if (hasValue(dtend)) {
115 try {
116 String dtenddate = dtend.getPropertyValueAsString();
117 /* CHECK: Funambol rolls dtend back if dtend(value=date)
118 &&dtstart(value==date). If Funambol has rolled them back, stop it here */
119 if (dtenddate.length() == com.funambol.common.pim.utility.TimeUtils.PATTERN_YYYY_MM_DD_LENGTH) {
120 if (dtstart.getPropertyValueAsString().equals(dtenddate)) {
121 String rolledUp = TimeUtils.rollOneDay(dtenddate, true);
122 dte = new net.fortuna.ical4j.model.property.DtEnd();
123 dte.getParameters().add(net.fortuna.ical4j.model.parameter.Value.DATE);
124 dte.setValue(rolledUp);
126 if (props.getProperty(Constants.UTC_RELATIVE_ALLDAY) == null) {
127 dte = new net.fortuna.ical4j.model.property.DtEnd();
128 dte.getParameters().add(net.fortuna.ical4j.model.parameter.Value.DATE);
129 String formatted = dtenddate.replace("-", "");
130 dte.setValue(formatted);
131 } else {
132 net.fortuna.ical4j.model.DateTime dedt = createOGo1AllDayDtEnd(dtenddate,
133 ctx.getPrincipal().getDevice().getTimeZone());
134 dte = new net.fortuna.ical4j.model.property.DtEnd(dedt);
136 } else {
137 net.fortuna.ical4j.model.DateTime dedt = parseIntoDateTime(dtenddate, tz);
138 dte = new net.fortuna.ical4j.model.property.DtEnd(dedt);
140 cc.getProperties().add(dte);
141 } catch (Exception ex) {
142 throw new ObjectTransformationException("Error caught in dtend conversion", ex);
145 com.funambol.common.pim.common.Property summ = calcontent.getSummary();
146 if (hasValue(summ)) {
147 net.fortuna.ical4j.model.property.Summary ical4jsumm =
148 new net.fortuna.ical4j.model.property.Summary(summ.getPropertyValueAsString());
149 cc.getProperties().add(ical4jsumm);
150 } else {
151 net.fortuna.ical4j.model.property.Summary blankSumm =
152 new net.fortuna.ical4j.model.property.Summary("No summary entered");
153 cc.getProperties().add(blankSumm);
155 com.funambol.common.pim.common.Property description = calcontent.getDescription();
156 if (hasValue(description)) {
157 net.fortuna.ical4j.model.property.Description ical4jdescription =
158 new net.fortuna.ical4j.model.property.Description(description.getPropertyValueAsString());
159 cc.getProperties().add(ical4jdescription);
161 com.funambol.common.pim.common.Property location = calcontent.getLocation();
162 if (hasValue(location)) {
163 net.fortuna.ical4j.model.property.Location ical4jlocation =
164 new net.fortuna.ical4j.model.property.Location(location.getPropertyValueAsString());
165 cc.getProperties().add(ical4jlocation);
167 com.funambol.common.pim.calendar.RecurrencePattern rp = calcontent.getRecurrencePattern();
168 if (rp != null) {
169 net.fortuna.ical4j.model.property.RRule ical4jrrule =
170 new net.fortuna.ical4j.model.property.RRule();
171 net.fortuna.ical4j.model.Recur ical4jrecur = ical4jrrule.getRecur();
172 String type = rp.getTypeDesc();
173 net.fortuna.ical4j.model.WeekDayList wdList =
174 ical4jrecur.getDayList();
175 for(String d: rp.getDayOfWeek()) {
176 net.fortuna.ical4j.model.WeekDay wd =
177 new net.fortuna.ical4j.model.WeekDay(d);
178 wdList.add(wd);
180 if (rp.isNoEndDate()) {
181 ical4jrecur.setCount(rp.getOccurrences());
182 ical4jrecur.setInterval(rp.getInterval());
183 } else {
184 try {
185 String endDate = rp.getEndDatePattern();
186 net.fortuna.ical4j.model.DateTime endD = parseIntoDateTime(endDate, tz);
188 ical4jrecur.setUntil(endD);
189 } catch (ParseException ex) {
190 java.util.logging.Logger.getLogger("global").log(java.util.logging.Level.SEVERE,
191 ex.getMessage(),
192 ex);
195 if (type.equals("D")) {
196 /* Daily recurrence */
197 ical4jrecur.setFrequency(net.fortuna.ical4j.model.Recur.DAILY);
198 } else if (type.equals("W")) {
199 ical4jrecur.setFrequency(net.fortuna.ical4j.model.Recur.WEEKLY);
200 } else if (type.equals("MP")) {
201 ical4jrecur.setFrequency(net.fortuna.ical4j.model.Recur.MONTHLY);
202 List<String> daysOfWeek = rp.getDayOfWeek();
203 String day = (String) rp.getDayOfWeek().get(0);
204 Short moffset = new Short(rp.getInstance());
205 net.fortuna.ical4j.model.WeekDay wd =
206 new net.fortuna.ical4j.model.WeekDay(day, moffset.intValue());
207 ical4jrecur.getDayList().add(wd);
208 } else if (type.equals("MD")) {
209 ical4jrecur.setFrequency(net.fortuna.ical4j.model.Recur.MONTHLY);
210 Short monthdaymask = new Short(rp.getDayOfMonth());
211 Integer mdmask = new Integer(monthdaymask.intValue());
212 ical4jrecur.getMonthDayList().add(mdmask);
213 } else if (type.equals("YM")) {
214 // Grumble grumble.. we don't know if its MONTH or MONTH_NTH
215 ical4jrecur.setFrequency(net.fortuna.ical4j.model.Recur.YEARLY);
216 Short monthofyear = new Short(rp.getMonthOfYear());
217 if (rp.getTypeId() == rp.TYPE_YEAR_NTH) {
218 Short moffset = new Short(rp.getInstance());
219 String day = (String) rp.getDayOfWeek().get(0);
220 net.fortuna.ical4j.model.WeekDay wd =
221 new net.fortuna.ical4j.model.WeekDay(day, moffset.intValue());
222 ical4jrecur.getDayList().add(wd);
223 ical4jrecur.getMonthList().add(new Integer(monthofyear.intValue()));
224 } else {
225 Short dayofmonth = new Short(rp.getDayOfMonth());
226 ical4jrecur.getMonthDayList().add(new Integer(dayofmonth.intValue()));
227 ical4jrecur.getMonthList().add(new Integer(monthofyear.intValue()));
230 if (rp.getExceptions() != null &&
231 rp.getExceptions().size() > 0) {
232 List<com.funambol.common.pim.calendar.ExceptionToRecurrenceRule> etrr =
233 rp.getExceptions();
234 StringBuffer dateString = new StringBuffer();
235 net.fortuna.ical4j.model.property.ExDate exDate =
236 new net.fortuna.ical4j.model.property.ExDate();
237 boolean is_date = false;
238 for (com.funambol.common.pim.calendar.ExceptionToRecurrenceRule et : etrr) {
239 if (dateString.length() > 0) {
240 dateString.append(",");
242 String date = et.getDate();
243 // Guaranteed to be in the wrong format, this slab is ripped from ExceptionToRecurrenceRule
244 String format = TimeUtils.getDateFormat(date.replaceAll("[Z:\\-]", ""));
245 if (format != null && TimeUtils.PATTERN_YYYY_MM_DD.equals(format)) {
246 try {
247 date = TimeUtils.convertDateFromTo(date, TimeUtils.PATTERN_YYYYMMDD);
248 is_date = true;
249 } catch (Exception ex) {
250 ex.printStackTrace(); // lets hope this enver happens
253 dateString.append(date);
255 if (is_date) {
256 exDate.getParameters().add(net.fortuna.ical4j.model.parameter.Value.DATE);
257 } else {
258 exDate.getParameters().add(net.fortuna.ical4j.model.parameter.Value.DATE_TIME);
260 try {
261 exDate.setValue(dateString.toString());
262 cc.getProperties().add(exDate);
263 } catch (ParseException ex) {
264 ex.printStackTrace();
268 cc.getProperties().add(ical4jrrule);
270 com.funambol.common.pim.common.Property categories = calcontent.getCategories();
271 if (hasValue(categories)) {
272 net.fortuna.ical4j.model.property.Categories cat =
273 new net.fortuna.ical4j.model.property.Categories();
274 cat.setValue(categories.getPropertyValueAsString());
275 cc.getProperties().add(cat);
277 if (cc.getName().equals(VToDo.VTODO)) {
278 com.funambol.common.pim.calendar.Task fnblTask = fnblcal.getTask();
279 com.funambol.common.pim.common.Property priority = fnblTask.getPriority();
280 if (hasValue(priority)) {
281 net.fortuna.ical4j.model.property.Priority prip = new net.fortuna.ical4j.model.property.Priority();
282 prip.setValue(priority.getPropertyValueAsString());
283 cc.getProperties().add(prip);
285 /* com.funambol.common.pim.common.Property complete = fnblTask.getComplete();
286 if (hasValue(complete)) {
287 String value = complete.getPropertyValueAsString();
288 if (value.equals("1")) {
289 net.fortuna.ical4j.model.property.Status stat = new net.fortuna.ical4j.model.property.Status();
290 stat.setValue("COMPLETED");
291 cc.getProperties().add(stat);
293 } */
294 com.funambol.common.pim.common.Property status = fnblTask.getComplete();
295 if (hasValue(status)) {
296 net.fortuna.ical4j.model.property.Status stat =
297 new net.fortuna.ical4j.model.property.Status();
298 //todo: probably better if we use the defined mappings in S4j2IcalMapping
299 Boolean statusValue = (Boolean) status.getPropertyValue();
300 if (statusValue.booleanValue()) {
301 stat.setValue("COMPLETED");
302 } else {
303 stat.setValue("IN-PROCESS");
306 cc.getProperties().add(stat);
309 // If we have DTEND instead of DUE, swap
310 if (dte != null) {
311 cc.getProperties().remove(dte);
312 net.fortuna.ical4j.model.property.Due due =
313 new net.fortuna.ical4j.model.property.Due(dte.getDate());
314 cc.getProperties().add(due);
318 if (props.getProperty(Constants.CONVERT_ALARMS) != null) {
319 com.funambol.common.pim.common.Property dalarm = calcontent.getDAlarm();
320 if (hasValue(dalarm)) {
321 try {
322 String[] attributes = dalarm.getPropertyValueAsString().split(";");
323 String dt = attributes[0];
324 if (!dt.contains("Z")) {
325 dt = dt.concat("Z");
327 attachVAlarm(dt, 0, cc, tz);
328 } catch (ParseException ex) {
329 Logger.getLogger(funambol2ical4j.class.getName()).log(Level.SEVERE, null, ex);
333 if (calcontent instanceof com.funambol.common.pim.calendar.Event) {
334 com.funambol.common.pim.calendar.Event calEvent =
335 (com.funambol.common.pim.calendar.Event) calcontent;
336 List<com.funambol.common.pim.calendar.Attendee> attendeeList = calEvent.getAttendees();
337 Iterator<com.funambol.common.pim.calendar.Attendee> attItr = attendeeList.iterator();
338 while (attItr.hasNext()) {
339 com.funambol.common.pim.calendar.Attendee attendee = attItr.next();
340 net.fortuna.ical4j.model.property.Attendee ical4jatt =
341 new net.fortuna.ical4j.model.property.Attendee();
342 String cn = attendee.getName();
343 net.fortuna.ical4j.model.parameter.Cn cnPara =
344 new net.fortuna.ical4j.model.parameter.Cn(cn);
345 // Fix as INVDIVIDUAL for now.
346 net.fortuna.ical4j.model.parameter.CuType cuPara =
347 net.fortuna.ical4j.model.parameter.CuType.INDIVIDUAL;
348 ical4jatt.getParameters().add(cnPara);
349 ical4jatt.getParameters().add(cuPara);
350 String email = attendee.getEmail();
351 if (email != null && email.length() > 0) {
352 email = "MAILTO:" + email;
353 try {
354 ical4jatt.setValue(email);
355 cc.getProperties().add(ical4jatt);
356 } catch (URISyntaxException ex) {
357 log.log(Level.SEVERE, "Error converting attendee email address", ex);
360 short status = attendee.getStatus();
361 net.fortuna.ical4j.model.parameter.PartStat partStat =
362 AttendeeConverter.getPartStartFromShort(status);
363 ical4jatt.getParameters().add(partStat);
366 return ical4jcal;
369 public static net.fortuna.ical4j.model.DateTime parseIntoDateTime(String dt, String timezone) throws ParseException {
370 SimpleDateFormat sdf = null;
371 TimeZone tz = null;
372 /* DANGER: Funambol will stick a stupid Z at the end of a datetime even when it isn't
373 * UTC. Cut it off */
374 if (dt.contains("Z") && dt.length() == com.funambol.common.pim.utility.TimeUtils.PATTERN_UTC_LENGTH) {
375 sdf = new SimpleDateFormat(com.funambol.common.pim.utility.TimeUtils.PATTERN_UTC);
376 if (timezone != null) {
377 tz = TimeZone.getTimeZone(timezone);
378 } else {
379 tz = TimeZone.getTimeZone("UTC");
381 sdf.setTimeZone(tz);
382 } else if (dt.length() == com.funambol.common.pim.utility.TimeUtils.PATTERN_UTC_WOZ_LENGTH) {
383 sdf = new SimpleDateFormat(com.funambol.common.pim.utility.TimeUtils.PATTERN_UTC_WOZ);
385 java.util.Date ds = sdf.parse(dt);
386 net.fortuna.ical4j.model.DateTime dedt =
387 new net.fortuna.ical4j.model.DateTime(ds);
388 if (tz != null) {
389 dedt.setUtc(true);
391 return dedt;
394 public static net.fortuna.ical4j.model.DateTime createOGo1AllDayDtStart(String dateString, String tz)
395 throws ParseException, ObjectTransformationException {
396 if (tz == null) {
397 throw new ObjectTransformationException("Please set the timezone for the device for GMT All day mode");
399 SimpleDateFormat sdf = new SimpleDateFormat(com.funambol.common.pim.utility.TimeUtils.PATTERN_YYYY_MM_DD);
400 TimeZone tzz = TimeZone.getTimeZone(tz);
401 sdf.setTimeZone(tzz);
402 java.util.Date ds = sdf.parse(dateString);
403 net.fortuna.ical4j.model.DateTime deds = new net.fortuna.ical4j.model.DateTime(ds);
404 deds.setUtc(true);
405 return deds;
409 public static net.fortuna.ical4j.model.DateTime createOGo1AllDayDtEnd(String dateString, String tz)
410 throws ParseException, ObjectTransformationException {
411 if (tz == null) {
412 throw new ObjectTransformationException("Please set the timezone for the device for GMT All day mode");
414 SimpleDateFormat sdf = new SimpleDateFormat(com.funambol.common.pim.utility.TimeUtils.PATTERN_YYYY_MM_DD);
415 TimeZone tzz = TimeZone.getTimeZone(tz);
416 sdf.setTimeZone(tzz);
417 java.util.Date dt = sdf.parse(dateString);
418 java.util.Calendar cl = java.util.Calendar.getInstance(tzz);
419 cl.setTime(dt);
420 cl.set(java.util.Calendar.HOUR, 23);
421 cl.set(java.util.Calendar.MINUTE, 59);
422 //cl.set(java.util.Calendar.SECOND, 59);
423 net.fortuna.ical4j.model.DateTime dedt = new net.fortuna.ical4j.model.DateTime(cl.getTime());
424 dedt.setUtc(true);
425 return dedt;
428 public static String attachVTimeZone(String vtimezoneLoc, Calendar toAttach) {
429 java.io.FileInputStream fis = null;
430 try {
431 java.io.File vloc = new java.io.File(vtimezoneLoc);
433 fis = new java.io.FileInputStream(vloc);
434 net.fortuna.ical4j.data.CalendarBuilder cbuild = new net.fortuna.ical4j.data.CalendarBuilder();
435 net.fortuna.ical4j.model.Calendar vt = cbuild.build(fis);
436 net.fortuna.ical4j.model.component.VTimeZone vs = (net.fortuna.ical4j.model.component.VTimeZone) vt.getComponents().get(0);
437 net.fortuna.ical4j.model.property.TzId tzid = (net.fortuna.ical4j.model.property.TzId) vs.getProperty("TZID");
439 toAttach.getComponents().add(vs);
440 fis.close();
441 return tzid.getValue();
442 } catch (Exception ex) {
443 java.util.logging.Logger.getLogger("global").log(java.util.logging.Level.SEVERE,
444 ex.getMessage(), ex);
446 return null;
449 public static void attachVAlarm(String atTime,
450 int type,
451 net.fortuna.ical4j.model.component.CalendarComponent toAttach,
452 String tz) throws ParseException {
453 net.fortuna.ical4j.model.component.VAlarm vl =
454 new net.fortuna.ical4j.model.component.VAlarm();
455 if (type == 0) { //display alarm
457 vl.getProperties().add(net.fortuna.ical4j.model.property.Action.DISPLAY);
459 net.fortuna.ical4j.model.DateTime triggerTime = parseIntoDateTime(atTime, tz);
460 /* net.fortuna.ical4j.model.property.Trigger trigger= new net.fortuna.ical4j.model.property.Trigger(triggerTime);
461 vl.getProperties().add(trigger); */
462 /* While its better for DateTime to go right into the event, which is legal,
463 * clients don't always let us */
464 // Find dtstart
465 net.fortuna.ical4j.model.property.DtStart dts =
466 (net.fortuna.ical4j.model.property.DtStart) toAttach.getProperty("DTSTART");
467 net.fortuna.ical4j.model.Dur dur = new net.fortuna.ical4j.model.Dur(dts.getDate(), triggerTime);
468 net.fortuna.ical4j.model.property.Trigger trigger =
469 new net.fortuna.ical4j.model.property.Trigger(dur);
470 vl.getProperties().add(trigger);
471 net.fortuna.ical4j.model.property.Description alarmDescription =
472 new net.fortuna.ical4j.model.property.Description("Event reminder");
473 vl.getProperties().add(alarmDescription);
474 if (toAttach instanceof net.fortuna.ical4j.model.component.VEvent) {
475 net.fortuna.ical4j.model.component.VEvent ve =
476 (net.fortuna.ical4j.model.component.VEvent) toAttach;
477 ve.getAlarms().add(vl);
478 } else if (toAttach instanceof net.fortuna.ical4j.model.component.VToDo) {
479 net.fortuna.ical4j.model.component.VToDo vt =
480 (net.fortuna.ical4j.model.component.VToDo) toAttach;
481 vt.getAlarms().add(vl);
485 private static boolean hasValue(com.funambol.common.pim.common.Property prop) {
486 if (prop != null && prop.getPropertyValueAsString() != null &&
487 prop.getPropertyValueAsString().length() > 0) {
488 return true;
490 return false;