/*
 * Filename: AuthStub.java
 *
 * Author: Joe Wang
 *
 * Copyright (c) 2003-2005 
 * The Trustees of Columbia University in the City of New York
 * Columbia University Information Technology
 *
 * This file is part of NINJa.
 *
 * NINJa is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * NINJa is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with NINJa; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */

package edu.columbia.print.ninja.core.authenticate;

import java.rmi.*;
import net.jini.core.lease.Lease;
import com.millipad.util.RemoteBlockingStack;
import net.jini.print.job.PrintRequest;
import javax.security.auth.callback.CallbackHandler;
import javax.print.attribute.DocAttributeSet;
import net.jini.print.service.PrintService;

/**
 * The stub responsible for preauthentication of print jobs on the client side.
 * The stub is unique to each invocation of requestStart.  The stub is also a leased
 * resource whose lease must be valid in order to be useful.<p>
 * The reason for stubbing is two-fold both having to do with cases where the
 * client is not in the same JVM as the server.<p>
 * Since the preauthentication may request additional information for the user
 * (i.e. password, confirmation, etc.) the client code would require a
 * callback handler.  If the client is remote to the server, the client would
 * require an rmi daemon, which may not always be practical as in a web client.
 * In this case, the preauthentication code is placed locally to the client code
 * via the stub.<p>
 * The remoteness of the server also means that with each request to preauthenticate,
 * the client must make an rmi call to the server incurring a performance hit.
 * If for instance, the user is asked to submit a password, a stub can verify
 * the information locally without having to so send anything over the wire.
 * @author Joe Wang <jw168@columbia.edu>
 * @since 1.0
 * @see edu.columbia.print.core.service.JobQueue#requestStart
 */
public class AuthStub implements java.io.Serializable {

	public static final int AUTHENTICATE_SUCCESSFUL = 1;
	public static final int PREAUTHENTICATE_FAILED = 2;
	public static final int PREAUTHENTICATE_TIMEOUT = 3;
	public static final int USER_CANCELED_REQUEST = 4;

	transient CallbackHandler cbh;
	MarshalledObject auth;
	RemoteBlockingStack feed;
	Lease lease;
	PrintService ps;
	PrintRequest[] reqs;
	MarshalledObject[] docs;
	boolean consume;

	/**
	 * @param auth The authenticator that handles the actual authentication.
	 * @param feed The stack on which to place authenticated jobs
	 * @param docs The attributes to authenticate against
	 * @param reqs The attributes to authenticate against
	 * @param jobs The attributes to authenticate against
	 * @param lease The lease for the stub.  This is required because the 
	 *              list must be able to expire referrences to the stub.
	 * @param ps The printService which the jobs will be posted to
	 * @param consume true if the job will cosume media
 	 * @see Authenticator#preauthenticate
	 */
	public AuthStub(MarshalledObject auth, RemoteBlockingStack feed, PrintRequest[] reqs, MarshalledObject[] docs, Lease lease, PrintService ps, boolean consume) {
		this.auth = auth;
		this.feed = feed;
		this.docs = docs;
		this.reqs = reqs;
		this.lease = lease;
		this.ps = ps;
		this.consume = consume;
		this.cbh = null;
        }

	/**
	 * @return the print service which is handling the request
	 */
	public PrintService getPrintService() {return ps;}

	/**
	 * set callback handler to handle callbacks.  This action is performed
	 * by the client.
	 * @param h the callback handler
	 */
	public void setCallbackHandler(CallbackHandler h) {cbh=h;}

	/**
	 * The lease is not automatically renewed and therefore must be
	 * renewed by the client.  This gives the client flexibility in
	 * when the lease expires.  The lease prevents the Authenticator
	 * from authenticating based on stale information.
	 * @return the lease associated with this stub
	 */
	public Lease getLease() {
		return lease;
		}

	/**
	 * Called when the client is ready to begin authenticating jobs.
	 * If the client is supplying a callback handler, it must be set
	 * prior to calling this function.
 	 * @see Authenticator#preauthenticate
	 */
	public int authenticate() throws net.jini.core.lease.LeaseDeniedException, net.jini.core.lease.UnknownLeaseException {
long time = -System.currentTimeMillis();
		Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
		int[] authed = null;
		Object[] cookies = new Object[reqs.length];
		try {
			Authenticator tmp = (Authenticator )auth.get();
			DocAttributeSet[] set = new DocAttributeSet[docs.length];
			for(int i=set.length-1; i>=0; i--) set[i] = (DocAttributeSet )docs[i].get();
			authed = tmp.preauthenticate(set, reqs,
				consume, this, cbh, cookies);
			if(authed==null) return PREAUTHENTICATE_FAILED;
			}
		catch(Exception e) {
			debug(e);
//			e.printStackTrace();
			return USER_CANCELED_REQUEST;
			}
                if(lease.getExpiration()<System.currentTimeMillis()) return PREAUTHENTICATE_TIMEOUT;
		for(int i=0; i<authed.length; i++) {
			//pipe authed jobs to the printer
			int index = authed[i];
			Object[] vector = {
				reqs[index],
				ps,
				auth,
				cookies[index]
				};
			try {
				feed.push(vector);
				}
			catch(java.rmi.RemoteException e) {
				e.printStackTrace();
				debug("can't start printer");
				}
			}
		return AUTHENTICATE_SUCCESSFUL;
		}

	static void debug(Object o) {com.millipad.util.Debug.print(AuthStub.class, o);}

	}

