Package com.sun.jmx.remote.generic

Source Code of com.sun.jmx.remote.generic.ServerSynchroMessageConnectionImpl$MessageReader

/*
* @(#)file      ServerSynchroMessageConnectionImpl.java
* @(#)author    Sun Microsystems, Inc.
* @(#)version   1.5
* @(#)lastedit  07/03/08
* @(#)build     @BUILD_TAG_PLACEHOLDER@
*
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
*
* The contents of this file are subject to the terms of either the GNU General
* Public License Version 2 only ("GPL") or the Common Development and
* Distribution License("CDDL")(collectively, the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy of the
* License at http://opendmk.dev.java.net/legal_notices/licenses.txt or in the
* LEGAL_NOTICES folder that accompanied this code. See the License for the
* specific language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file found at
*     http://opendmk.dev.java.net/legal_notices/licenses.txt
* or in the LEGAL_NOTICES folder that accompanied this code.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code.
*
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
*
*       "Portions Copyrighted [year] [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding
*
*       "[Contributor] elects to include this software in this distribution
*        under the [CDDL or GPL Version 2] license."
*
* If you don't indicate a single choice of license, a recipient has the option
* to distribute your version of this file under either the CDDL or the GPL
* Version 2, or to extend the choice of license to its licensees as provided
* above. However, if you add GPL Version 2 code and therefore, elected the
* GPL Version 2 license, then the option applies only if the new code is made
* subject to such option by the copyright holder.
*
*/

package com.sun.jmx.remote.generic;

import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.io.IOException;
import java.io.InterruptedIOException;
import javax.security.auth.Subject;

import javax.management.remote.generic.ConnectionClosedException;
import javax.management.remote.generic.*;
import javax.management.remote.message.*;
import com.sun.jmx.remote.generic.DefaultConfig;
import com.sun.jmx.remote.opt.util.ThreadService;
import com.sun.jmx.remote.opt.util.ClassLogger;
import com.sun.jmx.remote.opt.internal.ClientCommunicatorAdmin;
import com.sun.jmx.remote.opt.util.EnvHelp;

public class ServerSynchroMessageConnectionImpl implements ServerSynchroMessageConnection {

    public ServerSynchroMessageConnectionImpl(MessageConnection mc, Map env)
  throws IOException {
  if (mc == null) {
      throw new IllegalArgumentException("Null message connection.");
  }
 
  this.env = env;

  waitConnectedState = DefaultConfig.getTimeoutForWaitConnectedState(env);

  this.serverAdmin = DefaultConfig.getServerAdmin(this.env);

  connection = mc;
    }

    public void connect(Map env) throws IOException {
        synchronized(stateLock) {
      if (state != UNCONNECTED) {
    waitConnected();
    return;
      } else {
    state = CONNECTING;
      }
  }

  connection.connect(env);
 
  connection = serverAdmin.connectionOpen(connection);

        synchronized(stateLock) {
      if (state != CONNECTING) {
    // closed by another thread
    try {
        connection.close();
    } catch (Exception e) {
        // OK Already closed.
    }
    throw new IOException("The connecting is stooped by another thread.");
      }

      state = CONNECTED;
      stateLock.notifyAll();
  }
    }

    public void sendOneWay(Message msg) throws IOException {
  if (logger.traceOn()) {
      logger.trace("sendOneWay", "Send a message without response.");
  }

  waitConnected();

  synchronized(connectionLock) {
      connection.writeMessage(msg);
  }
    }

    public void setCallback(SynchroCallback cb) {
  if (logger.traceOn()) {
      logger.trace("setCallback", "be called.");
  }

  if (callback != null) {
      throw new IllegalArgumentException("The callback has been assigned.");
  }

  if (cb == null) {
      throw new IllegalArgumentException("Null callback.");
  }
  callback = cb;

  threads = new ThreadService(DefaultConfig.getServerMinThreads(env),
            DefaultConfig.getServerMaxThreads(env));

  reader = new MessageReader();
  threads.handoff(reader);
    }

    public String getConnectionId() {
  return connection.getConnectionId();
    }

    public void close() throws IOException {
  if (logger.traceOn()) {
      logger.trace("close", "Closing this SynchroMessageConnection.");
  }

  synchronized(stateLock) {
      if (state == TERMINATED) {
    return;
      }

      state = TERMINATED;

      if (logger.traceOn()) {
    logger.trace("close", "Close the callback reader.");
      }
      if (reader != null) {
    reader.stop();
      }

      if (threads != null) {
    threads.terminate();

    threads = null;
      }

      if (logger.traceOn()) {
    logger.trace("close", "Closing the underlying connection.");
      }
      if (connection != null) {
    connection.close();
      }

      serverAdmin.connectionClosed(connection);

      // clean
      if (logger.traceOn()) {
    logger.trace("close", "Clean all threads waiting theire responses.");
      }

      stateLock.notify();
  }
    }

