/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/ssx/org/apache/slide/urm/authenticator/userdb/impl/ssx/URMUserDBManagerSpiSSX.java,v 1.4 2005/03/02 10:53:32 eckehard Exp $
 * $Revision: 1.4 $
 * $Date: 2005/03/02 10:53:32 $
 *
 * ====================================================================
 *
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.slide.urm.authenticator.userdb.impl.ssx;

import com.softwareag.ssx.userdb.SSXAccount;
import com.softwareag.ssx.userdb.SSXConnectionCloseFailedException;
import com.softwareag.ssx.userdb.SSXUserDB;
import com.softwareag.ssx.userdb.SSXUserDBAdministrator;
import com.softwareag.ssx.userdb.SSXUserDBConstants;
import com.softwareag.ssx.userdb.SSXUserDBException;
import com.softwareag.ssx.userdb.SSXUserDBForbiddenException;
import com.softwareag.ssx.userdb.SSXUserDBNotImplementedException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.slide.urm.URMForbiddenException;
import org.apache.slide.urm.URMNotImplementedException;
import org.apache.slide.urm.authenticator.URMAuthenticatorException;
import org.apache.slide.urm.authenticator.userdb.URMUserDBManagerSpi;
import org.apache.slide.urm.common.URMCloseConnectionException;
import org.apache.slide.urm.common.URMConfigurationException;
import org.apache.slide.urm.common.URMConfigurator;
import org.apache.slide.urm.common.URMDeleteException;
import org.apache.slide.urm.common.URMInsertException;
import org.apache.slide.urm.common.URMInternalServerException;
import org.apache.slide.urm.common.URMUpdateException;
import org.apache.slide.urm.common.impl.URMConfiguratorUtil;
import org.apache.slide.urm.utils.messagelogger.MessageLogger;
import org.apache.slide.urm.utils.validatorcache.URMListener;

/**
 * Serveice Provider Interface implementation to access SSX for all UserDB related
 * methods.
 *
 * @author eckehard.hermann@softwareag.com
 * @author dieter.kessler@softwareag.com
 * @author zsolt.sasvarie@softwareag.com
 */
public class URMUserDBManagerSpiSSX implements URMUserDBManagerSpi {
    
    private static org.apache.log4j.Logger msLogger =
        org.apache.log4j.Logger.getLogger(URMUserDBManagerSpiSSX.class.getName());
        
    private static final String ATTR_NAME       = "name";
    private static final String ATTR_VALUE      = "value";
    private static final String PROP_NAME       = "name";
    private static final String PROP_KEY        = "key";
    private static final String PROP_WRITEABLE  = "writeable";
    private static final String PROP_FORMAT     = "format";
        
    private SSXUserDBAdministrator mSsxUserDbAdmin = null;
    private Set mWriteableUserPropKeys = new HashSet();
    private Map mAvailableUserPropKeysNATIVE_KEYS = new HashMap();
    private Map mAvailableUserPropKeysABSTRACT_KEYS = new HashMap();
//    private Set mAvailableUserPropKeys = new HashSet();
    private Set mWriteableGroupPropKeys = new HashSet();
    private Map mAvailableGroupPropKeysNATIVE_KEYS = new HashMap();
    private Map mAvailableGroupPropKeysABSTRACT_KEYS = new HashMap();
    
    private String mUserTypePropPrefix  = null;
    private String mUserTypePropPostfix  = null;
    private String mGroupTypePropPrefix = null;
    private String mGroupTypePropPostfix = null;
    
    private class URMLdapPropMapEntry {
        private String mPrefix;
        private String mPostfix;
        private String mNativeAttrname;
        private String mAbstractAttrname;
        private int mPrefixLen;
        private int mPostfixLen;
        
        private URMLdapPropMapEntry (String prefix, String postfix, String nativeAttrname, String abstractAttrname) {
            mPrefix  = prefix;
            mPrefixLen = mPrefix != null ? mPrefix.length() : 0;
            mPostfix = postfix;
            mPostfixLen = mPostfix != null ? mPostfix.length() : 0;
            mNativeAttrname = nativeAttrname;
            mAbstractAttrname = abstractAttrname;
        }
        
