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

Revision 1545, 24.0 KB checked in by wmerlotto, 15 years ago (diff)

Ticket #693 - Incrementado a sincronizacao de contatos, integracao com maven e codigo de autenticacao no LDAP.

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