/*
 * $Header: /home/cvspublic/jakarta-slide/src/share/org/apache/slide/common/SlideTokenImpl.java,v 1.17 2005/02/28 17:25:44 luetzkendorf Exp $
 * $Revision: 1.17 $
 * $Date: 2005/02/28 17:25:44 $
 *
 * ====================================================================
 *
 * Copyright 1999-2002 The Apache Software Foundation 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package org.apache.slide.common;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import org.apache.slide.authenticate.CredentialsToken;
import org.apache.slide.store.ResourceId;
import org.apache.slide.structure.ActionNode;
import org.apache.slide.structure.ObjectNode;
import org.apache.slide.structure.SubjectNode;

/**
 * Slide token class.
 *
 */
public final class SlideTokenImpl implements SlideToken {
    
    
    // ------------------------------------------------------------ Constructor
    
    
    /**
     * Constructor.
     *
     * @param credentialsToken Credentials stored in this token
     */
    public SlideTokenImpl(CredentialsToken credentialsToken) {
        this.credentialsToken = credentialsToken;
    }
    
    
    /**
     * Constructor.
     */
    public SlideTokenImpl() {
    }
    
    
    /**
     * Constructor.
     *
     * @param credentialsToken Credentials stored in this token
     * @param parameters Token parameters
     */
    public SlideTokenImpl(CredentialsToken credentialsToken,
                          Hashtable parameters) {
        this.credentialsToken = credentialsToken;
        this.parameters = new Hashtable(parameters);
    }
    
    
    // ----------------------------------------------------- Instance Variables
    
    
    /**
     * Credentials.
     */
    private CredentialsToken credentialsToken;
    
    
    /**
     * CacheInfo.
     */
    private CacheInfoToken cacheInfoToken;
    
    
    /**
     * Use lock tokens for lock resolution.
     */
    private boolean enforceLockTokens = false;
    
    
    /**
     * Always use a transaction for all operations. That will cause Slide to
     * enlist the store in the current transaction for all operations,
     * to be able to prevent dirty reads when doing complex updates.
     */
    private boolean forceStoreEnlistment = false;
    
    
    /**
     * Lock tokens.
     */
    private Hashtable lockTokens = new Hashtable();
    
    
    /**
     * Parameters.
     */
    private Hashtable parameters = new Hashtable();
    
    /**
     * Caches
     */
    private Hashtable permissionCache = new Hashtable();
    private Hashtable lockCache = new Hashtable();
    private Hashtable resolveCache = new Hashtable();
    private Hashtable matchPrincipalCache = new Hashtable();

    /**
     * Determines if this request is part of an externally controlled transaction. 
     */
    private boolean isExternalTransaction = false;
    
    
    // ------------------------------------------------------------- Properties
    
    
    /**
     * Returns the credentials token.
     *
     * @return String
     */
    public CredentialsToken getCredentialsToken() {
        return credentialsToken;
    }
    
    
    /**
     * Credentials token mutator.
     */
    public void setCredentialsToken(CredentialsToken credentialsToken) {
        this.credentialsToken = credentialsToken;
    }
    
    
    /**
     * Returns the CacheInfo token.
     *
     * @return CacheInfoToken
     */
    public CacheInfoToken getCacheInfoToken() {
        return cacheInfoToken;
    }
    
    
    /**
     * CacheInfo token mutator.
     */
    public void setCacheInfoToken(CacheInfoToken cacheInfoToken) {
        this.cacheInfoToken = cacheInfoToken;
    }
    
    
    /**
     * Use lock tokens in lock resolution ?
     *
     * @return boolean
     */
    public boolean isEnforceLockTokens() {
        return enforceLockTokens;
    }
    
    
    /**
     * Enforce lock tokens flag mutator.
     *
     * @param enforceLockTokens New flag value
     */
    public void setEnforceLockTokens(boolean enforceLockTokens) {
        this.enforceLockTokens = enforceLockTokens;
    }
    
    
    /**
     * Force store enlistment flag accessor. If true, that will cause Slide to
     * enlist the store in the current transaction for all operations,
     * to be able to prevent dirty reads when doing complex updates.
     *
     * @return boolean
     */
    public boolean isForceStoreEnlistment() {
        return forceStoreEnlistment;
    }
    
    
    /**
     * Force store enlistment flag mutator. If set to true, that will cause
     * Slide to enlist the store in the current transaction for all
     * operations, to be able to prevent dirty reads when doing complex
     * updates. That value should be set to true only in some very specific
     * critical sections of the code, as this would greatly decrease the
     * ability of Slide to handle multiple concurrent requests.
     *
     * @param forceStoreEnlistment New flag value
     */
    public void setForceStoreEnlistment(boolean forceStoreEnlistment) {
        this.forceStoreEnlistment = forceStoreEnlistment;
    }
    
    
    /**
     * Add a new lock token to the lock token list.
     *
     * @param lockId Lock token to add
     */
    public void addLockToken(String lockId) {
        lockTokens.put(lockId, lockId);
    }
    
    
    /**
     * Removes a lock token from the lock token list.
     *
     * @param lockId Lock token to remove
     */
    public void removeLockToken(String lockId) {
        lockTokens.remove(lockId);
    }
    
    
    /**
     * Clears the lock token list.
     */
    public void clearLockTokens() {
        lockTokens.clear();
    }
    
