
package client;

import common.PayableFileClassifier;
import common.MIMEType;

import java.rmi.RMISecurityManager;
import net.jini.discovery.LookupDiscovery;
import net.jini.discovery.DiscoveryListener;
import net.jini.discovery.DiscoveryEvent;
import net.jini.core.lookup.ServiceRegistrar;
import net.jini.core.lookup.ServiceTemplate;
import net.jini.core.transaction.server.TransactionManager;
import net.jini.core.transaction.server.TransactionConstants;
import net.jini.core.transaction.server.TransactionParticipant;
// import com.sun.jini.lease.LeaseRenewalManager;
import net.jini.lease.LeaseRenewalManager;
import net.jini.core.lease.Lease;
import net.jini.lookup.entry.Name;
import net.jini.core.entry.Entry;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

/**
 * TestTxn.java
 *
 *
 * Created: Tue Aug 3 1999
 *
 * @author Jan Newmarch
 * @version 1.1
 *    uses Jini 1.1 LeaseRenewalManager
 */

public class TestTxn implements DiscoveryListener {

    PayableFileClassifier classifier = null;
    TransactionManager mgr = null;

    long myClientID; // my account id

    public static void main(String argv[]) {
	new TestTxn();

        // stay around long enough to receive replies
        try {
            Thread.currentThread().sleep(100000L);
        } catch(java.lang.InterruptedException e) {
            // do nothing
        }
    }

    public TestTxn() {
	System.setSecurityManager(new RMISecurityManager());

	LookupDiscovery discover = null;
        try {
            discover = new LookupDiscovery(LookupDiscovery.ALL_GROUPS);
        } catch(Exception e) {
            System.err.println(e.toString());
            System.exit(1);
        }

        discover.addDiscoveryListener(this);

    }
    
    public void discovered(DiscoveryEvent evt) {

        ServiceRegistrar[] registrars = evt.getRegistrars();
 
        for (int n = 0; n < registrars.length; n++) {
	    System.out.println("Service found");
            ServiceRegistrar registrar = registrars[n];

	    new LookupThread(registrar).start();
	}

	    // System.exit(0);
    }

    public void discarded(DiscoveryEvent evt) {
	// empty
    }

    public class LookupThread extends Thread implements TransactionParticipant, java.io.Serializable {

	ServiceRegistrar registrar;
	long crashCount = 0; // ???

	LookupThread(ServiceRegistrar registrar) {
	    this.registrar = registrar;
	}


