/*
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999 Bull S.A.
 * Contact: jonas-team@objectweb.org
 * 
 * This library 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 any later version.
 * 
 * This library 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 library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */


package org.objectweb.jonas.ldap;

import java.io.Serializable;
import java.util.Enumeration;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.NamingEnumeration;
import javax.naming.NameClassPair;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.naming.StringRefAddr;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;



/**
 * This object acts as a factory for LDAP connections (tested on Netscape Directory Server 3.0)
 * @author Paul Desgranges
 * Contributor(s): 
 */
public class DataSourceLDAPImpl implements DataSourceLDAP,
					   javax.naming.Referenceable,
					   java.io.Serializable {


    // ----------------------
    // DataSource properties
    // ----------------------

    /**
     * @serial
     */
    private String pDataSourceName = null;
    /**
     * @serial
     */
    private String pPassword = null;
    /**
     * @serial
     */
    private String pUrl = null;
    /**
     * @serial
     */
    private String pUserName = null;

    /**
     * @serial
     * Be aware that we have 1 datasource for each bean (and may be more if
     * the bean make several lookups!) So, we can keep here the list of
     * attributes that are mapped as byte-array for this bean.
     */
    private String pBinAttribs = null;

    /**
     * @serial
     * Notice that we have always one DirContext per DataSource.
     */
    private DirContext ldapCtx = null;


    // -----------------------------------------------------------------
    // Constructors
    // -----------------------------------------------------------------

    /**
     * Constructor for DataSourceLDAPImplFactory
     */
    public DataSourceLDAPImpl() {
    }


    // DataSourceName property
    public String getDataSourceName() {
	return pDataSourceName;
    }
    public void setDataSourceName(String s) {
	pDataSourceName = s;
    }

    // UserName property
    public String getUserName() {
	return pUserName;
    }
    public void setUserName(String s) {
	pUserName = s;
    }

    // Password property
    public String getPassword() {
	return pPassword;
    }
    public void setPassword(String s) {
	pPassword = s;
    }

    // Url property
    public String getUrl() {
	return pUrl;
    }
    public void setUrl(String s) {
	pUrl = s;
    }

    // ----------------------------------------------------------------------------------
    // interface javax.naming.Referenceable
    // ----------------------------------------------------------------------------------

    /**
     * Retrieves the Reference of this object. 
     * 
     * @return  The non-null Reference of this object. 
     * @exception  NamingException  If a naming exception was encountered while retrieving the reference.  
     */
    public Reference getReference() throws NamingException {
	Reference ref = new Reference (this.getClass().getName(), 
				       "org.objectweb.jonas.ldap.DataSourceLDAPImplFactory",
				       null);
	ref.add(new StringRefAddr("datasource.name", getDataSourceName()));
	ref.add(new StringRefAddr("datasource.url", getUrl()));
	ref.add(new StringRefAddr("datasource.username", getUserName()));
	ref.add(new StringRefAddr("datasource.password", getPassword()));
	return ref;
    }

    // ----------------------------------------------------------------------------------
    // interface org.objectweb.jonas.ldap.DataSourceLDAP
    // ----------------------------------------------------------------------------------

    public void setBinAttribs(String s) {
	pBinAttribs = s;
    }

    /**
     * Attempts to get a context to interface the LDAP server via JNDI.
     * @return  a DirContext to the database.
     * @exception  NamingException - if a database-access error occurs.
     */
    public DirContext getDirContext() throws NamingException {
	if (ldapCtx == null) {
	    return getDirContext(pUserName, pPassword);
	} else {
	    return ldapCtx;
	}
    }



    /**
     * Attempts to get a context to interface the LDAP server via JNDI.
     *
     * @param  user - the database user on whose behalf the Connection 
     *  is being made.
     * @param password - the user's password
     * @return  a DirContext to the database
     * @exception  NamingException - if a jndi error occurs.
     */
    public DirContext getDirContext(String userName, String password) throws NamingException {

	if (ldapCtx == null) {
	    try {
		// Creates env 
		Hashtable envldap = new Hashtable(11);
		envldap.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
		envldap.put(Context.PROVIDER_URL, pUrl);
		if ((userName!=null) & (password!=null) & 
		    (!userName.equals("")) & (!password.equals(""))) {
		    // all IOs in LDAP are done for the account of:
		    envldap.put(Context.SECURITY_PRINCIPAL, userName);
		    envldap.put(Context.SECURITY_CREDENTIALS, password);
		}
		if (pBinAttribs != null) {
		    envldap.put("java.naming.ldap.attributes.binary", pBinAttribs);
		}

		// Creation initial context ldap
		ldapCtx = new InitialDirContext(envldap);
	    } catch (NamingException e) {
		throw e;
	    } catch (Exception e) {
		throw new NamingException("Unexpected exception in getDirContext");
	    }	
	}
	return ldapCtx;
    }
}

