/*
 * 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 net.jini.jeri;

import java.io.IOException;
import java.util.NoSuchElementException;

/**
 * Produces {@link OutboundRequest} instances to use for attempting to
 * send a particular request to a remote communication endpoint.
 *
 * <p>As long as {@link #hasNext hasNext} returns <code>true</code>,
 * the {@link #next next} method can be invoked to initiate an attempt
 * to make the request.  If successful, the <code>next</code> method
 * returns an <code>OutboundRequest</code> to use to write the request
 * data and read the response.
 *
 * <p>If the request communication attempt fails, such as if the
 * <code>next</code> invocation throws an exception or if a subsequent
 * I/O operation on the returned <code>OutboundRequest</code> or its
 * streams throws an exception, then if <code>hasNext</code> returns
 * <code>true</code> again, the <code>next</code> method can be
 * invoked again to retry the request attempt.  This process of
 * retrying failed request attempts can repeat as long as
 * <code>hasNext</code> returns <code>true</code> after the previous
 * failed request attempt.
 *
 * <p>Note that it is the user's responsibility to abstain from
 * retrying a request attempt if doing so might violate any applicable
 * guarantees of <i>at most once</i> execution semantics (invoking
 * {@link OutboundRequest#getDeliveryStatus getDeliveryStatus} on the
 * previous <code>OutboundRequest</code> might aid in making that
 * determination).
 *
 * <p>A typical <code>OutboundRequestIterator</code> is likely to
 * support making only one request attempt, in which case after one
 * invocation of <code>next</code> (successful or not),
 * <code>hasNext</code> will return <code>false</code>.  Reasons that
 * an <code>OutboundRequestIterator</code> might support multiple
 * request attempts include:
 *
 * <ul>
 *
 * <li>if the remote endpoint implementation features multiple
 * communication mechanism alternatives to attempt or
 *
 * <li>if the implementation can ascertain that the nature of the
 * previous request attempt failure indicates that it would be very
 * unlikely to reoccur in a subsequent attempt.
 *
 * </ul>
 *
 * The <code>hasNext</code> method should not return <code>true</code>
 * after successive failed request attempts indefinitely.  The request
 * retry mechanism provided by <code>OutboundRequestIterator</code> is
 * not intended for implementing a strategy of general retry of the
 * same communication mechanism after indeterminate failures.
 *
 * <p>Note that it is permitted, although unlikely, for an
 * <code>OutboundRequestIterator</code>'s <code>hasNext</code> method
 * to never return <code>true</code>, in which case the
 * <code>OutboundRequestIterator</code> does not support initiating
 * even one attempt to send the request.
 *
 * <p>An <code>OutboundRequestIterator</code> is not guaranteed to be
 * safe for concurrent use by multiple threads.
 *
 * 
 * @see Endpoint
 * @since 2.0
 **/
public interface OutboundRequestIterator {

    /**
     * Returns <code>true</code> if this iterator supports making at
     * least one more attempt to communicate the request, and
     * <code>false</code> otherwise.
     *
     * <p>If this method returns <code>true</code>, then it is
     * guaranteed that the next invocation of {@link #next next} on
     * this iterator will not throw a {@link NoSuchElementException}.
     *
     * <p>If <code>next</code> has been invoked on this iterator and
     * the previous invocation of <code>next</code> returned an
     * <code>OutboundRequest</code>, then this method should not be
     * invoked until that <code>OutboundRequest</code> has been used
     * to attempt to communicate the request and a failure has
     * occurred.
     *
     * <p>The security context in which this method is invoked may be
     * used for subsequent verification of security permissions; see
     * the <code>next</code> method specification for more details.
     *
     * @return <code>true</code> if this iterator supports making
     * another attempt to communicate the request, and
     * <code>false</code> otherwise
     **/
    boolean hasNext();

    /**
     * Initiates an attempt to communicate the request to the remote
     * endpoint.
     *
     * <p>After an invocation of {@link #hasNext hasNext} returns
     * <code>true</code>, it is guaranteed that the next invocation of
     * this method will not throw a {@link NoSuchElementException}.
     *
     * <p>If successful, this method returns an
     * <code>OutboundRequest</code> to use to write the request data
     * and read the response.  Even if this method throws an {@link
     * IOException} or a {@link SecurityException}, the iteration of
     * attempts to communicate the request may continue with another
     * invocation of <code>hasNext</code>.
     *
     * <p>The implementation verifies that the user's security context
     * has all of the security permissions necessary to communicate
     * the current request attempt with the remote endpoint and to
     * satisfy any required constraints, as appropriate to the
     * implementation of this interface.  The implementation is
     * allowed, however, to indicate failure of such a permission
     * check by either throwing a <code>SecurityException</code> from
     * this method or, after returning an <code>OutboundRequest</code>
     * from this method, throwing a <code>SecurityException</code>
     * from some subsequent operation on the
     * <code>OutboundRequest</code> or its streams.  If such a
     * <code>SecurityException</code> is thrown, request data must not
     * have been transmitted to the server (that is, if an
     * <code>OutboundRequest</code> has been returned, its {@link
     * OutboundRequest#getDeliveryStatus getDeliveryStatus} method
     * must return <code>false</code>), and the client's identity must
     * not have been revealed to the server.
     *
     * <p>Also, the implementation of this method or the returned
     * <code>OutboundRequest</code> must eventually verify that the
     * client and server have the requisite principals and credentials
     * to satisfy any required constraints and if not, throw an
     * <code>IOException</code>.  If such an <code>IOException</code>
     * is thrown, request data must not have been transmitted to the
     * server.
     *
     * <p>In verifying any such permission requirement or credential,
     * the implementation is allowed to use the security context in
     * effect for this or any previous invocation of a method on this
     * iterator or the security context in effect for any operation on
     * the <code>OutboundRequest</code> returned by this or any
     * previous invocation of this method on this iterator.
     * Therefore, this iterator and the <code>OutboundRequest</code>
     * instances that it produces should be used in a uniform security
     * context.
     *
     * @return the <code>OutboundRequest</code> to use to write the
     * request data and read the response
     *
     * @throws NoSuchElementException if this iterator does not
     * support making another attempt to communicate the request (that
     * is, if <code>hasNext</code> would return <code>false</code>)
     *
     * @throws IOException if an I/O exception occurs while performing
     * this operation; in this event, the recipient may have received
     * an indication of the request initiation attempt
     *
     * @throws SecurityException if the user does not have the
     * permissions necessary to communicate with the remote endpoint
     **/
    OutboundRequest next() throws IOException;
}
