package rmi;

import proof.*;
import Tools.*;
import sdsi.*;
import java.rmi.*;
import java.rmi.server.*;
import java.util.*;

/**
 * A ProofRecipient that accepts a single proof per subject (client)
 * and caches one per
 * (server) thread, so that the next attempt at the authorized action
 * will find the proof and succeed.
 * It is used by a server to cache the current authority under which
 * a client is operating.<p>
 *
 * It is not difficult to conceive of servers
 * where a cache with more than one entry would be desirable, but the
 * exact discipline of the cache may be application-specific. I envision
 * a collection of cache objects that can be parameterized according to
 * Snowflake restriction tags to define their eviction policy.<p>
 *
 * This class is notably <em>not</em> of the sort that requires an
 * SfProof to proceed. :v)
 */
public class OneLineCacheRecipient
	extends UnicastRemoteObject
	implements ProofRecipient {

	static HashMap cache = new HashMap();
	static boolean notVeryUseful = false;

	private OneLineCacheRecipient() throws RemoteException {}

	static OneLineCacheRecipient singleton;

	/**
	 * Get the distinguished cache object. This cheesy class defines
	 * only one such object per JVM.
	 */
	public static OneLineCacheRecipient getRecipient() {
		if (singleton==null) {
			try {
				singleton = new OneLineCacheRecipient();
			} catch (RemoteException ex) {
			}
		}
		return singleton;
	}

	/**
	 * Give the recipient a proof of a required property.
	 * This is the Remote method called by the client (actually by
	 * the client's {@link InvokeHack#invoke} helper method) to transmit
	 * a proof to the server's cache (this thing).
	 */
	public void hereIsProof(Proof proof)
		throws RemoteException {
		cache.put(proof.getSubject(), proof);
	}

	/**
	 * The server's <code>checkAuth()</code>-style method calls this
	 * method to retrieve the cached proof for a particular subject.
	 */
	public static Proof getCachedProof(Subject subj) {
		Proof proof = (Proof) cache.get(subj);
		if (notVeryUseful) {
			// Be just useful enough to allow one request through
			cache.remove(subj);
		}
		return proof;
	}

	/**
	 * This reconfiguration method is used by {@link timingexp.RMIExp}
	 * to turn proof caching on and ``off,'' where proofs last only a
	 * single request. This mode lets me time how long it takes to
	 * transmit the actual proof.
	 */
	public static void reconfigure(boolean state) {
		notVeryUseful = state;
	}
}
