org.atricore.idbus.idojos.dbidentitystore.IdentityDAO.java Source code

Java tutorial

Introduction

Here is the source code for org.atricore.idbus.idojos.dbidentitystore.IdentityDAO.java

Source

/*
 * Atricore IDBus
 *
 * Copyright (c) 2009, Atricore Inc.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.atricore.idbus.idojos.dbidentitystore;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.atricore.idbus.kernel.main.authn.*;
import org.atricore.idbus.kernel.main.authn.exceptions.SSOAuthenticationException;
import org.atricore.idbus.kernel.main.store.SimpleUserKey;
import org.atricore.idbus.kernel.main.store.exceptions.SSOIdentityException;

import java.io.IOException;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

/**
 * JDBC Identity DAO, used by AbstractDBIdentityStore.
 *
 * @author <a href="mailto:sgonzalez@josso.org">Sebastian Gonzalez Oyuela</a>
 * @version $Id: IdentityDAO.java 1040 2009-03-05 00:56:52Z gbrigand $
 */

public class IdentityDAO {

    private static final Log logger = LogFactory.getLog(IdentityDAO.class);

    private Connection _conn;
    private CredentialProvider _cp;

    private String _userQueryString;
    private int _userQueryVariables;

    private String _rolesQueryString;
    private int _rolesQueryVariables = 0;

    private String _credentialsQueryString;
    private int _credentialsQueryVariables;

    private String _userPropertiesQueryString;
    private int _userPropertiesQueryVariables = 0; // This will be calcultated when setting _userPropertiesQueryString

    private String _resetCredentialDml;
    private String _relayCredentialQueryString;

    private boolean _useColumnNamesAsPropNames = false;

    public IdentityDAO(Connection conn, CredentialProvider cp, String userQueryString, String rolesQueryString,
            String credentialsQueryString, String userPropertiesQueryString, String resetCredentialDml,
            String relayCredentialQueryString, boolean useColumnNamesAsPropNames) {

        _conn = conn;
        _cp = cp;

        _userQueryString = userQueryString;
        _userQueryVariables = countQueryVariables(userQueryString);

        _rolesQueryString = rolesQueryString;
        _rolesQueryVariables = countQueryVariables(rolesQueryString);

        _credentialsQueryString = credentialsQueryString;
        _credentialsQueryVariables = countQueryVariables(credentialsQueryString);

        _resetCredentialDml = resetCredentialDml;
        _relayCredentialQueryString = relayCredentialQueryString;

        // User properties query :
        if (userPropertiesQueryString != null) {
            _userPropertiesQueryString = userPropertiesQueryString;
            _userPropertiesQueryVariables = countQueryVariables(_userPropertiesQueryString);
        }
        _useColumnNamesAsPropNames = useColumnNamesAsPropNames;
    }

    public IdentityDAO(Connection conn, CredentialProvider cp, String userQueryString, String rolesQueryString,
            String credentialsQueryString, String userPropertiesQueryString, String resetCredentialDml,
            String relayCredentialQueryString) {
        this(conn, cp, userQueryString, rolesQueryString, credentialsQueryString, userPropertiesQueryString,
                resetCredentialDml, relayCredentialQueryString, false);

    }

    public BaseUser selectUser(SimpleUserKey key) throws SSOIdentityException {
        PreparedStatement stmt = null;
        ResultSet result = null;

        try {

            stmt = createPreparedStatement(_userQueryString);
            // We don't jave JDBC 3.0 drivers, so ... bind all variables manually
            for (int i = 1; i <= _userQueryVariables; i++) {
                stmt.setString(i, key.getId());
            }
            result = stmt.executeQuery();

            BaseUser user = fetchUser(result);
            if (user == null)
                throw new SSOIdentityException("Can't find user for : " + key);

            return user;
        } catch (SQLException sqlE) {
            logger.error("SQLException while listing user", sqlE);
            throw new SSOIdentityException("During user listing: " + sqlE.getMessage());
        } catch (IOException ioE) {
            logger.error("IOException while listing user", ioE);
            throw new SSOIdentityException("During user listing: " + ioE.getMessage());
        } catch (Exception e) {
            logger.error("Exception while listing user", e);
            throw new SSOIdentityException("During user listing: " + e.getMessage());
        } finally {
            closeResultSet(result);
            closeStatement(stmt);
        }

    }

