source: contrib/psync/src/main/java/br/com/prognus/psync/synclet/PIMItemsHandler.java @ 1009

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

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

Line 
1/**
2 * Copyright (C) 2007 Funambol
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the Honest Public License.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 * Honest Public License for more details.
11 *
12 * You should have received a copy of the Honest Public License
13 * along with this program; if not, write to Funambol,
14 * 643 Bair Island Road, Suite 305 - Redwood City, CA 94063, USA
15 */
16package br.com.prognus.psync.synclet;
17
18import java.util.ArrayList;
19import java.util.HashMap;
20import java.util.List;
21import java.util.Map;
22
23import com.funambol.framework.core.AbstractCommand;
24import com.funambol.framework.core.Add;
25import com.funambol.framework.core.Item;
26import com.funambol.framework.core.ItemizedCommand;
27import com.funambol.framework.core.Meta;
28import com.funambol.framework.core.Replace;
29import com.funambol.framework.core.Sync;
30import com.funambol.framework.core.Sync4jException;
31import com.funambol.framework.core.SyncML;
32import com.funambol.framework.engine.pipeline.MessageProcessingContext;
33import com.funambol.framework.logging.FunambolLogger;
34import com.funambol.framework.logging.FunambolLoggerFactory;
35
36/**
37 * This class extracts the PIM Items from the SyncML message.
38 * It creates a Map with three lists that contain the items separated based on
39 * their type. In case of large object, this class is able to recognize the
40 * large object item and is able to handle it using a Map cached in the
41 * MessageProcessingContext.
42 *
43 * @version $Id: PIMItemsHandler.java,v 1.1 2007-02-02 10:33:13 luigiafassina Exp $
44 */
45public class PIMItemsHandler {
46
47    // --------------------------------------------------------------- Constants
48    private final FunambolLogger logger =
49        FunambolLoggerFactory.getLogger("engine.pipeline");
50
51    private static final String BEGIN_VCARD     = "BEGIN:VCARD"                ;
52    private static final String END_VCARD_RN    = "END:VCARD\r\n"              ;
53    private static final String END_VCARD_N     = "END:VCARD\n"                ;
54    private static final String BEGIN_VCALENDAR = "BEGIN:VCALENDAR"            ;
55    private static final String END_VEVENT_RN   =
56        "END:VEVENT\r\nEND:VCALENDAR\r\n";
57    private static final String END_VEVENT_N    = "END:VEVENT\nEND:VCALENDAR\n";
58    private static final String END_VTODO_RN    =
59        "END:VTODO\r\nEND:VCALENDAR\r\n" ;
60    private static final String END_VTODO_N     = "END:VTODO\nEND:VCALENDAR\n" ;
61
62    public static final String KEY_VCARD  = "VCARD" ;
63    public static final String KEY_VEVENT = "VEVENT";
64    public static final String KEY_VTODO  = "VTODO" ;
65
66    // ---------------------------------------------------------- Public methods
67
68    /**
69     * Processes input message to extract the items in order to separate them
70     * into lists based on their type (vcard, vevent, vtodo).
71     *
72     * @param pContext the message processing context
73     * @param message the message to be processed
74     *
75     * @return mapItems the map with the three list of items
76     * @throws Sync4jException in case of errors
77     */
78    public Map extractIncomingPIMItems(MessageProcessingContext pContext,
79                                       SyncML message)
80    throws Sync4jException {
81
82        if (logger.isTraceEnabled()) {
83            logger.trace("Starting creation of incoming items lists...");
84        }
85
86        //
87        // Caches the map with lists of items into request context: in this way,
88        // if more synclet act on the same items, is not need to recycle on
89        // items of the message
90        //
91
92        //
93        // Contains the lists of the items
94        //
95        Map mapItems = null;
96        mapItems = (Map)pContext.getRequestProperty("MAP_INCOMING_ITEMS");
97
98        if (mapItems != null) {
99            if (logger.isTraceEnabled()) {
100                logger.trace("Exists a map of items: is not need to cycle on message");
101            }
102
103            //
104            // In this case the first synclet has just created the map and so
105            // the next synclets must act on that without recycle in message.
106            //
107            return mapItems;
108        } else {
109
110            if (logger.isTraceEnabled()) {
111                logger.trace("Creates a map to contains the lists of items");
112            }
113            mapItems = new HashMap();
114            initializeMapItems(mapItems);
115        }
116
117        //
118        // Used to handle large object item
119        //
120        Item firstItem = null;
121        Item lastItem  = null;
122        //
123        // Cache the large object
124        //
125        Map cache      = null;
126        cache = (Map)pContext.getSessionProperty("LARGE_OBJ_INCOMING");
127
128        String syncURI    = null;
129        String itemLocURI = null;
130
131        List<AbstractCommand> cmds = message.getSyncBody().getCommands();
132        for (AbstractCommand bodyc : cmds) {
133
134            if (bodyc instanceof Sync) {
135                syncURI = ((Sync)bodyc).getTarget().getLocURI();
136
137                //
138                // Processes incoming commands to identifier and separate the items.
139                //
140                List<ItemizedCommand> syncCmds = ((Sync)bodyc).getCommands();
141                for (ItemizedCommand c : syncCmds) {
142
143                    //
144                    // Skip other commands than Add and Replace
145                    //
146                    if (!(Replace.COMMAND_NAME.equals(c.getName()) ||
147                        Add.COMMAND_NAME.equals(c.getName()))      ) {
148                        continue;
149                    }
150
151                    List<Item> items = c.getItems();
152                    for (Item item: items) {
153
154                        itemLocURI = ((item.getSource() != null)
155                                      ? item.getSource().getLocURI()
156                                      : item.getTarget().getLocURI());
157
158                        if (firstItem == null) {
159                            firstItem = item;
160                        }
161
162                        if (firstItem == item) {
163                            if (cache == null || cache.isEmpty()) {
164                                if (item.isMoreData()) {
165                                    if (logger.isTraceEnabled()) {
166                                        logger.trace("The item " + itemLocURI +
167                                                     " is a large object");
168                                    }
169                                    cache = handleCache(cache, item, syncURI);
170                                }
171                            } else {
172                                cache = handleCache(cache, item, syncURI);
173                            }
174                        } //end if firstItem == item
175
176                        lastItem = item;
177
178                        if (!item.isMoreData()) {
179                            mapItems = fillMapItems(mapItems, item);
180                        }
181
182                    } //end for items
183                } //end for cmds
184            } //end if Sync
185
186            if (lastItem != firstItem) {
187                if (lastItem.isMoreData()) {
188                    cache = handleCache(cache, lastItem, syncURI);
189                }
190            }
191        } //end if cmds
192
193        pContext.setSessionProperty("LARGE_OBJ_INCOMING", cache);
194        pContext.setRequestProperty("MAP_INCOMING_ITEMS", mapItems);
195
196        return mapItems;
197    }
198
199    /**
200     * Processes output message to extract the items in order to separate them
201     * into lists based on their type (vcard, vevent, vtodo).
202     *
203     * @param message the message to be processed
204     *
205     * @return mapItems the map with the three list of items
206     * @throws Sync4jException in case of errors
207     */
208    public Map extractOutgoingPIMItems(SyncML message)
209    throws Sync4jException {
210        if (logger.isTraceEnabled()) {
211            logger.trace("Starting creation of outgoing items lists...");
212        }
213
214        Map mapItems = new HashMap();
215        initializeMapItems(mapItems);
216
217        List<AbstractCommand> cmds = message.getSyncBody().getCommands();
218        for (AbstractCommand bodyc : cmds) {
219
220            if (bodyc instanceof Sync) {
221
222                //
223                // Processes incoming commands to identifier and separate the items.
224                // Note: the large object items will not be considered.
225                //
226                List<ItemizedCommand> syncCmds = ((Sync)bodyc).getCommands();
227                for (ItemizedCommand c : syncCmds) {
228
229                    //
230                    // Skip other commands than Add and Replace
231                    //
232                    if (!(Replace.COMMAND_NAME.equals(c.getName()) ||
233                        Add.COMMAND_NAME.equals(c.getName()))      ) {
234                        continue;
235                    }
236
237                    List<Item> items = c.getItems();
238                    for (Item item: items) {
239                        mapItems = fillMapItems(mapItems, item);
240                    }//end for i items
241                }//end for c commands
242            }//end if Sync
243        }
244
245        return mapItems;
246    }
247
248    /**
249     * If the item has the size set, probably it is a large object item. In this
250     * case, after the synclet modifications, is need to fix the size property
251     * with the real dimension of the data's item.
252     *
253     * @param i the item to fix the size property
254     */
255    public void fixLargeObjectSize(Item i) {
256
257        Meta m = i.getMeta();
258        if (m == null) {
259            return;
260        }
261        if (m.getSize() != null && m.getSize() != 0) {
262            int size = i.getData().getData().length();
263            if (logger.isTraceEnabled()) {
264                logger.trace("Fixed size of large object item from " +
265                             m.getSize() + " to " + size);
266            }
267            i.getMeta().setSize(new Long(size));
268        }
269    }
270
271    // --------------------------------------------------------- Private methods
272
273    /**
274     * Handles large object storing its information into a Map.
275     *
276     * @param cache The map in which store the large object informations
277     * @param item the large object
278     * @param source the source with LocURI of item
279     *
280     * @return the map in which the large object is cached
281     */
282    private Map handleCache(Map cache, Item item, String source) {
283
284        if (cache == null || cache.isEmpty()) {
285            //
286            // It is the first chunk of the large object item
287            //
288            String uri = (item.getSource() != null)
289                       ? item.getSource().getLocURI()
290                       : item.getTarget().getLocURI()
291                       ;
292            cache = new HashMap();
293            cache.put("itemLocURI", uri);
294            cache.put("syncLocURI", source);
295            cache.put("data", item.getData().getData());
296
297        } else {
298
299            String cacheData   = (String)cache.get("data");
300            String cacheLocURI = (String)cache.get("syncLocURI")
301                               + "/"
302                               + (String)cache.get("itemLocURI")
303                               ;
304
305            String itemLocURI = source + "/" + ((item.getSource() != null)
306                                                ? item.getSource().getLocURI()
307                                                : item.getTarget().getLocURI());
308
309            if (cacheLocURI.equals(itemLocURI)) {
310                cacheData = cacheData + item.getData().getData();
311
312                if (item.isMoreData()) {
313                    cache.put("data", cacheData);
314                } else {
315                    item.getData().setData(cacheData);
316                    if (item.getMeta() == null) {
317                        item.setMeta(new Meta());
318                    }
319                    item.getMeta().setSize(new Long(cacheData.length()));
320                    cache.clear();
321                }
322            } else {
323                cache.clear();
324            }
325        }
326
327        return cache;
328    }
329
330    /**
331     * Fills the maps of items separated based on their type (vcard, vevent,
332     * vtodo).
333     *
334     * @param mapItems the map in which add the list of items separated based on
335     *                 them type
336     * @param item the item to handle
337     *
338     * @return the map with lists of items
339     */
340    private Map fillMapItems(Map mapItems, Item item) {
341
342        List vcardItems  = (List)mapItems.get(KEY_VCARD );
343        List veventItems = (List)mapItems.get(KEY_VEVENT);
344        List vtodoItems  = (List)mapItems.get(KEY_VTODO );
345
346        String data = item.getData().getData();
347
348        if ( data.startsWith(BEGIN_VCARD) &&
349            (data.endsWith(END_VCARD_RN) ||
350            data.endsWith(END_VCARD_N)    )) {
351
352            vcardItems.add(item);
353        } else if (data.startsWith(BEGIN_VCALENDAR)) {
354            if (data.endsWith(END_VEVENT_RN) ||
355                data.endsWith(END_VEVENT_N)    ) {
356
357                veventItems.add(item);
358            } else if (data.endsWith(END_VTODO_RN) ||
359                data.endsWith(END_VTODO_N)    ) {
360
361                vtodoItems.add(item);
362            }
363        }
364        if (logger.isTraceEnabled()) {
365            logger.trace("List vcard : " + vcardItems.toString() );
366            logger.trace("List vevent: " + veventItems.toString());
367            logger.trace("List vtodo : " + vtodoItems.toString() );
368        }
369        return mapItems;
370    }
371
372    /**
373     * Initializes the Map of items.
374     *
375     * @param mapItems the empty map
376     */
377    private void initializeMapItems(Map mapItems) {
378
379        List vcardItems  = new ArrayList();
380        List veventItems = new ArrayList();
381        List vtodoItems  = new ArrayList();
382
383        mapItems.put(KEY_VCARD , vcardItems );
384        mapItems.put(KEY_VEVENT, veventItems);
385        mapItems.put(KEY_VTODO , vtodoItems );
386    }
387}
Note: See TracBrowser for help on using the repository browser.