Package net.jini.jeri.connection

Source Code of net.jini.jeri.connection.ServerConnectionManager$InboundMux

/*
* 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.connection;

import com.sun.jini.jeri.internal.mux.MuxServer;
import com.sun.jini.logging.Levels;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import net.jini.core.constraint.InvocationConstraints;
import net.jini.io.UnsupportedConstraintException;
import net.jini.jeri.InboundRequest;
import net.jini.jeri.RequestDispatcher;

/**
* Provides server-side connection management using the <a
* href="{@docRoot}/net/jini/jeri/connection/doc-files/mux.html">Jini
* extensible remote invocation (Jini ERI) multiplexing protocol</a>
* to frame and multiplex requests and responses over connections.
*
* <p>A <code>ServerConnectionManager</code> is created by a
* connection-based {@link net.jini.jeri.ServerEndpoint} implemention to manage
* connections.  The {@link #handleConnection handleConnection} method
* is used to manage connections for a particular {@link
* ServerConnection}.
*
* <p>Each <i>session</i> of the Jini ERI multiplexing protocol is
* mapped to a new request.  Request data is read as the data received
* for the session, and response data is written as the data sent for
* the session.
*
* @author Sun Microsystems, Inc.
* @since 2.0
*
* @com.sun.jini.impl
*
* This implementation uses the {@link Logger} named
* <code>net.jini.jeri.connection.ServerConnectionManager</code> to
* log information at the following levels:
*
* <p><table summary="Describes what is logged by
* ServerConnectionManager to its logger at various logging levels"
* border=1 cellpadding=5>
*
* <tr> <th> Level <th> Description
*
* <tr> <td> {@link Levels#HANDLED HANDLED} <td>
* I/O exception initiating handling of a new request on a connection
*
* <tr> <td> {@link Levels#HANDLED HANDLED} <td>
* I/O exception initiating multiplexing on a new connection
*
* </table>
*
* <p>This implementation uses the {@link Logger} named
* <code>net.jini.jeri.connection.mux</code> to log information at the
* following levels:
*
* <p><table summary="Describes what is logged by
* ServerConnectionManager to the mux logger at various logging
* levels" border=1 cellpadding=5>
*
* <tr> <th> Level <th> Description
*
* <tr> <td> {@link Level#WARNING WARNING} <td> unexpected exception
* during asynchronous I/O processing, or thread creation failure
*
* <tr> <td> {@link Levels#HANDLED HANDLED} <td> I/O exception during
* asynchronous I/O processing
*
* <tr> <td> {@link Level#FINEST FINEST} <td> detailed implementation
* activity
*
* </table>
**/
public final class ServerConnectionManager {
    /**
     * ServerConnectionManager logger.
     */
    private static final Logger logger =
  Logger.getLogger("net.jini.jeri.connection.ServerConnectionManager");

    /**
     * Creates a new <code>ServerConnectionManager</code>.
     **/
    public ServerConnectionManager() {
    }

    /**
     * Request dispatcher wrapper around the request dispatcher passed to
     * handleConnection (i.e., the request dispatcher created by the runtime).
     */
    private static final class Dispatcher implements RequestDispatcher {
  /**
   * The request dispatcher passed to handleConnection.
   */
  private final RequestDispatcher dispatcher;
  /**
   * The connection passed to handleConnection.
   */
  private final ServerConnection c;

  Dispatcher(RequestDispatcher dispatcher,
       ServerConnection c)
  {
      this.dispatcher = dispatcher;
      this.c = c;
  }

  /**
   * Calls processRequestData on the connection, passing the streams
   * from the specified inbound request, to obtain the request handle,
   * wraps the mux inbound request, connection and handle in an inbound
   * request, checks for accept permission, and calls dispatch on the
   * underlying dispatcher. If an IOException is thrown, catch it. It
   * is assumed that the caller will always abort the request (even on
   * normal return).
   */
  public void dispatch(InboundRequest req) {
      try {
    InboundRequest sreq =
        new Inbound(req, c,
        c.processRequestData(
              req.getRequestInputStream(),
              req.getResponseOutputStream()));
    sreq.checkPermissions();
    dispatcher.dispatch(sreq);
      } catch (IOException e) {
    if (logger.isLoggable(Levels.HANDLED)) {
        logThrow(logger, "dispatchRequest",
           "{0} throws", new Object[]{c}, e);
    }
      }
  }
    }

    /**
     * Inbound request wrapper around the inbound request created by the mux.
     */
    private static final class Inbound implements InboundRequest {
  /**
   * The inbound request created by the mux.
   */
  private final InboundRequest req;
  /**
   * The connection on which the inbound request originates.
   */
  private final ServerConnection c;
  /**
   * The inbound request handle.
   */
  private final InboundRequestHandle handle;

  Inbound(InboundRequest req,
    ServerConnection c,
    InboundRequestHandle handle)
  {
      this.req = req;
      this.c = c;
      this.handle = handle;
  }