    public BaseRole[] selectRolesByUserKey(SimpleUserKey key) throws SSOIdentityException {
        PreparedStatement stmt = null;
        ResultSet result = null;

        try {

            stmt = createPreparedStatement(_rolesQueryString);
            // We don't jave JDBC 3.0 drivers, so ... bind all variables manually
            for (int i = 1; i <= _rolesQueryVariables; i++) {
                stmt.setString(i, key.getId());
            }
            result = stmt.executeQuery();

            BaseRole[] roles = fetchRoles(result);

            return roles;
        } catch (SQLException sqlE) {
            logger.error("SQLException while listing roles", sqlE);
            throw new SSOIdentityException("During roles listing: " + sqlE.getMessage());

        } catch (IOException ioE) {
            logger.error("IOException while listing roles", ioE);
            throw new SSOIdentityException("During roles listing: " + ioE.getMessage());

        } catch (Exception e) {
            logger.error("Exception while listing roles", e);
            throw new SSOIdentityException("During roles listing: " + e.getMessage());

        } finally {
            closeResultSet(result);
            closeStatement(stmt);
        }
    }

    public Credential[] selectCredentials(SimpleUserKey key) throws SSOIdentityException {
        PreparedStatement stmt = null;
        ResultSet result = null;

        try {

            if (logger.isDebugEnabled())
                logger.debug("[selectCredemtiasl()]]: key=" + key.getId());
            stmt = createPreparedStatement(_credentialsQueryString);
            // We don't jave JDBC 3.0 drivers, so ... bind all variables manually
            for (int i = 1; i <= _credentialsQueryVariables; i++) {
                stmt.setString(i, key.getId());
            }
            result = stmt.executeQuery();

            Credential[] creds = fetchCredentials(result);

            return creds;
        } catch (SQLException sqlE) {
            logger.error("SQLException while listing credentials", sqlE);
            throw new SSOIdentityException("During credentials listing: " + sqlE.getMessage());

        } catch (IOException ioE) {
            logger.error("IOException while listing credentials", ioE);
            throw new SSOIdentityException("During credentials listing: " + ioE.getMessage());

        } catch (Exception e) {
            logger.error("Exception while listing credentials", e);
            throw new SSOIdentityException("During credentials listing: " + e.getMessage());

        } finally {
            closeResultSet(result);
            closeStatement(stmt);
        }

    }

    /**
     * This will execute the configured query to get all user properties.
     * Because we sugested the use of 'UNION' key words to retrieve properties from multiple columns/tables,
     * we probably must send multiple times the username value to "avoid not all variables bound" error.
     * We could avoid this by using JDBC 3.0 drivers in the future.
     *
     * @param key
     * @throws SSOIdentityException
     */

