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

Revision 1103, 23.8 KB checked in by wmerlotto, 15 years ago (diff)

Ticket #554 - Melhorias na sincronizacao de eventos, contatos e adaptacao para Funambol 7.0

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