import com.jivesoftware.base.AuthToken;
import com.jivesoftware.base.AuthFactory;
import com.jivesoftware.base.UnauthorizedException;
import com.jivesoftware.base.Log;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import java.sql.*;

/**
 * A subclass of AuthFactory. It makes a SQL query to see if the supplied 
 * username and password match a user record. If they do, the appropriate 
 * AuthToken token is returned. If no matching User record is found an 
 * UnauthorizedException is thrown.
 */
public class CustomAuthFactory extends AuthFactory {

    // Database Queries.

    private static final String AUTHORIZE =
        "SELECT personid FROM person WHERE login=? AND password=?";

    private DataSource dataSource = null;
        
    /**
     * The same token can be used for all anonymous users, so cache it.
     */
    private static final AuthToken anonymousAuth = new CustomAuthToken(-1);

    public CustomAuthFactory() {
        try {
            // Lookup the database source at a hard-coded name. You'd probably want
            // to make this configurable for a real implementation.
            Context context = new InitialContext();
            dataSource = (DataSource)context.lookup("java:comp/env/jdbc/database");
        }
        catch (Exception e) {
            Log.error(e);
        }
    }

    public AuthToken createAuthToken(String username, String password)
            throws UnauthorizedException
    {
        if (username == null || password == null) {
            throw new UnauthorizedException();
        }
        long userID = 0;
        Connection con = null;
        PreparedStatement pstmt = null;
        try {
            con = dataSource.getConnection();
            pstmt = con.prepareStatement(AUTHORIZE);
            pstmt.setString(1, username);
            pstmt.setString(2, password);

            ResultSet rs = pstmt.executeQuery();
            // If the query had no results, the username and password
            // did not match a user record. Therefore, throw an exception.
            if (!rs.next()) {
                throw new UnauthorizedException();
            }
            userID = rs.getLong(1);
        }
        catch (Exception e) {
            Log.error(e);
            throw new UnauthorizedException();
        }
        finally {
            try { if (pstmt != null) { pstmt.close(); } }
            catch (Exception e) { Log.error(e); }
            try { if (con != null) { con.close(); } }
            catch (Exception e) { Log.error(e); }
        }
        // Got this far, so the user must be authorized.
        return new CustomAuthToken(userID);
    }

    public AuthToken createAnonymousAuthToken() {
        return anonymousAuth;
    }
}