/*
 * 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 javax.security.auth.Subject;

/**
 * Represents one or more communication endpoints on the current
 * (local) host to listen for and receive requests on and a template
 * for producing an <code>Endpoint</code> instance to send requests to
 * those communication endpoints.
 *
 * <p>A <code>ServerEndpoint</code> instance contains the information
 * necessary to listen for requests on the communication endpoints and
 * to produce <code>Endpoint</code> instances.  For example, a
 * TCP-based <code>ServerEndpoint</code> implementation typically
 * contains the TCP port to listen on and the host address to put in
 * the <code>Endpoint</code> instances it produces.  An implementation
 * that supports authentication typically contains the {@link Subject}
 * (if any) to use for server authentication.
 *
 * <p>The {@link #enumerateListenEndpoints enumerateListenEndpoints}
 * method can be invoked to
 *
 * <ul>
 *
 * <li>discover each of the discrete communication endpoints
 * represented by this <code>ServerEndpoint</code>, which are
 * individually represented as {@link ListenEndpoint ListenEndpoint}
 * instances,
 *
 * <li>ensure an active <i>listen operation</i> (see {@link
 * ListenEndpoint#listen ListenEndpoint.listen}) on each discrete
 * communication endpoint by choosing, for each endpoint, either to
 * start a new listen operation or to use an existing one, and
 *
 * <li>obtain an <code>Endpoint</code> instance that corresponds to
 * the chosen listen operations
 *
 * </ul>
 *
 * The obtained <code>Endpoint</code> instance can then be used to
 * send requests to the communication endpoints being listened on as a
 * result of that {@link #enumerateListenEndpoints
 * enumerateListenEndpoints} invocation.
 *
 * <p>Typically, a <code>ServerEndpoint</code> is just used to specify
 * the transport layer implementation to use when exporting a remote
 * object; for example, some constructors of {@link BasicJeriExporter
 * BasicJeriExporter} have a <code>ServerEndpoint</code> parameter to
 * specify the transport layer implementation.  The exporter
 * implementation is then responsible for using the supplied
 * <code>ServerEndpoint</code> to manage listen operations as
 * necessary and to obtain an <code>Endpoint</code> instance for
 * putting in the client-side proxy.
 *
 * <p>All aspects of the underlying communication mechanism that are
 * not specified here are defined by the particular implementation of
 * this interface.
 *
 * 
 * @since 2.0
 **/
public interface ServerEndpoint extends ServerCapabilities {

    /**
     * Enumerates the communication endpoints represented by this
     * <code>ServerEndpoint</code> by passing the
     * <code>ListenEndpoint</code> for each of them to
     * <code>listenContext</code>, which will ensure an active listen
     * operation on each endpoint, and returns an
     * <code>Endpoint</code> instance corresponding to the listen
     * operations chosen by <code>listenContext</code>.
     *
     * <p>This method uses <code>listenContext</code> to cooperate
     * with the caller to ensure the appropriate listen operations.
     * In this cooperation,
     *
     * <ul>
     *
     * <li>the <code>ServerEndpoint</code> is responsible for
     * declaring to the caller the discrete communication endpoints
     * represented by this <code>ServerEndpoint</code> as
     * <code>ListenEndpoint</code> instances passed to
     * <code>listenContext</code>'s {@link
     * ListenContext#addListenEndpoint addListenEndpoint} method, and
     *
     * <li>the caller is responsible for declaring the active listen
     * operations to be used for this
     * <code>ServerEndpoint.enumerateListenEndpoints</code> invocation
     * corresponding to each discrete communication endpoint as {@link
     * ListenCookie ListenCookie} instances returned from
     * <code>listenContext</code>'s <code>addListenEndpoint</code>
     * method.
     *
     * </ul>
     *
     * For each <code>ListenEndpoint</code>, the caller (through
     * <code>listenContext</code>) may choose to start a new listen
     * operation, or it may choose to reuse a previously started
     * listen operation that it has a <code>ListenCookie</code> for.
     *
     * <p>This method sequentially invokes
     * <code>addListenEndpoint</code> on <code>listenContext</code>
     * once for each discrete communication endpoint represented by
     * this <code>ServerEndpoint</code>, passing the
     * <code>ListenEndpoint</code> representing that communication
     * endpoint.  If any of the invocations of
     * <code>ListenContext.addListenEndpoint</code> throws an
     * exception, this method throws that exception.  Otherwise, this
     * method returns an <code>Endpoint</code> instance that sends
     * requests to be received by the listen operations chosen by
     * <code>listenContext</code>.
     *
     * @param listenContext the <code>ListenContext</code> to pass
     * this <code>ServerEndpoint</code>'s <code>ListenEndpoint</code>
     * instances to
     *
     * @return the <code>Endpoint</code> instance for sending requests
     * to this <code>ServerEndpoint</code>'s communication endpoints
     * being listened on
     *
     * @throws IOException if an I/O exception occurs while attempting
     * to listen for requests on the communication endpoints
     * represented by this <code>ServerEndpoint</code>.  This could
     * occur, for example, if an I/O resource associated with one of
     * the communication endpoints is already in exclusive use, or if
     * there are insufficient I/O resources for the operation.
     *
     * @throws SecurityException if the current security context does
     * not have the permissions necessary to listen for requests on
     * one of the communication endpoints represented by this
     * <code>ServerEndpoint</code>
     *
     * @throws IllegalArgumentException if an invocation of the
     * <code>addListenEndpoint</code> method on the supplied
     * <code>ListenContext</code> returns a <code>ListenCookie</code>
     * that does not correspond to the <code>ListenEndpoint</code>
     * that was passed to it
     *
     * @throws NullPointerException if <code>listenContext</code> is
     * <code>null</code>
     **/
    Endpoint enumerateListenEndpoints(ListenContext listenContext)
	throws IOException;

