KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > sync4j > syncclient > spds > SyncManagerImpl


1 /**
2  * Copyright (C) 2003-2005 Funambol
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  */

18
19 package sync4j.syncclient.spds;
20
21 import java.io.IOException JavaDoc;
22
23 import java.util.Enumeration JavaDoc;
24 import java.util.Hashtable JavaDoc;
25 import java.util.Vector JavaDoc;
26
27 import sync4j.syncclient.common.Base64;
28 import sync4j.syncclient.common.StringTools;
29
30 import sync4j.syncclient.sps.DataAccessException;
31 import sync4j.syncclient.sps.DataStore;
32 import sync4j.syncclient.sps.Record;
33 import sync4j.syncclient.util.StaticDataHelper;
34
35 /**
36  * The <i>SyncManager</i> is the contact point between a host application and the
37  * synchronization engine. It is designed to hidden as much as possible the
38  * details of the synchronization logic, protocol, communication and so on.
39  *
40  * @author Fabio Maggi @ Funambol
41  * @version $Id: SyncManagerImpl.java,v 1.17 2005/05/04 09:57:14 fabius Exp $
42  */

43 public class SyncManagerImpl {
44
45     //---------------------------------------------------------------- Constants
46

47     public final static int
48         ALERT_CODE_ONE_WAY_FROM_SERVER = 204 ;
49     public static final int
50         ALERT_CODE_REFRESH_FROM_SERVER = 205 ;
51     public static final int
52         ALERT_CODE_SLOW = 201 ;
53     public static final int
54         STATUS_CODE_FORBIDDEN = 403 ;
55     public static final int
56         STATUS_CODE_OK = 200 ;
57     public static final int
58         STATUS_CODE_AUTHENTICATION_ACCEPTED = 212 ;
59     public static final int
60         STATUS_REFRESH_REQUIRED = 508 ;
61
62     private static final String JavaDoc SESSION_ID = "12345678" ;
63
64     private static final String JavaDoc XML_ALERT = "/xml/alert.xml";
65     private static final String JavaDoc XML_INITIALIZATION = "/xml/init.xml" ;
66     private static final String JavaDoc XML_MODIFICATIONS = "/xml/mod.xml" ;
67     private static final String JavaDoc XML_MAPPING = "/xml/map.xml" ;
68
69     private static final char RECORD_STATE_NEW = 'N' ;
70     private static final char RECORD_STATE_DELETED = 'D' ;
71     private static final char RECORD_STATE_UPDATED = 'U' ;
72
73     private static final String JavaDoc TAG_ALERT = "Alert" ;
74     private static final String JavaDoc TAG_ADD = "Add" ;
75     private static final String JavaDoc TAG_CMD = "Cmd" ;
76     private static final String JavaDoc TAG_DATA = "Data" ;
77     private static final String JavaDoc TAG_DELETE = "Delete" ;
78     private static final String JavaDoc TAG_ITEM = "Item" ;
79     private static final String JavaDoc TAG_LOC_URI = "LocURI" ;
80     private static final String JavaDoc TAG_REPLACE = "Replace" ;
81     private static final String JavaDoc TAG_STATUS = "Status" ;
82     private static final String JavaDoc TAG_SYNC = "Sync" ;
83     private static final String JavaDoc TAG_SYNCBODY = "SyncBody" ;
84     private static final String JavaDoc TAG_SYNCHDR = "SyncHdr" ;
85     private static final String JavaDoc TAG_SYNCML = "SyncML" ;
86     private static final String JavaDoc TAG_TARGET = "Target" ;
87
88     //---------------------------------------------------------------- Private data
89

90     private Hashtable JavaDoc serverAlerts = null ;
91
92     private String JavaDoc alertXML = null ;
93     private String JavaDoc clientInitXML = null ;
94     private String JavaDoc modificationsXML = null ;
95     private String JavaDoc mappingXML = null ;
96
97     private String JavaDoc serverUrl = null ;
98     private String JavaDoc serverUrlStatus = null ;
99     private String JavaDoc gatewayApn = null ;
100     private String JavaDoc gatewayIp = null ;
101     private String JavaDoc gatewayPort = null ;
102     private String JavaDoc gatewayUrl = null ;
103
104     private String JavaDoc login = null ;
105
106     private String JavaDoc sourceUri = null ;
107     private String JavaDoc sourceType = null ;
108     private String JavaDoc sourceName = null ;
109
110     private Hashtable JavaDoc mappings = null ;
111
112     private DataStore dataStore = null ;
113
114     private long lastTimestamp ;
115     private long nextTimestamp ;
116
117     Runtime JavaDoc rt = null;
118
119     //------------------------------------------------------------- Constructors
120

121     /**
122      * Creates a SyncManagerImpl.
123      * The datastore is identified by the dataStoreName parameter
124      *
125      * @param dataStoreName The dataStore to Sync
126      *
127      */

128     protected SyncManagerImpl (String JavaDoc dataStoreName ,
129                                String JavaDoc sourceType ,
130                                String JavaDoc sourceName) {
131
132         this.sourceUri = dataStoreName ;
133         this.sourceType = sourceType ;
134         this.sourceName = sourceName ;
135         this.mappings = new Hashtable JavaDoc() ;
136         this.dataStore = DataStore.getDataStore(dataStoreName) ;
137
138     }
139
140     //----------------------------------------------------------- Public methods
141

142     public void setServerUrl (String JavaDoc serverUrl) {
143         this.serverUrl = serverUrl;
144     }
145
146     public void setLogin (String JavaDoc login) {
147         this.login = login;
148     }
149
150     public void setGatewayApn (String JavaDoc gatewayApn) {
151         this.gatewayApn = gatewayApn;
152     }
153
154     public void setGatewayIp (String JavaDoc gatewayIp) {
155         this.gatewayIp = gatewayIp;
156     }
157
158     public void setGatewayPort (String JavaDoc gatewayPort) {
159         this.gatewayPort = gatewayPort;
160     }
161
162     /** Synchronize synchronization sources.
163      * @throws SyncException if an error occurs during synchronization
164      * @throws AuthenticationException if the server responded with "non authorized" return code
165      */

166     public void sync() throws SyncException, AuthenticationException, UpdateException {
167
168         String JavaDoc response = "";
169
170         if (gatewayApn != null && gatewayApn.length() > 0) {
171             gatewayUrl = ";WAPGatewayIP=" +
172                          gatewayIp +
173                          ";WAPGatewayAPN=" +
174                          gatewayApn +
175                          ";WAPGatewayPort=" +
176                          gatewayPort ;
177         } else {
178             gatewayUrl = "";
179         }
180
181         serverUrl = serverUrl + gatewayUrl;
182
183         try {
184             lastTimestamp = dataStore.getLastTimestamp();
185         } catch (DataAccessException e) {
186             throw new SyncException(e.getMessage());
187         }
188
189         nextTimestamp = System.currentTimeMillis();
190
191         try {
192             loadResources();
193         } catch (IOException JavaDoc e) {
194             throw new UpdateException( "Error: ("
195             + e.getClass().getName()
196             + "): "
197             + e.getMessage()
198             );
199         }
200
201         prepareInizializationMessage();
202
203         StaticDataHelper.log("\n\n\n");
204         StaticDataHelper.log("debug - INIT - init\n:" + clientInitXML);
205
206         response = syncInitialization();
207
208         checkServerAlerts(response);
209
210         // start debug
211
StaticDataHelper.log("\n\n\n");
212         Enumeration JavaDoc keys = serverAlerts.keys();
213         while (keys.hasMoreElements()) {
214             String JavaDoc keyStr = (String JavaDoc) keys.nextElement();
215             StaticDataHelper.log("source - Name: " + keyStr + "| Status: " + serverAlerts.get(keyStr));
216         }
217         // end debug
218

219         StaticDataHelper.log("\n\n\n");
220         StaticDataHelper.log("debug - INIT - response\n:" + response);
221
222         serverUrlStatus = serverUrl;
223         serverUrl = response.substring(response.indexOf("<RespURI>") + 9,
224                                              response.indexOf("</RespURI>")) + gatewayUrl;
225
226         //
227
// execute init dataStore operation
228
//
229
dataStore.startDSOperations();
230
231         //
232
// Notifies the sources that the synchronization is going to begin
233
//
234

235         int alertCode = -1;
236
237         response = null;
238         prepareModificationMessage();
239
240         StaticDataHelper.log("\n\n\n\n\n\n\n");
241         StaticDataHelper.log("debug - MOD - msg\n:" + modificationsXML);
242
243         long timestampb = System.currentTimeMillis();
244
245         response = syncModifications();
246
247         if (response.indexOf("<Final/>") == -1 &&
248             response.indexOf("</Final>") == - 1) {
249
250             prepareAlertMessage();
251
252             response = sendAlertMessage();
253
254         }
255
256         StaticDataHelper.log("\n\n\n\n\n\n\n");
257         StaticDataHelper.log("debug - MOD - response\n:" + response);
258
259
260         long timestampc = System.currentTimeMillis();
261
262         boolean sendResponse = processModifications(response);
263
264         if (sendResponse) {
265
266             prepareMappingMessage();
267
268             StaticDataHelper.log("\n\n\n\n\n\n\n");
269             StaticDataHelper.log("debug - MAP - msg\n:" + mappingXML);
270
271             syncMapping();
272
273         }
274
275         //
276
// Set the last anchor to the next timestamp for all the sources that
277
// has been synchronized
278
//
279

280         try {
281
282             dataStore.commitDSOperations();
283
284             dataStore.setLastTimestamp(nextTimestamp);
285
286         } catch (DataAccessException e) {
287             throw new SyncException(e.getMessage());
288         }
289
290     }
291
292     //---------------------------------------------------------- Private methods
293

294     /**
295      * Synch initialization.
296      *
297      * @throws SyncException, AuthenticationException, UpdateException
298      * @return sync initialization response
299      **/

300     private String JavaDoc syncInitialization()
301     throws SyncException, AuthenticationException, UpdateException {
302
303         String JavaDoc response = "";
304
305         StaticDataHelper.log("Sync Initialization...");
306
307         try {
308             response = postRequest(clientInitXML);
309         } catch(SyncException e) {
310             String JavaDoc msg = "Err syncInit: " + e.getMessage();
311             StaticDataHelper.log(msg);
312             throw e;
313         } catch (Exception JavaDoc e) {
314             String JavaDoc msg = "Err syncInit: " + e.getMessage();
315             StaticDataHelper.log(msg);
316             throw new SyncException(msg);
317         }
318
319         checkStatus(response, TAG_SYNCHDR );
320         checkStatus(response, TAG_ALERT );
321
322         StaticDataHelper.log("Initialization done!");
323
324         return response;
325     }
326
327
328     /**
329      * Synch Modification.
330      *
331      * @throws UpdateException
332      * @return sync modification response
333      **/

334     private String JavaDoc syncModifications()
335     throws SyncException {
336
337         String JavaDoc response = null;
338
339         StaticDataHelper.log("Sync Modifications...");
340
341         try {
342             response = postRequest(modificationsXML);
343         } catch(SyncException e) {
344             String JavaDoc msg = "Err syncInit: " + e.getMessage();
345             throw new SyncException(msg);
346         } catch (Exception JavaDoc e) {
347             String JavaDoc msg = "Err syncMod: " + e.getMessage();
348             StaticDataHelper.log(msg);
349             throw new SyncException(msg);
350         }
351         StaticDataHelper.log("Modification done!");
352         return response;
353     }
354
355     /**
356      * Send alert message.
357      *
358      * @throws UpdateException
359      * @return sync modification response
360      **/

361     private String JavaDoc sendAlertMessage()
362     throws SyncException {
363
364         String JavaDoc response = null;
365
366         StaticDataHelper.log("Sync Modifications...");
367
368         try {
369             response = postRequest(alertXML);
370         } catch(SyncException e) {
371             String JavaDoc msg = "Error Modifications: " + e.getMessage();
372             throw new SyncException(msg);
373         } catch (Exception JavaDoc e) {
374             String JavaDoc msg = "Error Modifications: " + e.getMessage();
375             StaticDataHelper.log(msg);
376             throw new SyncException(msg);
377         }
378         StaticDataHelper.log("Modification done!");
379
380         return response;
381     }
382
383
384     /**
385      * Sync LUID-GUID mapping.
386      *
387      * @throws UpdateException
388      * @return sync modification response
389      **/

390     private void syncMapping()
391     throws SyncException {
392
393         StaticDataHelper.log("Sync mapping...");
394
395         try {
396             postRequest(mappingXML);
397         } catch (Exception JavaDoc e) {
398             String JavaDoc msg = "Err syncMod: " + e.getMessage();
399             StaticDataHelper.log(msg);
400             throw new SyncException(msg);
401         }
402         StaticDataHelper.log("Mapping done!");
403     }
404
405     /**
406      * Posts the given message to the url specified by <i>url</i>.
407      *
408      * @param request the request msg
409      * @return the url content as a byte array
410      * @throws SyncException in case of network errors
411      **/

412     private String JavaDoc postRequest(String JavaDoc request)
413     throws SyncException {
414
415         try {
416
417             SyncMLClientImpl syncMLClient = new SyncMLClientImpl(serverUrl);
418
419             return syncMLClient.sendMessage(request);
420
421         } catch (Exception JavaDoc e) {
422             String JavaDoc msg = "Error sending the request: " + e.getMessage();
423             StaticDataHelper.log(msg);
424             throw new SyncException(msg);
425         }
426     }
427
428     /**
429      * Checks if the given response message is authenticated from the server.
430      *
431      * @param msg the message to be checked
432      * @param statusOf the command of which we want to check the status
433      *
434      * @throws AuthenticationException in case the request has not been
435      * authenticated by the server
436      * @throws SyncException in case of other errors
437      **/

438     private void checkStatus(String JavaDoc msg, String JavaDoc statusOf)
439     throws SyncException, AuthenticationException, UpdateException {
440
441         Vector JavaDoc xmlMsg = new Vector JavaDoc();
442
443         xmlMsg.addElement(msg);
444
445         Vector JavaDoc statusTag = getXMLTag(getXMLTag(getXMLTag(xmlMsg, TAG_SYNCML),TAG_SYNCBODY), TAG_STATUS);
446
447         int l = statusTag.size();
448
449         for (int i=0; i < l; i++) {
450
451                 if (getXMLTagValue((String JavaDoc) statusTag.elementAt(i), TAG_CMD).equals(statusOf)) {
452
453                     String JavaDoc statusCode = getXMLTagValue((String JavaDoc) statusTag.elementAt(i), TAG_DATA);
454
455                     if (String.valueOf(STATUS_CODE_OK).equals(statusCode)) {
456                         //
457
// 200
458
//
459
return;
460                     } else if (String.valueOf(STATUS_REFRESH_REQUIRED).equals(statusCode)) {
461                         //
462
// 508
463
//
464
return;
465                     } else if (String.valueOf(STATUS_CODE_AUTHENTICATION_ACCEPTED).equals(statusCode)) {
466                         //
467
// 212
468
//
469
return;
470                     } else if (String.valueOf(STATUS_CODE_FORBIDDEN).equals(statusCode)) {
471                         //
472
// 403
473
//
474
throw new AuthenticationException(
475                             "Sorry, you are not authorized to synchronize "
476                             + sourceUri
477                             + ". Go to the preferences panel and make sure your account settings are correct."
478                         );
479                     } else {
480                         //
481
// Unhandled status code
482
//
483

484                         throw new UpdateException(statusCode);
485                     }
486                 }
487
488         } // next i
489

490         String JavaDoc msgE = msg;
491         StaticDataHelper.log(msgE);
492         throw new SyncException(msgE);
493     }
494
495     /**
496      * Checks response status for the synchronized databases and saves their
497      * serverAlerts. <br>
498      * If this is the first sync for the source, the status code might change
499      * according to the value of the PARAM_FIRST_TIME_SYNC_MODE configuration
500      * property.<br>
501      * If firstTimeSyncMode is not set, the alert is left unchanged. If it is
502      * set to a value, the specified value is used instead.
503      *
504      * @param msg the message to be checked
505      *
506      * @throws AuthenticationException in case the request has not been
507      * authenticated by the server
508      * @throws SyncException in case of other errors
509      **/

510     private void checkServerAlerts(String JavaDoc msg)
511     throws SyncException, AuthenticationException {
512
513         Vector JavaDoc xmlMsg = null;
514         Vector JavaDoc itemMsg = null;
515         Vector JavaDoc targetTag = null;
516
517         String JavaDoc alert = null;
518         String JavaDoc item = null;
519         String JavaDoc dataStore = null;
520
521         xmlMsg = new Vector JavaDoc();
522         xmlMsg.addElement(msg);
523
524         serverAlerts = new Hashtable JavaDoc();
525
526         Vector JavaDoc alertTag = getXMLTag(getXMLTag(getXMLTag(xmlMsg, TAG_SYNCML),TAG_SYNCBODY), TAG_ALERT);
527
528         int l = alertTag.size();
529
530         for (int i=0; i < l; i++) {
531             itemMsg = new Vector JavaDoc();
532
533             alert = getXMLTagValue((String JavaDoc) alertTag.elementAt(i), TAG_DATA);
534
535             item = getXMLTagValue((String JavaDoc) alertTag.elementAt(i), TAG_ITEM);
536
537             itemMsg.addElement(item);
538
539             targetTag = getXMLTag(itemMsg, TAG_TARGET);
540
541             int m = targetTag.size();
542
543             for (int j=0; j < m; j++) {
544                 dataStore = getXMLTagValue((String JavaDoc) targetTag.elementAt(j), TAG_LOC_URI);
545             }
546
547             StaticDataHelper.log("The server alert code for " + dataStore + " is " + alert);
548
549             serverAlerts.put(dataStore, alert);
550         }
551     }
552
553     /**
554      * Prepare inizialization message
555      *
556      **/

557     private void prepareInizializationMessage()
558     throws SyncException {
559
560         String JavaDoc dbAlertsXML = null ;
561
562         dbAlertsXML = createAlerts(sourceUri) ;
563
564         //
565
// authentication basic
566
//
567
login = new String JavaDoc(Base64.encode(login.getBytes()));
568
569         clientInitXML = messageFormat(clientInitXML, "{0}", SESSION_ID );
570         clientInitXML = messageFormat(clientInitXML, "{1}", serverUrl );
571         clientInitXML = messageFormat(clientInitXML, "{2}", login );
572         clientInitXML = messageFormat(clientInitXML, "{3}", dbAlertsXML );
573
574     }
575
576     /**
577      * Process the modifications from the received from server.
578      *
579      * @param modifications the modification message
580      *
581      * @return true if a response message is required, false otherwise
582      *
583      * @throws SyncException
584      */

585     private boolean processModifications(String JavaDoc modifications)
586     throws SyncException {
587
588         Vector JavaDoc xmlResponse = new Vector JavaDoc();
589         Vector JavaDoc bodyTags = new Vector JavaDoc();
590         Vector JavaDoc addTags = new Vector JavaDoc();
591         Vector JavaDoc replaceTags = new Vector JavaDoc();
592         Vector JavaDoc deleteTags = new Vector JavaDoc();
593
594         String JavaDoc key = null ;
595         String JavaDoc content = null ;
596
597         String JavaDoc syncMsg = null ;
598
599         Record record = null ;
600
601         boolean ret = false ;
602
603         xmlResponse.addElement(modifications);
604
605         bodyTags = getXMLTag(getXMLTag(xmlResponse, TAG_SYNCML), TAG_SYNCBODY );
606         addTags = getXMLTag(bodyTags, TAG_ADD );
607         replaceTags = getXMLTag(bodyTags, TAG_REPLACE );
608         deleteTags = getXMLTag(bodyTags, TAG_DELETE );
609
610         if (modifications.indexOf("<" + TAG_SYNC + ">") != - 1) {
611             ret = true;
612         }
613
614         for (int i=0, l = addTags.size(); i < l; i++) {
615
616             key = getXMLTagValue((String JavaDoc) addTags.elementAt(i), TAG_LOC_URI );
617
618             content = getXMLTagValue((String JavaDoc) addTags.elementAt(i), TAG_DATA );
619
620             StaticDataHelper sdh = new StaticDataHelper();
621             if (sdh.isEncode() && content != null) {
622                 try {
623                     content = new String JavaDoc (Base64.decode(content), "UTF-8");
624                 } catch (Exception JavaDoc e) {
625                     throw new SyncException(e.getMessage());
626                 }
627             }
628
629             content = StringTools.unescapeXml(content);
630
631             record = new Record(key, ' ', content);
632             String JavaDoc bbKey = "";
633
634             try {
635                 bbKey = dataStore.setRecord(record, false).getKey();
636             } catch(DataAccessException e) {
637                 throw new SyncException(e.getMessage());
638             }
639
640             ret = true;
641
642             mappings.put(bbKey, key);
643
644         }
645
646         for (int i=0, l = replaceTags.size(); i < l; i++) {
647
648             key = getXMLTagValue((String JavaDoc) replaceTags.elementAt(i), TAG_LOC_URI );
649
650             content = getXMLTagValue((String JavaDoc) replaceTags.elementAt(i), TAG_DATA );
651
652             StaticDataHelper sdh = new StaticDataHelper();
653             if (sdh.isEncode() && content != null) {
654                 try {
655                     content = new String JavaDoc (Base64.decode(content), "UTF-8");
656                 } catch (Exception JavaDoc e) {
657                     throw new SyncException(e.getMessage());
658                 }
659             }
660
661             content = StringTools.unescapeXml(content);
662
663             record = new Record(key, ' ', content);
664
665             try {
666                 dataStore.setRecord(record, true);
667             } catch(DataAccessException e) {
668                 throw new SyncException(e.getMessage());
669             }
670
671             ret = true;
672
673         }
674
675         for (int i=0, l = deleteTags.size(); i < l; i++) {
676
677             key = getXMLTagValue((String JavaDoc) deleteTags.elementAt(i), TAG_LOC_URI );
678
679             record = new Record();
680
681             record.setKey(key);
682
683             try {
684                 dataStore.deleteRecord(record);
685             } catch(DataAccessException e) {
686                 throw new SyncException(e.getMessage());
687             }
688
689             ret = true;
690
691         }
692
693         return ret;
694     }
695
696     /**
697      * Prepare modification message
698      *
699      **/

700     private void prepareModificationMessage()
701     throws SyncException {
702
703         Vector JavaDoc records = null ;
704
705         StringBuffer JavaDoc syncTag = new StringBuffer JavaDoc();
706
707         String JavaDoc alert;
708
709         int alertCode;
710
711         //
712
// Note we must sync only the sources that are aknoledged by the
713
// server with a server Alert command.
714
//
715
StaticDataHelper.log("serverAlerts: " + serverAlerts);
716
717         alert = (String JavaDoc)serverAlerts.get(sourceUri);
718
719         if (alert != null) {
720
721             alertCode = getSourceAlertCode(sourceUri);
722
723             if (alertCode == ALERT_CODE_SLOW) {
724                 //
725
// Slow Sync!
726
//
727
StaticDataHelper.log("Prepare slow sync for " + sourceUri);
728                 records = filterRecordsForSlowSync();
729             } else if (alertCode == ALERT_CODE_REFRESH_FROM_SERVER) {
730                 //
731
// Refresh from server
732
//
733
StaticDataHelper.log("Prepare refresh for " + sourceUri);
734                 records = new Vector JavaDoc(); // no items sent for refrsh
735
} else if (alertCode == ALERT_CODE_ONE_WAY_FROM_SERVER) {
736                 //
737
// One-way sync from server: no needs of client modifications
738
//
739
StaticDataHelper.log("Prepare one-way sync for " + sourceUri);
740                 records = new Vector JavaDoc(); // no items sent for one-way
741
} else {
742                 //
743
// Fast Sync!
744
//
745
StaticDataHelper.log("Prepare fast sync for " + sourceUri);
746                 //
747
// NOTE: filterRecordsForFastSync returns items in updated state
748
//
749

750                 records = filterRecordsForFastSync();
751
752             }
753
754
755         } else {
756
757             StaticDataHelper.log( "The server did not sent an Alert for " +
758                                    sourceUri +
759                                    ". The source will not be synchronized."
760                                 );
761         }
762
763         StaticDataHelper sdh = new StaticDataHelper();
764
765         if (sdh.isEncode()) {
766             records = encodeB64Records(records);
767         }
768
769         syncTag.append(prepareSyncTag(records, sourceUri));
770
771         modificationsXML = messageFormat(modificationsXML, "{0}", SESSION_ID );
772         modificationsXML = messageFormat(modificationsXML, "{1}", serverUrl );
773         modificationsXML = messageFormat(modificationsXML, "{2}", serverUrlStatus );
774         modificationsXML = messageFormat(modificationsXML, "{3}", syncTag.toString() );
775     }
776
777     /**
778      * Prepare alert message
779      *
780      **/

781     private void prepareAlertMessage() {
782
783         alertXML = messageFormat(alertXML, "{0}", SESSION_ID );
784         alertXML = messageFormat(alertXML, "{1}", serverUrl );
785         alertXML = messageFormat(alertXML, "{2}", serverUrl );
786         alertXML = messageFormat(alertXML, "{3}", serverUrlStatus );
787
788     }
789
790     /**
791      * Prepare mapping message
792      *
793      **/

794     private void prepareMappingMessage() {
795
796         String JavaDoc targetRef = null ;
797         String JavaDoc sourceRef = null ;
798
799         StringBuffer JavaDoc mapTag = new StringBuffer JavaDoc();
800
801         int i = 0;
802
803         for (Enumeration JavaDoc e = mappings.keys(); e.hasMoreElements(); ) {
804
805             if (i == 0) {
806                 mapTag.append("<Map>\n");
807
808                 mapTag.append("<CmdID>0</CmdID>\n");
809                 mapTag.append("<Target>\n");
810                 mapTag.append("<LocURI>" + sourceUri + "</LocURI>\n");
811                 mapTag.append("</Target>\n");
812                 mapTag.append("<Source>\n");
813                 mapTag.append("<LocURI>" + sourceUri + "</LocURI>\n");
814                 mapTag.append("</Source>\n");
815             }
816
817             sourceRef = (String JavaDoc) e.nextElement();
818             targetRef = (String JavaDoc) mappings.get(sourceRef);
819
820             mapTag.append("<MapItem>\n");
821             mapTag.append("<Target>\n");
822             mapTag.append("<LocURI>" + targetRef + "</LocURI>\n");
823             mapTag.append("</Target>\n");
824             mapTag.append("<Source>\n");
825             mapTag.append("<LocURI>" + sourceRef + "</LocURI>\n");
826             mapTag.append("</Source>\n");
827             mapTag.append("</MapItem>\n");
828
829             i++;
830         }
831
832         if (i > 0) {
833             mapTag.append("</Map>\n");
834         }
835         mappingXML = messageFormat(mappingXML, "{0}", SESSION_ID );
836         mappingXML = messageFormat(mappingXML, "{1}", serverUrl );
837         mappingXML = messageFormat(mappingXML, "{2}", serverUrl );
838         mappingXML = messageFormat(mappingXML, "{3}", mapTag.toString() );
839     }
840
841     /**
842      * Load the resources from the classpath.
843      *
844      * @throws IOException
845      **/

846     private void loadResources() throws IOException JavaDoc {
847
848         Class JavaDoc c = this.getClass();
849
850         alertXML = StaticDataHelper.read(
851             c.getResourceAsStream(XML_ALERT)
852         );
853
854         clientInitXML = StaticDataHelper.read(
855             c.getResourceAsStream(XML_INITIALIZATION)
856         );
857
858         modificationsXML = StaticDataHelper.read(
859             c.getResourceAsStream(XML_MODIFICATIONS)
860         );
861
862         mappingXML = StaticDataHelper.read(
863             c.getResourceAsStream(XML_MAPPING)
864         );
865
866     }
867
868     /**
869      * Contructs the alerts for the given databses.
870      * @param sourceUri
871      * @return the XML for the SyncML Alert commands
872      **/

873     private String JavaDoc createAlerts(String JavaDoc sourceUri) {
874
875         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
876
877         sb.append("<Alert>\n");
878         sb.append("<CmdID>1</CmdID>\n");
879         sb.append("<Data>");
880         sb.append("200");
881         sb.append("</Data>\n");
882         sb.append("<Item>\n");
883         sb.append("<Target><LocURI>");
884         sb.append(sourceUri);
885         sb.append("</LocURI></Target>\n");
886         sb.append("<Source><LocURI>");
887         sb.append(sourceUri);
888         sb.append("</LocURI></Source>\n");
889         sb.append("<Meta>\n");
890         sb.append("<Anchor xmlns=\"syncml:metinf\">\n");
891         sb.append("<Last>" + lastTimestamp + "</Last>\n");
892         sb.append("<Next>" + nextTimestamp + "</Next>\n");
893         sb.append("</Anchor>\n");
894         sb.append("</Meta>\n");
895         sb.append("</Item>\n");
896         sb.append("</Alert>");
897         sb.append("\n");
898
899         return sb.toString();
900     }
901
902    /**
903      * Make a String[] by tags find with search.
904      *
905      * @param xmlInput tags about search
906      * @param tag to find
907      * @return find tags
908      **/

909     private Vector JavaDoc getXMLTag(Vector JavaDoc xmlInput, String JavaDoc tag)
910     throws SyncException {
911
912         Vector JavaDoc xmlReturn = null ;
913         String JavaDoc xmlInputTag = null ;
914         String JavaDoc endTag = null ;
915
916         endTag = "</" + tag + ">" ;
917
918         xmlReturn = new Vector JavaDoc();
919
920         try {
921
922             for (int j=0, l = xmlInput.size(); j < l; j++) {
923
924                 xmlInputTag = (String JavaDoc) xmlInput.elementAt(j);
925
926                 //
927
// tag without namespace
928
// or tag with namespace
929
//
930
while (xmlInputTag.indexOf("<" + tag + ">") != -1 ||
931                        xmlInputTag.indexOf("<" + tag + " ") != -1) {
932
933                     xmlReturn.addElement(getXMLTagValue(xmlInputTag, tag));
934
935                     xmlInputTag =
936                         xmlInputTag.substring(
937                                         xmlInputTag.
938                                             indexOf(endTag) + endTag.length());
939
940                 }
941
942             }
943
944         } catch (Exception JavaDoc e) {
945             throw new SyncException("Parsing XML error, TAG " +
946                                     tag +
947                                     " - : " +
948                                     e.getMessage() );
949         }
950
951         return xmlReturn;
952
953     }
954
955     /**
956      * Make a String by value of <i>tag</i>.
957      *
958      * @param xml xml msg
959      * @param tag tag to find
960      * @return tag value
961      **/

962     private String JavaDoc getXMLTagValue(String JavaDoc xml, String JavaDoc tag) {
963
964         String JavaDoc startTag = null;
965         String JavaDoc endTag = null;
966
967         startTag = "<" + tag + ">";
968         endTag = "</" + tag + ">";
969
970         return xml.substring(xml.indexOf(startTag) + startTag.length(), xml.indexOf(endTag));
971
972     }
973
974     /**
975      * Retrieves the modified items since the last synchronization.
976      *
977      * @return the modified records since the last synchronization
978      **/

979     private Vector JavaDoc filterRecordsForFastSync()
980     throws SyncException {
981
982         Vector JavaDoc records = null;
983         Vector JavaDoc ret = new Vector JavaDoc();
984
985         try {
986             records = dataStore.getRecords('N');
987         } catch (DataAccessException e) {
988             throw new SyncException(e.getMessage());
989         }
990
991
992         for (int i=0, l = records.size(); i < l; i++) {
993             ret.addElement(records.elementAt(i));
994         }
995
996         try {
997             records = dataStore.getRecords('U');
998         } catch (DataAccessException e) {
999             throw new SyncException(e.getMessage());
1000        }
1001
1002        for (int i=0, l = records.size(); i < l; i++) {
1003            ret.addElement(records.elementAt(i));
1004        }
1005
1006        try {
1007            records = dataStore.getRecords('D');
1008        } catch (DataAccessException e) {
1009            throw new SyncException(e.getMessage());
1010        }
1011
1012        for (int i=0, l = records.size(); i < l; i++) {
1013            ret.addElement(records.elementAt(i));
1014        }
1015
1016        return ret;
1017
1018    }
1019
1020    /**
1021     * Retrieves all items belonging to the given datastore, regardless their
1022     * modification status. It is used for slow sync.
1023     *
1024     * @return all items in the source
1025     **/

1026    private Vector JavaDoc filterRecordsForSlowSync()
1027    throws SyncException {
1028
1029        Vector JavaDoc records = null;
1030
1031        try {
1032
1033            records = dataStore.getNoDeletedRecords();
1034
1035        } catch (DataAccessException e) {
1036            throw new SyncException(e.getMessage());
1037        }
1038
1039        for(int i=0, l = records.size(); i < l; i++) {
1040            ((Record) records.elementAt(i)).setState(RECORD_STATE_UPDATED);
1041        }
1042
1043        return records;
1044    }
1045
1046    /**
1047     * return Sync tag about sourceUri
1048     *
1049     * @param records records to sync
1050     * @param sourceURI source uri
1051     * @return sync tag value
1052     **/

1053    private String JavaDoc prepareSyncTag(Vector JavaDoc records, String JavaDoc sourceURI)
1054    throws SyncException {
1055
1056        StringBuffer JavaDoc addItems = new StringBuffer JavaDoc() ;
1057        StringBuffer JavaDoc replaceItems = new StringBuffer JavaDoc() ;
1058        StringBuffer JavaDoc deleteItems = new StringBuffer JavaDoc() ;
1059        StringBuffer JavaDoc add = new StringBuffer JavaDoc() ;
1060        StringBuffer JavaDoc replace = new StringBuffer JavaDoc() ;
1061        StringBuffer JavaDoc delete = new StringBuffer JavaDoc() ;
1062        StringBuffer JavaDoc syncTag = new StringBuffer JavaDoc() ;
1063
1064        Record record = null;
1065
1066        for(int i=0, l = records.size(); i < l; i++) {
1067
1068            record = (Record) records.elementAt(i);
1069
1070            try {
1071
1072                switch (record.getState()) {
1073                    case RECORD_STATE_DELETED:
1074                        deleteItems.append("<Item>\n")
1075                                .append("<Source><LocURI>")
1076                                .append(record.getKey())
1077                                .append("</LocURI></Source>\n")
1078                                .append("</Item>\n");
1079                        break;
1080
1081                    case RECORD_STATE_UPDATED:
1082
1083                        replaceItems.append("<Item>\n")
1084                                    .append("<Source><LocURI>")
1085                                    .append(record.getKey())
1086                                    .append("</LocURI></Source>\n")
1087                                    .append("<Data>")
1088                                    .append(StringTools.escapeXml(record.getUid()))
1089                                    .append("</Data>\n")
1090                                    .append("</Item>\n");
1091
1092                        break;
1093
1094                    case RECORD_STATE_NEW:
1095
1096                        addItems.append("<Item>\n")
1097                                .append("<Source><LocURI>")
1098                                .append(record.getKey())
1099                                .append("</LocURI></Source>\n")
1100                                .append("<Data>")
1101                                .append(StringTools.escapeXml(record.getUid()))
1102                                .append("</Data>\n")
1103                                .append("</Item>\n");
1104
1105                        break;
1106
1107
1108                } // end switch
1109

1110
1111            } catch (OutOfMemoryError JavaDoc oom) {
1112                throw new SyncException ("out-of-memory");
1113            }
1114
1115
1116        } // next i
1117

1118        //
1119
// NOTE: for JDK 1.1.8 compatibility we cannot use StringBuffer.append(StringBuffer)
1120
//
1121

1122        if (addItems.length()>0) {
1123            add.append("<Add>\n")
1124               .append("<CmdID>4</CmdID>\n")
1125               .append("<Meta><Type xmlns=\"syncml:metinf\">" + sourceType + "</Type></Meta>\n")
1126               .append(addItems.toString())
1127               .append("\n</Add>\n");
1128
1129       }
1130
1131       if (replaceItems.length()>0) {
1132          replace.append("<Replace>\n")
1133                 .append("<CmdID>4</CmdID>\n")
1134                 .append("<Meta><Type xmlns=\"syncml:metinf\">" + sourceType + "</Type></Meta>\n")
1135                 .append(replaceItems.toString())
1136                 .append("\n</Replace>\n");
1137
1138       }
1139
1140       if (deleteItems.length()>0) {
1141          delete.append("<Delete>\n")
1142                 .append("<CmdID>4</CmdID>\n")
1143                 .append(deleteItems.toString())
1144                 .append("\n</Delete>\n");
1145       }
1146
1147       syncTag.append("<Status>\n")
1148              .append("<CmdID>2</CmdID>\n")
1149              .append("<MsgRef>1</MsgRef><CmdRef>1</CmdRef><Cmd>Alert</Cmd>\n")
1150              .append("<TargetRef>")
1151              .append(sourceURI)
1152              .append("</TargetRef>\n")
1153              .append("<SourceRef>")
1154              .append(sourceURI)
1155              .append("</SourceRef>\n")
1156              .append("<Data>200</Data>\n")
1157              .append("<Item>\n")
1158              .append("<Data>" + "\n")
1159              .append("<Anchor xmlns=\"syncml:metinf\"><Next>")
1160              .append(nextTimestamp)
1161              .append("</Next></Anchor>\n")
1162              .append("</Data>\n")
1163              .append("</Item>\n")
1164              .append("</Status>\n")
1165              .append("<Sync>\n")
1166              .append("<CmdID>3</CmdID>\n")
1167              .append("<Target><LocURI>")
1168              .append(sourceURI)
1169              .append("</LocURI></Target>\n")
1170              .append("<Source><LocURI>")
1171              .append(sourceURI)
1172              .append("</LocURI></Source>\n")
1173              .append(add.toString())
1174              .append(replace.toString())
1175              .append(delete.toString())
1176              .append("</Sync>");
1177
1178              add = null;
1179              replace = null;
1180              delete = null ;
1181
1182       return syncTag.toString();
1183    }
1184
1185    /**
1186     * Returns the server alert code for the given source.
1187     *
1188     * @param sourceURI the source
1189     *
1190     * @return the server alert code for the given source or -1 if it is not
1191     * found/parsable
1192     */

1193    private int getSourceAlertCode(String JavaDoc sourceURI) {
1194        try {
1195            return Integer.parseInt((String JavaDoc)serverAlerts.get(sourceURI));
1196        } catch (Throwable JavaDoc t) {
1197            StaticDataHelper.log( "ERROR: unrecognized server alert code ("
1198                                + serverAlerts.get(sourceURI)
1199                                + ") for "
1200                                + sourceURI
1201                                );
1202        }
1203
1204        return -1;
1205    }
1206
1207    /**
1208     * Set variable in XML msg.
1209     *
1210     * @param msgXML msg XML
1211     * @param variable variable name
1212     * @param variableValue variable value
1213     * @return msg XML with setting variable value
1214     **/

1215    private String JavaDoc messageFormat(String JavaDoc msgXML, String JavaDoc variable, String JavaDoc variableValue) {
1216
1217        String JavaDoc msgXMLBefore = null;
1218        String JavaDoc msgXMLAfter = null;
1219
1220        msgXMLBefore = msgXML.substring(0, msgXML.indexOf(variable));
1221        msgXMLAfter = msgXML.substring(msgXML.indexOf(variable) + variable.length());
1222
1223        return (msgXMLBefore + variableValue + msgXMLAfter);
1224
1225    }
1226
1227    private Vector JavaDoc encodeB64Records(Vector JavaDoc records) {
1228
1229        String JavaDoc content = null;
1230
1231        for (int i = 0, l = records.size(); records != null && i < l; i++) {
1232
1233            content = ((Record) records.elementAt(i)).getUid();
1234
1235            if (content != null && content.length() > 0) {
1236                ((Record) records.elementAt(i)).setUid(new String JavaDoc(Base64.encode(content.getBytes())));
1237            }
1238
1239        }
1240
1241        return records;
1242    }
1243}
1244
Popular Tags