
/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/urm/org/apache/slide/urm/accesscontroler/impl/tamino/URMAccessControlerSpiTamino.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.
 */

/**
 * @author eckehard.hermann@softwareag.com
 * @author dieter.kessler@softwareag.com
 * @author zsolt.sasvarie@softwareag.com
 */
package org.apache.slide.urm.accesscontroler.impl.tamino;

        
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.Vector;

import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.apache.slide.urm.URMForbiddenException;
import org.apache.slide.urm.authenticator.URMDBTransactionException;
import com.softwareag.tamino.db.api.accessor.TDeleteException;
import com.softwareag.tamino.db.api.accessor.TInsertException;
import com.softwareag.tamino.db.api.accessor.TQuery;
import com.softwareag.tamino.db.api.accessor.TXMLObjectAccessor;
import com.softwareag.tamino.db.api.accessor.TXQuery;
import com.softwareag.tamino.db.api.accessor.TXQueryException;
import com.softwareag.tamino.db.api.common.TException;
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.accesscontroler.URMAccessControlerSpi;
import org.apache.slide.urm.accesscontroler.URMAce;
import org.apache.slide.urm.accesscontroler.URMAceCreateException;
import org.apache.slide.urm.accesscontroler.URMAcl;
import org.apache.slide.urm.accesscontroler.URMAclException;
import org.apache.slide.urm.accesscontroler.URMAclIdNotUniqueException;
import org.apache.slide.urm.accesscontroler.URMAction;
import org.apache.slide.urm.accesscontroler.URMActionIdNotUniqueException;
import org.apache.slide.urm.accesscontroler.URMActionInUseException;
import org.apache.slide.urm.accesscontroler.URMUnknownActionException;
import org.apache.slide.urm.accesscontroler.URMUnknownSubjectException;
import org.apache.slide.urm.accesscontroler.impl.URMAceImpl;
import org.apache.slide.urm.accesscontroler.impl.URMAclImpl;
import org.apache.slide.urm.accesscontroler.impl.URMActionImpl;
import org.apache.slide.urm.common.URMCloseConnectionException;
import org.apache.slide.urm.common.URMConfigurator;
import org.apache.slide.urm.common.URMConnectionException;
import org.apache.slide.urm.common.URMDeleteException;
import org.apache.slide.urm.common.URMInsertException;
import org.apache.slide.urm.common.URMInternalServerException;
import org.apache.slide.urm.common.URMParameterException;
import org.apache.slide.urm.common.URMUpdateException;
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.messagelogger.MessageLogger;

import org.apache.slide.urm.utils.validatorcache.URMListener;
import org.apache.slide.urm.utils.validatorcache.URMValidatorCache;
import org.apache.slide.urm.utils.accesscontrolercache.URMAccessControlerFifoCache;
import org.apache.slide.urm.URMException;

public class URMAccessControlerSpiTamino implements URMAccessControlerSpi {

    private static final String ATTR_NAME = "name";
    private static final String ATTR_VALUE = "value";
    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 URMAccessControlerFifoCache actionCache = null;
    private static URMAccessControlerFifoCache aclCache = null;
    private static Object mCacheInitSyncObj = new Object();
//    private static Set allActions = null;

    private TConnectionPoolManager mConnectionPoolManager = null;
    private URMTaminoConnectionHandler mConn = null;
    private char mSeparator = '/';
//    private Map actionDeltaCache = null;
//    private Map aclDeltaCache = null;

    /*
     * Inner class to reflect an ACE element
     */

    private class URMAceEntry {
        String m_Action = null;
        String m_ActType = null;
        String m_Subject = null;
        String m_SubType = null;
        String m_SubDom = null;

        private String m_s1 = null;
        public URMAceEntry(String action,
                           String actType,
                           String subject,
                           String subType,
                           String subDom) {
            m_Action = action;
            m_ActType = actType;
            m_Subject = subject;
            m_SubType = subType;
            m_SubDom = subDom;
        }
        public String getAction(){
            return m_Action;
        }
        public String getActType(){
            return m_ActType;
        }
        public String getSubject(){
            return m_Subject;
        }
        public String getSubType(){
            return m_SubType;
        }
        public String getSubDomain(){
            return m_SubDom;
        }
    }

    private static org.apache.log4j.Logger msLogger =
        org.apache.log4j.Logger.getLogger(URMAccessControlerSpiTamino.class.getName());

    private URMListener aclListenerSet = URMListener.getAclListenerSet();
    private Object mOwner = null;
    private URMConfigurator mConfigurator = null;

    private boolean mIsAlreadyClosed = false;

    /** Returns the action main cache. This cache is thread static and independent
     *
     * @return URMAccessControlerFifoCache, action cache
     */
    public static URMAccessControlerFifoCache getActionCache() {
        return actionCache;
    }

    /** Returns the acl main cache. This cache is thread static and independent
     *
     * @return URMAccessControlerFifoCache, acl cache
     */
    public static URMAccessControlerFifoCache getAclCache() {
        return aclCache;
    }

    /** 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 URMAccessControlerSpiTamino(URMConfigurator roleAdminConf, Object owner) throws URMConnectionException {
        mConfigurator = roleAdminConf;
        mOwner = owner;

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

        URMConfigurator attrbConfig = roleAdminConf.getSubConfigurator("/Authenticator/Administrator");
        Iterator roleattrs = URMConfiguratorUtil.getAttributeList(roleAdminConf, msLogger);
        // synchronize the initialization of the static members
        synchronized (mCacheInitSyncObj) {
            while (roleattrs != null && roleattrs.hasNext()) {
                URMConfigurator attrconf = ((URMConfigurator)roleattrs.next());
                Properties attr = attrconf.getProperties();
                if (attr == null)
                    continue;
                String attrname = (String)attr.get("name");
                if (attrname == null)
                    continue;
                if (attrname.equals("actionCache")) {
                    String actionCacheSize = (String)attr.get(ATTR_VALUE);
                    if (actionCache == null) {
                        int actionCacheSize_int = (new Integer(actionCacheSize)).intValue();
                        if (actionCacheSize_int > 0)  actionCache = new URMAccessControlerFifoCache();
                    }
                } else if (attrname.equals("aclCache")) {
                    String aclCacheSize = (String)attr.get(ATTR_VALUE);
                    if (aclCache == null) {
                        int aclCacheSize_int = (new Integer(aclCacheSize)).intValue();
                        if (aclCacheSize_int > 0) aclCache = new URMAccessControlerFifoCache(aclCacheSize_int);
                    }
                } else if (attrname.equals("validatorCache")) {
                        validatorCacheSize = (String)attr.get(ATTR_VALUE);
                } else if (attrname.equals("validatorUserCache")) {
                        validatorUserCacheSize = (String)attr.get(ATTR_VALUE);
                }
            }
        }
        if ((validatorCacheSize != null) && (validatorUserCacheSize != null)) {
            int validatorCacheSize_int = (new Integer (validatorCacheSize)).intValue();
            int validatorUserCacheSize_int = (new Integer (validatorCacheSize)).intValue();
            if ((validatorUserCacheSize_int > 0) && (validatorCacheSize_int > 0)) URMValidatorCache.initCache(validatorCacheSize_int,validatorUserCacheSize_int);
        }
    }

    public URMAccessControlerSpi duplicateObject(Object owner) throws URMConnectionException {
        return new URMAccessControlerSpiTamino(mConfigurator, owner);
    }


    /******************* URMAclAdmin methods *************** start ************/