        String getCompleteValue (String value) {
            if (mPrefix != null)
                return mPrefix + value + mPostfix;
            else
                return value;
        }
        
        String getExtractedValue (String completeValue) {
            if (mPrefix != null) {
                int fulllen = completeValue.length();
                try {
                    return completeValue.substring(mPrefixLen, fulllen - mPostfixLen);
                } catch (IndexOutOfBoundsException e) {
                    return completeValue;
                }
            }
            else
                return completeValue;
        }
    }

//    private static Hashtable msAdminInitPropNamesTable = null;
//
//    static {
//        String[] adminPropStringKeys = {
//            /*0*/ "allUsersCacheTime", "allUsersCacheSize", "allGroupsCacheTime", "allGroupsCacheSize",
//            /*4*/ "groupMembersCacheTime", "groupMembersCacheSize", "groupsOfUserCacheTime", "groupsOfUserCacheSize",
//            /*8*/ "userPropsCacheTime", "userPropsCacheSize", "allCacheTime", "allCacheSize",
//            /*12*/"defaultDomain", null};
//
//        int[] adminPropIntKeys = {
//            /*0*/ SSXUserDBConstants.SSX_ADMIN_IPT_ALLUSERS_VALIDTIME, SSXUserDBConstants.SSX_ADMIN_IPT_ALLUSERS_MAXELEMENT,
//            /*2*/ SSXUserDBConstants.SSX_ADMIN_IPT_ALLGROUPS_VALIDTIME, SSXUserDBConstants.SSX_ADMIN_IPT_ALLGROUPS_MAXELEMENT,
//            /*4*/ SSXUserDBConstants.SSX_ADMIN_IPT_GROUPMEMBERS_VALIDTIME, SSXUserDBConstants.SSX_ADMIN_IPT_GROUPMEMBERS_MAXELEMENT,
//            /*6*/ SSXUserDBConstants.SSX_ADMIN_IPT_GROUPSOFUSER_VALIDTIME, SSXUserDBConstants.SSX_ADMIN_IPT_GROUPSOFUSER_MAXELEMENT,
//            /*8*/ SSXUserDBConstants.SSX_ADMIN_IPT_PROPERTIES_VALIDTIME, SSXUserDBConstants.SSX_ADMIN_IPT_PROPERTIES_MAXELEMENT,
//            /*10*/SSXUserDBConstants.SSX_ADMIN_IPT_VALIDTIME_FORALL, SSXUserDBConstants.SSX_ADMIN_IPT_MAXELEMENT_FORALL,
//            /*12*/SSXUserDBConstants.SSX_ADMIN_EX_IPT_DEFAULTDOMAIN, 0};
//
//        msAdminInitPropNamesTable = new Hashtable();
//        for (int i = 0; adminPropStringKeys[i] != null; ++i)
//            msAdminInitPropNamesTable.put(adminPropStringKeys[i], new Integer(adminPropIntKeys[i]));
//    }
    
