/*
 * 
 * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved.
 * 
 * The contents of this file are subject to the Sun Community Source
 * License v3.0/Jini Technology Specific Attachment v 1.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://wwws.sun.com/software/jini/licensing/SCSL3_JiniTSA1.html.
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and limitations
 * under the License.
 * 
 * The Reference Code is Jini Technology Core Platform code, v2.0. The
 * Developer of the Reference Code is Sun Microsystems, Inc.
 * 
 * Contributor(s): Sun Microsystems, Inc.
 * 
 * The contents of this file comply with the Jini Technology Core
 * Platform Compatibility Kit, v2.0A.
 * 
 * Tester(s): Sun Microsystems, Inc.
 * 
 * Test Platform(s):
 * Java 2 SDK, Standard Edition, Version 1.4.2_03 for Solaris(TM)SPARC/x86
 * Java 2 SDK, Standard Edition, Version 1.4.2_03 for Linux (Intel x86)
 * Java 2 SDK, Standard Edition, Version 1.4.2_03 for Windows (Intel Platform)
 * 
 */
package com.sun.jini.outrigger;

import java.rmi.MarshalledObject;
import java.rmi.RemoteException;
import net.jini.core.event.RemoteEvent;
import net.jini.core.event.EventRegistration;
import net.jini.core.event.RemoteEventListener;
import net.jini.core.event.UnknownEventException;
import net.jini.core.event.RemoteEvent;
import net.jini.core.event.EventRegistration;
import net.jini.core.event.RemoteEventListener;
import net.jini.core.event.UnknownEventException;
import net.jini.space.InternalSpaceException;
import net.jini.id.Uuid;
import net.jini.security.ProxyPreparer;

/**
 * Subclass of EventRegistrationWatcher for transactional
 * event registrations.
 */
class TransactableEventWatcher extends EventRegistrationWatcher
    implements Transactable
{
    /** The listener that should be notified of matches */
    private final RemoteEventListener listener;

    /** 
     * The transaction (represented as a <code>Txn</code>) this
     * event registration is associated with.
     */
    private final Txn txn;
    
    /**
     * Create a new <code>TransactableEventWatcher</code>.
     * @param timestamp the value that is used
     *        to sort <code>TransitionWatcher</code>s.
     * @param startOrdinal the highest ordinal associated
     *        with operations that are considered to have occurred 
     *        before the operation associated with this watcher.
     * @param cookie The unique identifier associated
     *        with this watcher. Must not be <code>null</code>.
     * @param handback The handback object that
     *        should be sent along with event
     *        notifications to the the listener.
     * @param eventID The event ID for event type
     *        represented by this object. 
     * @param listener The object to notify of
     *        matches.
     * @param txn The transaction this registration is
     *        associated with.
     * @throws NullPointerException if the <code>cookie</code>,
     *         <code>listener</code>, or <code>txn</code> arguments are
     *         <code>null</code>.
     */
    TransactableEventWatcher(long timestamp, long startOrdinal, Uuid cookie,
	MarshalledObject handback, long eventID, 
	RemoteEventListener listener, Txn txn)
    {
	super(timestamp, startOrdinal, cookie, handback, eventID);

	if (listener == null)
	    throw new NullPointerException("listener must be non-null");

	if (txn == null)
	    throw new NullPointerException("txn must be non-null");

	this.listener = listener;
	this.txn = txn;
    }

    boolean isInterested(EntryTransition transition, long ordinal) {
	// If it is not available, or is not a new entry we don't care
	if (!(transition.isAvailable()) &&
	    (transition.isNewEntry()))
	    return false;

	// If it occurred before are registration we don't care
	if (ordinal <= startOrdinal)
	    return false;

	final Txn transitionTxn = transition.getTxn();

	// We care if the transition under the null transaction or ours.
	return (transitionTxn == null) || (transitionTxn == txn);
    }

    RemoteEventListener getListener(ProxyPreparer preparer) {
	return listener;
    }
    
    /**
     * Just need to terminate this registration and return 
     * <code>NOTCHANGED</code>.
     */
    public int prepare(TransactableMgr mgr, OutriggerServerImpl space) {
	cancel();
	return NOTCHANGED;
    }

    /**
     * This should never happen since we always return
     * <code>NOTCHANGED</code> from <code>prepare</code>.
     */
    public void commit(TransactableMgr mgr, OutriggerServerImpl space) {
	throw new InternalSpaceException
	    ("committing a TransactableRegistrationWatcher");
			   
    }

    /**
     * Just need to terminate this registration.
     */
    public void abort(TransactableMgr mgr, OutriggerServerImpl space) {
	// prepare does the right thing, and should forever
	prepare(mgr, space);
    }
}

