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

package org.apache.slide.urm.realm;

import java.util.Collections;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;

import org.apache.slide.urm.common.URMPrincipal;

/**
 * @author eckehard.hermann@softwareag.com
 * @author dieter.kessler@softwareag.com
 * @author zsolt.sasvarie@softwareag.com
 *
 * To change the template for this generated type comment go to
 * Window>Preferences>Java>Code Generation>Code and Comments
 */
public class PrincipalCache {
    private Hashtable   mPrincipalCache      = new Hashtable();
    private List        mCachedPrincipalKeys = null;
    private long        mPricipalCacheSize   = 0;
    private long        mPricipalValidTime   = 0;

    public PrincipalCache(long sizelimit, long validtime) {
        this.mPricipalCacheSize = sizelimit;
        this.mPricipalValidTime  = validtime;
        synchronized (mPrincipalCache) {
            if (mCachedPrincipalKeys == null) {
                mCachedPrincipalKeys = (Collections.synchronizedList(new LinkedList()));
            }
        }
    }
        
    public void add(String key, URMPrincipal princ, String credentials) {
        if (mPricipalCacheSize <= 0 || princ == null)
            return;
            
        if (mPrincipalCache.size() >= mPricipalCacheSize) {
            // remove an element from the principal cache
            Entry rem_princ = null;
            do {
                rem_princ = (Entry)mPrincipalCache.remove(mCachedPrincipalKeys.remove(0));
            } while (mCachedPrincipalKeys.size() > 0 && rem_princ == null);
        }
        mPrincipalCache.put(key, new Entry(key, credentials, princ));
        mCachedPrincipalKeys.add(key);
    }
    
    public URMPrincipal get(String key, String credential) {
        if (mPricipalCacheSize <= 0 || key == null)
            return null;
            
        Entry princ = (Entry)mPrincipalCache.get(key);
        if (princ != null) {
            URMPrincipal urmprinc = princ.validate(credential);
            if (urmprinc != null && mPricipalValidTime <
                            (System.currentTimeMillis() - urmprinc.getCreationTime())/1000) {
                princ = (Entry)mPrincipalCache.remove(key);
                return null;
            }
            else
                return urmprinc;
        }
        else
            return null;
    }

    public void remove(String key) {
        if (mPricipalCacheSize <= 0 || key == null)
            return;
            
        mPrincipalCache.remove(key);
    }

    private static class Entry {
        private final String mKey;
        private final int mCredentialHash;
        private final URMPrincipal mPrincipal;
        
        private Entry(String key, String credential, URMPrincipal princ) {
            mKey = key;
            mCredentialHash = credential.hashCode();
            mPrincipal = princ;
        }
        public boolean equals(Object obj) {
            if (obj != null)
                return mKey.equals(obj);
            else
                return false;
        }
        private URMPrincipal validate(String credential) {
            if (credential != null && mCredentialHash == credential.hashCode())
                return mPrincipal;
            return null;
        }
        private URMPrincipal getPrincipal() {
            return mPrincipal;
        }
        private String getKey() {
            return mKey;
        }
    }
}
