/*
 * 
 * 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.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.IOException;
import java.io.StreamCorruptedException;
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.id.Uuid;
import net.jini.id.UuidFactory;
import net.jini.security.ProxyPreparer;

/**
 * Subclass of <code>EventRegistrationWatcher</code> for non-transactional
 * persistent event registrations.
 */
class StorableEventWatcher extends EventRegistrationWatcher
    implements StorableResource
{
    /** The listener that should be notified of matches */
    private StorableReference listener;

    /**
     * Used during log recovery to create a mostly empty
     * <code>StorableEventWatcher</code>.  
     * <p> 
     * Note, we set the time stamp and tie-breaker here instead of
     * getting them from the log. This means they will be inconstant
     * with their value from the last VM we were in, but since they
     * never leak out and events are read-only anyway this should not
     * be a problem (this also allows us to keep the tie-breaker and
     * time stamp in final fields).
     *
     * @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 currentSeqNum Sequence number to start with.
     * @throws NullPointerException if the <code>notifier</code>
     *         argument is null.  
     */
    StorableEventWatcher(long timestamp, long startOrdinal,
			 long currentSeqNum) 
    {
	super(timestamp, startOrdinal, currentSeqNum);
    }

    /**
     * Create a new <code>StorableEventWatcher</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.
     * @throws NullPointerException if the <code>cookie</code>,
     *        or <code>listener</code> arguments are <code>null</code>.
     */
    StorableEventWatcher(long timestamp, long startOrdinal, Uuid cookie, 
			 MarshalledObject handback, long eventID, 
			 RemoteEventListener listener)
    {
	super(timestamp, startOrdinal, cookie, handback, eventID);

	if (listener == null)
	    throw new NullPointerException("listener must be non-null");
	this.listener = new StorableReference(listener);
    }
    
    boolean isInterested(EntryTransition transition, long ordinal) {
	return ((ordinal > startOrdinal) &&
		(transition.getTxn() == null) &&
		(transition.isAvailable()) &&
		(transition.isNewEntry()));
    }

    RemoteEventListener getListener(ProxyPreparer preparer) 
	throws ClassNotFoundException, IOException
    {
	return (RemoteEventListener)listener.get(preparer);
    }

    /**
     * Overridden by subclasses if there is any cleanup work they need
     * to do as part of <code>cancel</code> or
     * <code>removeIfExpired</code>. Called after releasing the lock
     * on <code>this</code>.  Will be called at most once.  
     * @param owner A reference to the owner.
     * @param expired <code>true</code> if being called from 
     *        <code>removeIfExpired</code> and false otherwise. 
     */
    void cleanup(TemplateHandle owner, boolean expired) {
	if (expired)
	    owner.getServer().scheduleCancelOp(cookie);
	else 
	    owner.getServer().cancelOp(cookie, false);
    }


    /**  
     * Store the persistent fields 
     */
    public void store(ObjectOutputStream out) throws IOException {
	cookie.write(out);
	out.writeLong(expiration);
	out.writeLong(eventID);
	out.writeObject(handback);
	out.writeObject(listener);
    }

    /**
     * Restore the persistent fields
     */
    public void restore(ObjectInputStream in) 
	throws IOException, ClassNotFoundException 
    {
	cookie = UuidFactory.read(in);
	expiration = in.readLong();
	eventID = in.readLong();
	handback = (MarshalledObject)in.readObject();	
	listener = (StorableReference)in.readObject();
	if (listener == null)
	    throw new StreamCorruptedException(
		"Stream corrupted, should not be null");
    }
}
