/** * This class implements methods to access PIM data in a data store. * @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.items.dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Timestamp; import java.util.Hashtable; import java.util.List; import javax.naming.Context; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import javax.sql.DataSource; import br.com.prognus.psync.exception.PIMDBAccessException; import br.com.prognus.psync.util.Def; import com.funambol.common.pim.common.Property; import com.funambol.framework.logging.FunambolLogger; import com.funambol.framework.logging.FunambolLoggerFactory; import com.funambol.framework.tools.DBTools; import com.funambol.framework.tools.DataSourceTools; public abstract class PIMEntityDAO { // ------------------------------------------------------------ Private data protected static final FunambolLogger log = FunambolLoggerFactory .getLogger(Def.LOGGER_NAME); protected String jndiDataSourceName; protected DataSource dataSource = null; // -------------------------------------------------------------- Properties protected String userId; public String getUserId() { return userId; } // ------------------------------------------------------------ Constructors /** * Creates a new instance of PIMEntityDAO, ready to be linked to a given * DataSource. * * @param jndiDataSourceName * the jndiname of the datasource to use * @param userId * corresponding to the "userid" field of the fun_pim_contact * table * @throws IllegalArgumentException * if there are errors looking up the dataSource with the given * jndiDataSourceName */ public PIMEntityDAO(String jndiDataSourceName, String userId) { Connection con = null; PreparedStatement ps = null; try { this.dataSource = DataSourceTools .lookupDataSource(jndiDataSourceName); } catch (NamingException ex) { throw new IllegalArgumentException("Error looking up datasource: " + jndiDataSourceName, ex); } try { con = getDataSource().getConnection(); PreparedStatement ldap_server = con .prepareStatement("select config_value from phpgw_config WHERE config_name = 'ldap_host' AND config_app = 'phpgwapi'"); ResultSet rs1 = ldap_server.executeQuery(); PreparedStatement ldap_dc = con .prepareStatement("select config_value from phpgw_config WHERE config_name = 'ldap_context' AND config_app = 'phpgwapi'"); ResultSet rs2 = ldap_dc.executeQuery(); rs1.next(); rs2.next(); String server = rs1.getString(1); String dc = rs2.getString(1); this.jndiDataSourceName = jndiDataSourceName; this.userId = LdapUID(server, dc, userId); } catch (Exception e) { throw new IllegalArgumentException("Error UID ldap", e); } finally { DBTools.close(con, ps, null); } } // -----------------------------------------------------------Public methods @SuppressWarnings("unchecked") protected String LdapUID(String server, String dc, String user) throws Exception { String uidNumber=null; Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, "ldap://" + server + ":" + 389); DirContext ctx = new InitialDirContext(env); // Searching User SearchControls ctls = new SearchControls(); ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); ctls.setCountLimit(1); ctls.setTimeLimit(10000); // Espera no max 10 segundos String filter = "(uid=" + user + ")"; NamingEnumeration answer = ctx.search(dc, filter, ctls); if (answer.hasMore()) { SearchResult sr = (SearchResult) answer.next(); try { // Getting User attributes uidNumber = sr.getAttributes().get("uidNumber").get(0).toString(); } catch (Exception e) { e.printStackTrace(); } } ctx.close(); if (uidNumber == null) { log.info("Error while connecting and binding to LDAP"); } return uidNumber; // LDAPConnection ldap = new LDAPConnection(); // String searchAttrs[] = { "uidNumber" }; // String id_owner = null; // // try { // // ldap.connect(server, 389); // LDAPSearchResults searchResults = ldap.search(dc, // LDAPConnection.SCOPE_SUB, "(uid=" + user + ")", // searchAttrs, false); // // while (searchResults.hasMore()) { // // LDAPEntry nextEntry = null; // try { // nextEntry = searchResults.next(); // } catch (LDAPException e) { // if (e.getResultCode() == LDAPException.LDAP_TIMEOUT // || e.getResultCode() == LDAPException.CONNECT_ERROR) // break; // else // continue; // } // LDAPAttributeSet attributeSet = nextEntry.getAttributeSet(); // Iterator allAttributes = attributeSet.iterator(); // // while (allAttributes.hasNext()) { // // LDAPAttribute attribute = (LDAPAttribute) allAttributes // .next(); // String attributeName = attribute.getName(); // Enumeration allValues = attribute.getStringValues(); // // if (allValues != null) { // // while (allValues.hasMoreElements()) { // // String Value = (String) allValues.nextElement(); // // if (Base64.isLDIFSafe(Value)) { // } else { // Value = Base64.encode(Value.getBytes()); // } // // if (attributeName.equalsIgnoreCase("uidNumber")) { // id_owner = Value; // break; // } // // } // } // } // } // // ldap.disconnect(); // // if (id_owner == null) { // throw new LDAPException(); // } // // } catch (LDAPException e) { // log.info("Error while connecting and binding to LDAP: " // + e.toString()); // } // return id_owner; } /** * Looks up the data source, making some guess attempts based on * jndiDataSourceName. * * @throws Exception */ protected DataSource getDataSource() throws Exception { return dataSource; } public abstract List getAllItems() throws PIMDBAccessException; public abstract void removeItem(String uid) throws PIMDBAccessException; public abstract void removeAllItems() throws PIMDBAccessException; public abstract char getItemState(String uid, Timestamp since) throws PIMDBAccessException; /** * Retrieves the UID list of the new items belonging to the user filtered * according to the given time interval. * * @param since * the earliest allowed last-update Timestamp * @param to * the latest allowed last-update Timestamp * @throws PIMDBAccessException * @return a List of UIDs (as String objects) */ public List getNewItems(Timestamp since, Timestamp to) throws PIMDBAccessException { log.info("\n\n==>DAO start getNewItems"); return getItemsHavingStatus(since, to, 'N'); } /** * Retrieves the UID list of the deleted items belonging to the user * filtered according to the given time interval. * * @param since * the earliest allowed last-update Timestamp * @param to * the latest allowed last-update Timestamp * @throws PIMDBAccessException * @return a List of UIDs (as String objects) */ public List getDeletedItems(Timestamp since, Timestamp to) throws PIMDBAccessException { log.info("\n\n==>DAO start getDeletedItems"); return getItemsHavingStatus(since, to, 'D'); } /** * Retrieves the UID list of the updated items belonging to the user * filtered according to the given time interval. * * @param since * the earliest allowed last-update Timestamp * @param to * the latest allowed last-update Timestamp * @throws PIMDBAccessException * @return a List of UIDs (as String objects) */ public List getUpdatedItems(Timestamp since, Timestamp to) throws PIMDBAccessException { log.info("\n\n==>DAO start getUpdatedItems"); return getItemsHavingStatus(since, to, 'U'); } // ---------------------------------------------------------- Private // methods /** * Retrieves the UID list of the items belonging to the user filtered * according to the given time interval and status. * * @param since * the earliest allowed last-update Timestamp * @param to * the latest allowed last-update Timestamp * @param status * 'D' for deleted items, 'N' for new items, 'U' for updated * items * @throws PIMDBAccessException * @return a List of UIDs (as String objects) */ protected abstract List getItemsHavingStatus(Timestamp since, Timestamp to, char status) throws PIMDBAccessException; /** * Checks (safely) whether the property is unset. * * @param property * may be null * @return false only if the property value is a non-null, but possibly * empty (""), string * * @see PIMEntityDAO#stringFrom(Property) */ protected static boolean isNullProperty(Property property) { return (property == null || property.getPropertyValueAsString() == null); } /** * Checks (safely) whether the property is unset or set to an empty string. * * @param property * may be null * @return false only if the property value is a non-null non-empty string * * @see PIMEntityDAO#stringFrom(Property, boolean) */ protected static boolean isEmptyProperty(Property property) { if (property == null) { return true; } String string = property.getPropertyValueAsString(); if (string == null || string.length() == 0) { return true; } return false; } /** * Extract a string from a property in a safe way. An empty string ("") is * considered as an acceptable value for the property: in such a case, an * empty String object will be returned. * * @param property * may be null * @return if existing, the property value will be returned as a String * object */ protected static String stringFrom(Property property) { if (property == null) { return null; } return property.getPropertyValueAsString(); } /** * Extract a string from a property in a safe way. This method is not * currently used, but it could be useful in the future for determining the * behaviour of the connector when dealing with empty properties. A field * whose value is extracted with stringFrom(..., true) will not be updated * in case its value is set to ""; a field whose value is extracted with * stringFrom(..., false) will be considered as explicitly kept blank if its * value is "". This means that single field deletions can be made tunable. * * @param property * may be null * @param emptyImpliesNull * if true, an empty string ("") will be treated as if it were * null; otherwise, in such a case an empty String object will be * returned * * @return if existing (and not empty if emptyImpliesNull is true), the * property value will be returned as a String object */ protected static String stringFrom(Property property, boolean emptyImpliesNull) { if (property == null) { return null; } String string = property.getPropertyValueAsString(); if (string == null || !emptyImpliesNull) { return string; } if (string.length() == 0) { return null; } return string; } /** * Gets a substring in a safe way. * * @param string * may be null or longer than maxLength * @param maxLength * @return null if the string is null, a truncated substring of string * otherwise */ protected static String truncate(String string, int maxLength) { if (string == null || string.length() <= maxLength) { return string; } return string.substring(0, maxLength); } }