    /**
     * A callback object for passing to {@link
     * ServerEndpoint#enumerateListenEndpoints
     * ServerEndpoint.enumerateListenEndpoints} to receive the
     * enumerated {@link ServerEndpoint.ListenEndpoint ListenEndpoint}
     * instances and to choose an active listen operation for each of
     * them on behalf of the caller of
     * <code>enumerateListenEndpoints</code>.
     **/
    interface ListenContext {

	/**
	 * Adds <code>listenEndpoint</code> to this
	 * <code>ListenContext</code>'s collection of
	 * <code>ListenEndpoint</code> instances for the
	 * <code>ServerEndpoint</code> it was passed to, starts a
	 * listen operation on <code>listenEndpoint</code> if
	 * necessary, and returns the <code>ListenCookie</code> for an
	 * active listen operation on <code>listenEndpoint</code>.
	 *
	 * <p>The returned <code>ListenCookie</code> must have been
	 * obtained from a <code>ListenHandle</code> returned from
	 * some invocation of {@link
	 * ServerEndpoint.ListenEndpoint#listen ListenEndpoint.listen}
	 * on a <code>ListenEndpoint</code> equivalent to
	 * <code>listenEndpoint</code> by {@link Object#equals
	 * Object.equals}.
	 *
	 * <p>This method may start a new listen operation on
	 * <code>listenEndpoint</code> by invoking its
	 * <code>listen</code> method and returning the
	 * <code>ListenCookie</code> from the resulting
	 * <code>ListenHandle</code>, or it may return a
	 * <code>ListenCookie</code> for a listen operation previously
	 * started (but still active) on an equivalent
	 * <code>ListenEndpoint</code>.  If this method does invoke
	 * <code>listen</code> on <code>listenEndpoint</code> and it
	 * throws an exception, then this method throws that
	 * exception.
	 *
	 * <p>The implementation of this method may invoke {@link
	 * ServerEndpoint.ListenEndpoint#checkPermissions
	 * checkPermissions} on <code>listenEndpoint</code> to verify
	 * that a party that it is operating on behalf of has all of
	 * the security permissions necessary to listen for requests
	 * on <code>listenEndpoint</code>.
	 *
	 * @param listenEndpoint the <code>ListenEndpoint</code> to
	 * add to this <code>ListenContext</code> and to return a
	 * <code>ListenCookie</code> for
	 *
	 * @return a <code>ListenCookie</code> that represents an
	 * active listen operation on <code>listenEndpoint</code>
	 *
	 * @throws IOException if an invocation of <code>listen</code>
	 * on <code>listenEndpoint</code> throws an
	 * <code>IOException</code>
	 *
	 * @throws SecurityException if an invocation of
	 * <code>checkPermissions</code> or <code>listen</code> on
	 * <code>listenEndpoint</code> throws a
	 * <code>SecurityException</code>
	 *
	 * @throws IllegalStateException if this method is invoked
	 * unexpectedly, such as before being passed to
	 * <code>ServerEndpoint.enumerateListenEndpoints</code> or
	 * after the invocation of
	 * <code>ServerEndpoint.enumerateListenEndpoints</code> that
	 * it was created for has returned
	 *
	 * @throws NullPointerException if <code>listenEndpoint</code>
	 * is <code>null</code>
	 **/
	ListenCookie addListenEndpoint(ListenEndpoint listenEndpoint)
	    throws IOException;
    }