    public URMUserDBManagerSpiSSX(URMConfigurator userDbConf, SSXUserDB userDb,
                                String username, char[] password, String domain)
                throws URMConfigurationException, URMAuthenticatorException {
        // create user database
        Properties ssxprops = new Properties();
        /* currently it is not unnecessary */
        Iterator attrs = URMConfiguratorUtil.getAttributeList(userDbConf, msLogger);
        while (attrs != null && attrs.hasNext()) {
            URMConfigurator attrconf = ((URMConfigurator)attrs.next());
            Properties attr = attrconf.getProperties();
            if (attr == null)
                continue;
            String attrname = attr.getProperty(ATTR_NAME);
            //if (attrname == null)
            //    continue;
            //Integer attrkey = (Integer)msAdminInitPropNamesTable.get(attrname);
            //if (attrkey == null || attrkey.intValue() == 0)
            //    MessageLogger.logMessage(msLogger, "URMSUE0002", attrname);
            //else
            //    ssxprops.put(attrkey, attr.get("value"));
            if (attrname != null && attrname.equals("defaultDomain")) {
                ssxprops.put(new Integer(SSXUserDBConstants.SSX_ADMIN_EX_IPT_DEFAULTDOMAIN), attr.getProperty("value"));
                break; // ignore all the other properties
            }
        }/**/

        // create administrator
        try {
            if (ssxprops.isEmpty())
                mSsxUserDbAdmin = userDb.getUserDBAdministrator(username, password, domain);
            else
                mSsxUserDbAdmin = userDb.getUserDBAdministratorEx(username, password, domain, ssxprops);
        } catch (SSXUserDBException e) {
            throw new URMAuthenticatorException(msLogger, "F", e);
        }
        URMConfigurator nconf = userDbConf.getSubConfigurator("NativeProperties");
        if (nconf != null) {
            URMConfigurator tmpconf = userDbConf.getSubConfigurator("/Authenticator");
            if (tmpconf != null && (attrs = URMConfiguratorUtil.getAttributeList(tmpconf, msLogger)) != null) {
                String atype = null;
                while (attrs.hasNext()) {
                    URMConfigurator attrconf = ((URMConfigurator)attrs.next());
                    Properties attr = attrconf.getProperties();
                    if (attr == null)
                        continue;
                    String attrname = (String)attr.get(ATTR_NAME);
                    if (attrname != null && attrname.equals("authType")) {
                        atype = attr.getProperty(ATTR_VALUE);
                        if (!atype.equalsIgnoreCase("ldap")) {
                            atype = null;
                            break;
                        }
                    }
                    else if (attrname.equals("serverType")) {
                        String stype = (String)attr.getProperty(ATTR_VALUE);
                        if (stype.equalsIgnoreCase("SunOneDirectory"))
                            mUserTypePropPrefix  = "uid=";
                    }
                    else if (attrname.equals("personBindDn"))
                        mUserTypePropPostfix = attr.getProperty(ATTR_VALUE);
                    else if (attrname.equals("groupBindDn"))
                        mGroupTypePropPostfix = attr.getProperty(ATTR_VALUE);
                    else if (attrname.equals("userIdField"))
                        mUserTypePropPrefix = attr.getProperty(ATTR_VALUE);
                    else if (attrname.equals("groupIdField"))
                        mGroupTypePropPrefix = attr.getProperty(ATTR_VALUE);
                }
                if (atype != null) {
                    if (mUserTypePropPrefix  == null)
                        mUserTypePropPrefix   = "cn=";
                    if (mGroupTypePropPrefix  == null)
                        mGroupTypePropPrefix  = "cn=";
                    if (mUserTypePropPostfix != null)
                        mUserTypePropPostfix  = "," + mUserTypePropPostfix;
                    if (mGroupTypePropPostfix != null)
                        mGroupTypePropPostfix = "," + mGroupTypePropPostfix;
                }
                else {
                    mUserTypePropPrefix = mUserTypePropPostfix = null;
                    mGroupTypePropPrefix = mGroupTypePropPostfix = null;
                }
            }
        }
        // user property names
        URMConfigurator conf = nconf.getSubConfigurator("User");
        if (conf != null) {
            Iterator props = URMConfiguratorUtil.getPropertyList(conf, msLogger);
            while (props != null && props.hasNext()) {
                URMConfigurator propconf = ((URMConfigurator)props.next());
                Properties prop = propconf.getProperties();
                if (prop == null)
                    continue;
                // LDAP key value
                String propname = prop.getProperty(PROP_NAME);
                if (propname == null)
                    continue;
    //            mAvailableUserNamePropKeys.add(propname);
                // WVCM Key value
                String propkey = prop.getProperty(PROP_KEY);
                if (propkey == null)
                    continue;
                URMLdapPropMapEntry prop_map_entry = null;
                String propformat =  prop.getProperty(PROP_FORMAT);
                if (propformat != null) {
                    if (propformat.equals("{user}"))
                        prop_map_entry = new URMLdapPropMapEntry(mUserTypePropPrefix,
                                        mUserTypePropPostfix, propname, propkey);
                    else if (propformat.equals("{group}"))
                        prop_map_entry = new URMLdapPropMapEntry(mGroupTypePropPrefix,
                                        mGroupTypePropPostfix, propname, propkey);
                    else
                        prop_map_entry = new URMLdapPropMapEntry(null, null, propname, propkey);
                }
                else
                    prop_map_entry = new URMLdapPropMapEntry(null, null, propname, propkey);
                Set keys = (Set) mAvailableUserPropKeysNATIVE_KEYS.get(propname);
                if (keys == null) keys = new HashSet();
                keys.add(prop_map_entry);
                mAvailableUserPropKeysNATIVE_KEYS.put(propname, keys);

                mAvailableUserPropKeysABSTRACT_KEYS.put(propkey, prop_map_entry);
//              mAvailableUserPropKeys.put(propkey, propname);
                String writeable = prop.getProperty(PROP_WRITEABLE);
                if (writeable != null && writeable.equalsIgnoreCase("true")) {
                    mWriteableUserPropKeys.add(propkey);
                }
            }
        }

        // group property names
        conf = nconf.getSubConfigurator("Group");
        if (conf != null) {
            Iterator props = URMConfiguratorUtil.getPropertyList(conf, msLogger);
            while (props != null && props.hasNext()) {
                URMConfigurator propconf = ((URMConfigurator)props.next());
                Properties prop = propconf.getProperties();
                if (prop == null)
                    continue;
                String propname = prop.getProperty(PROP_NAME);
                if (propname == null)
                    continue;
    //            mAvailableGroupNamePropKeys.add(propname);
                String propkey = prop.getProperty(PROP_KEY);
                if (propkey == null)
                    continue;
                URMLdapPropMapEntry prop_map_entry = null;
                String propformat =  prop.getProperty(PROP_FORMAT);
                if (propformat != null) {
                    if (propformat.equals("{user}"))
                        prop_map_entry = new URMLdapPropMapEntry(mUserTypePropPrefix, mUserTypePropPostfix, propname, propkey);
                    else if (propformat.equals("{group}"))
                        prop_map_entry =  new URMLdapPropMapEntry(mGroupTypePropPrefix, mGroupTypePropPostfix, propname, propkey);
                    else
                        prop_map_entry = new URMLdapPropMapEntry(null, null, propname, propkey);
                }
                else
                    prop_map_entry = new URMLdapPropMapEntry(null, null, propname, propkey);
                Set keys = (Set) mAvailableGroupPropKeysNATIVE_KEYS.get(propname);
                if (keys == null) keys = new HashSet();
                keys.add(prop_map_entry);
                mAvailableGroupPropKeysNATIVE_KEYS.put(propname, keys);

                mAvailableGroupPropKeysABSTRACT_KEYS.put(propkey, prop_map_entry);
//                mAvailableGroupPropKeys.put(propkey, propname);
                String writeable = prop.getProperty(PROP_WRITEABLE);
                if (writeable != null && writeable.equalsIgnoreCase("true")) {
                    mWriteableGroupPropKeys.add(propkey);
                }
            }
        }
    }