  /* delegate to both the underlying request and the connection */
  public void populateContext(Collection context) {
      req.populateContext(context);
      c.populateContext(handle, context);
  }

  /* pass-through to the connection */
  public InvocationConstraints checkConstraints(
              InvocationConstraints constraints)
      throws UnsupportedConstraintException
  {
      return c.checkConstraints(handle, constraints);
  }

  /* pass-through to the connection */
  public void checkPermissions() {
      c.checkPermissions(handle);
  }

  /* pass-through to the underlying request */
  public InputStream getRequestInputStream() {
      return req.getRequestInputStream();
  }

  /* pass-through to the underlying request */
  public OutputStream getResponseOutputStream() {
      return req.getResponseOutputStream();
  }

  /* pass-through to underlying request */
  public void abort() {
      req.abort();
  }
    }

    /**
     * Subclass wrapper around MuxServer for inbound connections.
     */
    private static final class InboundMux extends MuxServer {
  /**
   * The inbound connection.
   */
  private final ServerConnection c;

  /**
   * Constructs an instance from the connection's streams.
   */
  private InboundMux(ServerConnection c,
         RequestDispatcher dispatcher)
      throws IOException
  {
      super(c.getOutputStream(), c.getInputStream(), dispatcher);
      this.c = c;
  }

  /**
   * Constructs an instance from the connection's channel.
   */
  private InboundMux(ServerConnection c,
         RequestDispatcher dispatcher,
         boolean ignore)
      throws IOException
  {
      super(c.getChannel(), dispatcher);
      this.c = c;
  }

  /**
   * Constructs an instance from the connection.
   */
  static void create(ServerConnection c,
         RequestDispatcher dispatcher)
  {
      RequestDispatcher d = new Dispatcher(dispatcher, c);
      try {
    if (c.getChannel() == null) {
        new InboundMux(c, d).start();
    } else {
        new InboundMux(c, d, true).start();
    }
      } catch (IOException e) {
    if (logger.isLoggable(Levels.HANDLED)) {
        logThrow(logger, "handleConnection",
           "{0} throws", new Object[]{c}, e);
    }
    try {
        c.close();
    } catch (IOException ee) {
    }
      }
  }

  /**
   * Close the connection, so that the provider is notified.
   */
  protected void handleDown() {
      try {
    c.close();
      } catch (IOException e) {
      }
  }
    }

    /**
     * Log a throw.
     */
    private static void logThrow(Logger logger,
         String method,
         String msg,
         Object[] args,
         Exception e)
    {
  LogRecord lr = new LogRecord(Levels.HANDLED, msg);
  lr.setLoggerName(logger.getName());
  lr.setSourceClassName(ServerConnectionManager.class.getName());
  lr.setSourceMethodName(method);
  lr.setParameters(args);
  lr.setThrown(e);
  logger.log(lr);
    }

    /**
     * Starts handling requests received on the specified newly
     * accepted connection, dispatching them to the specified request
     * dispatcher asynchronously, and returns immediately.
     *
     * <p>The Jini ERI multiplexing protocol is started on the
     * connection (as the server).  As each request is received, the
     * {@link ServerConnection#processRequestData processRequestData}
     * method of the connection will be invoked with the request input
     * stream and the response output stream of the {@link
     * InboundRequest} created for the request, to obtain a handle for
     * the request.  The {@link ServerConnection#checkPermissions
     * checkPermissions} method of the connection is then invoked with
     * that handle, and if it returns normally,
     * <code>dispatcher</code> is invoked with the
     * <code>InboundRequest</code>.  All of this processing is
     * performed using the same security context in force when this
     * <code>handleConnection</code> method was invoked.  The {@link
     * InboundRequest#checkPermissions checkPermissions}, {@link
     * InboundRequest#checkConstraints checkConstraints}, and {@link
     * InboundRequest#populateContext populateContext} methods of each
     * <code>InboundRequest</code> created are implemented by
     * delegating to the corresponding method of the connection
     * passing the handle for the request and the other arguments (if
     * any).
     *
     * <P>The implementation may close the connection if it determines
     * that the client has closed its side of the connection, if there
     * is an unrecoverable problem with the connection, or for other
     * implementation-specific reasons.  The caller is responsible for
     * closing the connection when the {@link
     * net.jini.jeri.ServerEndpoint.ListenHandle#close close} method
     * of the associated {@link
     * net.jini.jeri.ServerEndpoint.ListenHandle ListenHandle} is
     * invoked.
     *
     * @param conn the server connection
     *
     * @param dispatcher the request dispatcher to use to dispatch
     * requests received on the specified connection
     *
     * @throws NullPointerException if <code>conn</code> or
     * <code>dispatcher</code> is <code>null</code>
     **/
    public void handleConnection(ServerConnection conn,
         RequestDispatcher dispatcher)
    {
  if (conn == null || dispatcher == null) {
      throw new NullPointerException();
  }
  InboundMux.create(conn, dispatcher);
    }
}
TOP

Related Classes of net.jini.jeri.connection.ServerConnectionManager$InboundMux

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.