Package com.shop.util.generic

Source Code of com.shop.util.generic.GenericIOClientImpl

/*
* Copyright 2008-2009 SHOP.COM
*
* Licensed 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 com.shop.util.generic;

import com.shop.util.LineReader;
import com.shop.util.chunked.ChunkedByteArray;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;

/**
* Internal implementation of the client
*
* @author Jordan Zimmerman
*/
class GenericIOClientImpl<T> implements GenericIOClient<T>, GenericIOInputStream.HeartbeatReceivedNotifier
{
  GenericIOClientImpl(Socket s, GenericIOServerImpl<T> parentServer) throws IOException
  {
    fSocket = s;
    fParentServer = parentServer;

    fIOInputStream = new GenericIOInputStream(new BufferedInputStream(fSocket.getInputStream(), fSocket.getReceiveBufferSize()), this);
    fIn = new LineReader(fIOInputStream);
    fOut = new GenericIOOutputStream(new BufferedOutputStream(fSocket.getOutputStream(), fSocket.getSendBufferSize()));
    fUserValue = new AtomicReference<T>(null);
    fLastReadTicks = new AtomicLong(System.currentTimeMillis());
    fLastFlushTicks = new AtomicLong(System.currentTimeMillis());
    fIsOpen = new AtomicBoolean(true);

    fSocket.setTcpNoDelay(true);

    String     hostname = fSocket.getInetAddress().getHostAddress();
    fAddress = InetSocketAddress.createUnresolved(hostname, s.getPort());

    GenericIOHeartbeatMonitor.instance.addClient(this);
  }

  @Override
  public String toString()
  {
    InetAddress localAddress = fAddress.getAddress();
    return (localAddress != null) ? localAddress.getHostAddress() : fAddress.getHostName();
  }

  @Override
  public void send(String line) throws IOException
  {
    int    length = line.length();
    for ( int i = 0; i < length; ++i )
    {
      char    c = line.charAt(i);
      fOut.write(c & 0xff);
    }
    fOut.write('\n');
  }

  @Override
  public void sendByte(byte b) throws IOException
  {
    fOut.write(b & 0xff);
  }

  @Override
  public void sendBytes(byte[] bytes, int offset, int length) throws IOException
  {
    fOut.write(bytes, offset, length);
  }

  @Override
  public void flush() throws IOException
  {
    fOut.flush();
    fLastFlushTicks.set(System.currentTimeMillis());
  }

  @Override
  public InetSocketAddress getAddress()
  {
    return fAddress;
  }

  @Override
  public int read() throws IOException
  {
    return fIn.read();
  }

  @Override
  public String readLine() throws IOException
  {
    return fIn.readLine();
  }

  @Override
  public ChunkedByteArray readBytes(int size) throws IOException
  {
    boolean          eof = false;
    ChunkedByteArray    bytes = (size < ChunkedByteArray.DEFAULT_CHUNK_SIZE) ? new ChunkedByteArray(size) : new ChunkedByteArray();
    while ( size-- > 0 )
    {
      int    i = fIn.read();
      if ( i < 0 )
      {
        eof = true;
        break;
      }
      bytes.append((byte)(i & 0xff));
      updateLastReadTicks();
    }

    if ( eof )
    {
      if ( bytes.size() == 0 )
      {
        return null;
      }
      throw new EOFException();
    }

    return bytes;
  }

  @Override
  public void disableHeartbeats()
  {
    GenericIOHeartbeatMonitor.instance.removeClient(this);
    fOut.disableEscapes();
    fIOInputStream.disableEscapes();
  }

  @Override
  public void close() throws IOException
  {
    try
    {
      if ( fIsOpen.get() )
      {
        flush();
      }
    }
    finally
    {
      internalClose();
    }
  }

  @Override
  public void setUserValue(T value)
  {
    fUserValue.set(value);
  }

  @Override
  public T getUserValue()
  {
    return fUserValue.get();
  }

  @Override
  public boolean    isOpen()
  {
    return fIsOpen.get();
  }

  @Override
  public void heartbeatReceived()
  {
    updateLastReadTicks();
  }

  @Override
  public GenericIOServer<T> getParentServer()
  {
    return fParentServer;
  }

  void    internalClose()
  {
    if ( !fIsOpen.compareAndSet(true, false) )
    {
      return;
    }

    try
    {
      fSocket.close();
    }
    catch ( IOException e )
    {
      // ignore
    }

    if ( fParentServer != null )
    {
      fParentServer.removeClient(this);
    }

    GenericIOHeartbeatMonitor.instance.removeClient(this);
  }

  void  sendHeartbeat() throws IOException
  {
    flush();
    fOut.writeHeartbeat();
    fLastFlushTicks.set(System.currentTimeMillis());
  }

  long    getLastReadTicks()
  {
    return fLastReadTicks.get();
  }

  long    getLastFlushTicks()
  {
    return fLastFlushTicks.get();
  }

  private void updateLastReadTicks()
  {
    fLastReadTicks.set(System.currentTimeMillis());
  }

  private final Socket           fSocket;
  private final GenericIOServerImpl<T>   fParentServer;
  private final InetSocketAddress     fAddress;
  private final GenericIOInputStream     fIOInputStream;
  private final LineReader         fIn;
  private final GenericIOOutputStream    fOut;
  private final AtomicReference<T>     fUserValue;
  private final AtomicLong         fLastReadTicks;
  private final AtomicLong        fLastFlushTicks;
  private final AtomicBoolean       fIsOpen;
}
TOP

Related Classes of com.shop.util.generic.GenericIOClientImpl

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.