    public Set getAllGroups()
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        try {
            Enumeration en = mSsxUserDbAdmin.getAllGroups();
            HashSet set = new HashSet();
            while(en != null && en.hasMoreElements())
                set.add(en.nextElement());
            return set;
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    }

    public Set getAllGroups(String domain)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        try {
            Enumeration en = mSsxUserDbAdmin.getAllGroups(domain);
            HashSet set = new HashSet();
            while(en != null && en.hasMoreElements())
                set.add(en.nextElement());
            return set;
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    }

    public Set getAllUsers()
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        try {
            Enumeration en = mSsxUserDbAdmin.getAllUsers();
            HashSet set = new HashSet();
            while(en != null && en.hasMoreElements())
                set.add(en.nextElement());
            return set;
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    }

    public Set getAllUsers(String domain)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        try {
            Enumeration en = mSsxUserDbAdmin.getAllUsers(domain);
            HashSet set = new HashSet();
            while(en != null && en.hasMoreElements())
                set.add(en.nextElement());
            return set;
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    }

    public Set getGroupsOfUser(String user, String domain)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        try {
            Enumeration en = mSsxUserDbAdmin.getGroupsOfUser(user, domain);
            HashSet set = new HashSet();
            while(en != null && en.hasMoreElements())
                set.add(en.nextElement());
            return set;
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    }

