Sync with 1838
[jgroupdav.git] / src / net / bionicmessage / objects / vCardObjectStore.java
blob8c66e9faa87500a1a0cf4b746e9798f91a6cecd7
1 /*
2 * vCardObjectStore.java
4 * Created on December 13, 2006, 10:44 PM
6 * To change this template, choose Tools | Template Manager
7 * and open the template in the editor.
8 */
10 package net.bionicmessage.objects;
12 import java.io.File;
13 import java.io.FileInputStream;
14 import java.io.IOException;
15 import java.util.ArrayList;
16 import java.util.Hashtable;
17 import java.util.Properties;
18 import java.util.logging.FileHandler;
19 import java.util.logging.Level;
20 import java.util.logging.Logger;
21 import java.util.Map;
22 import net.bionicmessage.groupdav.GroupDAVObject;
23 import net.bionicmessage.groupdav.groupDAV;
24 import net.bionicmessage.utils.HTMLFormatter;
26 import com.funambol.foundation.pdi.contact.*;
27 import com.funambol.foundation.pdi.parser.VcardParser;
28 import java.io.StringWriter;
29 import java.io.ByteArrayInputStream;
30 import java.io.PrintWriter;
31 import java.util.List;
32 /**
34 * @author matt
36 public class vCardObjectStore {
37 groupDAV client = null;
38 public static int OPTION_SSL = 1; /* Are we using SSL? */
39 public static int OPTION_I_AM_AN_EXPERT = 128; /* Allows the user to do dangerous things,
40 * such as changing the URL the store points to
41 * after init */
42 public static int OPTION_PURGE = 64; /* Purge the store contents, i.e for Funambol
43 * Slow sync */
44 public static int OPTION_TODO = 32;
45 public static int OPTION_NEWHANDLER = 16;
46 /** Retrieve password from store config file */
47 public static int OPTION_STOREDPASS = 8;
49 boolean sslmode = false;
50 boolean expertmode = false;
51 boolean purgemode = false;
52 boolean todomode = false;
53 boolean newhandler = false;
54 ObjectTracking obtrack = null;
55 String obtrackdir = "";
56 Properties props = null;
57 File propfile = null;
58 /* Queues for reports */
59 ArrayList addedToStore = new ArrayList();
60 ArrayList updatedInStore = new ArrayList();
61 ArrayList deletedFromStore = new ArrayList();
62 ArrayList untouched = new ArrayList();
63 ArrayList addedToServer = new ArrayList();
64 ArrayList updatedOnServer = new ArrayList();
65 ArrayList deletedFromServer = new ArrayList();
66 /* Object cache */
67 Hashtable objCache = new Hashtable();
68 /* Logger */
69 Logger log = Logger.getLogger("groupdav.vcardobjectstore");
70 FileHandler fh = null;
71 /** Creates a new instance of vCardObjectStore */
72 public vCardObjectStore(String storedir, int options) {
73 int ssltest = options & OPTION_SSL;
74 if (ssltest == OPTION_SSL) {
75 sslmode = true;
77 int experttest = options & OPTION_I_AM_AN_EXPERT;
78 if (experttest == OPTION_I_AM_AN_EXPERT) {
79 expertmode = true;
81 int purgetest = options & OPTION_PURGE;
82 if (purgetest == OPTION_PURGE) {
83 purgemode = true;
85 int todotest = options & OPTION_TODO;
86 if (todotest == OPTION_TODO) {
87 todomode = true;
89 int newtest = options & OPTION_NEWHANDLER;
90 if (newtest == OPTION_NEWHANDLER) {
91 newhandler = true;
93 obtrackdir = storedir+File.separatorChar+"obtrack"+File.separatorChar;
94 if (purgemode) {
95 File obtrackdirf = new File(obtrackdir);
96 String[] files = obtrackdirf.list();
97 if (obtrackdirf.exists() && files.length > 0) {
98 for (int i = 0; i < files.length; i++) {
99 String string = files[i];
100 File toDelete = new File(obtrackdir+File.separatorChar+string);
101 boolean deleted = toDelete.delete();
102 System.out.println("Delete " + toDelete.getAbsolutePath() + "..."+deleted);
105 obtrackdirf.delete();
107 obtrack = new ObjectTracking(obtrackdir);
108 props = new Properties();
109 propfile = new File(storedir+File.separatorChar+"vcardstoreprops");
110 if (propfile.exists()) {
111 try {
112 FileInputStream propstream = new FileInputStream(propfile);
113 props.load(propstream);
114 } catch (IOException ex) {
115 ex.printStackTrace();
118 try {
119 long curTime = new java.util.Date().getTime();
120 HTMLFormatter hf = new HTMLFormatter();
121 fh = new FileHandler(storedir + File.separatorChar + "storelog-"+curTime+".html");
122 fh.setFormatter(hf);
123 log.addHandler(fh);
124 fh.setLevel(Level.ALL);
125 log.setLevel(Level.ALL);
126 } catch (SecurityException ex) {
127 ex.printStackTrace();
128 } catch (IOException ex) {
129 ex.printStackTrace();
133 public void setServer(String url) {
134 if (props.getProperty("groupdav.server") == null || expertmode) {
135 props.setProperty("groupdav.server",url);
138 public void setStore(String storeurl) {
139 if (!storeurl.substring(storeurl.length()).equals("/")) {
140 storeurl = storeurl + "/";
142 if(props.getProperty("groupdav.store") == null || expertmode) {
143 props.setProperty("groupdav.store",storeurl);
146 public void connect_Base64(String b64cache) throws Exception {
147 client = new groupDAV(props.getProperty("groupdav.server"),b64cache);
148 afterConnect();
150 public void connect_plain(String user, String pass) throws Exception {
151 client = new groupDAV(props.getProperty("groupdav.server"),user,pass);
152 afterConnect();
154 public void connect_storedpass() throws Exception {
155 client = new groupDAV(props.getProperty("groupdav.server"),
156 props.getProperty("groupdav.user"),
157 props.getProperty("groupdav.pass"));
158 afterConnect();
162 private void afterConnect() throws Exception {
163 client.setLogger(log);
165 public Hashtable getStores() {
166 return client.getURLLocs();
168 private String addFromServerToStore(String url) throws Exception {
169 return addFromServerToStore(url,addedToStore);
171 /* Store->Server side */
172 private String addFromServerToStore(String url,List toAdd) throws Exception {
173 GroupDAVObject obj = client.getObject(url);
174 Contact ct = constructContactObject(obj.getContent());
175 String uid = ct.getUid();
176 objCache.put(uid,ct);
177 Name name = ct.getName();
178 String n = name.getDisplayName().getPropertyValueAsString();
179 if (name.getDisplayName().getPropertyValueAsString() == null) {
180 n = name.toString();
182 obtrack.createObject(uid,url,obj.getEtag(),
183 n.trim(),obj.getContent(),0,0);
184 toAdd.add(uid);
185 return uid;
187 private void updateObjectFromServer(String uid) throws Exception {
188 GroupDAVObject obj = client.getObject(obtrack.getObjectURL(uid));
189 Contact ct = constructContactObject(obj.getContent());
190 Name name = ct.getName();
191 objCache.put(uid,ct);
192 obtrack.updateEtag(uid,obj.getEtag());
193 obtrack.updateObject(uid,obj.getContent());
194 obtrack.updateName(uid,name.getDisplayName().getPropertyValueAsString().trim());
195 updatedInStore.add(uid);
197 private void deleteFromStore(String uid) throws Exception {
198 obtrack.deleteObject(uid);
199 deletedFromStore.add(uid);
201 /* -> End store/server side */
202 /* Client->Store->Server side */
203 /** Adds an object to the server.
204 * @param uid The UID of the object to add
205 * @param name Name of the object to be added
206 * @param contents The ical2 data of the object
207 * @param dtstart The DTSTART of the object in Unix time
208 * @param dtend The DTEND of the object in Unix time
209 * @return -1 if error, 0 if added, 1 if replaced,2 if merged.
211 public String addObject(String uid,
212 String name,
213 String contents) throws Exception {
214 if (contents.indexOf("\nUID:") == -1) {
215 int endLoc = contents.indexOf("END:VCARD");
216 StringBuffer sb = new StringBuffer();
217 sb.append(contents.substring(0, endLoc));
218 sb.append("UID:");
219 sb.append(uid);
220 sb.append("\r\n");
221 sb.append(contents.substring(endLoc));
222 contents = sb.toString();
223 sb = null;
225 /* Post to the server first so we don't have objects in the store
226 * which the server does not want */
227 GroupDAVObject gbo = client.postObject(props.getProperty("groupdav.store"),uid,contents);
228 addFromServerToStore(gbo.getLocation());
229 return uid;
232 * Replace a pre-existing object in the store with a new one.
233 * @param uid The UID of the object to replace
234 * @param name If the object's name has changed, the store will be updated with the new name
236 * If name is null, the name will not be modified.
237 * @param contents Contents of the object replacing the object
238 * @param dtstart The start time of the object. If dtstart and dtend are 0, dates will not be changed
239 * @param dtend The end time of the object. If dtstart and dtend are 0, dates will not be changed
241 public int replaceObject(String uid,
242 String name,
243 String contents) throws Exception {
244 String oldetag = obtrack.getObjectEtag(uid);
245 GroupDAVObject gbo = client.modifyObject(obtrack.getObjectURL(uid),contents,oldetag);
246 updatedOnServer.add(uid);
247 obtrack.updateObject(uid,contents);
248 obtrack.updateEtag(uid,gbo.getEtag());
249 if (name != null) {
250 obtrack.updateName(uid,name);
252 return 0;
254 public int mergeObject(String newuid, String contents1, String contents2)
255 throws Exception {
256 return -1;
258 public void deleteObject(String uid) throws Exception {
259 String oldetag = obtrack.getObjectEtag(uid);
260 GroupDAVObject gbo = client.deleteObject(obtrack.getObjectURL(uid),oldetag);
261 obtrack.deleteObject(uid);
262 deletedFromServer.add(uid);
264 public Contact getObjectFromStore(String uid) throws Exception {
265 if (objCache.get(uid) != null) {
266 log.fine("Object " + uid + "has been retrieved from store");
267 Contact ct = (Contact)objCache.get(uid);
268 return ct;
269 } else {
270 if (!obtrack.doesObjectExist(uid)) {
271 throw new Exception("We do not have an object for " + uid);
272 } else {
273 log.fine("We are constructing an object for " + uid);
274 return constructContactObject(obtrack.getObjectContents(uid));
280 * @param content
281 * @throws java.lang.Exception
282 * @return The UID of the object
284 private Contact constructContactObject(String content) throws Exception {
285 // Fix junk from KAddressBook
286 String ct = content.replace("::", ":");
287 ByteArrayInputStream bis = new ByteArrayInputStream(ct.getBytes());
288 VcardParser vcp = new VcardParser(bis,null,null);
289 return vcp.vCard();
291 public void startSync() throws Exception {
292 log.info("Sync started....");
293 obtrack.init();
294 List objects = client.listObjects(props.getProperty("groupdav.store"));
295 Map etags = client.getEtags();
296 for (int i = 0; i < objects.size(); i++) {
297 String url = (String)objects.get(i);
298 // Do we have the object?
299 boolean haveurl = obtrack.doesURLExist(url);
300 if (haveurl) {
301 String stuid = obtrack.findObjectByURL(url);
302 String stetag = obtrack.getObjectEtag(stuid);
303 String getag = (String)etags.get(url);
304 if (!stetag.equals(getag)) {
305 updateObjectFromServer(stuid);
306 } else {
307 untouched.add(stuid);
309 log.fine("We have the URL: " + url);
310 } else {
311 try {
312 addFromServerToStore(url);
313 } catch (Exception ex) {
314 log.throwing(this.getClass().getName(),"startSync",ex);
316 log.fine("We added the URL: " + url);
320 ArrayList URLarray = obtrack.getURLList();
321 for (int i = 0; i < URLarray.size(); i++) {
322 String url = (String)URLarray.get(i);
323 if (null == etags.get(url)) {
324 log.fine("Deleted on server: " + url);
325 deleteFromStore(obtrack.findObjectByURL(url));
330 public ArrayList getUnModifiedUIDS() {
331 return untouched;
333 public ArrayList getAddedToServerUIDS() {
334 return addedToServer;
336 public ArrayList getAddedToStoreUIDS() {
337 return addedToStore;
339 public ArrayList getDeletedFromServerUIDS() {
340 return deletedFromServer;
342 public ArrayList getDeletedFromStoreUIDS() {
343 return deletedFromStore;
345 public ArrayList getUpdatedInStoreUIDS() {
346 return updatedInStore;
348 public ArrayList getUpdatedOnServerUIDS() {
349 return updatedOnServer;
351 public void printDebugReport() throws Exception {
352 StringWriter sw = new StringWriter();
353 PrintWriter lw = new PrintWriter(sw);
354 ArrayList uids = obtrack.getUIDList();
355 for (int i = 0; i < uids.size(); i++) {
356 String uid = (String)uids.get(i);
357 String url = obtrack.getObjectURL(uid);
358 if (url == null) {
359 throw new Exception("URL for "+uid + " is null");
361 String etag = obtrack.getObjectEtag(uid);
362 String name = obtrack.getObjectName(uid);
363 String data = obtrack.getObjectContents(uid);
364 long dtstart = 0;
365 long dtend = 0;
366 if (!todomode) {
367 dtstart = obtrack.getDtStartForUid(uid);
368 dtend = obtrack.getDtEndFromUid(uid);
370 lw.println("----------");
371 lw.println("UID:"+uid);
372 lw.println("URL:"+url);
373 lw.println("ETAG:"+etag);
374 lw.println("NAME:"+name);
375 if (!todomode) {
376 lw.println("DTSTART:"+dtstart);
377 lw.println("DTEND:"+dtend);
379 lw.println("DATA FOLLOWS:");
380 lw.println(data);
381 lw.println("----------");
383 lw.println("Objects added to store: ");
384 for (int i = 0; i < addedToStore.size(); i++) {
385 String uid = (String)addedToStore.get(i);
386 lw.println("A: "+uid);
388 lw.println("Objects updated from server: ");
389 for (int i = 0; i < updatedInStore.size(); i++) {
390 String uid = (String)updatedInStore.get(i);
391 lw.println("U: "+uid);
393 lw.println("Objects deleted from store: ");
394 for (int i = 0; i < deletedFromStore.size(); i++) {
395 String uid = (String)deletedFromStore.get(i);
396 lw.println("D: "+uid);
398 lw.println("Objects added to the server: ");
399 for (int i = 0; i < addedToServer.size(); i++) {
400 String uid = (String)addedToServer.get(i);
401 lw.println("SA: "+uid);
403 lw.println("Objects merged to server: ");
404 for (int i = 0; i < updatedOnServer.size(); i++) {
405 String uid = (String)updatedOnServer.get(i);
406 lw.println("SM: "+uid);
408 lw.println("Objects deleted from server: ");
409 for (int i = 0; i < deletedFromServer.size(); i++) {
410 String uid = (String)deletedFromServer.get(i);
411 lw.println("SD: "+uid);
413 lw.flush();
414 lw.close();
415 log.info(sw.toString());
417 public void close() throws Exception {
418 fh.close();
419 obtrack.terminate();
421 public String searchUids(String name) throws Exception {
422 // Find potential names
423 ArrayList<String> potentialNames = obtrack.findObjectsByName(name);
424 for (int i = 0; i < potentialNames.size(); i++) {
425 String id = potentialNames.get(i);
426 // Do we have a match?
427 boolean match = obtrack.doesUidMatchTimes(id, 0,0);
428 if (match)
429 return id;
431 return null;
433 public static void main(String args[]) {
434 String storeloc = "";
435 if (args.length > 0 && args[0] != null) {
436 storeloc = args[0];
437 } else {
438 storeloc = System.getProperty("user.home") + System.getProperty("file.separator") + "vcardobjectstoretest";
440 vCardObjectStore vco = new vCardObjectStore(storeloc,
441 vCardObjectStore.OPTION_STOREDPASS + ICalendarObjectStore.OPTION_TODO);
443 try {
444 vco.connect_storedpass();
445 vco.startSync();
446 vco.printDebugReport();
447 } catch (Exception ex) {
448 ex.printStackTrace();