source: contrib/psync/src/main/java/br/com/prognus/psync/engine/source/PIMCalendarSyncSource.java @ 1009

Revision 1009, 23.7 KB checked in by wmerlotto, 15 years ago (diff)

Ticket #554 - Commit da versão inicial do psync.

Line 
1/**
2 * This class is a PIMSyncSource for ICal and VCal data, which could include
3 * either an Event or a Todo. NB: The Todo part is not currenlty implemented.
4 * @author Diorgenes Felipe Grzesiuk <diorgenes@prognus.com.br>
5 * @copyright Copyright 2007-2008 Prognus
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Foobar; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20package br.com.prognus.psync.engine.source;
21
22import java.io.ByteArrayInputStream;
23import java.sql.Timestamp;
24import java.util.List;
25import java.util.StringTokenizer;
26
27import br.com.prognus.psync.exception.EntityException;
28import br.com.prognus.psync.items.manager.PIMCalendarManager;
29import br.com.prognus.psync.items.model.CalendarWrapper;
30import br.com.prognus.psync.util.Def;
31
32import com.funambol.common.pim.calendar.Calendar;
33import com.funambol.common.pim.converter.BaseConverter;
34import com.funambol.common.pim.converter.CalendarToSIFE;
35import com.funambol.common.pim.converter.TaskToSIFT;
36import com.funambol.common.pim.converter.VCalendarConverter;
37import com.funambol.common.pim.converter.VComponentWriter;
38import com.funambol.common.pim.icalendar.ICalendarParser;
39import com.funambol.common.pim.model.VCalendar;
40import com.funambol.common.pim.sif.SIFCalendarParser;
41import com.funambol.common.pim.xvcalendar.XVCalendarParser;
42import com.funambol.framework.engine.SyncItem;
43import com.funambol.framework.engine.SyncItemImpl;
44import com.funambol.framework.engine.SyncItemKey;
45import com.funambol.framework.engine.SyncItemState;
46import com.funambol.framework.engine.source.SyncContext;
47import com.funambol.framework.engine.source.SyncSourceException;
48import com.funambol.framework.tools.beans.BeanInitializationException;
49import com.sun.org.apache.xerces.internal.impl.xs.SubstitutionGroupHandler;
50
51public class PIMCalendarSyncSource extends PIMSyncSource {
52
53        // ------------------------------------------------------------- Private
54        // data
55
56        private PIMCalendarManager manager;
57
58        // ---------------------------------------------------------------
59        // Properties
60
61        private Class entityType; // CalendarContent or one of its subclasses
62
63        public Class getEntityType() {
64                return entityType;
65        }
66
67        public void setEntityType(Class entityType) {
68                this.entityType = entityType;
69        }
70
71        // ----------------------------------------------------------- Public
72        // methods
73
74        public void beginSync(SyncContext context) {
75
76                this.manager = new PIMCalendarManager(JNDI_DATA_SOURCE_NAME, context
77                                .getPrincipal());
78                super.manager = this.manager;
79                super.beginSync(context);
80        }
81
82        /**
83         * Makes an array of SyncItemKey objects representing the ID(s) of the
84         * twin(s) of a given calendar.
85         *
86         * @param syncItem
87         *            the SyncItem representing the calendar whose twin(s) are
88         *            looked for
89         * @throws SyncSourceException
90         * @return possibly, just one or no key should be in the array, but it can't
91         *         be ruled out a priori that several keys get returned by this
92         *         method
93         */
94        public SyncItemKey[] getSyncItemKeysFromTwin(SyncItem syncItem)
95                        throws SyncSourceException {
96
97                try {
98
99                        Calendar calendar = convert(getContentFromSyncItem(syncItem),
100                                        syncItem.getType());
101
102                        List idList = null;
103                        idList = manager.getTwins(calendar);
104
105                        SyncItemKey[] keyList = new SyncItemKey[idList.size()];
106                        for (int i = 0; i < idList.size(); i++) {
107                                keyList[i] = new SyncItemKey((String) idList.get(i));
108                        }
109                        return keyList;
110                } catch (EntityException e) {
111                        throw new SyncSourceException("Error retrieving twin item keys.", e);
112                }
113        }
114
115        /**
116         * Adds a SyncItem object (representing a calendar).
117         *
118         * @param syncItem
119         *            the SyncItem representing the calendar
120         *
121         * @return a newly created syncItem based on the input object but with its
122         *         status set at SyncItemState.NEW and the GUID retrieved by the
123         *         back-end
124         */
125        public SyncItem addSyncItem(SyncItem syncItem) throws SyncSourceException {
126
127                if (log.isTraceEnabled()) {
128                        log.trace("PIMCalendarSyncSource addSyncItem begin");
129                }
130
131                Calendar c = null;
132                String content = null;
133
134                try {
135
136                        content = getContentFromSyncItem(syncItem);
137                        String contentType = syncItem.getType();
138
139                        c = convert(content, contentType);
140                        Timestamp ts = syncItem.getTimestamp();
141
142                        // Adds the calendar, wraps it in sync information and uses it to
143                        // create a new SyncItem which is the return value of this method
144                        SyncItemImpl newSyncItem = new SyncItemImpl(this, // syncSource
145                                        manager.addItem(c, ts), // key
146                                        null, // mappedKey
147                                        SyncItemState.NEW, // state
148                                        content.getBytes(), // content
149                                        null, // format
150                                        contentType, // type
151                                        ts // timestamp
152                        );
153
154                        return newSyncItem;
155
156                } catch (Exception e) {
157                        log.error("SyncSource error adding a new synchronization item.");
158                        throw new SyncSourceException("Error adding the item " + syncItem,
159                                        e);
160                }
161        }
162
163        /**
164         * Updates a SyncItem object (representing a calendar).
165         *
166         * @param syncItem
167         *            the SyncItem representing the calendar
168         *
169         * @return a newly created syncItem based on the input object but with its
170         *         status set at SyncItemState.UPDATED and the GUID retrieved by the
171         *         back-end
172         */
173        public SyncItem updateSyncItem(SyncItem syncItem)
174                        throws SyncSourceException {
175
176                if (log.isTraceEnabled()) {
177                        log.trace("Updates a SyncItem from " + sourceURI);
178                }
179
180                Calendar c = null;
181                String content = null;
182
183                try {
184
185                        String id = syncItem.getKey().getKeyAsString();
186                        content = getContentFromSyncItem(syncItem);
187                        String contentType = syncItem.getType();
188
189                        c = convert(content, contentType);
190
191                        // Modifies the calendar, wraps it in sync information and uses it
192                        // to
193                        // create a new SyncItem which is the return value of this method
194                        SyncItemImpl newSyncItem = new SyncItemImpl(this, // syncSource
195                                        manager.updateItem(id, c, syncItem.getTimestamp()), // key
196                                        null, // mappedKey
197                                        SyncItemState.UPDATED, // state
198                                        content.getBytes(), // content
199                                        null, // format
200                                        contentType, // type
201                                        null // timestamp
202                        );
203
204                        return newSyncItem;
205
206                } catch (Exception e) {
207                        log.error("SyncSource error updating a synchronization item.", e);
208                        throw new SyncSourceException(
209                                        "Error updating the item " + syncItem, e);
210                }
211        }
212
213        /**
214         * Deletes the item with a given syncItemKey.
215         *
216         * @param syncItemKey
217         * @param timestamp
218         *            in case of a soft deletion, this will be the registered moment
219         *            of deletion; if a hard deletion is used, this field is
220         *            irrelevant and may also be null
221         * @param softDelete
222         *            it is true if the client requires a soft deletion
223         * @throws SyncSourceException
224         */
225        public void removeSyncItem(SyncItemKey syncItemKey, Timestamp timestamp,
226                        boolean softDelete) throws SyncSourceException {
227
228                try {
229
230                        if (!softDelete) {
231                                if (log.isTraceEnabled()) {
232                                        log.trace("PIMCalendarSyncSource remove the SyncItem "
233                                                        + syncItemKey.getKeyAsString());
234                                }
235
236                                manager.removeItem(syncItemKey.getKeyAsString());
237                        }
238
239                } catch (EntityException e) {
240                        log.error("Sync source error: could not delete item with key"
241                                        + syncItemKey, e);
242                        throw new SyncSourceException("Error deleting item. ", e);
243                }
244        }
245
246        public SyncItem getSyncItemFromId(SyncItemKey syncItemKey)
247                        throws SyncSourceException {
248
249                String id = null;
250                SyncItem syncItem = null;
251
252                id = syncItemKey.getKeyAsString();
253                if (log.isTraceEnabled()) {
254                        log.trace("PIMCalendarSyncSource get SyncItem from " + id);
255                }
256
257                try {
258                        CalendarWrapper cw;
259                        try {
260                                cw = manager.getItem(id);
261                        } catch (Exception e) {
262                                return null;
263                        }
264                        // Retrieves the calendar, wraps it in sync information and uses it
265                        // to create a new SyncItem which is the return value of this method
266                        syncItem = createSyncItem(id, cw.getCalendar(), SyncItemState.NEW);
267
268                } catch (EntityException e) {
269                        throw new SyncSourceException("Error seeking SyncItem with ID: "
270                                        + id, e);
271                }
272
273                return syncItem;
274        }
275
276        public boolean mergeSyncItems(SyncItemKey syncItemKey, SyncItem syncItem)
277                        throws SyncSourceException {
278
279                try {
280                        Calendar calendar = convert(getContentFromSyncItem(syncItem),
281                                        syncItem.getType());
282
283                        boolean clientUpdateRequired = manager.mergeItems(syncItemKey
284                                        .getKeyAsString(), calendar, syncItem.getTimestamp());
285
286                        if (clientUpdateRequired) {
287                                syncItem = getSyncItemFromId(syncItemKey);
288                        }
289
290                        return true; //clientUpdateRequired 418
291
292                } catch (EntityException e) {
293
294                        log.error("SyncSource error: a merge did not succeed.", e);
295                        throw new SyncSourceException("Error merging SyncItem with ID "
296                                        + syncItemKey.getKeyAsString() + "with SyncItem "
297                                        + syncItem, e);
298                }
299        }
300
301        public void init() throws BeanInitializationException {
302        }
303
304        /**
305         * Makes an array of SyncItemKey objects representing all new calendar IDs,
306         * filtered according to a given time interval.
307         *
308         * @param since
309         *            the earlier limit of the time interval
310         * @param to
311         *            the later limit of the time interval
312         * @return a SyncItemKey array
313         */
314        public SyncItemKey[] getNewSyncItemKeys(Timestamp since, Timestamp to)
315                        throws SyncSourceException {
316
317                saveSyncTiming(since, to);
318
319                try {
320                        List idList = manager.getNewItems(since, to);
321                        return extractKeyArrayFromIdList(idList);
322                } catch (EntityException e) {
323                        throw new SyncSourceException("Error retrieving new item keys.", e);
324                }
325        }
326
327        /**
328         * Makes an array of SyncItemKey objects representing all deleted calendar
329         * IDs, filtered according to a given time interval.
330         *
331         * @param since
332         *            the earlier limit of the time interval
333         * @param to
334         *            the later limit of the time interval
335         * @return a SyncItemKey array
336         */
337        public SyncItemKey[] getUpdatedSyncItemKeys(Timestamp since, Timestamp to)
338                        throws SyncSourceException {
339
340                saveSyncTiming(since, to);
341
342                try {
343                        List idList = manager.getUpdatedItems(since, to);
344                        return extractKeyArrayFromIdList(idList);
345                } catch (EntityException e) {
346                        throw new SyncSourceException(
347                                        "Error retrieving updated item keys.", e);
348                }
349        }
350
351        /**
352         * Makes an array of SyncItemKey objects representing all deleted calendar
353         * IDs, filtered according to a given time interval.
354         *
355         * @param since
356         *            the earlier limit of the time interval
357         * @param to
358         *            the later limit of the time interval
359         * @return a SyncItemKey array
360         */
361        public SyncItemKey[] getDeletedSyncItemKeys(Timestamp since, Timestamp to)
362                        throws SyncSourceException {
363
364                saveSyncTiming(since, to);
365
366                try {
367                        List idList = manager.getDeletedItems(since, to);
368                        return extractKeyArrayFromIdList(idList);
369                } catch (EntityException e) {
370                        throw new SyncSourceException(
371                                        "Error retrieving deleted item keys.", e);
372                }
373        }
374
375        /**
376         * Makes an array of SyncItemKey objects representing all calendar IDs.
377         *
378         * @return a SyncItemKey array
379         */
380        public SyncItemKey[] getAllSyncItemKeys() throws SyncSourceException {
381
382                try {
383                        List idList = manager.getAllItems();
384                        return extractKeyArrayFromIdList(idList);
385
386                } catch (EntityException e) {
387                        throw new SyncSourceException("Error retrieving all item keys. ", e);
388                }
389        }
390
391        /**
392         * Gets the status of the SyncItem with the given key.
393         *
394         * @param syncItemKey
395         *            as a SyncItemKey object
396         * @throws SyncSourceException
397         * @return the status as a char
398         */
399        public char getSyncItemStateFromId(SyncItemKey syncItemKey)
400                        throws SyncSourceException {
401
402                String id = "N/A"; // default value for error tracking
403
404                try {
405
406                        // Slow sync
407                        // @todo Implement, depending on a syncMode check
408
409                        // Fast sync
410                        id = syncItemKey.getKeyAsString();
411                        if (log.isTraceEnabled()) {
412                                log
413                                                .trace("PIMCalendarSyncSource get SyncItem state from "
414                                                                + id);
415                        }
416                        char itemRawState = manager.getItemState(id, previousSyncTime);
417
418                        if (itemRawState == Def.PIM_STATE_UNCHANGED) {
419                                return SyncItemState.SYNCHRONIZED;
420                        } else {
421                                return itemRawState; // Def uses SyncItemState.* as constant
422                                // values for N, D and U states
423                        }
424                } catch (EntityException e) {
425                        throw new SyncSourceException(
426                                        "Error getting the state of SyncItem " + "with ID " + id, e);
427                }
428        }
429
430        // ---------------------------------------------------------- Private
431        // methods
432
433        /**
434         * Extracts the content from a syncItem.
435         *
436         * @param syncItem
437         * @return as a String object (same as
438         *         PIMSyncSource#getContentFromSyncItem(String), but trimmed)
439         */
440        protected String getContentFromSyncItem(SyncItem syncItem) {
441
442                String raw = super.getContentFromSyncItem(syncItem);
443
444                return raw.trim();
445        }
446
447        private String hackFix(String text) {
448
449                String result, head, title, clas, description, tail, new_title;
450                int p_categories, p_classes, p_location, p_dstart, values1, values2, op1, op2, op3, op4, op5, op6, op7, op8, qt1, qt2;
451
452                qt1 = 0;
453                qt2 = 0;
454
455                // Pega as posicoes das tags
456                p_categories = text.indexOf("CATEGORIES");
457                p_classes = text.indexOf("CLASS");
458
459                p_location = text.indexOf("LOCATION");
460                p_dstart = text.indexOf("DTSTART");
461
462                // Pega as posicoes das varias formas da tag SUMMARY
463                op1 = text.indexOf("SUMMARY:");
464                op2 = text.indexOf("SUMMARY;CHARSET=UTF-8:");
465                op3 = text.indexOf("SUMMARY;ENCODING=QUOTED-PRINTABLE:");
466                op4 = text.indexOf("SUMMARY;ENCODING=QUOTED-PRINTABLE;CHARSET=UTF-8:");
467
468                // Pega as posicoes das varias formas da tag DESCRIPTION
469                op5 = text.indexOf("DESCRIPTION:");
470                op6 = text.indexOf("DESCRIPTION;CHARSET=UTF-8:");
471                op7 = text.indexOf("DESCRIPTION;ENCODING=QUOTED-PRINTABLE:");
472                op8 = text.indexOf("DESCRIPTION;ENCODING=QUOTED-PRINTABLE;CHARSET=UTF-8:");
473
474                qt1 += (op1 == -1) ? 0 : op1 + 8;
475                qt1 += (op2 == -1) ? 0 : op2 + 22;
476                qt1 += (op3 == -1) ? 0 : op3 + 34;
477                qt1 += (op4 == -1) ? 0 : op4 + 48;
478
479                qt2 += (op5 == -1) ? 0 : op5 + 12;
480                qt2 += (op6 == -1) ? 0 : op6 + 26;
481                qt2 += (op7 == -1) ? 0 : op7 + 38;
482                qt2 += (op8 == -1) ? 0 : op8 + 52;
483
484                values1 = (p_categories == -1) ? p_classes : p_categories;
485                values2 = (p_location == -1) ? p_dstart : p_location;
486
487                head = text.substring(0, qt1);
488                title = text.substring(qt1, values1);
489                clas = text.substring(values1, qt2);
490                description = text.substring(qt2, values2);
491                tail = text.substring(values2);
492
493                new_title = title.replaceAll("\r\n ", " ");
494
495                // Retira os enters no final do titulo
496                int title_t, title_bl;
497
498                while(true){
499                        title_t = new_title.length();
500                        title_bl = new_title.lastIndexOf("=0D=0A=\r\n");
501
502                        if(title_bl != -1 && title_t == title_bl + 11){
503                                new_title = new_title.substring(0, title_bl) + "\r\n";
504                        } else {
505                                break;
506                        }
507                }
508
509                // Retira os enters no final da descricao
510                int description_t, description_bl;
511
512                while(true){
513                        description_t = description.length();
514                        description_bl = description.lastIndexOf("=0D=0A=\r\n");
515
516                        if(description_bl != -1 && description_t == description_bl + 11){
517                                description = description.substring(0, description_bl) + "\r\n";
518                        } else {
519                                break;
520                        }
521                }
522
523                result = head + new_title + clas + description + tail;
524
525                return result;
526        }
527
528        private Calendar webCalendar2Calendar(String text, String vCalType)
529                        throws EntityException {
530
531                try {
532                        // BugFix XVCalendarParser
533                        if (vCalType.equals(PIMSyncSource.TYPE[PIMSyncSource.VCAL])) {
534                                text = hackFix(text);
535                        }
536
537                        ByteArrayInputStream buffer = new ByteArrayInputStream(text.getBytes());
538
539                        VCalendar vcalendar;
540                        String version;
541                        String charset;
542
543                        if (log.isTraceEnabled()) {
544                                StringBuilder sb = new StringBuilder(text.length() + 60);
545                                sb.append("Converting: ").append(vCalType).append(
546                                                " => Calendar ").append("\nINPUT = {").append(text)
547                                                .append('}');
548                                log.trace(sb.toString());
549                        }
550
551                        if (vCalType.equals(PIMSyncSource.TYPE[PIMSyncSource.VCAL])) {
552                                // vCalendar (1.0):
553                                XVCalendarParser parser = new XVCalendarParser(buffer);
554                                vcalendar = (VCalendar) parser.XVCalendar();
555                                version = "1.0";
556                                charset = BaseConverter.CHARSET_UTF7; // (versit spec)
557                        } else {
558                                // iCalendar (2.0):
559                                ICalendarParser parser = new ICalendarParser(buffer);
560                                vcalendar = (VCalendar) parser.ICalendar();
561                                version = "2.0";
562                                charset = BaseConverter.CHARSET_UTF8; // (RFC 2445)
563                        }
564                        if (deviceCharset != null) {
565                                charset = deviceCharset; // overrides the default character
566                                // set
567                        }
568
569                        String retrievedVersion = null;
570                        if (vcalendar.getProperty("VERSION") != null) {
571                                retrievedVersion = vcalendar.getProperty("VERSION").getValue();
572                        }
573                        vcalendar.addProperty("VERSION", version);
574                        if (retrievedVersion == null) {
575                                if (log.isTraceEnabled()) {
576                                        log.trace("No version property was found in the vCal/iCal "
577                                                        + "data: version set to " + version);
578                                }
579                        } else if (!retrievedVersion.equals(version)) {
580                                if (log.isTraceEnabled()) {
581                                        log.trace("The version in the data was " + retrievedVersion
582                                                        + " but it's been changed to " + version);
583                                }
584                        }
585
586                        VCalendarConverter vcf = new VCalendarConverter(deviceTimeZone,
587                                        charset);
588
589                        Calendar c = null;
590                        c = vcf.vcalendar2calendar(vcalendar);
591
592                        if (log.isTraceEnabled()) {
593                                log.trace("Conversion done.");
594                        }
595
596                        return c;
597
598                } catch (Exception e) {
599                        throw new EntityException("Error converting " + vCalType
600                                        + " to Calendar. ", e);
601                }
602        }
603
604        private String calendar2webCalendar(Calendar calendar, String vCalType)
605                        throws EntityException {
606
607                try {
608
609                        String charset;
610                        if (vCalType.equals(PIMSyncSource.TYPE[PIMSyncSource.VCAL])) {
611                                // vCalendar (1.0):
612                                charset = BaseConverter.CHARSET_UTF7; // (versit spec)
613                        } else {
614                                // iCalendar (2.0):
615                                charset = BaseConverter.CHARSET_UTF8; // (RFC 2445)
616                        }
617                        if (deviceCharset != null) {
618                                charset = deviceCharset; // overrides the default character
619                                // set
620                        }
621
622                        VCalendarConverter vcf = new VCalendarConverter(deviceTimeZone,
623                                        charset);
624
625                        VCalendar vcalendar;
626                        String vcal;
627
628                        if (log.isTraceEnabled()) {
629                                log.trace("Converting: Calendar => " + vCalType);
630                        }
631
632                        if (vCalType.equals(PIMSyncSource.TYPE[VCAL])) { // VCAL
633
634                                vcalendar = vcf.calendar2vcalendar(calendar, true); // text/x-vcalendar
635
636                        } else { // ICAL
637
638                                vcalendar = vcf.calendar2vcalendar(calendar, false); // text/calendar
639                        }
640
641                        VComponentWriter writer = new VComponentWriter(
642                                        VComponentWriter.NO_FOLDING);
643                        vcal = writer.toString(vcalendar);
644
645                        if (log.isTraceEnabled()) {
646                                log.trace("OUTPUT = {" + vcal + "}. Conversion done.");
647                        }
648
649                        return vcal;
650
651                } catch (Exception e) {
652                        throw new EntityException("Error converting Calendar to "
653                                        + vCalType, e);
654                }
655        }
656
657        /**
658         * Create a new SyncItem from a Calendar. The status is passed as an
659         * argument.
660         *
661         * @param calendar
662         *            the Calendar object representing the input information
663         * @param status
664         * @throws EntityException
665         *             if the content type is wrong or any problem occurs while
666         *             creating a new SyncItem
667         * @return a newly created SyncItem object
668         */
669        private SyncItem createSyncItem(String id, Calendar calendar, char status)
670                        throws EntityException {
671
672                String contentType = getInfo().getPreferredType().getType();
673
674                if (log.isTraceEnabled()) {
675                        StringBuilder sb = new StringBuilder(100);
676                        sb.append("PIMCalendarSyncSource - creating item with:").append(
677                                        "\n> id: ").append(id).append("\n> status: ")
678                                        .append(status).append("\n> content-type: ").append(
679                                                        contentType);
680                        log.trace(sb.toString());
681                }
682
683                SyncItem syncItem = null;
684                String stream = convert(calendar, contentType);
685
686                try {
687                        syncItem = new SyncItemImpl(this, id, status);
688                } catch (Exception e) {
689                        throw new EntityException(e);
690                }
691
692                syncItem.setType(contentType);
693                syncItem.setContent(stream.getBytes());
694                if (log.isTraceEnabled()) {
695                        log.trace("PIMCalendarSyncSource created SyncItem");
696                }
697                return syncItem;
698        }
699
700        private SyncItemKey[] extractKeyArrayFromIdList(List idList) {
701
702                SyncItemKey[] keyList = new SyncItemKey[idList.size()];
703                for (int i = 0; i < idList.size(); i++) {
704                        keyList[i] = new SyncItemKey((String) idList.get(i));
705                }
706                return keyList;
707        }
708
709        /**
710         * Converts a calendar in vCalendar/iCalendar, SIF-E or SIF-T format to a
711         * Calendar object.
712         *
713         * @param content
714         *            as a String
715         * @param contentType
716         * @throws EntityException
717         *             if the contentType is wrong or the conversion attempt doesn't
718         *             succeed.
719         * @return a Calendar object
720         */
721        private Calendar convert(String content, String contentType)
722                        throws EntityException {
723                // Finds out which target type is required
724                for (int i = 0; i < TYPE.length; i++) {
725                        if (contentType.equals(TYPE[i])) {
726
727                                // Uses the proper converter method
728                                switch (i) {
729                                case VCAL:
730                                case ICAL:
731                                        return webCalendar2Calendar(content, contentType);
732                                case SIFE:
733                                case SIFT:
734                                        return sif2Calendar(content, contentType);
735                                default:
736                                        throw new EntityException("Can't make a Contact "
737                                                        + "out of a " + TYPE[i] + "!");
738                                }
739                        }
740                }
741                throw new EntityException("Content type unknown: " + contentType);
742        }
743
744        /**
745         * Converts a Calendar back to a streamable (vCalendar/iCalendar, SIF-E or
746         * SIF-T) format.
747         *
748         * @param calendar
749         * @param contentType
750         * @throws EntityException
751         *             if the contentType is wrong or the conversion attempt doesn't
752         *             succeed.
753         * @return the result in the required format
754         */
755        private String convert(Calendar calendar, String contentType)
756                        throws EntityException {
757
758                // Finds out which target type is required
759                for (int i = 0; i < TYPE.length; i++) {
760                        if (contentType.equals(TYPE[i])) {
761
762                                // Uses the proper converter method
763                                switch (i) {
764                                case VCAL:
765                                case ICAL:
766                                        return calendar2webCalendar(calendar, contentType);
767                                case SIFE:
768                                case SIFT:
769                                        return calendar2sif(calendar, contentType);
770                                default:
771                                        throw new EntityException("Can't make a " + TYPE[i]
772                                                        + "out of a Contact!");
773                                }
774                        }
775                }
776                throw new EntityException("Content type unknown: " + contentType);
777        }
778
779        private Calendar sif2Calendar(String xml, String sifType)
780                        throws EntityException {
781
782                if (log.isTraceEnabled()) {
783                        StringBuilder sb = new StringBuilder(xml.length() + 60);
784                        sb.append("Converting: ").append(sifType).append(" => Calendar ")
785                                        .append("\nINPUT = {").append(xml).append('}');
786                        log.trace(sb.toString());
787                }
788
789                ByteArrayInputStream buffer = null;
790                Calendar calendar = null;
791                try {
792                        calendar = new Calendar();
793                        buffer = new ByteArrayInputStream(xml.getBytes());
794                        if ((xml.getBytes()).length > 0) {
795                                SIFCalendarParser parser = new SIFCalendarParser(buffer);
796                                calendar = parser.parse();
797                        }
798                } catch (Exception e) {
799                        throw new EntityException("Error converting " + sifType
800                                        + " to Calendar. ", e);
801                }
802
803                if (log.isTraceEnabled()) {
804                        log.trace("Conversion done.");
805                }
806                return calendar;
807        }
808
809        private String calendar2sif(Calendar calendar, String sifType)
810                        throws EntityException {
811
812                if (log.isTraceEnabled()) {
813                        log.trace("Converting: Calendar => " + sifType);
814                }
815
816                String xml = null;
817                BaseConverter c2xml;
818                Object thing;
819
820                try {
821                        if (sifType.equals(PIMSyncSource.TYPE[SIFE])) { // SIF-E
822                                c2xml = new CalendarToSIFE(deviceTimeZone, deviceCharset);
823                                thing = calendar;
824                                // NB: A CalendarToSIFE converts a Calendar into a SIF-E
825                        } else { // SIF-T
826                                c2xml = new TaskToSIFT(deviceTimeZone, deviceCharset);
827                                thing = calendar.getTask();
828                                // NB: A TaskToSIFT converts just a Task into a SIF-T
829                        }
830
831                        xml = c2xml.convert(thing);
832
833                        if (log.isTraceEnabled()) {
834                                log.trace("OUTPUT = {" + xml + "}. Conversion done.");
835                        }
836                } catch (Exception e) {
837                        throw new EntityException(
838                                        "Error converting Calendar to " + sifType, e);
839                }
840                return xml;
841        }
842}
Note: See TracBrowser for help on using the repository browser.