source: contrib/funambol/trunk/modules/psync/src/main/java/br/com/prognus/psync/engine/source/PIMCalendarSyncSource.java @ 2082

Revision 2082, 24.0 KB checked in by emersonfaria, 14 years ago (diff)

Ticket #927 - Reestruturacao dos diretorios do Funambol

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