/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/urm/org/apache/slide/urm/authenticator/rolemanager/impl/tamino/URMRoleManagerSpiTamino.java,v 1.4 2005/03/02 10:53:34 eckehard Exp $
 * $Revision: 1.4 $
 * $Date: 2005/03/02 10:53:34 $
 *
 * ====================================================================
 *
 * 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.rolemanager.impl.tamino;

import com.softwareag.tamino.db.api.accessor.*;
import org.apache.slide.urm.common.*;

import java.util.*;

import com.softwareag.tamino.db.api.common.TAccessFailureException;
import com.softwareag.tamino.db.api.connection.TConnectionPoolManager;
import com.softwareag.tamino.db.api.objectModel.TIteratorException;
import com.softwareag.tamino.db.api.objectModel.TNoSuchXMLObjectException;
import com.softwareag.tamino.db.api.objectModel.TXMLObject;
import com.softwareag.tamino.db.api.objectModel.TXMLObjectIterator;
import com.softwareag.tamino.db.api.response.TResponse;
import org.apache.slide.urm.URMForbiddenException;
import org.apache.slide.urm.URMNotImplementedException;
import org.apache.slide.urm.accesscontroler.impl.tamino.URMAccessControlerSpiTamino;
import org.apache.slide.urm.authenticator.URMDBTransactionException;
import org.apache.slide.urm.authenticator.URMSubject;
import org.apache.slide.urm.authenticator.impl.URMSubjectImpl;
import org.apache.slide.urm.authenticator.rolemanager.URMRoleManagerSpi;
import org.apache.slide.urm.common.impl.URMConfiguratorUtil;
import org.apache.slide.urm.common.impl.tamino.URMTaminoConnection;
import org.apache.slide.urm.common.impl.tamino.URMTaminoConnectionHandler;
import org.apache.slide.urm.utils.URMFifoCache;
import org.apache.slide.urm.utils.messagelogger.MessageLogger;
import org.apache.slide.urm.utils.validatorcache.URMValidatorCache;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

/**
 * Implementation of the MetaDataStore access via Tamino.
 * All role-dependend functions are implemented in this class.
 *
 * @author eckehard.hermann@softwareag.com
 * @author dieter.kessler@softwareag.com
 * @author zsolt.sasvarie@softwareag.com
 */
public class URMRoleManagerSpiTamino implements URMRoleManagerSpi {

    private static org.apache.log4j.Logger msLogger =
        org.apache.log4j.Logger.getLogger(URMRoleManagerSpiTamino.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_WRITEABLE = "writeable";
    private static final int UPDATE = 1;
    private static final int QUERY = 2;
    private static final int START_TA = 3;
    private static final int COMMIT_TA = 4;
    private static final int ROLLBACK_TA = 5;
    private static final int CONNPOOL_INIT_SIZE = 1;
    private static URMFifoCache isRoleCache = null;
    private static URMFifoCache roleProfileCache = null;
    private static URMFifoCache preDefActionCache = null;
    private static URMFifoCache roleUserMappingCache = null;
    private static URMFifoCache roleGroupMappingCache = null;
    private static URMFifoCache userRoleMappingCache = null;
    private static URMFifoCache groupRoleMappingCache = null;
    private static URMFifoCache allRoleUserMappingCache = null;
    private static URMFifoCache allRoleGroupMappingCache = null;
    private static URMFifoCache ancestorCache = null;
    private static URMFifoCache allAncestorCache = null;
    private static URMFifoCache rolesOfAncestorCache = null;
    private static boolean allRoleSwitch = false;
    private static Set _roles = null;
    private String mDatabaseUri = null;
    private String mCollectionName = null;
//    private TConnection mConnection = null;
    private TConnectionPoolManager mConnectionPoolManager = null;
    private URMTaminoConnectionHandler mConn = null;
    private String mPoolName = null;
    private String mUserName = null;
    private String mUserPwd = null;
    private String mUserDomain = null;
    private Integer mConnPoolMax = null;
    private Integer mConnPoolTimeout = null;
//    private TXMLObjectAccessor mObjectAccessor = null;
    private Object mOwner = null;
    private boolean mInTransaction = false;
    private URMConfigurator mConfigurator = null;
    private Set mWriteableRolePropKeys = new HashSet();
    private Set mAvailableRolePropKeys = new HashSet();
//    private boolean mIsAlreadyClosed = false;

    /** Constructor of the Tamino role administrator. The passed configurator
     * must specify the "databaseUri" attribute. If the "collectionName" is not
     * specified than the default one URMConstants#DEFAULT_TAMINO_COLLECTION is used.
     *
     * @param roleAdminConf role administrator configuration.
     */
    public URMRoleManagerSpiTamino(URMConfigurator roleAdminConf, Object owner) throws URMConnectionException {
        mConfigurator = roleAdminConf;
        mOwner = owner;

        String userName = null;
        String userPwd = null;
        String userDomain = null;
        Integer connPoolMax = null;
        Integer connPoolTimeout = null;

        if (msLogger.isInfoEnabled())
            MessageLogger.logMessage(msLogger, "URMCOI0019", getClass().getName());
        URMConfigurator attrConf = roleAdminConf.getSubConfigurator("/Authenticator/Administrator");
        if (attrConf != null){
            Iterator attrs = URMConfiguratorUtil.getAttributeList(attrConf, msLogger);
            while (attrs != null && 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)
                    continue;
                if (msLogger.isInfoEnabled())
                    MessageLogger.logMessage(msLogger, "URMCOI0024", attrname, (String)attr.get(ATTR_VALUE));
                if (attrname.equals("databaseUri")) {
                    mDatabaseUri = (String)attr.get(ATTR_VALUE);
                }
                else if (attrname.equals("collectionName")) {
                    mCollectionName = (String)attr.get(ATTR_VALUE);
                }
                else if (attrname.equals("databaseAccount"))
                    userName = (String)attr.get(ATTR_VALUE);
                else if (attrname.equals("databasePassword"))
                    userPwd = (String)attr.get(ATTR_VALUE);
                else if (attrname.equals("databaseDomain"))
                    userDomain = (String)attr.get(ATTR_VALUE);
                else if (attrname.equals("connPoolMaxConns"))
                    connPoolMax = new Integer((String)attr.get(ATTR_VALUE));
                else if (attrname.equals("connPoolTimeout"))
                    connPoolTimeout = new Integer((String)attr.get(ATTR_VALUE));
            }
        }

        mUserName = (userName == null ? "" : userName);
        mUserPwd = (userPwd == null ? "" : userPwd);
        mUserDomain = (userDomain == null ? "" : userDomain);
        mConnPoolMax = (connPoolMax == null ? new Integer("60") : connPoolMax);
        mConnPoolTimeout = (connPoolTimeout == null ? new Integer("600") : connPoolTimeout);

        URMConfigurator roleConf = roleAdminConf.getSubConfigurator("/Authenticator/Administrator/RoleManager");
        if (roleConf != null){
            Iterator roleattrs = URMConfiguratorUtil.getAttributeList(roleConf, msLogger);
            while (roleattrs != null && roleattrs.hasNext()) {
                URMConfigurator attrconf = ((URMConfigurator)roleattrs.next());
                Properties attr = attrconf.getProperties();
                if (attr == null)
                    continue;
                String attrname = (String)attr.get(ATTR_NAME);
                if (attrname == null)
                    continue;
                if (msLogger.isInfoEnabled())
                    MessageLogger.logMessage(msLogger, "URMCOI0024", attrname, (String)attr.get(ATTR_VALUE));
                if (attrname.equals("roleManagerCache")) {
                    String cacheSize = (String)attr.get("value");
                    int size = (new Integer(cacheSize)).intValue();
                    if (size > 0) {
                        if (isRoleCache == null) isRoleCache = new URMFifoCache(size);
                        if (roleProfileCache == null) roleProfileCache = new URMFifoCache(size);
                        if (preDefActionCache == null) preDefActionCache = new URMFifoCache(size);
                        if (roleUserMappingCache == null) roleUserMappingCache = new URMFifoCache(size);
                        if (roleGroupMappingCache == null) roleGroupMappingCache = new URMFifoCache(size);
                        if (userRoleMappingCache == null) userRoleMappingCache = new URMFifoCache(size);
                        if (groupRoleMappingCache == null) groupRoleMappingCache = new URMFifoCache(size);
                        if (allRoleUserMappingCache == null) allRoleUserMappingCache = new URMFifoCache(size);
                        if (allRoleGroupMappingCache == null) allRoleGroupMappingCache = new URMFifoCache(size);
                        if (ancestorCache == null) ancestorCache = new URMFifoCache(size);
                        if (allAncestorCache == null) allAncestorCache = new URMFifoCache(size);
                        if (rolesOfAncestorCache == null) rolesOfAncestorCache = new URMFifoCache(size);
                    }
                } else if (attrname.equals("roleCacheSwitch")) {
                    String enable = (String)attr.get("value");
                    if ((_roles == null) && enable.equals("active")) allRoleSwitch = true;
                }
            }
        }
        // Role property names
        URMConfigurator conf = null;
        conf = roleAdminConf.getSubConfigurator("/Authenticator/Administrator/UserDatabase/MetadataProperties/Role");
        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;
                mAvailableRolePropKeys.add(propname);

                String writeable = prop.getProperty(PROP_WRITEABLE);
                if (writeable.equalsIgnoreCase("true")) {
                    mWriteableRolePropKeys.add(propname);
                }
            }
        }

        if (msLogger.isDebugEnabled())
            MessageLogger.logMessage(msLogger, "URMTRQ0001", mDatabaseUri, mCollectionName);