    public SSONameValuePair[] selectUserProperties(SimpleUserKey key) throws SSOIdentityException {
        PreparedStatement stmt = null;
        ResultSet result = null;

        try {

            if (logger.isDebugEnabled())
                logger.debug("[selectUserProperties()]]: key=" + key.getId());
            stmt = createPreparedStatement(_userPropertiesQueryString);

            // We don't jave JDBC 3.0 drivers, so ... bind all variables manually
            for (int i = 1; i <= _userPropertiesQueryVariables; i++) {
                stmt.setString(i, key.getId());
            }

            result = stmt.executeQuery();

            SSONameValuePair[] props = _useColumnNamesAsPropNames ? fecthSSONameValuePairsFromCols(result)
                    : fetchSSONameValuePairsFromRows(result);

            if (logger.isTraceEnabled())
                logger.trace("Retrieved " + props.length + " user properties");

            return props;
        } catch (SQLException sqlE) {
            logger.error("SQLException while listing user properties", sqlE);
            throw new SSOIdentityException("During user properties listing: " + sqlE.getMessage());

        } catch (IOException ioE) {
            logger.error("IOException while listing user properties", ioE);
            throw new SSOIdentityException("During user properties listing: " + ioE.getMessage());

        } catch (Exception e) {
            logger.error("Exception while listing user properties", e);
            throw new SSOIdentityException("During user properties listing: " + e.getMessage());

        } finally {
            closeResultSet(result);
            closeStatement(stmt);
        }
    }

    public void resetCredential(SimpleUserKey key, BaseCredential newPassword) throws SSOIdentityException {
        PreparedStatement stmt = null;
        try {
            if (logger.isDebugEnabled())
                logger.debug("[resetCredential()]]: key=" + key.getId());

            stmt = createPreparedStatement(_resetCredentialDml);
            stmt.setString(1, newPassword.getValue().toString());
            stmt.setString(2, key.getId());
            stmt.execute();
            _conn.commit();

        } catch (SQLException e) {
            logger.error("SQLException while updating user credential", e);
            throw new SSOIdentityException("During user update credential: " + e.getMessage());
        } finally {
            closeStatement(stmt);
        }
    }

    public String resolveUsernameByRelayCredential(String name, String value) throws SSOIdentityException {
        PreparedStatement stmt = null;
        ResultSet result = null;

        try {
            if (logger.isDebugEnabled())
                logger.debug("[resolveUsernameByRelayCredential(name, value)]]: name=" + name + " value=" + value);

            if (_relayCredentialQueryString.contains("#?#")) {
                stmt = createPreparedStatement(_relayCredentialQueryString.replace("#?#", name));
                stmt.setString(1, value);
            } else {
                stmt = createPreparedStatement(_relayCredentialQueryString);
                stmt.setString(1, name);
                stmt.setString(2, value);
            }
            result = stmt.executeQuery();

            String username = result.next() ? result.getString(1) : null;
            if (result.next()) {
                throw new SSOIdentityException("Statement " + stmt + " returned more than one row");
            }
            return username;

        } catch (SQLException sqlE) {
            logger.error("SQLException while loading user with relay credential", sqlE);
            throw new SSOIdentityException("During load user with relay credential: " + sqlE.getMessage());

        } catch (Exception e) {
            logger.error("Exception while loading user with relay credential", e);
            throw new SSOIdentityException("During load user with relay credential: " + e.getMessage());

        } finally {
            closeResultSet(result);
            closeStatement(stmt);
        }
    }

    // ------------------------------------------------------------------------------------------
    // Protected DB utils.
    // ------------------------------------------------------------------------------------------

    /**
     * Builds an array of credentials based on a ResultSet
     * Column names are used to build a credential.
     */
    protected Credential[] fetchCredentials(ResultSet rs)
            throws SQLException, IOException, SSOAuthenticationException {

        if (rs.next()) {

            List creds = new ArrayList();
            ResultSetMetaData md = rs.getMetaData();

            // Each column is a credential, the column name is used as credential name ...
            for (int i = 1; i <= md.getColumnCount(); i++) {
                String cName = md.getColumnLabel(i);
                String cValue = rs.getString(i);
                Credential c = _cp.newCredential(cName, cValue);
                creds.add(c);
            }

            return (Credential[]) creds.toArray(new Credential[creds.size()]);
        }

        return new Credential[0];

    }

