/** * * @author Diorgenes Felipe Grzesiuk * @copyright Copyright 2007-2008 Prognus * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Foobar; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package br.com.prognus.psync.engine.source; import java.io.Serializable; import java.sql.Timestamp; import java.util.TimeZone; import br.com.prognus.psync.exception.EntityException; import br.com.prognus.psync.items.manager.PIMEntityManager; import br.com.prognus.psync.util.Def; import com.funambol.framework.core.AlertCode; import com.funambol.framework.engine.SyncItem; import com.funambol.framework.engine.SyncItemKey; import com.funambol.framework.engine.SyncItemState; import com.funambol.framework.engine.source.AbstractSyncSource; import com.funambol.framework.engine.source.MergeableSyncSource; import com.funambol.framework.engine.source.SyncContext; import com.funambol.framework.engine.source.SyncSourceException; import com.funambol.framework.logging.FunambolLogger; import com.funambol.framework.logging.FunambolLoggerFactory; import com.funambol.framework.security.Sync4jPrincipal; import com.funambol.framework.server.Sync4jDevice; import com.funambol.framework.tools.beans.LazyInitBean; public abstract class PIMSyncSource extends AbstractSyncSource implements MergeableSyncSource, Serializable, LazyInitBean { // ---------------------------------------------------------------- // Constants protected static final String JNDI_DATA_SOURCE_NAME = "jdbc/fnblds"; public static final int SIFC = 0; // To be used as index for SIF-Contact public static final int SIFE = 1; // To be used as index for SIF-Event public static final int SIFN = 2; // To be used as index for SIF-Note public static final int SIFT = 3; // To be used as index for SIF-Task public static final int VCARD = 4; // To be used as index for VCard public static final int VCAL = 5; // To be used as index for VCal public static final int ICAL = 6; // To be used as index for ICal public static final int VNOTE = 7; // To be used as index for VNote public static final String[] TYPE = { "text/x-s4j-sifc", // SIF-Contact "text/x-s4j-sife", // SIF-Event "text/x-s4j-sifn", // SIF-Note "text/x-s4j-sift", // SIF-Task "text/x-vcard", // VCard "text/x-vcalendar", // VCal "text/calendar", // ICal "text/x-vnote", // VNote }; // ----------------------------------------------------------- Protected // data protected static final FunambolLogger log = FunambolLoggerFactory .getLogger(Def.LOGGER_NAME); protected PIMEntityManager manager; protected Sync4jPrincipal principal; protected String userId; protected int syncMode; protected Timestamp lastSyncTime; // n-th synchronization protected Timestamp previousSyncTime; // (n - 1)-th synchronization protected TimeZone deviceTimeZone = null; protected String deviceTimeZoneDescription = null; protected String deviceCharset = null; // ----------------------------------------------------------- Public // methods public void beginSync(SyncContext context) { log.trace("PIMSyncSource beginSync start"); principal = context.getPrincipal(); userId = principal.getUsername(); syncMode = context.getSyncMode(); Sync4jDevice device = context.getPrincipal().getDevice(); String timezone = device.getTimeZone(); if (device.getConvertDate()) { if (timezone != null && timezone.length() > 0) { deviceTimeZoneDescription = timezone; deviceTimeZone = TimeZone .getTimeZone(deviceTimeZoneDescription); } } deviceCharset = device.getCharset(); if (log.isTraceEnabled()) { StringBuilder sb = new StringBuilder("Beginning sync with:"); sb.append("\n> syncMode : ").append(syncMode); sb.append("\n> principal : ").append(principal); sb.append("\n> deviceTimeZoneDescr.: ").append( deviceTimeZoneDescription); sb.append("\n> deviceTimeZone : ").append(deviceTimeZone); sb.append("\n> charset : ").append(deviceCharset); log.trace(sb.toString()); } if (syncMode == AlertCode.REFRESH_FROM_CLIENT) { if (log.isTraceEnabled()) { log.trace("Performing REFRESH_FROM_CLIENT (203)"); } removeAllSyncItems(); } log.trace("PIMSyncSource beginSync end"); } public void endSync() { } /** * Gets the status of the SyncItem with the given key. * * @param syncItemKey * as a SyncItemKey object * @throws SyncSourceException * @return the status as a char */ public char getSyncItemStateFromId(SyncItemKey syncItemKey) throws SyncSourceException { if (log.isTraceEnabled()) { log.trace("PIMSyncSource getSyncItemStateFromId begin"); } String id = "N/A"; // default value for error tracking try { // Slow sync // @todo Implement, depending on a syncMode check // Fast sync id = syncItemKey.getKeyAsString(); char itemRawState = manager.getItemState(id, previousSyncTime); if (log.isTraceEnabled()) { log.trace("PIMSyncSource getSyncItemStateFromId end"); } if (itemRawState == Def.PIM_STATE_UNCHANGED) { return SyncItemState.SYNCHRONIZED; } else { return itemRawState; // Def uses SyncItemState.* as constant // values for N, D and U states } } catch (EntityException ee) { throw new SyncSourceException( "Error getting the state of SyncItem " + "with ID " + id, ee); } } /** * Not yet used. It just produces a log message. */ public void setOperationStatus(String operation, int statusCode, SyncItemKey[] keys) { if (log.isTraceEnabled()) { StringBuilder message = new StringBuilder("Received status code '"); message.append(statusCode).append("' for a '").append(operation) .append("' command for the following items: "); for (int i = 0; i < keys.length; i++) { message.append("\n> ").append(keys[i].getKeyAsString()); } log.trace(message.toString()); } } // ---------------------------------------------------------- Private // methods /** * Extracts the content from a syncItem. * * @param syncItem * @return as a String object */ protected String getContentFromSyncItem(SyncItem syncItem) { byte[] itemContent = syncItem.getContent(); // Add content processing here, if needed return new String(itemContent == null ? new byte[0] : itemContent); } protected void saveSyncTiming(Timestamp since, Timestamp to) { if (log.isTraceEnabled()) { if (!since.equals(previousSyncTime)) { log.trace("PIMSyncSource sync timing updated to " + since + " / " + to); } } this.previousSyncTime = since; this.lastSyncTime = to; } protected void removeAllSyncItems() { if (log.isTraceEnabled()) { log.trace("Perform REFRESH_FROM_CLIENT (203) for user " + userId); } try { manager.removeAllItems(); } catch (EntityException ee) { if (log.isTraceEnabled()) { log.trace("Error while performing REFRESH_FROM_CLIENT (203).", ee); } } } }