    public List getGroupMembers(String group)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        try {
            Enumeration en = mSsxUserDbAdmin.getGroupMembersEx(group);
            LinkedList list = new LinkedList();
            list.addFirst(null);
            while(en != null && en.hasMoreElements()) {
                SSXAccount member = (SSXAccount)en.nextElement();
                switch (member.getType()) {
                case SSXUserDBConstants.SSX_ACC_TYPE_USER:
                    list.addLast(member.getName());
                    break;
                case SSXUserDBConstants.SSX_ACC_TYPE_GROUP:
                    list.addFirst(member.getName());
                    break;
                default:
                    throw new URMInternalServerException(MessageLogger.getAndLogMessage(
                                msLogger, "URMSUE0005", new Integer(member.getType())));
                }
            }
            return list;
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    }

    public List getGroupMembers(String group, String domain)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        try {
            Enumeration en = mSsxUserDbAdmin.getGroupMembersEx(group, domain);
            LinkedList list = new LinkedList();
            list.addFirst(null);
            while(en != null && en.hasMoreElements()) {
                SSXAccount member = (SSXAccount)en.nextElement();
                switch (member.getType()) {
                case SSXUserDBConstants.SSX_ACC_TYPE_USER:
                    list.addLast(member.getName());
                    break;
                case SSXUserDBConstants.SSX_ACC_TYPE_GROUP:
                    list.addFirst(member.getName());
                    break;
                default:
                    throw new URMInternalServerException(MessageLogger.getAndLogMessage(
                                msLogger, "URMSUE0005", new Integer(member.getType())));
                }
            }
            return list;
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    }

    public Set getGroupsMemberOf(String group) throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        try {
            Enumeration en = mSsxUserDbAdmin.getGroupsMemberOf(group);
            HashSet set = new HashSet();
            while(en != null && en.hasMoreElements())
                set.add(en.nextElement());
            return set;
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    }

    public Set getGroupsMemberOf(String group, String domain) throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        try {
            Enumeration en = mSsxUserDbAdmin.getGroupsMemberOf(group, domain);
            HashSet set = new HashSet();
            while(en != null && en.hasMoreElements())
                set.add(en.nextElement());
            return set;
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    }

    public void createUser(String user, char[] password, String domain)
            throws URMNotImplementedException, URMForbiddenException, URMInsertException {
        try {
            mSsxUserDbAdmin.addUser(user, password, domain);
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMInsertException(msLogger, "E", e);
        }
    }

    public void createGroup(String group, String domain)
            throws URMNotImplementedException, URMForbiddenException, URMInsertException {
        try {
            mSsxUserDbAdmin.addGroup(group, domain);
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMInsertException(msLogger, "E", e);
        }
    }

    public void deleteUser(String user, String domain)
            throws URMNotImplementedException, URMForbiddenException, URMDeleteException {
        try {
            mSsxUserDbAdmin.removeUser(user, domain);
            resetCaches();
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMDeleteException(msLogger, "E", e);
        }
    }

    public void deleteGroup(String group, String domain)
            throws URMNotImplementedException, URMForbiddenException, URMDeleteException {
        try {
            mSsxUserDbAdmin.removeGroup(group, domain);
            resetCaches();
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMDeleteException(msLogger, "E", e);
        }
    }