    /**
     * Returns the underlying asynchronous trasport.
     */
    public MessageConnection getAsynchroConnection() {
  return connection;
    }

//----------------------------------------------
// private classes
//----------------------------------------------

    private class MessageReader implements Runnable {
  public MessageReader() {
  }
     
  public void run() {
      try {
    executingThread = Thread.currentThread();

    Message msg;
     
    while(!stopped()) {
        if (logger.traceOn()) {
      logger.trace("MessageReader-run", "Waiting a coming message...");
        }

        msg = null;
       
        try {
      msg = (Message)connection.readMessage();
        } catch (Exception e) {
      if (stopped()) {
          break;
      }

      callback.connectionException(e);

      // if rconnected, a new reader should be created.
      break;
        }

        if (stopped()) {   
      break;
        }
       
        threads.handoff(new RemoteJob(msg));
       
        if (msg instanceof CloseMessage) {
      break;
        }
    }
      } catch (Exception eee) {
    // need to stop
    if (logger.traceOn()) logger.trace("MessageReader-run", "stops.");
      }

      synchronized(stateLock) {
    executingThreadInterrupted = true;
      }

      if (logger.traceOn()) {
    logger.trace("MessageReader-run", "ended.");
      }
  }

  public void stop() {
      if (logger.traceOn()) {
    logger.trace("MessageReader-terminated", "be called.");
      }

      synchronized(stateLock) {
    if (Thread.currentThread() != executingThread
        && executingThread != null &&
        !executingThreadInterrupted) {

        executingThreadInterrupted = true;
       
        executingThread.interrupt();
    }
      }

      if (logger.traceOn()) {
    logger.trace("MessageReader-terminated", "done.");
      }
  }

  private boolean stopped() {
      synchronized(stateLock) {
    return (state != CONNECTED || executingThreadInterrupted);
      }
  }

  private Thread executingThread;

  // This flag is used to ensure that we interrupt the executingThread
  // only when it is running in this MessageReader object.
  private boolean executingThreadInterrupted = false;
    }

    private class RemoteJob implements Runnable {
  public RemoteJob(Message msg) {
      this.msg = msg;
  }

  public void run() {
      if (logger.traceOn()) {
    logger.trace("RemoteJob-run", "Receive a new request.");
      }

      try {
         Message resp = callback.execute(msg);

         if (resp != null) {
       synchronized(connectionLock) {
           connection.writeMessage(resp);
       }
         }
      } catch (Exception ie) {
    synchronized(stateLock) {
        if (state != CONNECTED && callback != null) {
      // inform the callback
      callback.connectionException(ie);
        }
    }
      }
  }

  private Message msg;
    }

    public Subject getSubject() {
  return serverAdmin.getSubject(connection);
    }

//----------------------------------------------
// private methods
//----------------------------------------------
    private void waitConnected() throws IOException {
  synchronized(stateLock) {
      if (state == CONNECTED) {
    return;
      } else if (state != CONNECTING) {
    throw new IOException("The connection was closed or failed.");
      }

      final long startTime = System.currentTimeMillis();
      long remainingTime = waitConnectedState;

      while (state == CONNECTING &&
       waitConnectedState > 0) {

    try {
        stateLock.wait(remainingTime);
    } catch (InterruptedException ire) {
        break;
    }

    remainingTime = waitConnectedState -
        (System.currentTimeMillis() - startTime);
      }
       
      if (state != CONNECTED) {
    throw new IOException("The connection is not connected.");
      } else {
    return;
      }
  }
    }

//----------------------------------------------
// private variables
//----------------------------------------------
    /**
     * This lock used to ensures no concurrent writes
     */
    private transient int[] connectionLock = new int[0];
    private transient MessageConnection connection;

    private transient ServerAdmin serverAdmin = null;

    private Map env;

    private transient SynchroCallback callback;
    private transient ThreadService threads;
    private transient MessageReader reader;

    // state issues
    private static final int UNCONNECTED = 1;
    private static final int CONNECTING = 2;
    private static final int CONNECTED = 3;
    private static final int FAILED = 4;
    private static final int TERMINATED = 5;

    private int state = UNCONNECTED;

    /**
     * Used to control access to the state variable, including
     * ensuring that only one thread manages state transitions.
     */
    private int[] stateLock = new int[0];

    private long  waitConnectedState;

    private final ClassLogger logger = new ClassLogger(
       "javax.management.remote.misc", "SynchroMessageConnectionImpl");
}
TOP

Related Classes of com.sun.jmx.remote.generic.ServerSynchroMessageConnectionImpl$MessageReader

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.