    /**
     * Represents a communication endpoint on the current (local) host
     * to listen for and receive requests on.
     *
     * <p>A <code>ListenEndpoint</code> instance contains the
     * information necessary to listen for requests on the
     * communication endpoint.  For example, a TCP-based
     * <code>ListenEndpoint</code> implementation typically contains
     * the TCP port to listen on.  An implementation that supports
     * authentication typically contains the {@link Subject} (if any)
     * to use for server authentication.
     *
     * <p>The {@link #listen listen} method can be used to start a
     * <i>listen operation</i> on the communication endpoint that it
     * represents, during which requests received on the endpoint will
     * be dispatched to a supplied {@link RequestDispatcher}.
     *
     * <p><code>ListenEndpoint</code> instances make up the discrete
     * communication endpoints represented by a
     * <code>ServerEndpoint</code>, and they are passed to a {@link
     * ServerEndpoint.ListenContext ListenContext} as part of a {@link
     * ServerEndpoint#enumerateListenEndpoints
     * ServerEndpoint.enumerateListenEndpoints} invocation.
     *
     * <p>An instance of this interface should implement {@link
     * Object#equals Object.equals} to return <code>true</code> if and
     * only if the argument is equivalent to the instance in trust,
     * content, and function.  The <code>equals</code> method should
     * not invoke comparison methods (such as <code>equals</code>) on
     * any pluggable component without first verifying that the
     * component's implementation is at least as trusted as the
     * implementation of the corresponding component in the
     * <code>equals</code> argument (such as by verifying that the
     * corresponding component objects have the same actual class).
     * If any such verification fails, the <code>equals</code> method
     * should return <code>false</code> without invoking a comparison
     * method on the component.  Furthermore, these guidelines should
     * be recursively obeyed by the comparison methods of each such
     * component for its subcomponents.  To avoid opening a security
     * hole, implementations should only compare object identity
     * (<code>==</code>) of <code>Subject</code> instances, rather
     * than comparing their contents.
     *
     * <p>The equivalence relation of a <code>ListenEndpoint</code>
     * should not be a function of any state in an associated
     * <code>ServerEndpoint</code> that only applies to the
     * <code>ServerEndpoint</code>'s template for producing
     * <code>Endpoint</code> instances.
     **/
    interface ListenEndpoint {

	/**
	 * Verifies that the current security context has all of the
	 * security permissions necessary to listen for requests on
	 * this <code>ListenEndpoint</code>.
	 *
	 * <p>This method should be used when an invocation of
	 * <code>ListenEndpoint.listen</code> is used to receive
	 * requests for a variety of interested parties, each with
	 * potentially different security permissions possibly more
	 * limited than those granted to the code managing the shared
	 * endpoint, so that the managing code can enforce proper
	 * access control for each party.
	 *
	 * @throws SecurityException if the current security context
	 * does not have the permissions necessary to listen for
	 * requests on this <code>ListenEndpoint</code>
	 *
	 * @see InboundRequest#checkPermissions
	 **/
	void checkPermissions();