    public Properties getUserProperties(String user)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        try {
            Properties userProps = new Properties();
            Properties ssxUserProps = mSsxUserDbAdmin.getUserProperties(user);
            Iterator propIter = ssxUserProps.keySet().iterator();
            while (propIter.hasNext()) {
                String currentKey  = (String) propIter.next();
                Set currentNames = (Set) mAvailableUserPropKeysNATIVE_KEYS.get(currentKey);
                if (currentNames != null){
                    Iterator keyiter = currentNames.iterator();
                    while (keyiter.hasNext()){
                        URMLdapPropMapEntry current = (URMLdapPropMapEntry) keyiter.next();
                        userProps.put(current.mAbstractAttrname,
                                      current.getExtractedValue(ssxUserProps.getProperty(currentKey)));
                    }
                }
            }
            return userProps;
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    }

    public Properties getUserProperties(String user, String domain)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        try {
            Properties userProps = new Properties();
            Properties ssxUserProps =mSsxUserDbAdmin.getUserProperties(user, domain);
            Iterator propIter = ssxUserProps.keySet().iterator();
            while (propIter.hasNext()) {
                String currentKey  = (String) propIter.next();
                Set currentNames = (Set) mAvailableUserPropKeysNATIVE_KEYS.get(currentKey);
                if (currentNames != null){
                    Iterator keyiter = currentNames.iterator();
                    while (keyiter.hasNext()){
                        URMLdapPropMapEntry current = (URMLdapPropMapEntry) keyiter.next();
                        userProps.put(current.mAbstractAttrname,
                                      current.getExtractedValue(ssxUserProps.getProperty(currentKey)));
                    }
                }
            }
            return userProps;
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    }

    public void setUserProperties(String user, Properties props)
            throws URMNotImplementedException, URMForbiddenException, URMUpdateException {
        try {
//            mSsxUserDbAdmin.setUserProperties(user, props);
            Properties ssxUserProps = new Properties();
            Iterator propIter = props.keySet().iterator();
            while (propIter.hasNext()) {
                // WVCM key
                String currentValue = (String) propIter.next();
                URMLdapPropMapEntry current = (URMLdapPropMapEntry)mAvailableUserPropKeysABSTRACT_KEYS.get(currentValue);
                try {
                    ssxUserProps.put(current.mNativeAttrname, current.getCompleteValue(props.getProperty(currentValue)));
                } catch (NullPointerException npe) {
                    throw new URMUpdateException(MessageLogger.getAndLogMessage(msLogger, "URMMPE0002", currentValue, current.mNativeAttrname));
                }
            }
            mSsxUserDbAdmin.setUserProperties(user, ssxUserProps);
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMUpdateException(msLogger, "E", e);
        }
    }

    public void setUserProperties(String user, String domain, Properties props)
            throws URMNotImplementedException, URMForbiddenException, URMUpdateException {
        try {
//            mSsxUserDbAdmin.setUserProperties(user, domain, props);
            Properties ssxUserProps = new Properties();
            Iterator propIter = props.keySet().iterator();
            while (propIter.hasNext()) {
                // WVCM key
                String currentValue = (String) propIter.next();
                URMLdapPropMapEntry current = (URMLdapPropMapEntry)mAvailableUserPropKeysABSTRACT_KEYS.get(currentValue);
                try {
                    ssxUserProps.put(current.mNativeAttrname, current.getCompleteValue(props.getProperty(currentValue)));
                } catch (NullPointerException npe) {
                    throw new URMUpdateException(MessageLogger.getAndLogMessage(msLogger, "URMMPE0002", currentValue, current.mNativeAttrname));
                }
            }
            mSsxUserDbAdmin.setUserProperties(user, domain, ssxUserProps);
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMUpdateException(msLogger, "E", e);
        }
    }

    public Properties getGroupProperties(String group) throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        try {
//            return mSsxUserDbAdmin.getGroupProperties(group);
            Properties groupProps = new Properties();
            Properties ssxGroupProps = mSsxUserDbAdmin.getGroupProperties(group);
            Iterator propIter = ssxGroupProps.keySet().iterator();
            while (propIter.hasNext()) {
                String currentKey  = (String) propIter.next();
                Set currentNames = (Set) mAvailableGroupPropKeysNATIVE_KEYS.get(currentKey);
                if (currentNames != null){
                    Iterator keyiter = currentNames.iterator();
                    while (keyiter.hasNext()){
                        URMLdapPropMapEntry current = (URMLdapPropMapEntry) keyiter.next();
                        groupProps.put(current.mAbstractAttrname,
                                      current.getExtractedValue(ssxGroupProps.getProperty(currentKey)));
                    }
                }
            }
            return groupProps;
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    }