    public List showLockTokens() {
        return new ArrayList(lockTokens.keySet());
    }
    
    /**
     * Checks if the given lock token is present.
     *
     * @param lockToken Lock token to check
     * @return boolean True if the given lock token is present
     */
    public boolean checkLockToken(String lockToken) {
        return lockTokens.containsKey(lockToken);
    }
    
    
    /**
     * Add a new parameter to the parameter list.
     *
     * @param parameterName Parameter to add
     * @param parameterValue Parameter value
     */
    public void addParameter(String parameterName, Object parameterValue) {
        parameters.put(parameterName, parameterValue);
    }
    
    
    /**
     * Removes a parameter from the parameter list.
     *
     * @param parameterName Parameter to remove
     */
    public void removeParameter(String parameterName) {
        parameters.remove(parameterName);
    }
    
    
    /**
     * Clears the parameter list.
     */
    public void clearParameters() {
        parameters.clear();
    }
    
    
    /**
     * Return parameter list.
     */
    public Enumeration getParameterNames() {
        return parameters.keys();
    }
    
    /**
     * Returns a named parameter. 
     */
    public Object getParameter(String name) {
        return parameters.get(name);
    }
    
    /**
     * allows to cache the result of a permission check
     *
     * @return true if successful added to cache, false else
     */
    public void cachePermission(ObjectNode object, ActionNode action, boolean permission){
        String key = object.getUri()+ action.getUri();
        Boolean perm = (permission ? Boolean.TRUE : Boolean.FALSE);
        permissionCache.put(key,perm);
    }
    
    /**
     * checks if the permission cache contains an entry for the ObjectNode and
     * ActionNode combination.
     *
     * @return true if granted, false if denied, null if nothing in the cache.
     */
    public Boolean checkPermissionCache(ObjectNode object, ActionNode action){
        String key = object.getUri()+ action.getUri();
        return (Boolean) permissionCache.get(key);
    }
    
    /**
     * Force security check. Always TRUE for tokens.
     * User SlideTokenWrapper to obtain temporaryly insecure tokens.
     *
     * @return   a boolean
     */
    public boolean isForceSecurity() {
        return true;
    }
    
    /**
     * Force lock check. If false, checkLock of LockImpl will
     * return immediately.
     *
     * @return   a boolean
     */
    public boolean isForceLock() {
        return true;
    }
    
    /**
     * allows to cache the result of a lock check
     */
    public void cacheLock(ObjectNode object, ActionNode action, boolean lock) {
        String key = object.getUri()+ action.getUri();
        Boolean locked = (lock ? Boolean.TRUE : Boolean.FALSE);
        lockCache.put(key,locked);
    }
    
    /**
     * checks if the lock cache contains an entry for the ObjectNode and
     * ActionNode combination.
     *
     * @return true if locked, false otherwise
     */
    public Boolean checkLockCache(ObjectNode object, ActionNode action) {
        String key = object.getUri()+ action.getUri();
        return (Boolean) lockCache.get(key);
    }
    
    /**
     * Allows to cache the result of a resolve operation
     */
    public void cacheResolve(Uri uri, ResourceId resourceId) {
        if (resourceId != null) {
            resolveCache.put(uri, resourceId);
        } else {
            resolveCache.remove(uri);
        }
    }
    
    /**
     * Checks if the resolve cache contains an entry for the specified uri.
     * @return the cached resourceId or null
     */
    public ResourceId checkResolveCache(Uri uri) {
        return (ResourceId)resolveCache.get(uri);
    }
    
    /**
     * Allows to cache the result of a matchPrincipal operation
     */
    public void cacheMatchPrincipal(SubjectNode checkSubject, SubjectNode matchSubject, boolean match) {
        String key = String.valueOf(checkSubject)+String.valueOf(matchSubject);
        matchPrincipalCache.put(key, (match ? Boolean.TRUE : Boolean.FALSE));
    }
    
    /**
     * Checks if the matchPrincipal cache
     * @return the cached Boolean or null
     */
    public Boolean checkMatchPrincipalCache(SubjectNode checkSubject, SubjectNode matchSubject) {
        String key = String.valueOf(checkSubject)+String.valueOf(matchSubject);
        return (Boolean)matchPrincipalCache.get(key);
    }
    
    public void setForceLock(boolean forceLock) {
        throw new UnsupportedOperationException();
    }
    
    public void setForceSecurity(boolean forceSecurity) {
        throw new UnsupportedOperationException();
    }

    /**
     * Checks if this request is part of an externally controlled transaction. 
     */
    public boolean isExternalTransaction() {
        return isExternalTransaction;
    }

    /**
     * Sets if this request is part of an externally controlled transaction. 
     */
    public void setExternalTx() {
        isExternalTransaction = true;
    }
    
}