    protected SSONameValuePair[] fecthSSONameValuePairsFromCols(ResultSet rs) throws SQLException {
        List<SSONameValuePair> props = new ArrayList<SSONameValuePair>();

        ResultSetMetaData rsmd = rs.getMetaData();

        int cols = rsmd.getColumnCount();

        while (rs.next()) {
            for (int i = 1; i <= cols; i++) {
                String cName = rsmd.getColumnName(i);
                String cValue = rs.getString(i);
                SSONameValuePair prop = new SSONameValuePair(cName, cValue);
                props.add(prop);
            }
        }

        return props.toArray(new SSONameValuePair[props.size()]);
    }

    /**
     * Builds an array of name-value pairs on a ResultSet
     * The resultset must have two columns, the first one contains names and the second one values.
     */
    protected SSONameValuePair[] fetchSSONameValuePairsFromRows(ResultSet rs)
            throws SQLException, IOException, SSOAuthenticationException {
        List<SSONameValuePair> props = new ArrayList<SSONameValuePair>();

        while (rs.next()) {
            // First column is a name and second is a value.
            String cName = rs.getString(1);
            String cValue = rs.getString(2);
            SSONameValuePair prop = new SSONameValuePair(cName, cValue);
            props.add(prop);
        }

        return props.toArray(new SSONameValuePair[props.size()]);
    }

    /**
     * Builds a user based on a result set.
     * ResultSet must have one and only one record.
     */
    protected BaseRole[] fetchRoles(ResultSet rs) throws SQLException, IOException {

        List roles = new ArrayList();

        while (rs.next()) {

            BaseRole role = new BaseRoleImpl();
            String rolename = rs.getString(1);
            role.setName(rolename);

            roles.add(role);

        }

        return (BaseRole[]) roles.toArray(new BaseRole[roles.size()]);
    }

    /**
     * Builds a user based on a result set.
     */
    protected BaseUser fetchUser(ResultSet rs) throws SQLException, IOException {

        if (rs.next()) {
            BaseUser user = new BaseUserImpl();
            String username = rs.getString(1);
            user.setName(username);

            return user;
        }

        return null;
    }

    /**
     * Creates a new prepared statement for the received query string.
     *
     * @param query
     * @throws SQLException
     */
    private PreparedStatement createPreparedStatement(String query) throws SQLException {

        if (logger.isDebugEnabled())
            logger.debug("[createPreparedStatement()] : " + "(" + query + ")");

        PreparedStatement stmt = _conn.prepareStatement(query + " ");

        return stmt;
    }

    protected void closeStatement(PreparedStatement stmt) throws SSOIdentityException {
        try {
            if (stmt != null) {
                stmt.close();
            }
        } catch (SQLException se) {
            if (logger.isDebugEnabled()) {
                logger.debug("Error clossing statement");
            }

            throw new SSOIdentityException("Error while clossing statement: \n " + se.getMessage());

        } catch (Exception e) {
            if (logger.isDebugEnabled()) {
                logger.debug("Error clossing statement");
            }

            // throw new SSOIdentityException("Error while clossing statement: \n " + e.getMessage());
        }
    }

    protected void closeResultSet(ResultSet result) throws SSOIdentityException {
        try {
            if (result != null) {
                result.close();
            }
        } catch (SQLException se) {
            if (logger.isDebugEnabled()) {
                logger.debug("Error while clossing result set");
            }

            throw new SSOIdentityException("SQL Exception while closing\n" + se.getMessage());
        } catch (Exception e) {
            if (logger.isDebugEnabled()) {
                logger.debug("Error while clossing result set");
            }

            // throw new SSOIdentityException("Exception while closing Result Set\n" + e.getMessage());

        }
    }

    /**
     * This util counts the number of times that the '?' char appears in the received query string.
     */
    protected int countQueryVariables(String qry) {
        StringTokenizer st = new StringTokenizer(qry, "?", true);
        int count = 0;
        while (st.hasMoreTokens()) {
            String tk = st.nextToken();
            if ("?".equals(tk)) {
                count++;
            }
        }
        return count;
    }

}