/*      mConnection = getConnection(userDomain, userName, userPwd);
        try {
            mConnection.useAutoCommitMode();
        } catch (TTransactionModeChangeException e) {
            throw new URMConnectionException(msLogger, "F", e);
        }
        objectAccessor = mConnection.newXMLObjectAccessor(
                            TAccessLocation.newInstance(mCollectionName),
                            TDOMObjectModel.getInstance() );
        if (objectAccessor == null)
            throw new URMConnectionException(MessageLogger.getAndLogMessage(
                    msLogger, "URMTRC0002", mDatabaseUri, mCollectionName));
*/
        if (msLogger.isInfoEnabled())
            MessageLogger.logMessage(msLogger, "URMCOI0018", getClass().getName());
    }

    public URMRoleManagerSpi duplicateObject(Object owner) throws URMConnectionException {
        return new URMRoleManagerSpiTamino(mConfigurator, owner);
    }

    /** Checks whether the role of a specific name exists.
     *
     * @param role name of a role.
     * @return true if this is the name of an existing role.
     *
     * @exception URMNotImplementedException if the method is not
     *            implemented by the user database.
     * @exception URMForbiddenException if the user has not the permission
     *            to invoke the method.
     * @exception URMException if an unpredictable internal error occurs.
     */
    public boolean isRole(String role)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {

        if (isRoleCache != null /*&& accessCacheAllowed()*/) {
        Boolean roleEntry = (Boolean) isRoleCache.get(role);
        if (roleEntry != null)
            return roleEntry.booleanValue();
    }
    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(QUERY)) == null)
            throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        TXQuery query = TXQuery.newInstance("for    $b in input()/Role " +
                                            "where  $b/RoleName = '" + role + "' " +
                                            "return $b/RoleName");
        try {
            TResponse response = objectAccessor.xquery(query);
            TXMLObject tobj = response.getFirstXMLObject();
            Object obj_el = tobj != null ? tobj.getElement() : null;
            if (obj_el != null && obj_el instanceof Element){
                Node elem1 = ((Element)obj_el).getFirstChild();
                String s1 = elem1.getNodeValue();
                if (isRoleCache != null /*&& tConn.accessCache()*/) isRoleCache.add(role, new Boolean(true));
                return true;
            }
            else
                return false;
        } catch (TXQueryException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }

    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    /** Creates a new Role.
     * All role must have unique names.
     *
     * @param role name of new role.
     *
     * @exception URMNotImplementedException if the method is not
     *            implemented by the user database.
     * @exception URMForbiddenException if the user has not the permission
     *            to invoke the method.
     * @exception URMException if an unpredictable internal error occurs
     */
    public void createRole(String role)
            throws URMNotImplementedException, URMForbiddenException, URMInsertException, URMInternalServerException {
    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(UPDATE)) == null)
            throw new URMInsertException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        try {
            if (!this.isRole(role)) {
                TXMLObject xmlobj = TXMLObject.newInstance("<Role><RoleName>" + role +
                                                            "</RoleName></Role>");

                try {
                    TResponse response = objectAccessor.insert(xmlobj);
                    // reset caches
                    _roles = null;
                        if (isRoleCache != null /*&& tConn.accessCache()*/) isRoleCache.add(role, new Boolean(true));
                } catch (TInsertException e) {
                    throw new URMInsertException(msLogger, "E", e);
                }
            } else {
                throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0009", role));
            }
        } catch (URMInternalServerException e) {
            throw new URMInsertException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMInsertException)
            throw (URMInsertException)e;
        else throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    /** Deletes the role of the given name.
     *
     * @param role name of the role that should be deleted.
     *
     * @exception URMNotImplementedException if the method is not
     *            implemented by the user database.
     * @exception URMForbiddenException if the user has not the permission
     *            to invoke the method.
     * @exception URMException if an unpredictable internal error occurs
     */
    public void deleteRole(String role)
            throws URMNotImplementedException, URMInternalServerException,
                   URMForbiddenException, URMDeleteException {

    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(UPDATE)) == null)
            throw new URMDeleteException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        // Check first for any existing ACLs having this role as owner
        /*
        try {
            TResponse response = objectAccessor.xquery(xquery);
            TXMLObject tobj = response.getFirstXMLObject();
            Object obj_el = tobj != null ? tobj.getElement() : null;
            if (obj_el != null && obj_el instanceof Element){
                Node elem1 = ((Element)obj_el).getFirstChild();
                String s1 = elem1.getNodeValue();
                throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0053", role, s1));
            }
        } catch (TXQueryException e) {
            e.printStackTrace();
            throw new URMDeleteException(msLogger, "E", e);
        }

        // Check for any existing ACEs containing this role
        */
     
        TXQuery xquery = TXQuery.newInstance("update delete input()/AccessControlList/ACE[Subject = '" + role +
                                                   "' and Subject/@Type = " +
                                                    org.apache.slide.urm.common.URMConstants.ROLE + "]");

        try {
            TResponse response = objectAccessor.xquery(xquery);
             /*MLObject tobj = response.getFirstXMLObject();
             Object obj_el = tobj != null ? tobj.getElement() : null;
             if (obj_el != null && obj_el instanceof Element){
                 Node elem1 = ((Element)obj_el).getFirstChild();
                 String s1 = elem1.getNodeValue();
                 throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0053", role, s1));
             }*/
        } catch (TXQueryException e) {
            throw new URMDeleteException(msLogger, "E", e);
        }

        xquery = TXQuery.newInstance("update replace input()/AccessControlList/Owner[text() = '" + role +
                                                   "' and @Type = " + URMConstants.ROLE + "] with "+
                                                   "<Owner Type=\""+URMConstants.ROLE+"\">"+URMConstants.URM_ADMIN_ROLE+"</Owner>");
        try {
            TResponse response = objectAccessor.xquery(xquery);
        } catch (TXQueryException e) {
            throw new URMDeleteException(msLogger, "E", e);
        }


        // delete anchestor/role mapping
        xquery = TXQuery.newInstance("update for $b in input()/Role/AncestorRole " +
                                            "where  $b = '" + role + "' " +
                                            "do delete $b");
        try {
            TResponse response = objectAccessor.xquery(xquery);
        } catch (TXQueryException e) {
            throw new URMDeleteException(msLogger, "E", e);
        }
                
        
        // delete user-group/role mapping
        xquery = TXQuery.newInstance("update for $b in input()/UserRoleMapping/Role " +
                                            "where  $b = '" + role + "' " +
                                            "do delete $b");
        try {
            TResponse response = objectAccessor.xquery(xquery);
        } catch (TXQueryException e) {
            throw new URMDeleteException(msLogger, "E", e);
        }
        
