/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.jini.outrigger;
/**
* Subclass of <code>TransitionWatcher</code> for blocking queries.
* <code>QueryWatcher</code>s are waiting for a set of conditions (time,
* transitions, etc.) that will <em>resolve</em> the query. Threads can
* block on resolution by calling the <code>waitOnResolution</code> method.
* Once <code>waitOnResolution</code> than can use subclass specific
* methods to obtain the result.
* <p>
* Resolution may involve <em>capturing</em> one or more entries (that
* is locking or removing an entry from the space). It is important
* that a <code>QueryWatcher</code> never capture an entry after the
* watcher enters the resolved state, since that could allow a caller
* to believe that the call failed, when it fact it locked or removed
* an entry and/or in entries being removed/locked that are never
* returned to the client. Put another way, the decision to capture an
* entry has to be done atomically with the check that ensures that
* the related query is still unresolved.
*/
abstract class QueryWatcher extends TransitionWatcher {
/** When this query ends */
private final long expiration;
/**
* Create a new <code>QueryWatcher</code>.
* @param expiration the initial expiration time
* for this <code>QueryWatcher</code> in
* milliseconds since the beginning of the epoch.
* @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.
*/
QueryWatcher(long expiration, long timestamp, long startOrdinal)
{
super(timestamp, startOrdinal);
this.expiration = expiration;
}
public long getExpiration() {
return expiration;
}
/**
* Process a transition which was posted before the watcher was
* placed in <code>TransitionWatchers</code> object. Assumes that
* the entry in the transition matches matches the template in the
* <code>TemplateHandle</code> associated with this watcher. Does
* not assume <code>isInterested</code> has been called.
* @param transition A <code>EntryTransition</code> that
* describes the transition and what
* entry is transitioning. This method
* will assume that <code>transition.getHandle</code>
* returns a non-null value.
* @param now An estimate of the current time (not the time
* when the event occured).
* @return <code>true</code> if the query has been resolved, and
* <code>false</code> otherwise. Note, even if this
* call returns <code>true</code>, <code>waitOnResolution</code>
* must still be called.
*
* @throws NullPointerException if <code>transition</code> is
* <code>null</code>.
*/
abstract boolean catchUp(EntryTransition transition, long now);
/**
* This method does nothing. Since each <code>QueryWatcher</code>
* has a thread that blocks until the expiration time is reached
* it simpler to do the removal there instead of in the
* reaping thread.
* @param now An estimate of the current time that must be
* less than or equal to the current time.
*/
void removeIfExpired(long now) { }
/**
* Block until the query this object represents is resolved. If the
* query is already resolved, return immediately. This method must be
* called even if it is know that the query has been resolved.
* This method should be called exactly once.
*/
abstract void waitOnResolution() throws InterruptedException;
/**
* Returns <code>true</code> if this query has been resolved. If the
* calling thread is owns the lock on this object the answer is
* definitive. If the lock is not held only a <code>true</code> answer
* can be considered definitive.
* @return <code>true</code> if the query has been
* resolved, <code>false</code> otherwise.
*/
abstract boolean isResolved();
}