    public Properties getGroupProperties(String group, String domain) throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        try {
//            return mSsxUserDbAdmin.getGroupProperties(group, domain);
            Properties groupProps = new Properties();
            Properties ssxGroupProps = mSsxUserDbAdmin.getGroupProperties(group, domain);
            Iterator propIter = ssxGroupProps.keySet().iterator();
            while (propIter.hasNext()) {
                String currentKey = (String) propIter.next();
                Set currentNames = (Set) mAvailableGroupPropKeysNATIVE_KEYS.get(currentKey);
                if (currentNames != null){
                    Iterator keyiter = currentNames.iterator();
                    while (keyiter.hasNext()){
                        URMLdapPropMapEntry current = (URMLdapPropMapEntry) keyiter.next();
                        groupProps.put(current.mAbstractAttrname,
                                      current.getExtractedValue(ssxGroupProps.getProperty(currentKey)));
                    }
                }
            }
            return groupProps;
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    }

    public void setGroupProperties(String group, Properties props) throws URMNotImplementedException, URMForbiddenException, URMUpdateException {
        try {
//            mSsxUserDbAdmin.setGroupProperties(group, props);
            Properties ssxGroupProps = new Properties();
            Iterator propIter = props.keySet().iterator();
            while (propIter.hasNext()) {
                // LDAP key
                String currentValue = (String) propIter.next();
                URMLdapPropMapEntry current = (URMLdapPropMapEntry)mAvailableGroupPropKeysABSTRACT_KEYS.get(currentValue);
                try {
                    ssxGroupProps.put(current.mNativeAttrname, current.getCompleteValue(props.getProperty(currentValue)));
                } catch (NullPointerException npe) {
                    throw new URMUpdateException(MessageLogger.getAndLogMessage(msLogger, "URMMPE0002", currentValue, current.mNativeAttrname));
                }
            }
            mSsxUserDbAdmin.setGroupProperties(group, ssxGroupProps);
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMUpdateException(msLogger, "E", e);
        }
    }

    public void setGroupProperties(String group, String domain, Properties props) throws URMNotImplementedException, URMForbiddenException, URMUpdateException {
        try {
//            mSsxUserDbAdmin.setGroupProperties(group, domain, props);
            Properties ssxGroupProps = new Properties();
            Iterator propIter = props.keySet().iterator();
            while (propIter.hasNext()) {
                 // LDAP key
                String currentValue = (String) propIter.next();
                URMLdapPropMapEntry current = (URMLdapPropMapEntry)mAvailableGroupPropKeysABSTRACT_KEYS.get(currentValue);
                try {
                    ssxGroupProps.put(current.mNativeAttrname, current.getCompleteValue(props.getProperty(currentValue)));
                } catch (NullPointerException npe) {
                    throw new URMUpdateException(MessageLogger.getAndLogMessage(msLogger, "URMMPE0002", currentValue, current.mNativeAttrname));
                }
            }
            mSsxUserDbAdmin.setGroupProperties(group, domain, ssxGroupProps);
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMUpdateException(msLogger, "E", e);
        }
    }

    public void addUserToGroup(String user, String group)
            throws URMNotImplementedException, URMForbiddenException, URMInsertException {
        try {
            mSsxUserDbAdmin.addUserToGroup(user, group);
            resetCaches();
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMInsertException(msLogger, "E", e);
        }
    }

    public void addUserToGroup(String user, String group, String domain)
            throws URMNotImplementedException, URMForbiddenException, URMInsertException {
        try {
            mSsxUserDbAdmin.addUserToGroup(user, group, domain);
            resetCaches();
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMInsertException(msLogger, "E", e);
        }
    }