    /* (non-Javadoc)
     */
    public URMAcl getAcl(String id) throws URMInternalServerException {

    URMAcl retAcl = null;
    // check if acl has already been loaded and cached
    if (aclCache != null){
        if (accessCacheAllowed()) {
            if (aclCache.contains(id)) {
                // we must call both 'contains' and 'get', because the acl could correctly be null
                try {
                    return (URMAcl) aclCache.get(id, this);
                } catch (Exception e){
                }
            }
        } else {
            // we must call both 'contains' and 'get', because the acl could correctly be null
            Map aclDeltaCache = getAclDeltaCache();
            if (aclDeltaCache.containsKey(id)){
                return (URMAcl) aclDeltaCache.get(id);
            } else {
                if (aclCache.contains(id)) {
                    // we must call both 'contains' and 'get', because the acl could correctly be null
                    try {
                        return (URMAcl) aclCache.get(id, this);
                    } catch (Exception e){
                    }
                }
            }
        }
    }

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

        String resId = new String();
        String resInherit = new String();
        String resOwner = new String();
        String resOwnerType = new String();
        String resDomain = new String();

        TXQuery query = TXQuery.newInstance("for $b in input()/AccessControlList " +
                                            "where  $b/ResourceId = '" + id + "' " +
                                            "return $b");
        try {
            TResponse response = objectAccessor.xquery(query);
            TXMLObjectIterator 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 currentNode = null;
                    currentNode = ((Element)obj_el).getFirstChild();
                    String oAction = null;
                    int oActType = 0;
                    String oSubject = null;
                    int oSubType = 0;
                    String oSubDom = null;
                    boolean oinvert = false;
//                    int oPosition = 0;
                    int index = 0;
                    List aceList = new ArrayList();
                    
                    // create ACL object
                    while (currentNode != null) {
                        if ("ResourceId".equals(currentNode.getNodeName())){
                            Node resNode = currentNode;
                            resId = resNode.getFirstChild().getNodeValue();
                        } else

                        if ("Inheritable".equals(currentNode.getNodeName())){
                            Node inheritNode = currentNode;
                            resInherit = inheritNode.getFirstChild().getNodeValue();
                        } else

                        if ("Owner".equals(currentNode.getNodeName())){
                            Node ownNode = currentNode;
                            resOwner = ownNode.getFirstChild().getNodeValue();
                            if (ownNode.hasAttributes()) {
                                NamedNodeMap ownAttr = ownNode.getAttributes();
                                Node nodeType = ownAttr.getNamedItem("Type");
                                if ( nodeType != null) {
                                    resOwnerType = nodeType.getNodeValue();
                                }
                                Node nodeDomain = ownAttr.getNamedItem("Domain");
                                if (nodeDomain != null) {
                                    resDomain = nodeDomain.getNodeValue();
                                }
                            }
                        } else
                        // And read the ACEs
                        if ("ACE".equals(currentNode.getNodeName())) {

                            Node ace = currentNode;
                            ace.getAttributes();
                            if (ace.hasAttributes()) {
                               NamedNodeMap subAttr = ace.getAttributes();
//                               Node subType = subAttr.getNamedItem("Position");
//                               if (subType != null) {
//                                   oPosition = new Integer(subType.getNodeValue()).intValue();
 //                              }
                               Node subDom = subAttr.getNamedItem("Invert");
                               if (subDom != null) {
                                   oinvert = subDom.getNodeValue().equals("true");
                                }
                            }
                            // finished with ace attributes
                            Node aceNode = ace.getFirstChild();
                            while (aceNode != null) {

                                // Read the Subject element
                                if (aceNode != null && "Subject".equals(aceNode.getNodeName())) {
                                      oSubject = aceNode.getFirstChild().getNodeValue();
                                      if (aceNode.hasAttributes()) {
                                            NamedNodeMap subAttr = aceNode.getAttributes();
                                            Node subType = subAttr.getNamedItem("Type");
                                            if (subType != null) {
                                                oSubType = new Integer(subType.getNodeValue()).intValue();
                                            }
                                            Node subDom = subAttr.getNamedItem("Domain");
                                            if (subDom != null) {
                                                oSubDom = subDom.getNodeValue();
                                            }
                                        }
                                        
                                } else
                                // Read the Action element
                                if ("Action".equals(aceNode.getNodeName())){
                                    oAction = aceNode.getFirstChild().getNodeValue();
                                    if (aceNode.hasAttributes()) {
                                        NamedNodeMap actAttr = aceNode.getAttributes();
                                        Node actType = actAttr.getNamedItem("Type");
                                        if (actType != null) {
                                            oActType = new Integer(actType.getNodeValue()).intValue();
                                        }
                                    }
                                } // read action of one ace
                                aceNode =  aceNode.getNextSibling();
                            }
                            // read ace elements
                            aceList.add(index, new URMAceImpl(oActType,
                                                                             oSubject,
                                                                             oSubType,
                                                                             oSubDom,
                                                                             oAction,
                                                                             oinvert,
                                                                             this));
                            index++;
                        }
                        currentNode = currentNode.getNextSibling();
                    }
                    
                    Integer ownerType = new Integer(resOwnerType);
                    try {
                        retAcl = new URMAclImpl(this, resId, resOwner,
                                                       ownerType.intValue(),
                                                       resDomain,
                                                       (resInherit.equals("1") ? true : false),
                                                       aceList);
    
                    } catch (URMParameterException e) {
                        throw new URMInternalServerException(msLogger, "E", e);
                    }
                    
                    // add action to cache, if no transaction is running or if the current transaction did not change the action
                    if (aclCache != null) {
                        if (tConn.accessCache() || ((tConn.getAclDeltaCache() != null) &&
                            (!tConn.getAclDeltaCache().containsKey(id))))
                             aclCache.add(id,retAcl);
                    }
                    return retAcl;
                } // finished with ACL object
            }