	public void run() {
	    long cost = 0;

	    // try to find a classifier if we haven't already got one
	    if (classifier == null) {
		System.out.println("Searching for classifier");
		Class[] classes = new Class[] {PayableFileClassifier.class};
		ServiceTemplate template = new ServiceTemplate(null, classes, 
							       null);
		
		try {
		    Object obj = registrar.lookup(template);
		    System.out.println(obj.getClass().toString());
		    Class cls = obj.getClass();
		    Class[] clss = cls.getInterfaces();
		    for (int n = 0; n < clss.length; n++) {
			System.out.println(clss[n].toString());
		    }
		    classifier = (PayableFileClassifier) registrar.lookup(template);
		} catch(java.rmi.RemoteException e) {
		    e.printStackTrace();
		    System.exit(2);
		}
		if (classifier == null) {
		    System.out.println("Classifier null");
		} else {
		    System.out.println("Getting cost");
		    try {
			cost = classifier.getCost();
		    } catch(java.rmi.RemoteException e) {
			e.printStackTrace();
		    }
		    if (cost > 20) {
			System.out.println("Costs too much: " + cost);
			classifier = null;
		    }
		}


	    }

	    // try to find a transaction manager if we haven't already got one
	    if (mgr == null) {
		System.out.println("Searching for txnmgr");

		Class[] classes = new Class[] {TransactionManager.class};
		ServiceTemplate template = new ServiceTemplate(null, classes, 
							       null);


		/*
		Entry[] entries = {new Name("TransactionManager")};
		ServiceTemplate template = new ServiceTemplate(null, null, 
							       entries);
		*/

		try {
		    mgr = (TransactionManager) registrar.lookup(template);
		} catch(java.rmi.RemoteException e) {
		    e.printStackTrace();
		    System.exit(2);
		}
		if (mgr == null) {
		    System.out.println("Manager null");
		    return;
		}

	    }

	    if (classifier != null && mgr != null) {
		System.out.println("Found both");
		TransactionManager.Created tcs = null;


		System.out.println("Creating transaction");
		try {
		    tcs = mgr.create(Lease.FOREVER);
		} catch(java.rmi.RemoteException e) {
		    mgr = null;
		    return;
		} catch(net.jini.core.lease.LeaseDeniedException e) {
		    mgr = null;
		    return;
		}

		long transactionID = tcs.id;

		// join in ourselves
		System.out.println("Joining transaction");

		// but first, export ourselves since we don't extend UnicastRemoteObject
		try {
		    UnicastRemoteObject.exportObject(this);
		} catch(RemoteException e) {
		    e.printStackTrace();
		}

		try {
		    mgr.join(transactionID, this, crashCount);
		} catch(net.jini.core.transaction.UnknownTransactionException e) {
		    e.printStackTrace();
		} catch(java.rmi.RemoteException e) {
		    e.printStackTrace();
		} catch(net.jini.core.transaction.server.CrashCountException e) {
		    e.printStackTrace();
		} catch(net.jini.core.transaction.CannotJoinException e) {
		    e.printStackTrace();
		}

		new LeaseRenewalManager().renewUntil(tcs.lease,
						     Lease.FOREVER,
						     null);
		System.out.println("crediting...");
		try {
		    classifier.credit(cost, myClientID,
				      mgr, transactionID);
		} catch(Exception e) {
		    System.err.println(e.toString());
		}

		System.out.println("classifying...");
		MIMEType type = null;
		try {
		    type = classifier.getMIMEType("file1.txt");
		} catch(java.rmi.RemoteException e) {
		    System.err.println(e.toString());
		}

		// if we get a good result, commit, else abort
		if (type != null) {
		    System.out.println("Type is " + type.toString());
		    System.out.println("Calling commit");
		    // new CommitThread(mgr, transactionID).run();
		    
		    try { 
			System.out.println("mgr state " + mgr.getState(transactionID));
			mgr.commit(transactionID);
		    } catch(Exception e) {
			e.printStackTrace();
		    }
		    
		} else {
		    try {
			mgr.abort(transactionID);
		    } catch(java.rmi.RemoteException e) {
		    } catch(net.jini.core.transaction.CannotAbortException e) {
		    } catch( net.jini.core.transaction.UnknownTransactionException e) {
		    }
		}
	    }
	}

	public int prepare(TransactionManager mgr, long id) {
	    System.out.println("Preparing...");
	    return TransactionConstants.PREPARED;
	}
	
	public void commit(TransactionManager mgr, long id) {
	    System.out.println("committing");
	}
	
	
	public void abort(TransactionManager mgr, long id) {
	    System.out.println("aborting");
  
	}
	
	public int prepareAndCommit(TransactionManager mgr, long id) {
	    int result = prepare(mgr, id);
	    if (result == TransactionConstants.PREPARED) {
		commit(mgr, id);
		result = TransactionConstants.COMMITTED;
	    }
	    return result;
	}

    } // LookupThread

    class CommitThread extends Thread {
	TransactionManager mgr;
	long transactionID;

	public CommitThread(TransactionManager m, long id) {
	    mgr = m;
	    transactionID = id;
	    try {
		Thread.sleep(1000);
	    } catch(Exception e) {
	    }
	}

	public void run() {
	    try {
		mgr.abort(transactionID);
	    } catch(Exception e) {
		e.printStackTrace();
	    }
	}
    } // CommitThread

} // TestTxn