	/**
	 * Listens for requests received on the communication endpoint
	 * represented by this <code>ListenEndpoint</code>,
	 * dispatching them to the supplied
	 * <code>RequestDispatcher</code> in the form of {@link
	 * InboundRequest} instances.
	 *
	 * <p>This method starts a continuing <i>listen operation</i>
	 * and then immediately returns a <code>ListenHandle</code>
	 * that represents the listen operation that was started.  For
	 * the duration of the listen operation, all requests received
	 * on the communication endpoint will be dispatched to the
	 * supplied <code>RequestDispatcher</code> as
	 * <code>InboundRequest</code> instances.  The returned
	 * <code>ListenHandle</code> can be used to stop the listen
	 * operation and to obtain a {@link
	 * ServerEndpoint.ListenCookie ListenCookie} to identify the
	 * listen operation as the return value of the {@link
	 * ServerEndpoint.ListenContext#addListenEndpoint
	 * ListenContext.addListenEndpoint} method.
	 *
	 * <p>Typically, this method is invoked by a
	 * <code>ListenContext</code> implementation when its
	 * <code>addListenEndpoint</code> method is called as part of
	 * the execution of a
	 * <code>ServerEndpoint.enumerateListenEndpoints</code>
	 * invocation.  The <code>Endpoint</code> instance that can be
	 * used to send requests to the communication endpoints
	 * represented by the <code>ServerEndpoint</code> (including
	 * this <code>ListenEndpoint</code>) is produced by the
	 * <code>ServerEndpoint</code> implementation given, in part,
	 * the <code>ListenCookie</code> obtained from the
	 * <code>ListenHandle</code> returned by this method.
	 *
	 * <p>This method verifies that the current security context
	 * has all of the security permissions necessary to listen for
	 * requests on this <code>ListenEndpoint</code>, as
	 * appropriate to the implementation of this interface (see
	 * {@link #checkPermissions}).  Note that in addition to this
	 * security check, the implementation of this interface may
	 * also perform a further security check per request received
	 * (when the origin of a given request is known), to verify
	 * that the same security context also has all of the
	 * permissions necessary to receive requests from that
	 * particular origin (see {@link
	 * InboundRequest#checkPermissions}).  This interface does not
	 * provide an API for determining when such a security check
	 * has failed; the behavior will be as if the associated
	 * request never occurred.
	 *
	 * <p>Implementations of this method should provide robust
	 * behavior (such as continuing to listen for requests) in the
	 * event that the supplied <code>RequestDispatcher</code>'s
	 * <code>dispatch</code> method throws an unchecked exception.
	 *
	 * <p>Requests may be dispatched in separate threads as
	 * necessary for requests received on this
	 * <code>ListenEndpoint</code> while others are still being
	 * processed by earlier <code>dispatch</code> invocations.
	 * The implementation of this interface must assume that there
	 * may be arbitrary execution dependencies between the
	 * processing of such concurrently received requests, and thus
	 * it must not attempt any particular serialization of their
	 * processing; therefore, a request received must be either
	 * dispatched or rejected within a reasonable period of time,
	 * rather than be queued indefinitely waiting for the return
	 * of earlier <code>dispatch</code> invocations.
	 *
	 * <p>Implementations of this method should generally dispatch
	 * a request in a daemon thread with a security context at
	 * least as restrictive as the one in which this method was
	 * invoked, and without holding visible synchronization locks.
	 *
	 * @param requestDispatcher the <code>RequestDispatcher</code>
	 * to use to dispatch incoming requests received on this
	 * communication endpoint
	 *
	 * @return a <code>ListenHandle</code> that represents the
	 * listen operation that was started
	 *
	 * @throws IOException if an I/O exception occurs while
	 * attempting to listen for requests on this
	 * <code>ListenEndpoint</code>.  This could occur, for
	 * example, if an I/O resource associated with this
	 * communication endpoint is already in exclusive use, or if
	 * there are insufficient I/O resources for the operation.
	 *
	 * @throws SecurityException if the current security context
	 * does not have the permissions necessary to listen for
	 * requests on this <code>ListenEndpoint</code>
	 *
	 * @throws NullPointerException if
	 * <code>requestDispatcher</code> is <code>null</code>
	 **/
	ListenHandle listen(RequestDispatcher requestDispatcher)
	    throws IOException;
    }

    /**
     * Represents a listen operation that has been started on a {@link
     * ServerEndpoint.ListenEndpoint ListenEndpoint}.
     *
     * <p>A <code>ListenHandle</code> is returned from a successful
     * <code>ListenEndpoint.listen</code> invocation to represent the
     * listen operation started by that invocation.  This object can
     * be used to stop the listen operation and to obtain a
     * <code>ListenCookie</code> to identify the listen operation as
     * the return value of the {@link
     * ServerEndpoint.ListenContext#addListenEndpoint
     * ListenContext.addListenEndpoint} method.
     **/
    interface ListenHandle {

	/**
	 * Stops listening for requests on the associated
	 * <code>ListenEndpoint</code>.
	 *
	 * <p>After this method has returned, no more requests will be
	 * dispatched to the <code>RequestDispatcher</code> for the
	 * listen operation represented by this
	 * <code>ListenHandle</code>, and the listen operation is no
	 * longer considered active.  This method frees any resources
	 * associated with the listen operation.
	 *
	 * <p>Invoking this method terminates any requests that have
	 * been received because of the listen operation and
	 * dispatched to the associated <code>RequestDispatcher</code>
	 * but have not yet had their response output stream closed
	 * (see {@link InboundRequest#abort InboundRequest.abort});
	 * subsequent I/O operations on such requests will fail with
	 * an <code>IOException</code>, except some operations that
	 * may succeed because they only affect data in local I/O
	 * buffers.
	 **/
	void close();

	/**
	 * Returns a <code>ListenCookie</code> to identify the listen
	 * operation as the return value of the {@link
	 * ServerEndpoint.ListenContext#addListenEndpoint
	 * ListenContext.addListenEndpoint} method.
	 *
	 * @return a <code>ListenCookie</code> to identify the listen
	 * operation
	 **/
	ListenCookie getCookie();
    }

    /**
     * A cookie to identify a listen operation as the return value of
     * the {@link ServerEndpoint.ListenContext#addListenEndpoint
     * ListenContext.addListenEndpoint} method.
     **/
    interface ListenCookie {
    }
}