            // add action to cache, if no transaction is running or if the current transaction did not change the action
            if (aclCache != null) {
                if (tConn.accessCache() || ((tConn.getAclDeltaCache() != null) &&
                    (!tConn.getAclDeltaCache().containsKey(id)))) aclCache.add(id,null);
            }
            return null;
        } 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 URMInternalServerException)
            throw (URMInternalServerException)e;
        else throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    /*
     *  (non-Javadoc)
     */
    public List getAclPath(List acls) throws URMInternalServerException {

    try {
        URMAcl aclTemp = null;

        // allocate return list in the size of the input resource id's
        int aclSize = acls.size();
        List retList = new ArrayList(aclSize);
        Map resIdMap = new HashMap(aclSize);
        Set resIdGetFromDB = new HashSet();
        Set actionSet = new HashSet();
//        Map readFromCache = new HashMap();
        if (acls == null) return null;
        Iterator aclIterForCache = acls.iterator();
        if (aclCache != null){
            // check if in Transaction
            if (accessCacheAllowed()) {
                //if not in transaction, try to load from aclCache
                while (aclIterForCache.hasNext()) {
                    String currentResource = (String) aclIterForCache.next();
                    aclTemp = (URMAcl)aclCache.get(currentResource, this);
                    if (aclCache.contains(currentResource)) {
                        if (aclTemp != null) resIdMap.put(aclTemp.getId(), aclTemp);
                    } else {
                        resIdGetFromDB.add(currentResource);
                    }
                }
            } else {
                //if in transaction, first try to load from aclDeltaCache
                while (aclIterForCache.hasNext()) {
                    String currentResource = (String) aclIterForCache.next();
                    // check if in delta cache
                    Map aclDeltaCache = getAclDeltaCache();
                    if (aclDeltaCache.containsKey(currentResource)) {

                        aclTemp = (URMAcl)aclDeltaCache.get(currentResource);
                        if (aclTemp != null) resIdMap.put(aclTemp.getId(), aclTemp);
                    } else {
                        // check if not in delta cache, load from cache
                        aclTemp = (URMAcl)aclCache.get(currentResource, this);
                        if (aclCache.contains(currentResource)) {
                            if (aclTemp != null) resIdMap.put(aclTemp.getId(), aclTemp);
                        } else {
                            resIdGetFromDB.add(currentResource);
                        }
                    }
                }
            }
        }

        // check if acls have to be loaded from db
        if (!resIdGetFromDB.isEmpty()) {
            TXMLObjectAccessor objectAccessor = null;
            URMTaminoConnection tConn = null;
            if ((tConn = prologue(QUERY)) == null)
                throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
            objectAccessor = tConn.getAccessor();

            // build a string of the remaining acl-id's to read
            Iterator aclIter = resIdGetFromDB.iterator();
            String resourceIds =  new String();
            String szOr = "";
            boolean bStarted = false;
            while(aclIter.hasNext()) {
                String currentacl = (String) aclIter.next();
                if (bStarted) {
                    szOr = " or $b/ResourceId = ";
                }
                resourceIds =  resourceIds.concat(szOr + "'" + currentacl + "'");
                bStarted = true;
            }

            // Read all remaing ACLs with one call
            String resId = new String();
            String resInherit = new String();
            String resOwner = new String();
            String resOwnerType = new String();
            String resDomain = new String();
            List list = null;

            int maxInd = 10; // that's a good start anyway
            String oAction = null;
            int oActType = 0;
            String oSubject = null;
            int oSubType = 0;
            String oSubDom = null;
            boolean oinvert = false;
//            int oPosition = 0;
            TXQuery query = TXQuery.newInstance("for $b in input()/AccessControlList " +
                                                "where  $b/ResourceId = " + resourceIds +
                                                " return $b");
            try {
                TResponse response = objectAccessor.xquery(query);
                TXMLObjectIterator iter = response.getXMLObjectIterator();
                while (iter != null && iter.hasNext()) {
                    TXMLObject tobj = iter.next();
                    Object obj_el = tobj != null ? tobj.getElement() : null;
                    list = new ArrayList();
                    if (obj_el != null && obj_el instanceof Element) {
                        Node currentAclElementNode = ((Element)obj_el).getFirstChild();
                        int i = 0;
                        while (currentAclElementNode != null) {
                            if ("ResourceId".equals(currentAclElementNode.getNodeName())){
                                resId = currentAclElementNode.getFirstChild().getNodeValue();
                            } else

                            if ("Inheritable".equals(currentAclElementNode.getNodeName())){
                                resInherit = currentAclElementNode.getFirstChild().getNodeValue();
                            } else

                            if ("Owner".equals(currentAclElementNode.getNodeName())){
                                resOwner = currentAclElementNode.getFirstChild().getNodeValue();
                                if (currentAclElementNode.hasAttributes()) {
                                    NamedNodeMap ownAttr = currentAclElementNode.getAttributes();
                                    Node nodeType = ownAttr.getNamedItem("Type");
                                    if ( nodeType != null) {
                                        resOwnerType = nodeType.getNodeValue();
                                    }
                                    Node nodeDomain = ownAttr.getNamedItem("Domain");
                                    if (nodeDomain != null) {
                                        resDomain = nodeDomain.getNodeValue();
                                    }
                                }
                            } else
                            // And read the ACEs
                            if ("ACE".equals(currentAclElementNode.getNodeName())) {

                                Node ace = currentAclElementNode;
                                ace.getAttributes();
                                if (ace.hasAttributes()) {
                                    NamedNodeMap subAttr = ace.getAttributes();
//                                    Node subType = subAttr.getNamedItem("Position");
//                                    if (subType != null) {
//                                        oPosition = new Integer(subType.getNodeValue()).intValue();
//                                   }
                                    Node subDom = subAttr.getNamedItem("Invert");
                                    if (subDom != null) {
                                        oinvert = subDom.getNodeValue().equals("true");
                                    }
                                }
                                // finished with ace attributes
                                Node aceNode = ace.getFirstChild();
                                while (aceNode != null) {

                                // Read the Subject element
                                if (aceNode != null && "Subject".equals(aceNode.getNodeName())) {
                                      oSubject = aceNode.getFirstChild().getNodeValue();
                                      if (aceNode.hasAttributes()) {
                                            NamedNodeMap subAttr = aceNode.getAttributes();
                                            Node subType = subAttr.getNamedItem("Type");
                                            if (subType != null) {
                                                oSubType = new Integer(subType.getNodeValue()).intValue();
                                            }
                                            Node subDom = subAttr.getNamedItem("Domain");
                                            if (subDom != null) {
                                                oSubDom = subDom.getNodeValue();
                                            }
                                        }
                                    } else // read ace subject

                                    // Read the Action element
                                    if ("Action".equals(aceNode.getNodeName())){
                                        oAction = aceNode.getFirstChild().getNodeValue();
                                        if (aceNode.hasAttributes()) {
                                            NamedNodeMap actAttr = aceNode.getAttributes();
                                            Node actType = actAttr.getNamedItem("Type");
                                            if (actType != null) {
                                                oActType = new Integer(actType.getNodeValue()).intValue();
                                            }
                                        }
                                    } // read action of one ace
                                    aceNode =  aceNode.getNextSibling();
                                } // read ace elements
                                list.add(i, new URMAceImpl(oActType,
                                                                oSubject,
                                                                oSubType,
                                                                oSubDom,
                                                                oAction,
                                                                oinvert,
                                                                this));
                                i++;
                                // performance improvement. One Tamino call for all actions.
                                actionSet.add(oAction);
                                }// finished with one acl
                                currentAclElementNode = currentAclElementNode.getNextSibling();
                            }
                            // One complete Acl has been read
                            aclTemp = new URMAclImpl(this, resId, resOwner,
                                                                  new Integer(resOwnerType).intValue() ,
                                                                  resDomain,
                                                                  (resInherit.equals("1") ? true : false),
                                                                  list);
                            resIdMap.put(resId, aclTemp);
                            // add action to cache, if no transaction is running or if the current transaction did not change the action
                            if (aclCache != null) {
                                if (tConn.accessCache() || ((tConn.getAclDeltaCache() != null) &&
                                    (!tConn.getAclDeltaCache().containsKey(resId)))) aclCache.add(resId,aclTemp);
                            }
                        }
                    }

                } 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);
                }
            }

            // Sort returned acls
            for (int i = 0; i < aclSize; i++){
                String currentAclForSort = (String)acls.get(i);
                if (resIdMap.containsKey(currentAclForSort)) {
                    Object currentResAcl = resIdMap.get(currentAclForSort);
                    retList.add(currentResAcl);
                } else {
                    // add action to cache, if no transaction is running or if the current transaction did not change the action
                    Map aclDeltaCache = getAclDeltaCache();
                    if (aclCache != null) {
                        if (accessCacheAllowed() || ((aclDeltaCache != null) &&
                            (!aclDeltaCache.containsKey(currentAclForSort)))) aclCache.add(currentAclForSort,null);
                    }
                }
            }
            // load actions of the acl into cache
            loadActionSetIntoCache(actionSet);

            return retList;

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

    /* (non-Javadoc)
     *
     */
    public String createAcl(String id, String owner, int ownerType,
                            String ownerDomain, boolean inheritable)
        throws URMAclIdNotUniqueException, URMInternalServerException, URMInsertException {

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

        if (owner == null)
            throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0026", "owner"));

        if (id != null && id.startsWith("URMid"))
            throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0026", "id"));

        try {
            if (!this.existAcl(id)) {

                String xmlInst = new String("<AccessControlList><ResourceId>" +
                                 (id == null ? "URMidXXX" : id) + "</ResourceId>" +
                                 "<Inheritable>" +
                                 (inheritable ? "1" : "0") +
                                 "</Inheritable>" +
                                 "<Owner Type='" +
                                 ownerType + "'");
                if (ownerDomain != null) {
                    xmlInst = xmlInst.concat(" Domain='" + ownerDomain + "'");
                }
                xmlInst = xmlInst.concat(">" +
                                         owner + "</Owner>" +
                                         "</AccessControlList>");
                TXMLObject xmlobj = TXMLObject.newInstance(xmlInst);
                try {
                    TResponse response = objectAccessor.insert(xmlobj);
                } catch (TInsertException e) {
                    throw new URMInsertException(msLogger, "E", e);
                }

                if (id == null) {
                    TXQuery query = TXQuery.newInstance("declare namespace tf='http://namespaces.softwareag.com/tamino/TaminoFunction' " +
                                                        "update for $b in input() " +
                                                        "where  $b/AccessControlList/ResourceId = 'URMidXXX' " +
                                                        "do replace $b/AccessControlList/ResourceId with " +
                                                        "<ResourceId>URMid{tf:getInoId($b)}</ResourceId>");
                    try {
                        TResponse response = objectAccessor.xquery(query);
                        TXMLObjectIterator iter = response.getXMLObjectIterator();
                        int i = 0;
                        if (iter == null || !iter.hasNext()) {
                            throw new URMAclIdNotUniqueException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0009"));
                        }
                        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) {
                                if (((Element)obj_el).hasAttributes()) {
                                    NamedNodeMap indAttr = ((Element)obj_el).getAttributes();
                                    Node indType = indAttr.getNamedItem("ino:id");
                                    if (indType != null) {
                                        id = "URMid";
                                        id = id.concat(indType.getNodeValue());
                                    }
                                }
                            }
                        }
                    } catch (TNoSuchXMLObjectException e) {
                        throw new URMInternalServerException(msLogger, "E", e);
                    } catch (TIteratorException e) {
                        throw new URMInternalServerException(msLogger, "E", e);
                    } catch (TXQueryException e) {
                        throw new URMInternalServerException(msLogger, "E", e);
                    }
                }

               URMAcl newAcl = new URMAclImpl(this, id, owner, ownerType, ownerDomain, inheritable, new ArrayList());
               // if acl has been cached, remove it from cache
                if (actionCache != null ) {
                    if (tConn.accessCache()) {
                        aclCache.add(id, newAcl);
                        aclListenerSet.removeEvent(id);
                    } else {
                        // add new value to deltaCache, because it is removed
                        tConn.getAclDeltaCache().put(id, newAcl);
                    }
                }

            } else {
                throw new URMAclIdNotUniqueException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0025", id));
            }
        } catch (URMInternalServerException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
        return id;
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMAclIdNotUniqueException)
            throw (URMAclIdNotUniqueException)e;
        else if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        else if (e instanceof URMInsertException)
            throw (URMInsertException)e;
        else throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

     /* (non-Javadoc)
     *
     */
    public void deleteAcl(String resourceId)
            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();

        TQuery query = TQuery.newInstance("AccessControlList[ResourceId = '" + resourceId + "']");
        try {
            TResponse response = objectAccessor.delete(query);
            // if acl has been cached, remove it from cache
            if (actionCache != null ) {
                if (tConn.accessCache()) {
                    aclCache.remove(resourceId);
                    aclListenerSet.removeEvent(resourceId);
                } else {
                    // add null to deltaCache, because acl is removed
                    tConn.getAclDeltaCache().put(resourceId, null);
                }
            }
        } catch (TDeleteException e) {
//            e.printStackTrace();
            throw new URMDeleteException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMDeleteException)
            throw (URMDeleteException)e;
        else if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        else throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    /* (non-Javadoc)
     */
    public URMAction createAction(String id) throws URMActionIdNotUniqueException, URMInternalServerException, URMInsertException {

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

        if (id == null) {
            throw new URMInsertException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0040", id));
        }

        try {
            String inoId = new String();
            if (!this.existAction(id)) {
//                TConnection DKconn = tConn.getConnection();
//                System.out.println("create action with Iso: " + DKconn.getIsolationDegree() +
//                                          " Lock: " + DKconn.getLockMode());
//                objectAccessor = DKconn.newXMLObjectAccessor(
//                                    TAccessLocation.newInstance("URM"),
//                                    TDOMObjectModel.getInstance() );

                TXMLObject xmlobj = TXMLObject.newInstance("<Action><ActionId>" + id + "</ActionId></Action>");
                TResponse response = objectAccessor.insert(xmlobj);
                URMAction action = new URMActionImpl(this, id, null);

                // add action to cache, if no transaction is running or if the current transaction did not change the action
                if (actionCache != null) {
                    if (tConn.accessCache() || ((tConn.getActionDeltaCache() != null) &&
                        (!tConn.getActionDeltaCache().containsKey(id)))) actionCache.add(id, action);
                }
//                if (allActions != null && tConn.accessCache()) allActions.add(id);
                return action;

            } else {
                throw new URMInsertException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0040", id));
            }
        } catch (URMInternalServerException e) {
            throw new URMInsertException(msLogger, "E", e);
        } catch (TInsertException e) {
            throw new URMInsertException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMActionIdNotUniqueException)
            throw (URMActionIdNotUniqueException)e;
        else if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        else if (e instanceof URMInsertException)
            throw (URMInsertException)e;
        else throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    /* (non-Javadoc)
    */
    public void deleteAction(String id)
        throws URMActionInUseException, 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 the Action exists in any ACE
        TXQuery xquery = TXQuery.newInstance("for    $b in input()/AccessControlList " +
                                             "where  $b/ACE/Action = '" + id + "' " +
                                             "return $b/ResourceId");
        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 URMActionInUseException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0030", id));
            }
        } catch (TXQueryException ex) {
            TException de = ex.getDeepestTException();
            if (de == null)
                de = ex;
            if (msLogger.isDebugEnabled())
                MessageLogger.logMessage(msLogger, "URMTRE0013", de.getMessage());

//            throw new URMConnectionException(msLogger, "F", de);
            
            throw new URMDeleteException(msLogger, "E", de);
        }

        // Check if Action exists in Predefined Action of a Role
        
        xquery = TXQuery.newInstance("for $a in input()/Role " +
                                                   "where $a/PredefinedActions = '" + id + "' " +
                                                   "return $a/RoleName");
        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 URMActionInUseException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0058", id, s1));
            }
        } catch (TXQueryException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }

        // Check if the Action exists as AggregatedAction

        xquery = TXQuery.newInstance("for    $b in input()/Action " +
                                     "where  $b/BaseAction = '" + id + "' " +
                                     "return $b/ActionId");
        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 URMActionInUseException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0029", id));
            }
        } catch (TXQueryException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }

        // Delete this

        TQuery query = TQuery.newInstance("Action[ActionId = '" + id + "']");
        try {
            TResponse response = objectAccessor.delete(query);
            // if action has been cached, remove it from cache
            if (actionCache != null ) {
                if (tConn.accessCache()) {
                    actionCache.remove(id);
                    aclListenerSet.resetEvent();
                } else {
                    // value is null, because it is removed
                    tConn.getActionDeltaCache().put(id, null);
                }
            }
        } catch (TDeleteException e) {
            throw new URMDeleteException(msLogger, "E", e);
        }

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

    /* (non-Javadoc)
     */
    public URMAction getAction(String name)
        throws URMInternalServerException {

    URMAction action = null;
    // check if action has allready been loaded
    if (actionCache != null){
        // if in Transaction ?
        if (accessCacheAllowed()) {
            // if no, go to action cache
            try {
                action = (URMAction) actionCache.get(name, this);
            } catch (Exception e){
            }
            if (action != null) return action;
        } else {
            // if yes, check first if something is in the delta cache
            Map actionDeltaCache = getActionDeltaCache();
            if (actionDeltaCache.containsKey(name)) {
                action = (URMAction) actionDeltaCache.get(name);
                return action;
            } else {
                try {
                    action = (URMAction) actionCache.get(name, this);
                } catch (Exception e){
                }
                if (action != null) return action;
            }

        }
    }

    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()/Action " +
                                            "where  $b/ActionId = '" + name + "' " +
                                            "return $b");
        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 currentNode = ((Element)obj_el).getFirstChild();;
                // Scan the action name and all aggregated actions
                String a1 = new String();
                Set s1 = new HashSet();
                while (currentNode != null) {
                    if ("ActionId".equals(currentNode.getNodeName())) {
                        // This is superfluous. 'name' must be identical to 'a1'!
                        a1 = currentNode.getFirstChild().getNodeValue();
                    } else
                    if ("BaseAction".equals(currentNode.getNodeName())) {
                        s1.add(currentNode.getFirstChild().getNodeValue());
                    }
                    currentNode = currentNode.getNextSibling();
                }
                action = new URMActionImpl(this, a1, s1);

                // add action to cache, if no transaction is running or if the current transaction did not change the action
                if (actionCache != null) {
                    if (tConn.accessCache() || ((tConn.getActionDeltaCache() != null) &&
                        (!tConn.getActionDeltaCache().containsKey(a1)))) actionCache.add(a1, action);
                }
                return action;
            }
            else
                return null;
        } catch (TXQueryException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        else throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    /* (non-Javadoc)
     */
    public Set getAllActions()
        throws URMInternalServerException {

    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()/Action " +
                                            "return $b");
        try {
            TResponse response = objectAccessor.xquery(query);
            TXMLObjectIterator iter = response.getXMLObjectIterator();
            Set retSet = 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 currentNode = null;
                        currentNode = ((Element)obj_el).getFirstChild();

                        String a1 = new String();
                        Set s1 = new HashSet();

                        while (currentNode != null) {
                            if ("ActionId".equals(currentNode.getNodeName())){
                                Node actNode = currentNode;
                                a1 = actNode.getFirstChild().getNodeValue();
                            } else

                            if ("BaseAction".equals(currentNode.getNodeName())){
                                Node baseNode = currentNode;
                                s1.add(baseNode.getFirstChild().getNodeValue());
                            }
                            currentNode = currentNode.getNextSibling();
                        }
                        URMAction action = new URMActionImpl(this, a1, s1);

                        // add action to cache
                        if (actionCache != null) {
                            if (tConn.accessCache() || ((tConn.getActionDeltaCache() != null) &&
                                (!tConn.getActionDeltaCache().containsKey(a1)))) actionCache.add(a1, action);
                        }
                        retSet.add(action);
                    }
            }
            return retSet;

         } 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 URMInternalServerException)
            throw (URMInternalServerException)e;
        else throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    public void loadActionSetIntoCache(Set actions)
        throws URMInternalServerException {

    try {
        // return if cache is enabled
        if (actionCache == null) return;

        if (actions == null) return;
        // build a string of the remaining action-id's to read
        Iterator actionIter = actions.iterator();
        String actionIds =  new String();
        String szOr = "";
        boolean bStarted = false;
        while(actionIter.hasNext()) {
            String currentaction = (String) actionIter.next();
            if (!actionCache.contains(currentaction)) {
                if (bStarted) {
                    szOr = " or $b/ActionId = ";
                }
                actionIds =  actionIds.concat(szOr + "'" + currentaction + "'");
                bStarted = true;
            }
        }

        // return if nothing to load
        if (!bStarted) return;
        /*        String queryStr = "for    $b in input()/Action " +
                                            "where  $b/ActionId = " + actionIds +
                                            " return $b";
        System.out.println(queryStr);
         */
        TXQuery query = TXQuery.newInstance("for    $b in input()/Action " +
                                            "where  $b/ActionId = " + actionIds +
                                            " return $b");


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

        try {
            TResponse response = objectAccessor.xquery(query);
            TXMLObjectIterator iter = response.getXMLObjectIterator();
            Set retSet = 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 currentNode = null;
                        currentNode = ((Element)obj_el).getFirstChild();

                        String a1 = new String();
                        Set s1 = new HashSet();

                        while (currentNode != null) {
                            if ("ActionId".equals(currentNode.getNodeName())){
                                Node actNode = currentNode;
                                a1 = actNode.getFirstChild().getNodeValue();
                            } else

                            if ("BaseAction".equals(currentNode.getNodeName())){
                                Node baseNode = currentNode;
                                s1.add(baseNode.getFirstChild().getNodeValue());
                            }
                            currentNode = currentNode.getNextSibling();
                        }
                        URMAction action = new URMActionImpl(this, a1, s1);
                         // add action to cache
                        if (tConn.accessCache() || ((tConn.getActionDeltaCache() != null) &&
                            (!tConn.getActionDeltaCache().containsKey(a1)))) actionCache.add(a1, action);
                        retSet.add(action);
                    }
            }

         } 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 URMInternalServerException)
            throw (URMInternalServerException)e;
        else throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

        /* (non-Javadoc)
      */
    public Set getAllActionsAsString()
        throws URMInternalServerException {

//    if (allActions != null && accessCacheAllowed()) return new HashSet(allActions);

    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()/Action " +
                                            "return $b");
        try {
            TResponse response = objectAccessor.xquery(query);
            TXMLObjectIterator iter = response.getXMLObjectIterator();
            Set retSet = 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 currentNode = null;
                        currentNode = ((Element)obj_el).getFirstChild();

                        String a1 = new String();
                        Set s1 = new HashSet();

                        while (currentNode != null) {
                            if ("ActionId".equals(currentNode.getNodeName())){
                                Node actNode = currentNode;
                                a1 = actNode.getFirstChild().getNodeValue();
                            } else

                            if ("BaseAction".equals(currentNode.getNodeName())){
                                Node baseNode = currentNode;
                                s1.add(baseNode.getFirstChild().getNodeValue());
                            }
                            currentNode = currentNode.getNextSibling();
                        }
                        URMAction action = new URMActionImpl(this, a1, s1);
                        // add action to cache
                        if (actionCache != null) {
                            if (tConn.accessCache() || ((tConn.getActionDeltaCache() != null) &&
                                (!tConn.getActionDeltaCache().containsKey(a1))))
                                   actionCache.add(a1, action);
                        }
                        retSet.add(a1);

                    }
            }
