an attempt (not-working) at deploying s4j automatically to snapshot repo. fix problem...
[funambol-groupdav-connector.git] / src / main / java / net / bionicmessage / funambol / groupdav / contacts / ContactSyncSource.java
blob8c81bfa997f4821d0a70a88c42c9084bc173ec5c
1 /*
2 * ContactSyncSource.java
4 * Created on Oct 28, 2007, 12:13:41 PM
6 * GroupDAV connector for Funambol v6.5
7 * Copyright (C) 2007-2008 Mathew McBride
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Affero General Public License as
11 * published by the Free Software Foundation, either version 3 of the
12 * License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Affero General Public License for more details.
19 * You should have received a copy of the GNU Affero General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 package net.bionicmessage.funambol.groupdav.contacts;
24 //import com.funambol.foundation.pdi.contact.Contact;
25 import com.funambol.common.pim.contact.Contact;
26 import com.funambol.framework.engine.SyncItem;
27 import com.funambol.framework.engine.SyncItemKey;
28 import com.funambol.framework.engine.SyncItemState;
29 import com.funambol.framework.engine.source.AbstractSyncSource;
30 import com.funambol.framework.engine.source.SyncContext;
31 import com.funambol.framework.engine.source.SyncSourceException;
32 import com.funambol.framework.tools.beans.BeanInitializationException;
33 import com.funambol.framework.tools.beans.LazyInitBean;
34 import java.io.File;
35 import java.io.Serializable;
36 import java.sql.Timestamp;
37 import java.util.ArrayList;
38 import java.util.Hashtable;
39 import java.util.Iterator;
40 import java.util.Map;
41 import java.util.Properties;
42 import java.util.logging.FileHandler;
43 import java.util.logging.Level;
44 import java.util.logging.Logger;
45 import net.bionicmessage.funambol.framework.Constants;
46 import net.bionicmessage.funambol.framework.Utilities;
47 import net.bionicmessage.objects.MultipleSourceVCardObjectStore;
48 import net.bionicmessage.utils.HTMLFormatter;
50 /**
52 * @author matt
54 public class ContactSyncSource extends AbstractSyncSource implements LazyInitBean, Serializable {
56 private Properties connectorProperties = null;
57 private MultipleSourceVCardObjectStore so = null;
58 private FileHandler fh = null;
59 private Logger log = null;
60 private int syncType = 0;
61 private Map itemStates = null;
62 private Map sources = null;
63 private Properties addrStoreProperties = null;
64 private SyncContext ctx;
66 public ContactSyncSource() {
69 public void beginSync(SyncContext syncContext) throws SyncSourceException {
70 log = Logger.getLogger(Constants.CONTACT_LOGGER_NAME+"-"+System.currentTimeMillis());
71 log.info("Begin sync for Contact Sync Source");
72 this.ctx = syncContext;
73 String principalName = Utilities.cleanFilePath(ctx.getPrincipal().getName());
74 String storeDir = connectorProperties.getProperty(Constants.STOREDIR_PATH);
75 File stdir = new File(storeDir + File.separatorChar + principalName + File.separatorChar);
76 int storeopts = 0;
77 try {
78 /** Set up logging */
79 if (!stdir.exists()) {
80 stdir.mkdirs();
82 // Setup the logger
83 HTMLFormatter hf = new HTMLFormatter();
84 if (connectorProperties.getProperty(Constants.SINGLE_LOG) != null) {
85 fh = new FileHandler(stdir.toString() + File.separatorChar + "connector.html");
86 storeopts += MultipleSourceVCardObjectStore.OPTION_SINGLELOG;
87 } else {
88 long curTime = new java.util.Date().getTime();
89 fh = new FileHandler(stdir.toString() + File.separatorChar + "connector-" + curTime + ".html");
91 fh.setFormatter(hf);
92 log.addHandler(fh);
93 log.setLevel(Level.ALL);
95 itemStates = new Hashtable();
96 syncType = ctx.getSyncMode();
97 log.info("Beginning sync for " + principalName + " for mode=" + syncType);
98 if (syncType == 201 || syncType == 205) {
99 storeopts += 64;
101 } catch (Exception e) {
102 e.printStackTrace();
103 log.throwing("beginSync", "ContactSyncSource", e);
104 throw new SyncSourceException(e);
106 // Perform setup
107 itemStates = new Hashtable();
108 syncType = ctx.getSyncMode();
109 String creds = ctx.getPrincipal().getEncodedCredentials();
110 sources = new Hashtable();
111 addrStoreProperties = new Properties();
112 // Process the sources
113 Iterator configKeys = connectorProperties.keySet().iterator();
114 while (configKeys.hasNext()) {
115 String keyName = (String) configKeys.next();
116 if (keyName.contains(Constants.SOURCE_LOCATION_BASE)) {
117 String sourceLocation = connectorProperties.getProperty(keyName);
118 sourceLocation = sourceLocation.replace("%USER%", syncContext.getPrincipal().getUsername());
119 String sourceName = MultipleSourceVCardObjectStore.BASE_PROPERTY_SOURCE.concat(keyName.replace(Constants.SOURCE_LOCATION_BASE, ""));
120 addrStoreProperties.setProperty(sourceName, sourceLocation);
123 String domainString = connectorProperties.getProperty(Constants.SERVER_HOST);
125 // Parse users email address
126 if (domainString.contains(Constants.DOMAIN_REPLACE)) {
127 String emailAddr = ctx.getPrincipal().getUser().getUsername();
128 if (!emailAddr.contains("@")) {
129 emailAddr = ctx.getPrincipal().getUser().getEmail();
131 String[] emailComponenets = emailAddr.split("@");
132 String domain = emailComponenets[1];
133 domainString = domainString.replace(Constants.DOMAIN_REPLACE, domain);
134 int one = 2;
136 addrStoreProperties.setProperty(MultipleSourceVCardObjectStore.PROPERTY_SERVER,
137 domainString);
138 addrStoreProperties.setProperty(MultipleSourceVCardObjectStore.PROPERTY_SERVER, connectorProperties.getProperty(Constants.SERVER_HOST));
139 addrStoreProperties.setProperty(MultipleSourceVCardObjectStore.PROPERTY_STORE_LOCATION, storeDir);
140 // Create store
141 so = new MultipleSourceVCardObjectStore(stdir.toString(), storeopts);
142 so.setProperties(addrStoreProperties);
143 so.loadSourcesFromProps();
144 try {
145 so.connect_Base64(creds);
146 // Sync
147 so.startSync();
148 } catch (Exception e) {
149 e.printStackTrace();
150 log.throwing("ContactSyncSource", e.getMessage(), e);
151 throw new SyncSourceException(e);
155 public SyncItemKey[] getAllSyncItemKeys() {
156 log.info("getAllSyncItemKeys()");
157 SyncItemKey[] newKeys = this.getNewSyncItemKeys(null, null);
158 SyncItemKey[] updatedKeys = this.getUpdatedSyncItemKeys(null, null);
159 SyncItemKey[] allKnownKeys = new SyncItemKey[newKeys.length + updatedKeys.length];
160 int curKey = 0;
161 for (int i = 0; i < newKeys.length; i++) {
162 allKnownKeys[curKey] = newKeys[i];
163 curKey++;
165 for (int i = 0; i < updatedKeys.length; i++) {
166 allKnownKeys[curKey] = updatedKeys[i];
167 curKey++;
169 return allKnownKeys;
172 // <editor-fold defaultstate="collapsed" desc=" UML Marker ">
173 // #[regen=yes,id=DCE.E775E834-2208-1C54-5D7B-F71213CEDF17]
174 // </editor-fold>
175 public SyncItemKey[] getDeletedSyncItemKeys(java.sql.Timestamp sinceTs, java.sql.Timestamp untilTs)
176 throws SyncSourceException {
177 log.info("getDeletedSyncItemKeys()");
178 ArrayList deletedUIDS = so.getDeletedFromStoreUIDS();
179 SyncItemKey[] keys = new SyncItemKey[deletedUIDS.size()];
180 for (int i = 0; i < deletedUIDS.size(); i++) {
181 String key = (String) deletedUIDS.get(i);
182 SyncItemKey sk = new SyncItemKey(key);
183 keys[i] = sk;
185 return keys;
188 // <editor-fold defaultstate="collapsed" desc=" UML Marker ">
189 // #[regen=yes,id=DCE.EE4A388C-A94E-B384-EC8A-2E349EACBA40]
190 // </editor-fold>
191 public SyncItemKey[] getNewSyncItemKeys(java.sql.Timestamp sinceTs, java.sql.Timestamp untilTs) {
192 log.info("getNewSyncItemKeys()");
193 ArrayList newUIDS = so.getAddedToStoreUIDS();
194 SyncItemKey[] keys = new SyncItemKey[newUIDS.size()];
195 for (int i = 0; i < newUIDS.size(); i++) {
196 String key = (String) newUIDS.get(i);
197 SyncItemKey sk = new SyncItemKey(key);
198 keys[i] = sk;
199 itemStates.put(sk, "new");
201 return keys;
204 public SyncItem getSyncItemFromId(SyncItemKey syncItemKey) throws SyncSourceException {
205 String uid = syncItemKey.getKeyAsString();
206 log.info("getSyncItemFromId(" + uid + ")");
207 try {
208 Contact object = so.getObjectFromStore(uid);
209 OutboundFunambolContactObject obc = getOutboundProcessor(object);
210 SyncItem si = obc.generateSyncItem(this);
211 si.setState(getStateForItem(syncItemKey));
212 si.setType(this.getType());
213 return si;
214 } catch (Exception ex) {
215 log.log(Level.SEVERE, "getSyncItemFromId", ex);
216 throw new SyncSourceException(ex);
220 public void removeSyncItem(SyncItemKey syncItem, Timestamp arg1, boolean arg2) throws SyncSourceException {
221 log.info("removeSyncItem(" + syncItem.getKeyAsString() + ")");
222 try {
223 so.deleteObject(syncItem.getKeyAsString());
224 } catch (Exception e) {
225 throw new SyncSourceException(e);
229 public SyncItem updateSyncItem(SyncItem toUpdate) throws SyncSourceException {
230 log.info("updateSyncItem(" + toUpdate.getKey().getKeyAsString() + ")");
231 try {
232 InboundFunambolContactObject ifcb = initInboundProcessor(toUpdate);
233 String output = ifcb.getStringRepresentation(Constants.TYPE_CONTACT_VCARD21);
234 String name = ifcb.getObjectName();
235 String uid = ifcb.getUid();
236 so.replaceObject(uid, name, output);
237 return getSyncItemFromId(toUpdate.getKey());
238 } catch (Exception e) {
239 log.info("Exception caught in updateSyncItem");
240 throw new SyncSourceException(e);
244 public SyncItem addSyncItem(SyncItem toAdd) throws SyncSourceException {
245 log.info("addSyncItem(" + toAdd.getKey().getKeyAsString() + ")");
246 try {
247 InboundFunambolContactObject ifcb = initInboundProcessor(toAdd);
248 String output = ifcb.getStringRepresentation(Constants.TYPE_CONTACT_VCARD21);
249 String name = ifcb.getObjectName();
250 String uid = ifcb.getUid();
251 String srvUid = so.addObject(ifcb.getDestinationStore(), uid, name, output);
252 return getSyncItemFromId(new SyncItemKey(srvUid));
253 } catch (Exception e) {
254 log.info("Exception caught in addSyncItem");
255 throw new SyncSourceException(e);
259 public SyncItemKey[] getSyncItemKeysFromTwin(SyncItem syncItem) throws SyncSourceException {
260 log.info("getSyncItemKeysFromTwin " + syncItem.getKey().getKeyAsString());
261 String uid = syncItem.getKey().getKeyAsString();
262 String data = new String(syncItem.getContent());
263 try {
264 InboundFunambolContactObject ifcb = initInboundProcessor(syncItem);
265 String name = ifcb.getObjectName();
266 String match = so.searchUids(name);
267 if (match != null) {
268 log.info("Match found: " + match);
269 SyncItemKey[] matches = new SyncItemKey[1];
270 matches[0] = new SyncItemKey(match);
271 return matches;
273 } catch (Exception ex) {
274 log.info("Error cause data=" + data);
275 log.log(Level.SEVERE, "getSyncItemKeysFromTwin", ex);
276 throw new SyncSourceException(ex);
278 return null;
281 public void setOperationStatus(String reason, int status, SyncItemKey[] keys) {
282 for (int i = 0; i < keys.length; i++) {
283 SyncItemKey syncItemKey = keys[i];
284 log.info("setOperationStatus(" + reason + "," + status + "," + syncItemKey.getKeyAsString() + ")");
289 @Override
290 public void endSync() throws SyncSourceException {
291 log.info("endSync()");
292 try {
293 so.close();
294 fh.close();
295 } catch (Exception e) {
296 log.info("Exception caught in endSync()");
297 throw new SyncSourceException(e);
299 super.endSync();
303 * Called to get the keys of the items updated in the time frame sinceTs - untilTs.
304 * <br><code>sinceTs</code> null means all keys of the items updated until <code>untilTs</code>.
305 * <br><code>untilTs</code> null means all keys of the items updated since <code>sinceTs</code>.
306 * @param sinceTs consider the changes since this point in time.
307 * @param untilTs consider the changes until this point in time.
308 * @return an array of keys containing the <code>SyncItemKey</code>'s key of the updated
309 * items in the given time frame. It MUST NOT return null for
310 * no keys, but instad an empty array.
312 // <editor-fold defaultstate="collapsed" desc=" UML Marker ">
313 // #[regen=yes,id=DCE.A80FDB1D-9EC6-0537-6211-5EC359BAAB6D]
314 // </editor-fold>
315 public SyncItemKey[] getUpdatedSyncItemKeys(Timestamp sinceTs, Timestamp untilTs) {
316 log.info("getUpdatedSyncItemKeys()");
317 ArrayList updatedKeys = so.getUpdatedInStoreUIDS();
318 SyncItemKey[] keys = new SyncItemKey[updatedKeys.size()];
319 for (int i = 0; i < updatedKeys.size(); i++) {
320 String key = (String) updatedKeys.get(i);
321 SyncItemKey sk = new SyncItemKey(key);
322 keys[i] = sk;
323 itemStates.put(sk, "updated");
325 return keys;
328 public void init() throws BeanInitializationException {
331 private OutboundFunambolContactObject getOutboundProcessor(Contact origObject) throws Exception {
332 OutboundFunambolContactObject obc = new OutboundFunambolContactObject();
333 obc.setContactObject(origObject);
334 return obc;
337 private char getStateForItem(SyncItemKey sik) {
338 String state = (String) itemStates.get(sik);
339 if (state == null) {
340 return SyncItemState.SYNCHRONIZED;
341 } else if (state.equals("new")) {
342 return SyncItemState.NEW;
343 } else if (state.equals("updated")) {
344 return SyncItemState.UPDATED;
346 return SyncItemState.UNKNOWN;
349 public void setConnectorProperties(Properties p) {
350 connectorProperties = p;
353 public Properties getConnectorProperties() {
354 return connectorProperties;
357 public SyncContext getSyncContext() {
358 return ctx;
361 /** Create the inbound object processing class (default is
362 * InboundFunambolContactObject
363 * @see InboundFunambolContactObject
365 private InboundFunambolContactObject initInboundProcessor(SyncItem si) throws Exception {
366 InboundFunambolContactObject ifcb;
367 ifcb = new InboundFunambolContactObject();
368 ifcb.setSyncSource(this);
369 ifcb.setOriginalSyncItem(si);
370 return ifcb;