/* * 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. * * @author Sun Microsystems, Inc. * @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 { } }