//            if (tConn.accessCache()) {
//                allActions = Collections.synchronizedSet(new HashSet(retSet));
//            }
            return retSet;

         } 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 URMInternalServerException)
            throw (URMInternalServerException)e;
        else throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    /* (non-Javadoc)
     */
/*    public void beginTransaction() throws URMDBTransactionException {
    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(UPDATE)) == null)
            throw new URMDBTransactionException(MessageLogger.getAndLogMessage(msLogger, "URMCOE00004"));
            objectAccessor = tConn.getAccessor();

        internalBeginTransaction();

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

    /* (non-Javadoc)
     */

    /* public void endTransaction(boolean manner) throws URMDBTransactionException {

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

        internalEndTransaction(manner);

    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMInternalServerException)
            throw (URMDBTransactionException)e;
        else throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }
*/
    /*
     *  (non-Javadoc)
     */
    /*
    public Set getUserWithPermissionReport(String action, String resource)
            throws URMInternalServerException {

    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()/AccessControllist " +
                                            "where  $b/ResourceId = '" + resource + "' " +
                                            "and ACE/Action = '" + action + "' " +
                                            "return $b/AccessConrolList");
        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){
                // Scan the ACE for
                Node elem1 = ((Element)obj_el).getFirstChild();
                String s1 = elem1.getNodeValue();
                HashSet hs = new HashSet();
                // while () ...
                //      URMUser u1 = new URMUserImpl(s1);
                //      hs.add(u1);
                return hs;
            }
            else
                return null;
        } catch (TXQueryException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        else throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }
     */
    /*
     *  (non-Javadoc)
     */
    /*
    public Set getUserPermissionReport(String user, String domain, String resource)
            throws URMInternalServerException {

    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()/AccessControllist " +
                                            "where  $b/ResourceId = '" + resource + "' " +
                                            "and ACE/Subject = '" + user + "' " +
                                            "return $b/AccessConrolList");
        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){
                // Scan the ACE
                Node elem1 = ((Element)obj_el).getFirstChild();
                String s1 = elem1.getNodeValue();
                HashSet hs = new HashSet();
                // while () ...
                //      URMAction a1 = new URMActionImpl(s1);
                //      hs.add(a1);
                return hs;
            }
            else
                return null;
        } catch (TXQueryException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        else throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }
     */
    /******************* URMAclAdmin methods ******************* end **********/

    /* (non-Javadoc)
    */
    public void setAclInheritable(String aclId, boolean inheritable)
            throws 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 (this.existAcl(aclId)) {
            TXQuery query = TXQuery.newInstance("update insert <Inheritable>" + inheritable + "</Inheritable> " +
                                "into input()/AccessControlList[ResourceId[" + aclId + "']]");
            try {
                TResponse response = objectAccessor.xquery(query);
               // if acl has been cached, remove it from cache
                if (actionCache != null ) {
                    if (tConn.accessCache()) {
                        aclCache.remove(aclId);
                        aclListenerSet.removeEvent(aclId);
                    } else {
                        // add new value to deltaCache, because it is removed
                        tConn.getAclDeltaCache().put(aclId, getAcl(aclId));
                    }
                }
                TXMLObjectIterator iter = response.getXMLObjectIterator();
                if (iter == null || !iter.hasNext()) {
                    return;
                } else {
                    throw new URMInsertException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0033"));
                }
            } catch (TXQueryException e) {
                throw new URMInsertException(msLogger, "E", e);
            }
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMInsertException)
            throw (URMInsertException)e;
        else if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        else throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    /* (non-Javadoc)
     * @return a List of URMAce
     */
    public List getAllAces(String aclId) throws URMInternalServerException {

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

        List list = null;
        list = new ArrayList();

        TResponse response = null;
        TXMLObjectIterator iter = null;
        int maxInd = 10; // that's a good start anyway
        String oAction = null;
        int oActType = 0;
        String oSubject = null;
        int oSubType = 0;
        String oSubDom = null;
        boolean oinvert = false;

        TXQuery query = TXQuery.newInstance("for    $b in input()/AccessControlList " +
                                            "where  $b/ResourceId = '" + aclId + "' " +
                                            "return $b/ACE");
        try {
            response = objectAccessor.xquery(query);
            iter = response.getXMLObjectIterator();

            int i = 0;
            maxInd = 0; // reset loop counter
            while (iter != null && iter.hasNext()) {
                maxInd++;
                TXMLObject tobj = iter.next();
                Object obj_el = tobj != null ? tobj.getElement() : null;
                if (obj_el != null && obj_el instanceof Element) {
                    if (((Element)obj_el).hasAttributes()) {
                        NamedNodeMap indAttr = ((Element)obj_el).getAttributes();
//                        Node indType = indAttr.getNamedItem("Position");
//                        if (indType != null) {
//                            i = new Integer(indType.getNodeValue()).intValue();
//                        }
                        Node invert = indAttr.getNamedItem("Invert");
                        if (invert != null) {
                            oinvert = (invert.getNodeValue().equals("true"));
                        }

                    }
                    Node aceNode = ((Element)obj_el).getFirstChild();
                    while (aceNode != null) {

                        // Read the Subject element
                        if (aceNode != null && "Subject".equals(aceNode.getNodeName())) {
                            oSubject = aceNode.getFirstChild().getNodeValue();
                            if (aceNode.hasAttributes()) {
                                NamedNodeMap subAttr = aceNode.getAttributes();
                                Node subType = subAttr.getNamedItem("Type");
                                if (subType != null) {
                                    oSubType = new Integer(subType.getNodeValue()).intValue();
                                }
                                Node subDom = subAttr.getNamedItem("Domain");
                                if (subDom != null) {
                                    oSubDom = subDom.getNodeValue();
                                }
                            }
                        } else

                        // Read the Action element
                        if ("Action".equals(aceNode.getNodeName())){
                            oAction = aceNode.getFirstChild().getNodeValue();
                            if (aceNode.hasAttributes()) {
                                NamedNodeMap actAttr = aceNode.getAttributes();
                                Node actType = actAttr.getNamedItem("Type");
                                if (actType != null) {
                                    oActType = new Integer(actType.getNodeValue()).intValue();
                                }
                            }
                        }
                        aceNode =  aceNode.getNextSibling();
                    }
                }

                list.add(i, new URMAceImpl(oActType,
                                           oSubject,
                                           oSubType,
                                           oSubDom,
                                           oAction,
                                           oinvert,
                                           this));
                i++;
            }

        return list;
        } catch (URMAceCreateException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        } 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) {
            throw new URMInternalServerException(msLogger, "E", e);
        }

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

    /* (non-Javadoc)
     */
    public void updateOrder(String aclId, /*int[] oldIds,*/ int[] newIds)
        throws URMAclException, URMUpdateException, URMInternalServerException {

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

//        Set set = new HashSet();
        int maxInd = 10; // that's a good start anyway
        ArrayList oAction = new ArrayList(maxInd);
        ArrayList oActType = new ArrayList(maxInd);
        ArrayList oSubject = new ArrayList(maxInd);
        ArrayList oSubType = new ArrayList(maxInd);
        ArrayList oSubDom = new ArrayList(maxInd);
        ArrayList oInvert = new ArrayList(maxInd);

        TResponse response = null;
        TXMLObjectIterator iter = null;

        TXQuery query = TXQuery.newInstance("for    $b in input()/AccessControlList " +
                                            "where  $b/ResourceId = '" + aclId + "' " +
                                            "return $b/ACE");

        try {
            response = objectAccessor.xquery(query);
            iter = response.getXMLObjectIterator();

            int i = 0;
            maxInd = 0; // reset loop counter
            while (iter != null && iter.hasNext()) {
                maxInd++;
                TXMLObject tobj = iter.next();
                Object obj_el = tobj != null ? tobj.getElement() : null;
                if (obj_el != null && obj_el instanceof Element) {
                    if (((Element)obj_el).hasAttributes()) {
                        NamedNodeMap indAttr = ((Element)obj_el).getAttributes();
//                        Node indType = indAttr.getNamedItem("Position");
//                        if (indType != null) {
//                            i = new Integer(indType.getNodeValue()).intValue();
//                        }
                        Node invertNode = indAttr.getNamedItem("Invert");
                        if (invertNode != null) {
                            oInvert.add(i, invertNode.getNodeValue());
                        }

                    }
                    Node aceNode = ((Element)obj_el).getFirstChild();
                    while (aceNode != null) {

                        // Read the Subject element
                        if (aceNode != null && "Subject".equals(aceNode.getNodeName())) {
                            oSubject.add(i,aceNode.getFirstChild().getNodeValue());
                            if (aceNode.hasAttributes()) {
                                NamedNodeMap subAttr = aceNode.getAttributes();
                                Node subType = subAttr.getNamedItem("Type");
                                if (subType != null) {
                                    oSubType.add(i, subType.getNodeValue());
                                }
                                Node subDom = subAttr.getNamedItem("Domain");
                                if (subDom != null) {
                                    oSubDom.add(i, subDom.getNodeValue());
                                } else {
                                    oSubDom.add(i, "");
                                }
                            }
                        } else

                        // Read the Action element
                        if ("Action".equals(aceNode.getNodeName())){
                            oAction.add(i, aceNode.getFirstChild().getNodeValue());
                            if (aceNode.hasAttributes()) {
                                NamedNodeMap actAttr = aceNode.getAttributes();
                                Node actType = actAttr.getNamedItem("Type");
                                if (actType != null) {
                                    oActType.add(i, actType.getNodeValue());
                                }
                            }
                        }

                        aceNode =  aceNode.getNextSibling();

                    }
                }
                i++;
            }
        } catch (TXQueryException e) {
            throw new URMUpdateException(msLogger, "E", e);
        } catch (TNoSuchXMLObjectException e) {
            throw new URMUpdateException(msLogger, "E", e);
        } catch (TIteratorException e) {
            throw new URMUpdateException(msLogger, "E", e);
        }


        String strACEs = new String();
        String strDomain = new String();

        if (oAction.size() != newIds.length) {
            throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0034"));
        }

//        Object updSet[] = new Object[newIds.length - 1];

        // Store the Acl with a different Ace sequence.

        // Prepare the Ace insertion string
        String strDel = "";
        int j = 0;
        int i = 0;
        while (maxInd > j ) {
            i = newIds[j];
            String domain = (String) oSubDom.get(i);
            if (!domain.equals("")){
                strDomain = "Domain=" + domain;
            } else {
                strDomain = "";
            }
            strACEs = strACEs.concat(strDel + "<ACE Position='" + j + "'" + "Invert='" + oInvert.get(i) + "'>" +
                                             "<Subject Type='" + oSubType.get(i) +
                                             strDomain + "'>" + oSubject.get(i) +
                                             "</Subject><Action Type='" + oActType.get(i) + "'>" + oAction.get(i) +
                                             "</Action></ACE>");
            strDel = ",";
            j++;
        }

        // First remove the old Ace's
        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()/AccessControlList[ResourceId = '" + aclId + "']/ACE");
                response = objectAccessor.xquery(query2);
                iter = response.getXMLObjectIterator();
            }
        }  catch (TXQueryException e) {
            throw new URMUpdateException(msLogger, "E", e);
        }

        // Store new
        query = TXQuery.newInstance("update insert (" + strACEs +
                                    ") following input()/AccessControlList[ResourceId = '" + aclId + "']/Owner");
        try {
            response = objectAccessor.xquery(query);
            // if acl has been cached, remove it from cache
            if (actionCache != null ) {
                if (tConn.accessCache()) {
                   aclCache.remove(aclId);
                   aclListenerSet.removeEvent(aclId);
                } else {
                    // add new value to deltaCache, because it is removed
                    tConn.getAclDeltaCache().put(aclId, getAcl(aclId));
                }
            }
            iter = response.getXMLObjectIterator();
            if (iter == null || !iter.hasNext()) {
                throw new URMUpdateException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0035"));
            }
        } catch (TXQueryException e) {
            throw new URMUpdateException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMAclException)
            throw (URMAclException)e;
        else if (e instanceof URMUpdateException)
            throw (URMUpdateException)e;
        else if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        else throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    /* (non-Javadoc)
     *
     */
    public void updateOwner(String aclId, String owner, int ownerType, String ownerDomain)
            throws URMUpdateException, URMInternalServerException {

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

        if (!this.existAcl(aclId)) {
            throw new URMUpdateException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0036", aclId));
        }

        TXQuery query = TXQuery.newInstance("update replace input()/AccessControlList[ResourceId = '" + aclId + "']/Owner " +
                                            "with <Owner Type='" + ownerType + "' " +
                                             (ownerDomain == null ? "" : ("Domain = '" + ownerDomain + "' ")) +
                                            "> " + owner + " </Owner>");
        try {
            TResponse response = objectAccessor.xquery(query);
            // if acl has been cached, remove it from cache
            if (actionCache != null ) {
                if (tConn.accessCache()) {
                    aclCache.remove(aclId);
                    // aclListenerSet.removeEvent(aclId); Owner is not checked by the Semantic at them moment
                } else {
                    // add new value to deltaCache, because it is removed
                    tConn.getAclDeltaCache().put(aclId, getAcl(aclId));
                }
            }
            TXMLObjectIterator iter = response.getXMLObjectIterator();
            if (iter == null || !iter.hasNext()) {
                throw new URMUpdateException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0037", aclId));
            }
        } catch (TXQueryException e) {
            throw new URMUpdateException(msLogger, "E", e);
        }


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

    /*
     * define one additional ACE and the position where to insert
     * 0 = always first
     * 1 = after first existing, new position 2
     * >max = always last
     */
    public List defineAce(String aclId,
                          String resOwner,
                          int resOwnerType,
                          String resDomain,
                          boolean resInherit,
                          int type,
                          String subject,
                          int subjectType,
                          String domain,
                          String action,
                          int position,
                          boolean invert,
                          List list)
                        throws URMUnknownSubjectException,
                               URMUnknownActionException,
                               URMAceCreateException,
                               URMInternalServerException {
    
    try {
        String invertStr = (new Boolean(invert)).toString();
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(UPDATE)) == null)
            throw new URMAceCreateException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();
    
        TResponse response = null;

        if (position >= list.size()) position = list.size();
             
        // Store new
        TXQuery query = TXQuery.newInstance("update insert (" +
                   "<ACE Position='" + position + "'" + "Invert='" + invertStr + "'>" +
                   "<Subject Type='" + subjectType +
                   (domain != null ? ("' Domain = '" + domain + "'>") : "'>") + subject +
                   "</Subject><Action Type='" + type + "'>" + action +
                   "</Action></ACE>"+
                   ") following input()/AccessControlList[ResourceId = '" + aclId + "']/" +
                   (position == 0 ? "Owner" : ("ACE[" + position + "]")));
        
        try {
             response = objectAccessor.xquery(query);
             URMAce ace = new URMAceImpl(type, subject, subjectType, domain, action, invert,this);
             list.add(position, ace);
             URMAcl newAcl = new URMAclImpl(this, aclId, resOwner, resOwnerType, resDomain, resInherit, list);
             // if acl has been cached, remove it from cache
             if (actionCache != null ) {
                if (tConn.accessCache()) {
                    aclCache.add(aclId, newAcl);
                    aclListenerSet.removeEvent(aclId);
                } else {
                    // add new value to deltaCache, because it is removed
                    tConn.getAclDeltaCache().put(aclId, newAcl);
                }
             }
        } catch (TXQueryException e) {
            throw new URMAceCreateException(msLogger, "E", e);
        }
        return list;
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMUnknownSubjectException)
            throw (URMUnknownSubjectException)e;
        else if (e instanceof URMUnknownActionException)
            throw (URMUnknownActionException)e;
        else if (e instanceof URMAceCreateException)
            throw (URMAceCreateException)e;
        else if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        else throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    /* (non-Javadoc)
     */
    public List removeAce (String aclId,
                            String resOwner,
                            int resOwnerType,
                            String resDomain,
                            boolean resInherit,
                            int id,
                            List list)
        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();

        // switch to Tamino counting:
        // Tamino occurrences start with 1
        // Java occurrences start with 0
        TXQuery query = TXQuery.newInstance("update delete " +
            "input()/AccessControlList[ResourceId = '" + aclId + "']/ACE[" + (id+1) + "]");
        try {
            TResponse response = objectAccessor.xquery(query);
        } catch (TXQueryException e) {
            throw new URMDeleteException(msLogger, "E", e);
        }

        if (id < list.size() && id >= 0) list.remove(id);
        // if acl has been cached, remove it from cache
        URMAcl newAcl = new URMAclImpl(this, aclId, resOwner, resOwnerType, resDomain, resInherit, list);
        // if acl has been cached, remove it from cache
        if (actionCache != null ) {
            if (tConn.accessCache()) {
                aclCache.add(aclId, newAcl);
                aclListenerSet.removeEvent(aclId);
            } else {
                // add new value to deltaCache, because it is removed
                tConn.getAclDeltaCache().put(aclId, newAcl);
            }
        }
        return list;
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMDeleteException)
            throw (URMDeleteException)e;
        else if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        else throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }


    /******************* URMAcl methods ************************ end **********/


    /******************* URMAction methods ***************** start ************/

    /* (non-Javadoc)
     */
    public void removeAction(String name)
        throws 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 ACEs containing this action
        TXQuery xquery = TXQuery.newInstance("for    $b in input()/AccessControlList " +
                                             "where  $b/ACE/Action = '" + name + "' " +
                                             "return $b/ActionId");
        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, "URMCOE0030", name));
            }
        } catch (TXQueryException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }

        // Check also for any existing base Actions
        xquery = TXQuery.newInstance("for    $b in input()/Action " +
                                     "where  $b/BaseAction = '" + name + "' " +
                                     "return $b/ActionId");
        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, "URMCOE0029", name));
            }
        } catch (TXQueryException e) {
            throw new URMDeleteException(msLogger, "E", e);
        }
        
        // Check also for any existing predefined Action
        xquery = TXQuery.newInstance("for    $b in input()/Role " +
                                     "where  $b/PredefinedActions = '" + name + "' " +
                                     "return $b/RoleName");
        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, "URMCOE0029", name));
            }
        } catch (TXQueryException e) {
            throw new URMDeleteException(msLogger, "E", e);
        }


        TQuery query = TQuery.newInstance("Action[ActionId = '" + name + "']");
        try {
            TResponse response = objectAccessor.delete(query);

            // if action has been cached, remove it from cache
            if (actionCache != null ) {
                if (tConn.accessCache()) {
                    actionCache.remove(name);
                    aclListenerSet.resetEvent();
                } else {
                    // value is null, because it is removed
                    tConn.getActionDeltaCache().put(name, null);
                }
            }
        } catch (TDeleteException e) {
            throw new URMDeleteException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        else if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        else if (e instanceof URMDeleteException)
            throw (URMDeleteException)e;
        else throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    /*
     *
     */
    public void addBaseAction(String name, String baseAction)
        throws URMForbiddenException,
               URMInsertException, URMInternalServerException {

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

        // Check that Ancestor is an existing Role
        if (!this.existAction(name)) {
            throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0038", name));
        }

        // Check that the Base is an existing Role
        if (!this.existAction(baseAction)) {
            throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0038", baseAction));
        }

        try {
            checkActionCircularDependency(baseAction, name);
        } catch (URMForbiddenException e) {
            throw new URMInsertException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0043", baseAction, name));
        }

/*        // Check if the base action itself is an aggregated one.
        TXQuery query = TXQuery.newInstance("for    $b in input()/Action " +
                                            "where  $b/ActionId = '" + baseAction + "' " +
                                            "return $b/BaseAction");
        try {
            TResponse response = objectAccessor.xquery(query);
            TXMLObjectIterator iter = response.getXMLObjectIterator();
            if (iter != null && iter.hasNext()) {
                throw new URMInsertException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0039"));
            }
        } catch (TXQueryException e) {
            throw new URMInsertException(msLogger, "E", e);
            }
*/
        // See if this base action already exist.
        try {
            TXQuery query = TXQuery.newInstance("for    $b in input()/Action " +
                                        "where  $b/ActionId = '" + name + "' " +
                                        "return $b/BaseAction");
            try {
                TResponse response = objectAccessor.xquery(query);
                TXMLObjectIterator 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 node = ((Element)obj_el).getFirstChild();
                        if (node != null)
                            if (node.getNodeValue().equals(baseAction))
                                throw new URMInsertException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0040", name));
                    }
                }
            } 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 (URMInternalServerException e) {
            throw new URMInsertException(msLogger, "E", e);
        }

        TXQuery query = TXQuery.newInstance("update insert <BaseAction>" + baseAction + "</BaseAction> " +
                                    "into input()/Action[ActionId = '" + name + "']");
        try {
            TResponse response = objectAccessor.xquery(query);
            TXMLObjectIterator iter = response.getXMLObjectIterator();
        } catch (TXQueryException e) {
            throw new URMInsertException(msLogger, "E", e);
        }

        // if action has been cached, remove the old status from cache
        if (actionCache != null ) {
            if (tConn.accessCache()) {
                actionCache.remove(name);
                aclListenerSet.resetEvent();
            } else {
              // remove and reload the action to keep the cache valid
              tConn.getActionDeltaCache().remove(name);
              tConn.getActionDeltaCache().put(name, getAction(name));
            }
        }

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

    /*
     *
     */
    public void removeBaseAction(String name, String baseAction)
        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();


        TXQuery query = TXQuery.newInstance("update delete " +
            "input()/Action[BaseAction = '" + baseAction + "' and " +
                "ActionId = '" + name + "']/BaseAction[text()= '" + baseAction + "']");
        try {
            TResponse response = objectAccessor.xquery(query);
            if (response.getFirstXMLObject() == null)
                throw new URMDeleteException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0038", baseAction));

            // if action has been cached, remove the old status from cache
            if (actionCache != null ) {
                if (tConn.accessCache()) {
                    actionCache.remove(name);
                    aclListenerSet.resetEvent();
                } else {
                  // remove and reload the action to keep the cache valid
                  tConn.getActionDeltaCache().remove(name);
                  tConn.getActionDeltaCache().put(name, getAction(name));
                }
            }
        } catch (TXQueryException e) {
            throw new URMDeleteException(msLogger, "E", e);
        }

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

    /******************* URMAction methods ********************* end **********/


    /******************* Special methods *********************** start ********/

    /**
     * Helper function to the reporting functions.
     * The input parameter specifies a path ('/' separated) of resource Ids.
     * All ACLs (referenced via the resource Ids) will be inspected.
     * The second input parameter specifies a list of actions.
     * Returned will only the ACLs and ACEs that contain an action, specified
     * in inActions.
     *
     * @param resourceIds List of ACLs in the order they should be validated
     * @param inActions of Strings inActions. Action names to be identified.
     *
     * @return List of ACLs with only these ACEs that contain one of the inAction
     * parameter.
     *
     * @throws URMInternalServerException
     */
    public List getAclsWithSpecificAction(List resourceIds,
                                             List inActions)
        throws URMInternalServerException {

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

        List retList = new ArrayList();


        /*
         * Loop over all ACLs
         */
        boolean firstAcl = true; // processing the deepest resource Id
        boolean aceCreated = false;
        Iterator resourceIter = resourceIds.iterator();

        while (resourceIter != null && resourceIter.hasNext()) {

            List tempAceList = new ArrayList(); // of URMAce's
            String currentAclId = (String)resourceIter.next();
            URMAcl currentAcl = this.getAcl(currentAclId);
            // Only continue, if the Inheritable flag is set or
            // if it's the deepest (first) Acl.
            if ((currentAcl != null) && (currentAcl.getInheritable() || firstAcl)) {
                firstAcl = false;
                List currentAces = this.getAllAces(currentAclId);

                // Loop over all actions (Ace) of one Acl
                Iterator currentAceIter = currentAces.iterator();
                while (currentAceIter != null && currentAceIter.hasNext()) {
                    URMAce currentAce = (URMAce)currentAceIter.next();

                    if (currentAce != null) { // should always be true!
                        URMAction currentAction = currentAce.getAction();
                        Set currentActionBaseActions = currentAction.getBaseActions();

                        // Loop over all input actions
                        Iterator inActionIter = inActions.iterator();
                        while (inActionIter != null && inActionIter.hasNext()) {
                            String inCheckAction = (String)inActionIter.next();
                            if (currentAction.getName().equals(inCheckAction) || currentActionBaseActions.contains(inCheckAction)) {
                                aceCreated = true;
                                tempAceList.add(currentAce);
                            }
                        }
                    } else {
                        throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0041"));
                    }
                }
                if (aceCreated) {
                    try {
                        URMAcl retAcl = new URMAclImpl(this,
                                                       currentAclId,
                                                       currentAcl.getOwner().getName(),
                                                       currentAcl.getOwner().getType(),
                                                       currentAcl.getOwner().getDomain(),
                                                       currentAcl.getInheritable(),
                                                       tempAceList);
                    retList.add(retAcl);
                    } catch (URMParameterException e) {
                        throw new URMInternalServerException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0041"));
                    }
                }
                // next Acl please
                aceCreated = false;
            } else {
                firstAcl = false;
            }
        }
        return retList;
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    // just for internal usage (for synchronization with the user database)
    // called by URMRoleManagerSpiTamino.syncronizeUsersGroupsRoles(...)
    public static void clearAclCache() {
        if (aclCache != null)
            aclCache.clear();
    }

    /******************* Special methods *********************** end **********/

    /* (non-Javadoc)
     */
    private void close() throws URMCloseConnectionException {
        if (!mIsAlreadyClosed)
            mIsAlreadyClosed = true;
        return;
    }

    /*
     * existAcl checks whether the given ResourceId exists as a
     * valid ACL in the Database.
     *
     * @param resource id
     * @return true / false
     *
     */
    private boolean existAcl(String id)
        throws URMInternalServerException {

    // check if acl is in the cache and if in transaction, check if it has not bee deleted
    if (aclCache != null) {
        Map aclDeltaCache = getAclDeltaCache();
        if ((accessCacheAllowed()) && (aclCache.contains(id))){
            try {
                if (aclCache.get(id,this) != null) return true;
                else return false;
            } catch (URMException e) {
                throw new URMInternalServerException(e);
            }
            }
        else if ((aclDeltaCache != null) && (aclDeltaCache.containsKey(id))) {
            if (aclDeltaCache.get(id) != null) return true;
            else return false;
        }
    }

    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()/AccessControlList " +
                                            "where  $b/ResourceId = '" + id + "' " +
                                            "return $b/ResourceId");
        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();
                return true;
            }
            else
                return false;
        } catch (TXQueryException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    /*
     * existAction checks whether the given ResourceId exists as a
     * valid Action in the Database.
     *
     * @param resource id
     * @return true / false
     *
     */
    private boolean existAction(String id)
        throws URMInternalServerException {

    // check if action is in the cache and if in transaction, check if it has not bee deleted
    if (actionCache != null) {
        if ((accessCacheAllowed()) && (actionCache.contains(id)))
            return true;
       else {
            Map actionDeltaCache = getActionDeltaCache();
            if ((actionDeltaCache != null) && (actionDeltaCache.containsKey(id))) {
                if (actionDeltaCache.get(id) != null) return true;
                else return false;
            }
       }
    }

    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()/Action " +
                                            "where  $b/ActionId = '" + id + "' " +
                                            "return $b/ActionId");
        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();
                return true;
            }
            else
                return false;
        } catch (TXQueryException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    private void checkActionCircularDependency(String newAct, 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 (newAct.equals(current)) {
            throw new URMForbiddenException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0043", current, newAct));
        }
        Set newset = new HashSet();
        TXQuery xquery = TXQuery.newInstance("for    $b in input()/Action " +
                                             "where  $b/BaseAction = '" + current + "' " +
                                             "return $b/ActionId");
        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()) {
            checkActionCircularDependency(newAct, (String) iter.next());
        }
    } catch (Exception e) {
        epilogue(false);
        if (e instanceof URMForbiddenException)
            throw (URMForbiddenException)e;
        throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogue(true);
    }
    }

    /*
     * resolveAggregatedAction returns all base actions if the input parameter
     * is an aggregated action.
     */
    private Set resolveAggregatedAction(String action)
        throws URMInternalServerException {

    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()/Action " +
                                            "where  $b/ActionId = '" + action + "' " +
                                            "return $b/ActionId/BaseAction");
        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){
                HashSet hs = new HashSet();
                Node elem1 = ((Element)obj_el).getFirstChild();
                while (elem1 != null) {
                    hs.add(elem1.getNodeValue());
                    elem1 = elem1.getNextSibling();
                }
                return hs;
            }
            else
                return null;
        } catch (TXQueryException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }

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

    /*
     * 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);
    }

    /*
     * get current delta caches
     */
    private Map getActionDeltaCache()
        throws URMInternalServerException {
        if (mConn == null)
            try {
                mConn = URMTaminoConnectionHandler.getInstance(mConfigurator);
            } catch (Exception e) {
                throw new URMInternalServerException(msLogger, "URMCOF0047", e);
            }

        return mConn.getActionDeltaCache(mOwner);
    }

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

        return mConn.getAclDeltaCache(mOwner);
    }

    /*
     * Always perform this at the beginning of each method
     */
    private URMTaminoConnection prologue(int mode)
        throws URMInternalServerException {

        if (mIsAlreadyClosed) {
            return null;
        }
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        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);
    }
        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 an endTransaction method
     */
    private boolean epilogueTA(boolean commit) throws URMInternalServerException {
        try {
            return mConn.releaseTAConnection(commit, mOwner);
        } catch (URMConnectionException e) {
            throw new URMInternalServerException(msLogger, "URMCOF0048", e);
        }
    }

    /*
     * beginTranscation invokes the Tamino useLocalTransactionMode() in the prologue
     * Also create a new TaminoConnection object (per Principal / per Thread) with
     * new delta - caches for ACLs and Actions
     */
    public void beginTransaction() throws URMDBTransactionException, URMInternalServerException {
        try {
            TXMLObjectAccessor objectAccessor = null;
            URMTaminoConnection tConn = null;
            if ((tConn = prologue(START_TA)) == null)
                throw new URMDBTransactionException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
            objectAccessor = tConn.getAccessor();

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

    /*
     * Perform the explicit commit/rollback.
     * The delta chaches will be used in epilogueTA to remove the corresponding objects
     * from the static caches.
     */
    public void endTransaction(boolean manner) throws URMDBTransactionException, URMInternalServerException {
    try {
        TXMLObjectAccessor objectAccessor = null;
        URMTaminoConnection tConn = null;
        if ((tConn = prologue(manner == true ? COMMIT_TA : ROLLBACK_TA)) == null)
            throw new URMDBTransactionException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0004"));
        objectAccessor = tConn.getAccessor();

    } catch (Exception e) {
        epilogueTA(false);
        if (e instanceof URMInternalServerException)
            throw (URMInternalServerException)e;
        else throw new URMInternalServerException (e); //(RuntimeException)e;
    } finally {
        epilogueTA(manner);
    }
    }
    
    /**
     * Signals the cache that an ACL does not exist
     */
    public void addTransientEmptyAcl (String aclId) {
        if (aclCache != null) aclCache.add(aclId,null);
    }
}