    public void removeUserFromGroup(String user, String group)
            throws URMNotImplementedException, URMForbiddenException, URMDeleteException {
        try {
            mSsxUserDbAdmin.removeUserFromGroup(user, group);
            resetCaches();
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMDeleteException(msLogger, "E", e);
        }
    }

    public void removeUserFromGroup(String user, String group, String domain)
            throws URMNotImplementedException, URMForbiddenException, URMDeleteException {
        try {
            mSsxUserDbAdmin.removeUserFromGroup(user, group, domain);
            resetCaches();
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMDeleteException(msLogger, "E", e);
        }
    }

    public void addGroupToGroup(String memberGroup, String toGroup) throws URMNotImplementedException, URMForbiddenException, URMInsertException {
        try {
            mSsxUserDbAdmin.addGroupToGroup(memberGroup, toGroup);
            resetCaches();
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMInsertException(msLogger, "E", e);
        }
    }

    public void addGroupToGroup(String memberGroup, String toGroup, String domain) throws URMNotImplementedException, URMForbiddenException, URMInsertException {
        try {
            mSsxUserDbAdmin.addGroupToGroup(memberGroup, toGroup, domain);
            resetCaches();
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMInsertException(msLogger, "E", e);
        }
    }

    public void removeGroupFromGroup(String memberGroup, String fromGroup) throws URMNotImplementedException, URMForbiddenException, URMDeleteException {
        try {
            mSsxUserDbAdmin.removeGroupFromGroup(memberGroup, fromGroup);
            resetCaches();
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMDeleteException(msLogger, "E", e);
        }
    }

    public void removeGroupFromGroup(String memberGroup, String fromGroup, String domain) throws URMNotImplementedException, URMForbiddenException, URMDeleteException {
        try {
            mSsxUserDbAdmin.removeGroupFromGroup(memberGroup, fromGroup, domain);
            resetCaches();
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMDeleteException(msLogger, "E", e);
        }
    }

    public void changeUserPassword(String user, char[] oldpassword, char[] newpassword)
            throws URMNotImplementedException, URMForbiddenException, URMUpdateException {
        try {
            mSsxUserDbAdmin.changeUserPassword(user, oldpassword, newpassword);
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMUpdateException(msLogger, "E", e);
        }
    }

    public void changeUserPassword(String user, String domain, char[] oldpassword, char[] newpassword)
            throws URMNotImplementedException, URMForbiddenException, URMUpdateException {
        try {
            mSsxUserDbAdmin.changeUserPassword(user, domain, oldpassword, newpassword);
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMUpdateException(msLogger, "E", e);
        }
    }

    public boolean isUser(String user)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        try {
            return mSsxUserDbAdmin.isUser(user);
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    }

    public boolean isUser(String user, String domain)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        try {
            return mSsxUserDbAdmin.isUser(user, domain);
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    }

    public boolean isGroup(String group)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        try {
            return mSsxUserDbAdmin.isGroup(group);
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    }

    public boolean isGroup(String group, String domain)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        try {
            return mSsxUserDbAdmin.isGroup(group, domain);
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMNotImplementedException(msLogger, "F", e);
        } catch (SSXUserDBForbiddenException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    }

    public void close() throws URMCloseConnectionException {
        try {
            mSsxUserDbAdmin.close();
        } catch (SSXConnectionCloseFailedException e) {
            throw new URMCloseConnectionException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMCloseConnectionException(msLogger, "E", e);
        }
        
    }

    public Set getWriteablePropKeys(boolean isUser) {
        if (isUser)
            return mWriteableUserPropKeys;
        else
            return mWriteableGroupPropKeys;
    }
    
    public Set getAvailablePropKeys(boolean isUser) {
        if (isUser)
            return mAvailableUserPropKeysABSTRACT_KEYS.keySet();
        else
            return mAvailableGroupPropKeysABSTRACT_KEYS.keySet();
    }
    
    private void resetCaches() {
        URMListener listener = URMListener.getAclListenerSet();
        if (listener != null) {
            listener.resetEvent();
        }
    }
    
    public void clearCaches() {
        mSsxUserDbAdmin.getOwnerUserDatabase().clearCaches();
    }
}