//        // Check for any Ancestors with this role name
//        try {
//            Set en = this.getRolesOfAncestor(role);
//            if (en.size() > 0)
//                throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0006", role));
//
//        } catch (URMInternalServerException e) {
//            throw new URMForbiddenException(msLogger, "E", e);
//        }
//
//        // Check for any existing RoleMappings with this name
//        try {
//            Set en = this.getUserMappingOfRole(role);
//            if (en.size() > 0)
//                throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0007", role));
//
//            en = this.getGroupMappingOfRole(role);
//            if (en.size() > 0)
//                throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0008", role));
//
//        } catch (URMInternalServerException e) {
//            throw new URMForbiddenException(msLogger, "E", e);
//        }

        // Delete the Mother
        TQuery query = TQuery.newInstance("Role[RoleName = '" + role + "']");
        try {
            TResponse response = objectAccessor.delete(query);
            
//            if (tConn.accessCache()) {
                // reset caches
                _roles = null;
                if (isRoleCache != null) isRoleCache.remove(role);
                if (roleProfileCache != null) roleProfileCache.remove(role);
                if (preDefActionCache != null) preDefActionCache.remove(role);
                if (roleGroupMappingCache != null) roleGroupMappingCache.clear();
                if (roleUserMappingCache != null) roleUserMappingCache.clear();
                if (groupRoleMappingCache != null) groupRoleMappingCache.clear();
                if (userRoleMappingCache != null) userRoleMappingCache.clear();
                if (allRoleGroupMappingCache != null) allRoleGroupMappingCache.clear();
                if (allRoleUserMappingCache != null) allRoleUserMappingCache.clear();
                if (ancestorCache != null) ancestorCache.clear();
                if (allAncestorCache != null) allAncestorCache.clear();
                if (rolesOfAncestorCache != null) rolesOfAncestorCache.clear();
//            }
            resetCaches();
        } catch (TDeleteException e) {
            throw new URMDeleteException(msLogger, "E", e);
        }
        
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMDeleteException)
            throw (URMDeleteException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }


    /** Returns a set of all existing roles.
     *
     * @return set of roles.
     *
     * @exception URMNotImplementedException if the method is not
     *            implemented by the user database.
     * @exception URMForbiddenException if the user has not the permission
     *            to invoke the method.
     * @exception URMException if an unpredictable internal error occurs
     */
    public Set getAllRoles()
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        if (_roles != null /*&& accessCacheAllowed()*/) return _roles;
    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(QUERY)) == null)
            throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        TXQuery query = TXQuery.newInstance("for    $b in input()/Role\n" +
                                            "return $b/RoleName");
        try {
            TResponse response = objectAccessor.xquery(query);
            TXMLObjectIterator iter = response.getXMLObjectIterator();
            HashSet roles = new HashSet();
            while (iter != null && iter.hasNext()) {
                TXMLObject tobj = iter.next();
                Object obj_el = tobj != null ? tobj.getElement() : null;
                if (obj_el != null && obj_el instanceof Element) {
                    Node node = ((Element)obj_el).getFirstChild();
                    if (node != null) {
                        String rolename = node.getNodeValue();
                        URMSubject urmSubject = new URMSubjectImpl(rolename,
                                                                   org.apache.slide.urm.common.URMConstants.ROLE,
                                                                   null);

                        roles.add(urmSubject);
                    }
                }
            }
            if (allRoleSwitch) _roles = roles;
            return roles;
        } catch (TXQueryException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TNoSuchXMLObjectException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TIteratorException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    /** Sets the profile of a role.
     *
     * @param roleName object
     * @param profileProperties profile of the role
     *
     * @exception URMNotImplementedException if the method is not
     *            implemented by the user database.
     * @exception URMForbiddenException if the user has not the permission
     *            to invoke the method.
     * @exception URMUpdateException if an unpredictable internal error occurs
     */
    public void setProfileOfRole(String roleName, Properties profileProperties)
            throws URMNotImplementedException, URMForbiddenException,
                   URMUpdateException, URMInternalServerException {

    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(UPDATE)) == null)
            throw new URMUpdateException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        String strKey = null, strValu = null;
        String strProps = "";


        // Prepare the Property insertion string
        for (Enumeration keys = profileProperties.keys(); keys.hasMoreElements();) {
            String val, key = (String)keys.nextElement();
            if ((val = profileProperties.getProperty(key)) != null) {
                strProps = strProps.concat("<Property><Key>" + key +
                                            "</Key><Value>" + val +
                                            "</Value></Property>");
            }
        }

        // Check if <Properties> already exist
        TXQuery query = TXQuery.newInstance("for    $b in input()/Role " +
                                            "where  $b/RoleName = '" + roleName + "' " +
                                            "return $b/Properties");
        TResponse response = null;
        TXMLObjectIterator iter = null;
        try {
            response = objectAccessor.xquery(query);
            iter = response.getXMLObjectIterator();

            Vector roles = new Vector();
            if (iter != null && iter.hasNext()) {
                // Remove the <Properties> element first
                TXQuery query2 = TXQuery.newInstance("update delete " +
                            "input()/Role[RoleName = '" + roleName + "']/Properties");
                response = objectAccessor.xquery(query2);
                iter = response.getXMLObjectIterator();
            }
        }  catch (TXQueryException e) {
        throw new URMUpdateException(msLogger, "E", e);
        }

        query = TXQuery.newInstance("update insert <Properties>" + strProps + "</Properties> " +
                                    "following input()/Role/RoleName[text() = '" + roleName + "']");
        try {
            response = objectAccessor.xquery(query);
            iter = response.getXMLObjectIterator();
            if (iter == null || !iter.hasNext()) {
                TXMLObject xmlobj = TXMLObject.newInstance(
                    "<Role><RoleName>" + roleName + "</RoleName>" +
                    "<Properties>" + strProps + "</Properties> " +
                    "</Role>");
                try {
                    response = objectAccessor.insert(xmlobj);
                } catch (TInsertException e) {
                    throw new URMUpdateException(msLogger, "E", e);
                }
            }
            
        } catch (TXQueryException e) {
            throw new URMUpdateException(msLogger, "E", e);
        }
        if (roleProfileCache != null) roleProfileCache.add(roleName,profileProperties);
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMUpdateException)
            throw (URMUpdateException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

   
    public Properties getProfileOfRole(String roleName)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {

    Properties props = null;
        if (roleProfileCache != null /*&& accessCacheAllowed()*/) {
        props = (Properties) roleProfileCache.get(roleName);
        if (props != null) {
            Properties newProps = new Properties();
            Iterator propiter = props.keySet().iterator();
            while (propiter.hasNext()) {
                String currentkey = (String) propiter.next();
                newProps.put(currentkey,props.getProperty(currentkey));
            }
            return newProps;
        }
    }

    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(QUERY)) == null)
            throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        props = new Properties();

        TXQuery query = TXQuery.newInstance("for    $b in input()/Role " +
                                            "where  $b/RoleName = '" + roleName + "' " +
                                            "return $b/Properties/Property");
        try {
            TResponse response = objectAccessor.xquery(query);
            TXMLObjectIterator iter = response.getXMLObjectIterator();
            Vector roles = new Vector();
            while (iter != null && iter.hasNext()) {
                TXMLObject tobj = iter.next();
                Object obj_el = tobj != null ? tobj.getElement() : null;
                if (obj_el != null && obj_el instanceof Element) {
                    String pkey = null, pval = null;
                    Node currNode = ((Element)obj_el).getFirstChild();
                    for (;currNode != null; currNode = currNode.getNextSibling()) {
                        Node tnode = currNode.getFirstChild();
                        while (tnode != null && tnode.getNodeType() != Node.TEXT_NODE)
                            tnode = tnode.getNextSibling();
                        if (tnode == null)
                            continue;
                        String tval = tnode.getNodeValue();
                        if ("Value".equals(currNode.getNodeName())) {
                            pval = tval;
                            if (pkey != null) {
                                if (mAvailableRolePropKeys.contains(pkey)) props.put(pkey, pval);
                                break;
                            }
                        } else
                        if ("Key".equals(currNode.getNodeName())) {
                            pkey = tval;
                            if (pval != null) {
                                if (mAvailableRolePropKeys.contains(pkey)) props.put(pkey, pval);
                                break;
                            }
                        }
                    }
                }
            }
            if (roleProfileCache != null /*&& tConn.accessCache()*/) roleProfileCache.add(roleName, props);
        return props;

        } catch (TXQueryException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TNoSuchXMLObjectException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TIteratorException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    public void deleteProfileOfRole(String roleName)
            throws URMNotImplementedException, URMForbiddenException, URMDeleteException, URMInternalServerException {

    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(UPDATE)) == null)
            throw new URMDeleteException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        boolean delete_subnode = false;

  
        TResponse response = null;
        TXMLObjectIterator iter = null;
        try {
           // Remove the <Properties> element
           TXQuery query2 = TXQuery.newInstance("update delete " +
                            "input()/Role[RoleName = '" + roleName + "']/Properties");
           response = objectAccessor.xquery(query2);
           if (response.getFirstXMLObject() == null)
               throw new URMDeleteException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0005", roleName));

           if (roleProfileCache != null /*&& tConn.accessCache()*/) roleProfileCache.remove(roleName);
           iter = response.getXMLObjectIterator();
            
        }  catch (TXQueryException e) {
        throw new URMDeleteException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMDeleteException)
            throw (URMDeleteException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    public void setPredefinedAction(String role, String action, Boolean type)
            throws URMNotImplementedException, URMForbiddenException, URMInsertException, URMInternalServerException {

    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(UPDATE)) == null)
            throw new URMInsertException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        if (action == null || type == null)
            throw new URMInsertException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0026", (action == null ? "action" : "type")));

        // Check if <PredefeinedActions> already exist
        TXQuery query = TXQuery.newInstance("for    $b in input()/Role " +
                                            "where  $b/RoleName = '" + role + "' " +
                                            "return $b/PredefinedActions");
        TResponse response = null;
        TXMLObjectIterator iter = null;
        try {
            response = objectAccessor.xquery(query);
            iter = response.getXMLObjectIterator();
            while(iter != null && iter.hasNext()) {
                // Check if the Action already exists
                // throw exception, if so
                TXMLObject tobj;
                tobj = iter.next();
                Object obj_el = tobj != null ? tobj.getElement() : null;
                if (obj_el != null && obj_el instanceof Element) {
                    Node actNode = ((Element)obj_el).getFirstChild();
                    if (actNode != null) {
                        String actStr = actNode.getNodeValue();
                        if (actStr.equals(action)) {
                            throw new URMInsertException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0040"));
                        }
                    }
                }
            }
        }  catch (TXQueryException e) {
        throw new URMInsertException(msLogger, "E", e);
        }  catch (TNoSuchXMLObjectException e) {
        throw new URMInsertException(msLogger, "E", e);
        }  catch (TIteratorException e) {
        throw new URMInsertException(msLogger, "E", e);
        }
        String _type = null;
        if (type.booleanValue()) _type = "'1'";
        else _type = "'0'";
        query = TXQuery.newInstance("update insert <PredefinedActions Type=" +
                                    _type + ">" +
                                    action + "</PredefinedActions> " +
                                    "into input()/Role[RoleName = '" + role + "']");
        try {
            response = objectAccessor.xquery(query);
            
            // reset caches
            if (preDefActionCache != null /*&& tConn.accessCache()*/) preDefActionCache.remove(role);
            resetCaches();
            
        } catch (TXQueryException e) {
            throw new URMInsertException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMInsertException)
            throw (URMInsertException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    public Map getPredefinedActions(String role)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {

    Map preActions = null;
        if (preDefActionCache != null /*&& accessCacheAllowed()*/) {
        preActions = (Map) preDefActionCache.get(role);
        if (preActions != null){
            Map newPreActions = new HashMap();
            Iterator actioniter = preActions.keySet().iterator();
            while (actioniter.hasNext()) {
                String currentkey = (String) actioniter.next();
                newPreActions.put(currentkey,preActions.get(currentkey));
            }
            return newPreActions;
        }
    }
    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(QUERY)) == null)
           throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        Map acts = new HashMap();

        TXQuery query = TXQuery.newInstance("for    $b in input()/Role " +
                                            "where  $b/RoleName = '" + role + "' " +
                                            "return $b/PredefinedActions");
        try {
            TResponse response = objectAccessor.xquery(query);
            TXMLObjectIterator iter = response.getXMLObjectIterator();
            while (iter != null && iter.hasNext()) {
                TXMLObject tobj;
                Boolean actType = new Boolean(true);
                tobj = iter.next();
                Object obj_el = tobj != null ? tobj.getElement() : null;
                if (obj_el != null && obj_el instanceof Element) {

                    Node actNode = ((Element)obj_el).getFirstChild();

                    if (actNode != null) {
                        String action = actNode.getNodeValue();
                    }

                    NamedNodeMap actAttr = ((Element)obj_el).getAttributes();
                    if (actAttr != null) {
                        Node actTypeNode = actAttr.getNamedItem("Type");
                        if (actTypeNode != null) {
                            actType = (actTypeNode.getNodeValue().equals("1") ? new Boolean(true) : new Boolean(false));
                        }
                    }

                    acts.put(actNode.getNodeValue(), actType);
                }
            }
            if (preDefActionCache != null /*&&  tConn.accessCache()*/) preDefActionCache.add(role, acts);
            return acts;
        } catch (TXQueryException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TNoSuchXMLObjectException e) {
        throw new URMInternalServerException(msLogger, "E", e);
        } catch (TIteratorException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    public void deletePredefinedAction(String role, String action)
            throws URMNotImplementedException, URMForbiddenException, URMDeleteException, URMInternalServerException {

    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(UPDATE)) == null)
            throw new URMDeleteException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        // Check if <PredefeinedActions> already exist
        TXQuery query = TXQuery.newInstance("for    $b in input()/Role " +
                                            "where  $b/RoleName = '" + role + "' " +
                                            "return $b/PredefinedActions");
        TResponse response = null;
        TXMLObjectIterator iter = null;
        try {
            response = objectAccessor.xquery(query);
            iter = response.getXMLObjectIterator();

            Vector roles = new Vector();
            if (iter != null && iter.hasNext()) {
                // Remove the <Properties> element
                TXQuery query2 = TXQuery.newInstance("update delete " +
                            "input()/Role[RoleName = '" + role +
                            "']/PredefinedActions[text() = '" + action + "']");
                response = objectAccessor.xquery(query2);
                
                // reset caches
                    if (preDefActionCache != null /*&& tConn.accessCache()*/) preDefActionCache.remove(role);
                resetCaches();
                    
            } else {
                throw new URMDeleteException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0038", action));
            }
        }  catch (TXQueryException e) {
        throw new URMDeleteException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMDeleteException)
            throw (URMDeleteException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    public void addUserLink(String role, String domain, String user)
            throws URMNotImplementedException, URMForbiddenException, URMInsertException, URMInternalServerException {

    // delete user from cache
    String userdomain = null;
    if ((domain == null) || (domain.equals(""))) userdomain = user;
    else userdomain = user + ":" + domain;

    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(UPDATE)) == null)
            throw new URMInsertException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        try {
            Set rset = this.getRoleMappingOfUser(user, domain);
            if (rset != null) {
                Iterator riter = rset.iterator();
                while (riter.hasNext())
                    if (role.equals(((URMSubject)(riter.next())).getName()))
                        throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0010", role, user, domain));
            }
        } catch (URMInternalServerException e) {
            throw new URMInsertException(msLogger, "E", e);
        }

        String userQuery = "UserName = '" + user;
        if (domain != null) {
            userQuery = userQuery.concat("' and UserName/@Domain = '" + domain + "' ");
        } else {
            userQuery = userQuery.concat("' and not(UserName/@Domain)");
        }

        TXQuery query = TXQuery.newInstance("update insert <Role>" + role + "</Role> " +
                            "into input()/UserRoleMapping[" + userQuery + "]");
        try {
            TResponse response = objectAccessor.xquery(query);
            TXMLObjectIterator iter = response.getXMLObjectIterator();
            if (iter == null || !iter.hasNext()) {
                String userUpdate = "<UserName";
                if (domain != null)
                    userUpdate = userUpdate.concat(" Domain='" + domain + "'");

                userUpdate = userUpdate.concat(">" + user + "</UserName>");

                TXMLObject xmlobj = TXMLObject.newInstance(
                    "<UserRoleMapping>" + userUpdate +
                    "<Role>" + role + "</Role></UserRoleMapping>");
                try {
                    response = objectAccessor.insert(xmlobj);
                } catch (TInsertException e) {
                    throw new URMInsertException(msLogger, "E", e);
                }
            }
//          if (accessCacheAllowed()){
                if (roleUserMappingCache != null) roleUserMappingCache.remove(userdomain);
                if (userRoleMappingCache != null) userRoleMappingCache.remove(role);
                if (allRoleUserMappingCache != null) allRoleUserMappingCache.clear();
//          }
            resetCaches();
        } catch (TXQueryException e) {
            throw new URMInsertException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMInsertException)
            throw (URMInsertException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    public void addGroupLink(String role, String domain, String group)
            throws URMNotImplementedException, URMForbiddenException, URMInsertException, URMInternalServerException {


    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(UPDATE)) == null)
            throw new URMInsertException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        try {
            Set rset = this.getRoleMappingOfGroup(group, domain);
            if (rset != null) {
                Iterator riter = rset.iterator();
                while (riter.hasNext())
                    if (role.equals(((URMSubject)(riter.next())).getName()))
                        throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0011", role, group, domain));
            }
        } catch (URMInternalServerException e) {
            throw new URMInsertException(msLogger, "E", e);
        }

        String userQuery = "GroupName = '" + group;
        if (domain != null) {
            userQuery = userQuery.concat("' and GroupName/@Domain = '" + domain + "' ");
        } else {
            userQuery = userQuery.concat("' and not(GroupName/@Domain)");
        }

        TXQuery query = TXQuery.newInstance("update insert <Role>" + role + "</Role> " +
                            "into input()/UserRoleMapping[" + userQuery + "]");
        try {
            TResponse response = objectAccessor.xquery(query);
            TXMLObjectIterator iter = response.getXMLObjectIterator();
            if (iter == null || !iter.hasNext()) {
                String userUpdate = "<GroupName";
                if (domain != null)
                    userUpdate = userUpdate.concat(" Domain='" + domain + "'");

                userUpdate = userUpdate.concat(">" + group + "</GroupName>");

                TXMLObject xmlobj = TXMLObject.newInstance(
                    "<UserRoleMapping>" + userUpdate +
                    "<Role>" + role + "</Role></UserRoleMapping>");
                try {
                    response = objectAccessor.insert(xmlobj);
                } catch (TInsertException e) {
                    throw new URMInsertException(msLogger, "E", e);
                }
            }
            // delete group from cache
//          if (accessCacheAllowed()){
                String groupdomain = null;
                if ((domain == null) || (domain.equals(""))) groupdomain = group;
                else groupdomain = group + ":" + domain;
                if (roleGroupMappingCache != null) roleGroupMappingCache.remove(groupdomain);
                if (groupRoleMappingCache != null) groupRoleMappingCache.remove(role);
                if (allRoleGroupMappingCache != null) allRoleGroupMappingCache.clear();
//          }
            resetCaches();
        } catch (TXQueryException e) {
            throw new URMInsertException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMInsertException)
            throw (URMInsertException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    public void addAncestor(String role, String ancestor)
            throws URMNotImplementedException, URMForbiddenException,
                   URMInsertException, URMInternalServerException {

    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(UPDATE)) == null)
            throw new URMInsertException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        // Check that Ancestor is an existing Role
        if (!this.isRole(ancestor)) {
            throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0005", ancestor));
        }

        // See if the ancestor chain does not contain a circular dependency.
        try {
            checkRoleCircularDependency(ancestor, role);
        } catch (URMForbiddenException e) {
            throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0044", ancestor, role));
        }

        TXQuery query = TXQuery.newInstance("update insert <AncestorRole>" + ancestor + "</AncestorRole>" +
            " into input()/Role[RoleName = '" + role + "']");
        try {
            TResponse response = objectAccessor.xquery(query);
            
//            if (accessCacheAllowed()){
                if (ancestorCache != null) ancestorCache.remove(role);
                if (allAncestorCache != null) allAncestorCache.clear();;
                if (rolesOfAncestorCache != null) rolesOfAncestorCache.clear();
//            }
            resetCaches();
            
        } catch (TXQueryException e) {
            throw new URMInsertException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        else if (e instanceof URMInsertException)
            throw (URMInsertException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    public void deleteUserLink(String role, String user, String domain)
            throws URMNotImplementedException, URMForbiddenException, URMDeleteException, URMInternalServerException {

    // delete user from cache
    String userdomain = null;
    if ((domain == null) || (domain.equals(""))) userdomain = user;
    else userdomain = user + ":" + domain;

    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(UPDATE)) == null)
            throw new URMDeleteException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        TXQuery xquery = TXQuery.newInstance("update delete " +
                "input()/UserRoleMapping[UserName = '" + user + "' and " +
                 (domain == null ? "not(UserName/@Domain)" : "UserName/@Domain = '" + domain + "'") +
                 "]/Role[text() = '" + role + "']");
        try {
            TResponse response = objectAccessor.xquery(xquery);
            if (response.getFirstXMLObject() == null)
                throw new URMDeleteException(MessageLogger.getAndLogMessage(msLogger, "URMTRE0014", user, domain, role));
//            if (accessCacheAllowed()){
                if (roleUserMappingCache != null) roleUserMappingCache.remove(userdomain);
                if (allRoleUserMappingCache != null) allRoleUserMappingCache.clear();
                if (userRoleMappingCache != null) userRoleMappingCache.remove(role);
//            }
            resetCaches();
        } catch (TXQueryException e) {
            throw new URMDeleteException(msLogger, "E", e);
        }

    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMDeleteException)
            throw (URMDeleteException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    public void deleteGroupLink(String role, String group, String domain)
            throws URMNotImplementedException, URMForbiddenException, URMDeleteException, URMInternalServerException {

    String groupdomain = null;
    if ((domain == null) || (domain.equals(""))) groupdomain = group;
    else groupdomain = group + ":" + domain;

    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(UPDATE)) == null)
            throw new URMDeleteException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        TXQuery query = TXQuery.newInstance("update delete " +
                "input()/UserRoleMapping[GroupName = '" + group + "' and " +
                 (domain == null ? "not(GroupName/@Domain)" : "GroupName/@Domain = '" + domain + "'") +
                "]/Role[text() = '" + role + "']");
        try {
            TResponse response = objectAccessor.xquery(query);
            if (response.getFirstXMLObject() == null)
                throw new URMDeleteException(MessageLogger.getAndLogMessage(msLogger, "URMTRE0015", group, domain, role));
            // delete group from cache
//            if (accessCacheAllowed()){
                if (roleGroupMappingCache != null) roleGroupMappingCache.remove(groupdomain);
                if (allRoleGroupMappingCache != null) allRoleGroupMappingCache.clear();
                if (groupRoleMappingCache != null) groupRoleMappingCache.remove(role);
//            }
            resetCaches();
        } catch (TXQueryException e) {
            throw new URMDeleteException(msLogger, "E", e);
        }

        
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMDeleteException)
            throw (URMDeleteException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    public void deleteAncestor(String role, String ancestor)
            throws URMNotImplementedException, URMForbiddenException, URMDeleteException, URMInternalServerException {

    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(UPDATE)) == null)
            throw new URMDeleteException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        TXQuery query = TXQuery.newInstance("update delete " +
            "input()/Role[RoleName = '" + role + "']/AncestorRole[text() = '" + ancestor + "']");
        try {
            TResponse response = objectAccessor.xquery(query);
            if (response.getFirstXMLObject() == null)
                throw new URMDeleteException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0055", ancestor));
//            if (tConn.accessCache()) {
            if (ancestorCache != null) ancestorCache.remove(role);
            if (allAncestorCache != null) allAncestorCache.clear();
            if (rolesOfAncestorCache != null) rolesOfAncestorCache.clear();
//            }
            resetCaches();
            
        } catch (TXQueryException e) {
            throw new URMDeleteException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMDeleteException)
            throw (URMDeleteException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    public Set getRoleMappingOfUser(String user, String domain)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {

    String userdomain = null;
    if ((domain == null) || (domain.equals(""))) userdomain = user;
    else userdomain = user + ":" + domain;

        if (roleUserMappingCache != null /*&& accessCacheAllowed()*/) {
        Set result = (Set) roleUserMappingCache.get(userdomain);
        if (result != null) return result;
    }

    try {



        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(QUERY)) == null)
            throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        String roleQuery = "UserName = '" + user;
        if (domain != null) {
            roleQuery = roleQuery.concat("' and $b/UserName/@Domain = '" + domain + "' ");
        } else {
            roleQuery = roleQuery.concat("' and not($b/UserName/@Domain) ");
        }

        TXQuery query = TXQuery.newInstance("for    $b in input()/UserRoleMapping " +
                                            "where  $b/" + roleQuery +
                                            "return $b/Role");
        try {
            TResponse response = objectAccessor.xquery(query);
            TXMLObjectIterator iter = response.getXMLObjectIterator();
            HashSet roles = new HashSet();
            while (iter != null && iter.hasNext()) {
                TXMLObject tobj = iter.next();
                Object obj_el = tobj != null ? tobj.getElement() : null;
                if (obj_el != null && obj_el instanceof Element) {
                    Node node = ((Element)obj_el).getFirstChild();
                    if (node != null) {
                        String rolename = node.getNodeValue();
                        roles.add(new URMSubjectImpl(node.getNodeValue(),
                                                     org.apache.slide.urm.common.URMConstants.ROLE,
                                                     null));
                    }
                }
            }

            if (roleUserMappingCache != null /*&& tConn.accessCache()*/) roleUserMappingCache.add(userdomain, roles);
            return roles;
        } catch (TXQueryException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TNoSuchXMLObjectException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TIteratorException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }

    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    public Set getAllRoleMappingOfUser(String user, String domain)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {

    String userdomain = null;
    if ((domain == null) || (domain.equals(""))) userdomain = user;
    else userdomain = user + ":" + domain;

        if (allRoleUserMappingCache != null /*&& accessCacheAllowed()*/) {
        Set result = (Set) allRoleUserMappingCache.get(userdomain);
        if (result != null) return result;
    }

    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(QUERY)) == null)
            throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        String roleQuery = "UserName = '" + user;
        if (domain != null) {
            roleQuery = roleQuery.concat("' and $b/UserName/@Domain = '" + domain + "' ");
        } else {
            roleQuery = roleQuery.concat("' and not($b/UserName/@Domain) ");
        }

        TXQuery query = TXQuery.newInstance("for    $b in input()/UserRoleMapping " +
                                            "where  $b/" + roleQuery +
                                            "return $b/Role");
        try {
            TResponse response = objectAccessor.xquery(query);
            TXMLObjectIterator iter = response.getXMLObjectIterator();
            HashSet roles = new HashSet();
            while (iter != null && iter.hasNext()) {
                TXMLObject tobj = iter.next();
                Object obj_el = tobj != null ? tobj.getElement() : null;
                if (obj_el != null && obj_el instanceof Element) {
                    Node node = ((Element)obj_el).getFirstChild();
                    if (node != null) {
                        String rolename = node.getNodeValue();
                        roles.add(new URMSubjectImpl(rolename,
                                                     org.apache.slide.urm.common.URMConstants.ROLE,
                                                     null));
                        Set roleSet = this.getAllAncestors(rolename);
                       roles.addAll(roleSet);
                    }
                }
            }
            if (allRoleUserMappingCache != null /*&& tConn.accessCache()*/) allRoleUserMappingCache.add(userdomain, roles);
            return roles;
        } catch (TXQueryException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TNoSuchXMLObjectException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TIteratorException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    public Set getRoleMappingOfGroup(String group, String domain)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {

    String groupdomain = null;
    if ((domain == null) || (domain.equals(""))) groupdomain = group;
    else groupdomain = group + ":" + domain;

    // delete group from cache
        if (roleGroupMappingCache != null /*&& accessCacheAllowed()*/) {
        Set result = (Set) roleGroupMappingCache.get(groupdomain);
        if (result != null) return result;
    }

    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(QUERY)) == null)
            throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        String roleQuery = "GroupName = '" + group;
        if (domain != null) {
            roleQuery = roleQuery.concat("' and $b/GroupName/@Domain = '" + domain + "' ");
        } else {
            roleQuery = roleQuery.concat("' and not($b/GroupName/@Domain) ");
        }

        TXQuery query = TXQuery.newInstance("for    $b in input()/UserRoleMapping " +
                                            "where  $b/" + roleQuery +
                                            "return $b/Role");
        try {
            TResponse response = objectAccessor.xquery(query);
            TXMLObjectIterator iter = response.getXMLObjectIterator();
            HashSet roles = new HashSet();
            while (iter != null && iter.hasNext()) {
                TXMLObject tobj = iter.next();
                Object obj_el = tobj != null ? tobj.getElement() : null;
                if (obj_el != null && obj_el instanceof Element) {
                    Node node = ((Element)obj_el).getFirstChild();
                    if (node != null) {
                        roles.add(new URMSubjectImpl(node.getNodeValue(),
                                                     org.apache.slide.urm.common.URMConstants.ROLE,
                                                     null));
                    }
                }
            }
            if (roleGroupMappingCache != null /*&& tConn.accessCache()*/) roleGroupMappingCache.add(groupdomain, roles);
            return roles;
        } catch (TXQueryException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TNoSuchXMLObjectException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TIteratorException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }

    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    public Set getAllRoleMappingOfGroup(String group, String domain)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {

    // delete group from cache
    String groupdomain = null;
    if ((domain == null) || (domain.equals(""))) groupdomain = group;
    else groupdomain = group + ":" + domain;

        if (allRoleGroupMappingCache != null /*&& accessCacheAllowed()*/) {
        Set result = (Set) allRoleGroupMappingCache.get(groupdomain);
        if (result != null) return result;
    }

    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(QUERY)) == null)
            throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        String roleQuery = "GroupName = '" + group;
        if (domain != null) {
            roleQuery = roleQuery.concat("' and $b/GroupName/@Domain = '" + domain + "' ");
        } else {
            roleQuery = roleQuery.concat("' and not($b/GroupName/@Domain) ");
        }

        TXQuery query = TXQuery.newInstance("for    $b in input()/UserRoleMapping " +
                                            "where  $b/" + roleQuery +
                                            "return $b/Role");
        try {
            TResponse response = objectAccessor.xquery(query);
            TXMLObjectIterator iter = response.getXMLObjectIterator();
            HashSet roles = new HashSet();
            while (iter != null && iter.hasNext()) {
                TXMLObject tobj = iter.next();
                Object obj_el = tobj != null ? tobj.getElement() : null;
                if (obj_el != null && obj_el instanceof Element) {
                    Node node = ((Element)obj_el).getFirstChild();
                    if (node != null) {
                        String rolename = node.getNodeValue();
                        roles.add(new URMSubjectImpl(rolename,
                                                     org.apache.slide.urm.common.URMConstants.ROLE,
                                                     null));
                        Set roleSet = this.getAllAncestors(rolename);
                        Iterator roleIter = roleSet.iterator();
                        roles.addAll(roleSet);
                     }
                }
            }
            if (allRoleGroupMappingCache != null /*&& tConn.accessCache()*/) allRoleGroupMappingCache.add(groupdomain, roles);
            return roles;
        } catch (TXQueryException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TNoSuchXMLObjectException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TIteratorException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    public Set getUserMappingOfRole(String role)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {

        if (userRoleMappingCache != null /*&& accessCacheAllowed()*/) {
        Set result = (Set) userRoleMappingCache.get(role);
        if (result != null) return result;
    }

    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(QUERY)) == null)
            throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();
        TXQuery query = TXQuery.newInstance("for    $b in input()/UserRoleMapping " +
                                            "where  $b/Role = '" + role + "' " +
                                            "return $b/UserName");
        try {
            TResponse response = objectAccessor.xquery(query);
            TXMLObjectIterator iter = response.getXMLObjectIterator();
            HashSet users = new HashSet();
            while (iter != null && iter.hasNext()) {
                String userName = null, userDomain = null;
                TXMLObject tobj = iter.next();
                Object obj_el = tobj != null ? tobj.getElement() : null;
                if (obj_el != null && obj_el instanceof Element) {
                    Node node = ((Element)obj_el).getFirstChild();
                    if (node != null) {
                        userName = node.getNodeValue();
                    }

                    NamedNodeMap usrAttr = ((Element)obj_el).getAttributes();
                    if (usrAttr != null) {
                        Node usrDomainNode = usrAttr.getNamedItem("Domain");
                        if (usrDomainNode != null) {
                            userDomain = usrDomainNode.getNodeValue();
                        }
                    }

                    if (userName != null) {
                        URMSubject urmSubject = new URMSubjectImpl(userName,
                                                                   org.apache.slide.urm.common.URMConstants.USER,
                                                                   userDomain);
                        users.add(urmSubject);
                    }
                }
            }
            if (userRoleMappingCache != null /*&& tConn.accessCache()*/) userRoleMappingCache.add(role, users);
            return users;
        } catch (TXQueryException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TNoSuchXMLObjectException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TIteratorException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    public Set getGroupMappingOfRole(String role)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {
        if (groupRoleMappingCache != null /*&& accessCacheAllowed()*/) {
        Set result = (Set) groupRoleMappingCache.get(role);
        if (result != null) return result;
    }

    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(QUERY)) == null)
            throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();
        TXQuery query = TXQuery.newInstance("for    $b in input()/UserRoleMapping " +
                                            "where  $b/Role = '" + role + "' " +
                                            "return $b/GroupName");
        try {
            TResponse response = objectAccessor.xquery(query);
            TXMLObjectIterator iter = response.getXMLObjectIterator();
            HashSet groups = new HashSet();
            while (iter != null && iter.hasNext()) {
                String groupName = null, groupDomain = null;
                TXMLObject tobj = iter.next();
                Object obj_el = tobj != null ? tobj.getElement() : null;
                if (obj_el != null && obj_el instanceof Element) {
                    Node node = ((Element)obj_el).getFirstChild();
                    if (node != null){
                        groupName = node.getNodeValue();
                    }

                    NamedNodeMap usrAttr = ((Element)obj_el).getAttributes();
                    if (usrAttr != null) {
                        Node usrDomainNode = usrAttr.getNamedItem("Domain");
                        if (usrDomainNode != null) {
                            groupDomain = usrDomainNode.getNodeValue();
                        }
                    }

                    if (groupName != null) {
                        URMSubject urmSubject = new URMSubjectImpl(groupName,
                                                                   org.apache.slide.urm.common.URMConstants.GROUP,
                                                                   groupDomain);
                        groups.add(urmSubject);
                    }
                }
            }
            if (groupRoleMappingCache != null /*&& tConn.accessCache()*/) groupRoleMappingCache.add(role, groups);
            return groups;
        } catch (TXQueryException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TNoSuchXMLObjectException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TIteratorException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    public Set getAncestors(String role)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {

        if (ancestorCache != null /*&& accessCacheAllowed()*/){
        Set result  = (Set)ancestorCache.get(role);
        if (result != null) return result;
    }
    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(QUERY)) == null)
            throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();
        TXQuery query = TXQuery.newInstance("for    $b in input()/Role " +
                                            "where  $b/RoleName = '" + role + "' " +
                                            "return $b/AncestorRole");
        try {
            TResponse response = objectAccessor.xquery(query);
            TXMLObjectIterator iter = response.getXMLObjectIterator();
            HashSet ancestors = new HashSet();
            while (iter != null && iter.hasNext()) {
                TXMLObject tobj = iter.next();
                Object obj_el = tobj != null ? tobj.getElement() : null;
                if (obj_el != null && obj_el instanceof Element) {
                    Node node = ((Element)obj_el).getFirstChild();
                    if (node != null) {
                        String rolename = node.getNodeValue();
                        URMSubject urmSubject = new URMSubjectImpl(rolename,
                                                                   org.apache.slide.urm.common.URMConstants.ROLE,
                                                                   null);

                        ancestors.add(urmSubject);
                    }
                }
            }
            if (ancestorCache != null /*&& tConn.accessCache()*/) ancestorCache.add(role, ancestors);
            return ancestors;
        } catch (TXQueryException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TNoSuchXMLObjectException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TIteratorException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    public Set getAllAncestors(String role)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {

        if (allAncestorCache != null /*&& accessCacheAllowed()*/){
        Set result  = (Set)allAncestorCache.get(role);
        if (result != null) return result;
    }

    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(QUERY)) == null)
            throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        Set resultSet = new HashSet();
        readAllAncestorRoles(role, resultSet);
        if (allAncestorCache != null /*&& tConn.accessCache()*/) allAncestorCache.add(role, resultSet);
        return resultSet;
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    public Set getRolesOfAncestor(String role)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException {

        if (rolesOfAncestorCache != null /*&& accessCacheAllowed()*/){
        Set result  = (Set)rolesOfAncestorCache.get(role);
        if (result != null) return result;
    }

    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(QUERY)) == null)
            throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        TXQuery query = TXQuery.newInstance("for    $b in input()/Role " +
                                            "where  $b/AncestorRole = '" + role + "' " +
                                            "return $b/RoleName");
        try {
            TResponse response = objectAccessor.xquery(query);
            TXMLObjectIterator iter = response.getXMLObjectIterator();
            HashSet ancestors = new HashSet();
            while (iter != null && iter.hasNext()) {
                TXMLObject tobj = iter.next();
                Object obj_el = tobj != null ? tobj.getElement() : null;
                if (obj_el != null && obj_el instanceof Element) {
                    Node node = ((Element)obj_el).getFirstChild();
                    if (node != null) {
                        String rolename = node.getNodeValue();
                        URMSubject urmSubject = new URMSubjectImpl(rolename,
                                                                   org.apache.slide.urm.common.URMConstants.ROLE,
                                                                   null);

                        ancestors.add(urmSubject);
                    }
                }
            }
            if (rolesOfAncestorCache != null /*&& tConn.accessCache()*/) rolesOfAncestorCache.add(role, ancestors);
            return ancestors;
        } catch (TXQueryException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TNoSuchXMLObjectException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TIteratorException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }

    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMNotImplementedException)
            throw (URMNotImplementedException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

        public void close() throws URMCloseConnectionException {
/*
        try {
            if (!mIsAlreadyClosed) {
                mIsAlreadyClosed = true;
                // mConnection.close();  not set anymore !
            }
        } catch (TConnectionCloseException e) {
            throw new URMCloseConnectionException(msLogger, "E", e);
        }
*/
    }

    public void beginTransaction() throws URMDBTransactionException, URMInternalServerException {
        // nothing to do here
    }

    public void endTransaction(boolean manner) throws URMDBTransactionException, URMInternalServerException {

        // need to clear all caches
        if (manner == true) {
            if (isRoleCache != null) isRoleCache.clear();
            if (roleProfileCache != null) roleProfileCache.clear();
            if (preDefActionCache != null) preDefActionCache.clear();
            if (roleUserMappingCache != null) roleUserMappingCache.clear();
            if (roleGroupMappingCache != null) roleGroupMappingCache.clear();
            if (userRoleMappingCache != null) userRoleMappingCache.clear();
            if (groupRoleMappingCache != null) groupRoleMappingCache.clear();
            if (allRoleUserMappingCache != null) allRoleUserMappingCache.clear();
            if (allRoleGroupMappingCache != null) allRoleGroupMappingCache.clear();
            if (ancestorCache != null) ancestorCache.clear();
            if (allAncestorCache != null) allAncestorCache.clear();
            if (rolesOfAncestorCache != null) rolesOfAncestorCache.clear();
            resetCaches();
        }
        
    }

//    private static URMConnectionException newConvertedException(
//                                        TException srcEx, String prefixStr) {
//        TException de = srcEx.getDeepestTException();
//        if (de != null && de instanceof TAuthorizationException)
//            if (srcEx.hasAccessFailureException())
//                return new URMConnectionException(
//                            (prefixStr != null ? prefixStr : "") +
//                            srcEx.getAccessFailureException());
//            else
//                return new URMConnectionException(
//                            (prefixStr != null ? prefixStr : "") +
//                            srcEx.getDeepestTException().getMessage());
//        else
//            if (srcEx.hasAccessFailureException())
//                return new URMConnectionException(
//                            (prefixStr != null ? prefixStr : "") +
//                            srcEx.getAccessFailureException());
//            else
//                return new URMConnectionException((prefixStr != null ? prefixStr : "") +
//                            srcEx.getDeepestTException().getMessage());
//    }

    /*
     * Check via the TaminoConnection object, if we can access the cache
     */
//    private boolean accessCacheAllowed()
//        throws URMInternalServerException {
//        if (mConn == null)
//            try {
//                mConn = URMTaminoConnectionHandler.getInstance(mConfigurator);
//            } catch (Exception e) {
//                throw new URMInternalServerException(msLogger, "URMCOF0047", e);
//            }
//
//        return mConn.accessCache(mOwner);
//    }

    /*
     * Always perform this at the beginning of each method
     */
    private URMTaminoConnection prologue(int mode)
        throws URMInternalServerException {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;

//        if (mIsAlreadyClosed) {
//            throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
//        }

        if (mConn == null)
            try {
                mConn = URMTaminoConnectionHandler.getInstance(mConfigurator);
            } catch (Exception e) {
                throw new URMInternalServerException(msLogger, "URMCOF0047", e);
            }

        try {
            tConn = mConn.getObjectAccessor(mode, mOwner);
        } catch (URMDBTransactionException e) {
            throw new URMInternalServerException(msLogger, "URMCOF0047", e);
        } catch (URMConnectionException e) {
        if (msLogger.isInfoEnabled())
            throw new URMInternalServerException(msLogger, "URMCOF0047", e);
        }
        if (tConn == null) throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOF0047"));
        return tConn;
    }

    /*
     * Always perform this at the end of each method
     */
    private boolean epilogue(boolean commit) throws URMInternalServerException {
        try {
            return mConn.releaseConnection(commit, mOwner);
        } catch (URMConnectionException e) {
            throw new URMInternalServerException(msLogger, "URMCOF0048", e);
        }
    }

    /*
     * Always perform this at the end of each method
     */
    private boolean epilogueTA(boolean commit) throws URMInternalServerException {
        try {
            return mConn.releaseTAConnection(commit, mOwner);
        } catch (URMConnectionException e) {
            throw new URMInternalServerException(msLogger, "URMCOF0048", e);
        }
    }

    private void readAllAncestorRoles(String role, Set resultSet)
            throws URMNotImplementedException, URMForbiddenException, URMInternalServerException{

        Set roles = this.getAncestors(role);
        for (Iterator iter = roles.iterator(); iter.hasNext(); ) {
            URMSubject arole = (URMSubject)iter.next();
            if (!resultSet.contains(arole)) {
                resultSet.add(arole);
                readAllAncestorRoles(arole.getName(), resultSet);
            }
        }
    
    }
    /*
     * Call this function recursively before adding a new ancestor role.
     * Since nesting of role is not limited, we need to guarantee that no
     * circular dependency is created.
     *
     * @param newRole - the new role to be added as ancestor
     * @param current - the current (parent) to be checked
     */
    private void checkRoleCircularDependency(String newRole, String current)
        throws URMForbiddenException, URMInternalServerException {

    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(QUERY)) == null)
            throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        if (newRole.equals(current)) {
            throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0044", current, newRole));
        }
        Set newset = new HashSet();
        TXQuery xquery = TXQuery.newInstance("for    $b in input()/Role " +
                                             "where  $b/AncestorRole = '" + current + "' " +
                                             "return $b/RoleName");
        try {
            TResponse response = objectAccessor.xquery(xquery);
            TXMLObjectIterator iter = response.getXMLObjectIterator();

            while (iter != null && iter.hasNext()) {
                TXMLObject tobj;
                tobj = iter.next();
                Object obj_el = tobj != null ? tobj.getElement() : null;
                if (obj_el != null && obj_el instanceof Element) {
                    Node node = ((Element)obj_el).getFirstChild();
                    newset.add(node.getNodeValue());
                }
            }
        } catch (TXQueryException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (TNoSuchXMLObjectException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        } catch (TIteratorException e) {
            throw new URMForbiddenException(msLogger, "E", e);
        }
        Iterator iter = newset.iterator();
        while (iter!= null && iter.hasNext()) {
            checkRoleCircularDependency(newRole, (String) iter.next());
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
       epilogue(true);
    }
    }

    public void synchronizeUsersGroupsRoles(String domain, Set existingUsers, Set existingGroups)
            throws URMInternalServerException, URMDeleteException {

    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(UPDATE)) == null)
            throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        Set sbjs = getNeedlessMappedSubjects(domain, existingUsers, existingGroups);
        // domain also can be here an attribute -- for better performance
        //removeACLsOfSOwner(sbjs); // ACLs should not be deleted
        removeACEsOfSubjects(sbjs);
        URMAccessControlerSpiTamino.clearAclCache();
        removeUserRoleMapping(sbjs);
        // user-role mapping cache clear should be here
        if (roleUserMappingCache != null) roleUserMappingCache.clear();
        if (roleGroupMappingCache != null) roleGroupMappingCache.clear();
        if (userRoleMappingCache != null) userRoleMappingCache.clear();
        if (groupRoleMappingCache != null) groupRoleMappingCache.clear();
        if (allRoleUserMappingCache != null) allRoleUserMappingCache.clear();
        if (allRoleGroupMappingCache != null) allRoleGroupMappingCache.clear();
        resetCaches();
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        else if (e instanceof URMDeleteException)
            throw (URMDeleteException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    public Set getAvailableDomains() throws URMInternalServerException {
        // if tamino will have the function distinct-values(...) it will be easier and faster

    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(QUERY)) == null)
            throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

        HashSet dmns = new HashSet();
        try {
            // in UserRoleMapping
            TXQuery query = TXQuery.newInstance("count(input()/UserRoleMapping[not(//@Domain)])");
            TResponse response = objectAccessor.xquery(query);
            TXMLObjectIterator iter = response.getXMLObjectIterator();
            if (iter != null && iter.hasNext()) {
                TXMLObject tobj = iter.next();
                Object obj_el = tobj != null ? tobj.getElement() : null;
                if (obj_el != null && obj_el instanceof Element) {
                    Node tnode = ((Node)obj_el).getFirstChild();
                    if (tnode != null && tnode.getNodeType() == Node.TEXT_NODE) {
                        String tval = tnode.getNodeValue();
                        if (tval != null) {
                            int num = 0;
                            try {
                                num = Integer.parseInt(tval);
                            } catch (NumberFormatException e1) {}
                            if (num > 0)
                                dmns.add(null);
                        }
                    }
                }
            }
            query = TXQuery.newInstance("for $b in input()/UserRoleMapping" +
                                        " where $b//@Domain return $b//@Domain");
            response = objectAccessor.xquery(query);
            iter = response.getXMLObjectIterator();
            while (iter != null && iter.hasNext()) {
                TXMLObject tobj = iter.next();
                Object obj_el = tobj != null ? tobj.getElement() : null;
                if (obj_el != null && obj_el instanceof Element) {
                    Node tnode = ((Node)obj_el).getFirstChild();
                    if (tnode != null && tnode.getNodeType() != Node.TEXT_NODE) {
                        String tval = tnode.getNodeValue();
                        if (tval != null && !dmns.contains(tval))
                            dmns.add(tval);
                    }
                }
            }
            // in AccessControlList
            query = TXQuery.newInstance("count(input()/AccessControlList[not(//@Domain)])");
            response = objectAccessor.xquery(query);
            iter = response.getXMLObjectIterator();
            if (iter != null && iter.hasNext()) {
                TXMLObject tobj = iter.next();
                Object obj_el = tobj != null ? tobj.getElement() : null;
                if (obj_el != null && obj_el instanceof Element) {
                    Node tnode = ((Node)obj_el).getFirstChild();
                    if (tnode != null && tnode.getNodeType() == Node.TEXT_NODE) {
                        String tval = tnode.getNodeValue();
                        if (tval != null) {
                            int num = 0;
                            try {
                                num = Integer.parseInt(tval);
                            } catch (NumberFormatException e1) {}
                            if (num > 0)
                                dmns.add(null);
                        }
                    }
                }
            }
            query = TXQuery.newInstance("for $b in input()/AccessControlList where $b//@Domain return $b/@Domain");
            response = objectAccessor.xquery(query);
            iter = response.getXMLObjectIterator();
            while (iter != null && iter.hasNext()) {
                TXMLObject tobj = iter.next();
                Object obj_el = tobj != null ? tobj.getElement() : null;
                if (obj_el != null && obj_el instanceof Element) {
                    Node tnode = ((Node)obj_el).getFirstChild();
                    if (tnode != null && tnode.getNodeType() != Node.TEXT_NODE) {
                        String tval = tnode.getNodeValue();
                        if (tval != null && !dmns.contains(tval))
                            dmns.add(tval);
                    }
                }
            }
        } catch (TXQueryException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TNoSuchXMLObjectException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TIteratorException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }

        return dmns;
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    // private methodes for synchronize
    private Set getNeedlessMappedSubjects(String domain, Set existingUsers, Set existingGroups)
            throws URMInternalServerException {

    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(QUERY)) == null)
            throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();
        HashSet subjs = new HashSet();
        try {
            TXQuery query = TXQuery.newInstance("for    $b in input()/UserRoleMapping " +
                                                "where " + (domain != null ? "$b//@Domain = '"+domain+"'"
                                                    : "not($b//@Domain)") + " return $b");
            TResponse response = objectAccessor.xquery(query);
            TXMLObjectIterator iter = response.getXMLObjectIterator();
            URMSubject subj = null;
            String nn = null;
            while (iter != null && iter.hasNext()) {
                TXMLObject tobj = iter.next();
                Object obj_el = tobj != null ? tobj.getElement() : null;
                if (obj_el != null && obj_el instanceof Element) {
                    Node node = ((Node)obj_el).getFirstChild();
                    int type = 0;
                    String name = null;
                    while (node != null && (nn = node.getNodeName()) != null) {
                        if (nn.equals("UserName")) {
                            type = URMConstants.USER;
                            break;
                        }
                        else if (nn.equals("GroupName")) {
                            type = URMConstants.GROUP;
                            break;
                        }
                        node = node.getNextSibling();
                    }

                    if (type == 0)
                        continue;

                    Node tnode = (Node)node.getFirstChild();
                    while (tnode != null && tnode.getNodeType() != Node.TEXT_NODE)
                        tnode = tnode.getNextSibling();
                    if (tnode == null || (name = tnode.getNodeValue()) == null)
                        continue;
                    if (type == URMConstants.USER) {
                        if (existingUsers.contains(name))
                            continue;
                    }
                    else if (existingGroups.contains(name))
                            continue;
                    subjs.add(new URMSubjectImpl(name, type, domain));
                }
            }
            query = TXQuery.newInstance("for    $b in input()/AccessControlList/Owner " +
                                        "where " + (domain != null ? "$b/@Domain = '"+domain+"'"
                                            : "not($b/@Domain)") +
                                        " and ($b/@Type = "+String.valueOf(URMConstants.USER)+
                                        " or $b/@Type = "+String.valueOf(URMConstants.GROUP)+") "+
                                        "return $b");
            response = objectAccessor.xquery(query);
            iter = response.getXMLObjectIterator();
            subj = null;
            while (iter != null && iter.hasNext()) {
                TXMLObject tobj = iter.next();
                Object obj_el = tobj != null ? tobj.getElement() : null;
                if (obj_el != null && obj_el instanceof Element) {
                    String stype = ((Element)obj_el).getAttribute("Type");
                    int type = 0;
                    if (stype.equals(String.valueOf(URMConstants.USER)))
                        type = URMConstants.USER;
                    else if (stype.equals(String.valueOf(URMConstants.GROUP)))
                        type = URMConstants.GROUP;
                    
                    if (type == 0)
                        continue;
                    
                    String name = null;
                    Node tnode = ((Node)obj_el).getFirstChild();
                    while (tnode != null && tnode.getNodeType() != Node.TEXT_NODE)
                        tnode = tnode.getNextSibling();
                    if (tnode == null || (name = tnode.getNodeValue()) == null)
                        continue;
                    if (type == URMConstants.USER) {
                        if (existingUsers.contains(name))
                            continue;
                    }
                    else if (existingGroups.contains(name))
                            continue;
                    subjs.add(new URMSubjectImpl(name, type, domain));
                }
            }
            query = TXQuery.newInstance("for    $b in input()/AccessControlList/ACE/Subject " +
                                        "where " + (domain != null ? "$b/@Domain = '"+domain+"'"
                                            : "not($b/@Domain)") +
                                        " and ($b/@Type = "+String.valueOf(URMConstants.USER)+
                                        " or $b/@Type = "+String.valueOf(URMConstants.GROUP)+") "+
                                        "return $b");
            response = objectAccessor.xquery(query);
            iter = response.getXMLObjectIterator();
            subj = null;
            while (iter != null && iter.hasNext()) {
                TXMLObject tobj = iter.next();
                Object obj_el = tobj != null ? tobj.getElement() : null;
                if (obj_el != null && obj_el instanceof Element) {
                    String stype = ((Element)obj_el).getAttribute("Type");
                    int type = 0;
                    if (stype.equals(String.valueOf(URMConstants.USER)))
                        type = URMConstants.USER;
                    else if (stype.equals(String.valueOf(URMConstants.GROUP)))
                        type = URMConstants.GROUP;
                    
                    if (type == 0)
                        continue;
                    
                    String name = null;
                    Node tnode = ((Node)obj_el).getFirstChild();
                    while (tnode != null && tnode.getNodeType() != Node.TEXT_NODE)
                        tnode = tnode.getNextSibling();
                    if (tnode == null || (name = tnode.getNodeValue()) == null)
                        continue;
                    if (type == URMConstants.USER) {
                        if (existingUsers.contains(name))
                            continue;
                    }
                    else if (existingGroups.contains(name))
                            continue;
                    subjs.add(new URMSubjectImpl(name, type, domain));
                }
            }
        } catch (TXQueryException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TNoSuchXMLObjectException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } catch (TIteratorException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }

        return subjs;

    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    private void removeACEsOfSubjects(Set subjects) throws URMDeleteException, URMInternalServerException {
    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(UPDATE)) == null)
            throw new URMDeleteException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();
        Iterator subjs = subjects.iterator();
        String wherestr = null;
        if (subjs.hasNext()) {
            URMSubject subj = (URMSubject)subjs.next();
            String domain = subj.getDomain();
            wherestr = "(Subject = '" + subj.getName() + "' and Subject/@Type = "
                            + String.valueOf(subj.getType()) + " and " +
                            (domain != null ? "Subject/@Domain = '"+domain+"')"
                                : "not(Subject/@Domain))");
            while (subjs.hasNext()) {
                subj = (URMSubject)subjs.next();
                domain = subj.getDomain();
                wherestr += (" or (Subject = '" + subj.getName() + "' and Subject/@Type = "
                            + String.valueOf(subj.getType()) + " and " +
                            (domain != null ? "Subject/@Domain = '"+domain+"')"
                                : "not(Subject/@Domain))"));
            }
        }
        if (wherestr == null)
            return;
        TXQuery query = TXQuery.newInstance("update delete " +
                        "input()/AccessControlList/ACE[" + wherestr + "]");
        try {
            TResponse response = objectAccessor.xquery(query);
        } catch (TXQueryException e) {
            throw new URMDeleteException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMDeleteException)
            throw (URMDeleteException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    private void removeACLsOfOwnerSubjects(Set subjects) throws URMDeleteException, URMInternalServerException {
    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(UPDATE)) == null)
            throw new URMDeleteException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();
        for (Iterator iter = subjects.iterator(); iter.hasNext();) {
            URMSubject subj = (URMSubject)iter.next();
            TQuery query = TQuery.newInstance("AccessControlList[Owner = '" + subj.getName() +
                            "' and Owner/@Type = '" + String.valueOf(subj.getType()) + "' and " +
                            (subj.getDomain() != null ? "Owner/@Domain = '"+subj.getDomain()+"' "
                                : "not(" + "Owner/@Domain)") + "]");
            try {
                TResponse response = objectAccessor.delete(query);
            } catch (TDeleteException e) {
                // do not throw "No matching document found" exception
                Exception deepest_throwable = e.getDeepestTException();
                String code = null;
                if (deepest_throwable != null && deepest_throwable instanceof TAccessFailureException) {
                    code = ((TAccessFailureException)deepest_throwable).getCode();
                }
                if (code == null || !code.equals("INOXIE8300"))
                    throw new URMDeleteException(msLogger, "E", e);
            }
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMDeleteException)
            throw (URMDeleteException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    private void removeUserRoleMapping(Set subjects) throws URMDeleteException, URMInternalServerException {
    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(UPDATE)) == null)
            throw new URMDeleteException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();
        for (Iterator iter = subjects.iterator(); iter.hasNext();) {
            URMSubject subj = (URMSubject)iter.next();
            String userORgroup = (subj.getType() == URMConstants.USER ? "UserName" : "GroupName");
            TQuery query = TQuery.newInstance("UserRoleMapping[" +
                            userORgroup +
                            " = '" + subj.getName() + "' and " +
                            (subj.getDomain() != null ? userORgroup + "/@Domain = '"+subj.getDomain()+"' "
                                : "not(" + userORgroup + "/@Domain)") + "]");
            try {
                TResponse response = objectAccessor.delete(query);
            } catch (TDeleteException e) {
                // do not throw "No matching document found" exception
                Exception deepest_throwable = e.getDeepestTException();
                String code = null;
                if (deepest_throwable != null && deepest_throwable instanceof TAccessFailureException) {
                    code = ((TAccessFailureException)deepest_throwable).getCode();
                }
                if (code == null || !code.equals("INOXIE8300"))
                    throw new URMDeleteException(msLogger, "E", e);
            }
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMDeleteException)
            throw (URMDeleteException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    /*public void deleteUserGroupRoleMapping(String name, String domain, boolean isUser) throws URMDeleteException, URMInternalServerException {
    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(UPDATE)) == null)
            throw new URMDeleteException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();
        if (name != null) {
            String userORgroup = null;
            if (isUser) userORgroup = "UserName";
            else userORgroup = "GroupName";
            TQuery query = TQuery.newInstance("UserRoleMapping[" +
                            userORgroup +
                            " = '" + name + "' and " +
                            (domain != null ? userORgroup + "/@Domain = '"+domain+"' "
                                : "not(" + userORgroup + "/@Domain)") + "]");
            try {
                TResponse response = objectAccessor.delete(query);
                // user-role mapping cache clear should be here
                if (isUser) {
                    if (roleUserMappingCache != null) roleUserMappingCache.clear();
                    if (userRoleMappingCache != null) userRoleMappingCache.clear();
                    if (allRoleUserMappingCache != null) allRoleUserMappingCache.clear();
                }
                else {
                    if (roleGroupMappingCache != null) roleGroupMappingCache.clear();
                    if (groupRoleMappingCache != null) groupRoleMappingCache.clear();
                    if (allRoleGroupMappingCache != null) allRoleGroupMappingCache.clear();
                }
                resetCaches();
            } catch (TDeleteException e) {
                // do not throw "No matching document found" exception
                Exception deepest_throwable = e.getDeepestTException();
                String code = null;
                if (deepest_throwable != null && deepest_throwable instanceof TAccessFailureException) {
                    code = ((TAccessFailureException)deepest_throwable).getCode();
                }
                if (code == null || !code.equals("INOXIE8300"))
                    throw new URMDeleteException(msLogger, "E", e);
            }
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMDeleteException)
            throw (URMDeleteException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }*/
    
    public void deleteRoleMappingAndACEsOfUserGroupSubject(String name, String domain, boolean isUser) throws URMDeleteException, URMInternalServerException {
        if (name == null)
            return;
        try {
            TXMLObjectAccessor objectAccessor = null;
            URMTaminoConnection tConn = null;
            if ((tConn = prologue(UPDATE)) == null)
                throw new URMDeleteException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
            objectAccessor = tConn.getAccessor();
            
            // delete user or group to role mappings
            String userORgroup = null;
            int subj_type;
            if (isUser) { userORgroup = "UserName"; subj_type = URMConstants.USER; }
            else { userORgroup = "GroupName"; subj_type = URMConstants.GROUP; }
            TQuery query = TQuery.newInstance("UserRoleMapping[" +
                            userORgroup + " = '" + name + "' and " +
                            (domain != null ? userORgroup + "/@Domain = '"+domain+"' "
                                : "not(" + userORgroup + "/@Domain)") + "]");
            try {
                TResponse response = objectAccessor.delete(query);
            } catch (TDeleteException e) {
                // do not throw "No matching document found" exception
                Exception deepest_throwable = e.getDeepestTException();
                String code = null;
                if (deepest_throwable != null && deepest_throwable instanceof TAccessFailureException) {
                    code = ((TAccessFailureException)deepest_throwable).getCode();
                }
                if (code == null || !code.equals("INOXIE8300"))
                    throw new URMDeleteException(msLogger, "E", e);
            }
            // delete ACEs
            TXQuery xquery = TXQuery.newInstance("update delete input()/AccessControlList/ACE[" +
                                        "Subject = '" + name + "' and Subject/@Type = "
                                            + String.valueOf(subj_type) + " and " +
                                            (domain != null ? "Subject/@Domain = '"+domain+"')"
                                            : "not(Subject/@Domain)")
                                        + "]");
            // update Owner
            try {
                TResponse response = objectAccessor.xquery(xquery);
            } catch (TXQueryException e) {
                throw new URMDeleteException(msLogger, "E", e);
            }
            xquery = TXQuery.newInstance("update replace input()/AccessControlList/Owner[text() = '" + name +
                                     "' and @Type = " + subj_type + " and " +
                                    (domain != null ? "@Domain = '"+domain+"')"
                                                : "not(@Domain)") + "] with "+
                                    "<Owner Type=\""+URMConstants.ROLE+"\">"+URMConstants.URM_ADMIN_ROLE+"</Owner>");
            try {
                TResponse response = objectAccessor.xquery(xquery);
            } catch (TXQueryException e) {
                throw new URMDeleteException(msLogger, "E", e);
            }
            // user-role mapping cache and acl cache clear
            if (isUser) {
                if (roleUserMappingCache != null) roleUserMappingCache.clear();
                if (userRoleMappingCache != null) userRoleMappingCache.clear();
                if (allRoleUserMappingCache != null) allRoleUserMappingCache.clear();
            }
            else {
                if (roleGroupMappingCache != null) roleGroupMappingCache.clear();
                if (groupRoleMappingCache != null) groupRoleMappingCache.clear();
                if (allRoleGroupMappingCache != null) allRoleGroupMappingCache.clear();
            }
            URMAccessControlerSpiTamino.clearAclCache();
            resetCaches();
        } catch (Exception e) {
            epilogue(false);
            if (e instanceof URMDeleteException)
                throw (URMDeleteException)e;
            throw new URMInternalServerException (e); //(RuntimeException)e;
        } finally {
            epilogue(true);
        }
    }
        
    public boolean hasACEsOfSubject(String name, String domain, int subjType) throws URMInternalServerException {
        if (name == null)
            return false;
        try {
            URMTaminoConnection tConn = null;
            if ((tConn = prologue(QUERY)) == null)
                throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
            TXMLObjectAccessor objectAccessor = tConn.getAccessor();
            TXQuery query = TXQuery.newInstance("count(input()/AccessControlList/ACE" +
                                        "[(Subject = '" + name + "' and Subject/@Type = "
                                            + String.valueOf(subjType) + " and " +
                                            (domain != null ? "Subject/@Domain = '"+domain+"')"
                                            : "not(Subject/@Domain))")
                                        + "])");
            try {
                TResponse response = objectAccessor.xquery(query);
                TXMLObjectIterator iter = response.getXMLObjectIterator();
                if (iter != null && iter.hasNext()) {
                    TXMLObject tobj = iter.next();
                    Object obj_el = tobj != null ? tobj.getElement() : null;
                    if (obj_el != null && obj_el instanceof Element) {
                        Node tnode = ((Node)obj_el).getFirstChild();
                        if (tnode != null && tnode.getNodeType() == Node.TEXT_NODE) {
                            String tval = tnode.getNodeValue();
                            if (tval != null) {
                                int num = 0;
                                try {
                                    num = Integer.parseInt(tval);
                                } catch (NumberFormatException e1) {}
                                if (num > 0)
                                    return true;
                            }
                        }
                    }
                }
            } catch (TXQueryException e) {
                throw new URMInternalServerException(msLogger, "E", e);
            }
            return false;
        } catch (Exception e) {
            epilogue(false);
            if (e instanceof URMInternalServerException)
                throw (URMInternalServerException)e;
            throw new URMInternalServerException (e); //(RuntimeException)e;
        } finally {
            epilogue(true);
        }
    }

    /*private boolean hasACLsOfSubject(String name, String domain, int subjType) throws URMInternalServerException {
        if (name == null)
            return false;
        try {
            URMTaminoConnection tConn = null;
            if ((tConn = prologue(QUERY)) == null)
                throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
            TXMLObjectAccessor objectAccessor = tConn.getAccessor();
            TXQuery query = TXQuery.newInstance("count(input()/AccessControlList" +
                                        "[(Owner = '" + name + "' and Owner/@Type = "
                                            + String.valueOf(subjType) + " and " +
                                            (domain != null ? "Owner/@Domain = '"+domain+"')"
                                            : "not(Owner/@Domain))")
                                        + "])");
            try {
                TResponse response = objectAccessor.xquery(query);
                TXMLObjectIterator iter = response.getXMLObjectIterator();
                if (iter != null && iter.hasNext()) {
                    TXMLObject tobj = iter.next();
                    Object obj_el = tobj != null ? tobj.getElement() : null;
                    if (obj_el != null && obj_el instanceof Element) {
                        Node tnode = ((Node)obj_el).getFirstChild();
                        if (tnode != null && tnode.getNodeType() == Node.TEXT_NODE) {
                            String tval = tnode.getNodeValue();
                            if (tval != null) {
                                int num = 0;
                                try {
                                    num = Integer.parseInt(tval);
                                } catch (NumberFormatException e1) {}
                                if (num > 0)
                                    return true;
                            }
                        }
                    }
                }
            } catch (TXQueryException e) {
                throw new URMInternalServerException(msLogger, "E", e);
            }
            return false;
        } catch (Exception e) {
            epilogue(false);
            if (e instanceof URMInternalServerException)
                throw (URMInternalServerException)e;
            throw new URMInternalServerException (e); //(RuntimeException)e;
        } finally {
            epilogue(true);
        }
    }*/
        
    public Set getAvailableRolePropKeys() {
        return mAvailableRolePropKeys;
    }


    public Set getWriteableRolePropKeys() {
       return mWriteableRolePropKeys;
    }

    private void resetCaches() {
        URMValidatorCache.getCache().reset();
    }
}
