All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.simpleframework.transport.Wrapper Maven / Gradle / Ivy

/*
 * Wrapper.java February 2008
 *
 * Copyright (C) 2008, Niall Gallagher 
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General 
 * Public License along with this library; if not, write to the 
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
 * Boston, MA  02111-1307  USA
 */

package org.simpleframework.transport;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.ByteChannel;
import java.nio.charset.Charset;

/**
 * The Wrapper object represents a packet that wraps an
 * unmodifiable buffer. This ensures that the contents of the buffer
 * are not modified during the use of the packet. To ensure that the
 * buffer can not be modified the append methods will
 * always append zero bytes, also the write methods do 
 * no compact the buffers when some content has been written. 
 * 
 * @author Niall Gallagher
 */
class Wrapper implements Packet {

   /**
    * This is the ready only byte buffer that this packet wraps.
    */
   private ByteBuffer buffer;
   
   /**
    * This is the unique sequence number for this packet.
    */
   private long sequence;
   
   /**
    * This determines if the packet has already been closed.
    */
   private boolean closed;
   
   /**
    * Constructor for the Wrapper object. This will
    * create a wrapper for the provided buffer which will enable
    * the buffer to be written to a byte channel without being
    * modified by the write process.
    * 
    * @param buffer this is the buffer that is to be wrapped
    * @param sequence this is the sequence number for this packet
    */
   public Wrapper(ByteBuffer buffer, long sequence) {
      this.sequence = sequence;
      this.buffer = buffer;
   }

   /**
    * The sequence number represents the order with which this is
    * to be delivered to the underlying network. This allows safer
    * transfer of packets in an asynchronous environment where it 
    * may be possible for a packet to be written out of sequence. 
    * The sequence number also determines the order of closure.
    *
    * @return this returns an increasing packet sequence number
    */ 
   public long sequence() {
      return sequence;
   }

   /**
    * This is used to determine how much space is left to append 
    * data to this packet. This is typically equivilant to capacity
    * minus the length. However in the event that the packet uses 
    * a private memory store that can not be written to then this
    * can return zero regardless of the capacity and length.
    *
    * @return the space left within the buffer to append data to
    */   
   public int space() {
      return 0;
   }

   /**
    * This represents the capacity of the backing store. The buffer
    * is full when length is equal to capacity and it can typically
    * be appended to when the length is less than the capacity. The
    * only exception is when space returns zero, which
    * means that the packet can not have bytes appended to it.
    *
    * @param this is the capacity of othe backing byte storage
    */    
   public int capacity() {
      return length();
   }

   /**        
    * This is used to determine how mnay bytes remain within this
    * packet. It represents the number of write ready bytes, so if
    * the length is greater than zero the packet can be written to
    * a byte channel. When length is zero the packet can be closed.
    * 
    * @return this is the number of bytes remaining in this packet
    */
   public int length() {
      int offset = buffer.position();
      int limit = buffer.limit();
     
      if(closed) {
         return 0;              
      } 
      return limit - offset;
   }

   /**
    * This is used to encode the underlying byte sequence to text.
    * Converting the byte sequence to text can be useful when either
    * debugging what exactly is being sent. Also, for transports 
    * that require string delivery of packets this can be used. 
    *
    * @return this returns the bytes sequence as a string object
    */  
   public String encode() throws IOException {
      return encode("ISO-8859-1"); 
   }
   
   /**
    * This is used to encode the underlying byte sequence to text.
    * Converting the byte sequence to text can be useful when either
    * debugging what exactly is being sent. Also, for transports 
    * that require string delivery of packets this can be used. 
    *
    * @param charset this is the character set to use for encoding
    *
    * @return this returns the bytes sequence as a string object
    */   
   public String encode(String encoding) throws IOException {
      ByteBuffer segment = buffer.duplicate();
      
      if(segment == null) {
         return new String();
      }
      return encode(encoding, segment);
   }
   
   /**
    * This is used to encode the underlying byte sequence to text.
    * Converting the byte sequence to text can be useful when either
    * debugging what exactly is being sent. Also, for transports 
    * that require string delivery of packets this can be used. 
    *
    * @param charset this is the character set to use for encoding
    * @param buffer this is the buffer that will be encoded
    *
    * @return this returns the bytes sequence as a string object
    */   
   private String encode(String encoding, ByteBuffer buffer) throws IOException {
      Charset charset = Charset.forName(encoding); 
      CharBuffer text = charset.decode(buffer);

      return text.toString();
   }

   /**
    * This will not append any bytes to the packet. Because this is
    * an immutable implementation of the Packet it can
    * not modify the underlying buffer. So this will simply return
    * having made no changes to either the buffer of the packet.
    *
    * @param buffer this is the buffer containing the bytes
    *
    * @return returns the number of bytes that have been moved
    */    
   public int append(ByteBuffer buffer) throws IOException {
      return append(buffer, 0);
   }

   /**
    * This will not append any bytes to the packet. Because this is
    * an immutable implementation of the Packet it can
    * not modify the underlying buffer. So this will simply return
    * having made no changes to either the buffer of the packet.
    *
    * @param buffer this is the buffer containing the bytes
    * @param count this is the number of bytes that should be used
    *
    * @return returns the number of bytes that have been moved
    */    
   public int append(ByteBuffer buffer, int count) throws IOException {
      if(closed) {
        throw new PacketException("Packet is closed");              
      }
      return 0;
   }
   
   /**
    * This write method will write the contents of the packet to the
    * provided byte channel. If the whole packet can be be written
    * then this will simply return the number of bytes that have. 
    * The number of bytes remaining within the packet after a write
    * can be acquired from the length method. Once all
    * of the bytes are written the packet must be closed.
    *
    * @param channel this is the channel to write the packet to
    *
    * @return this returns the number of bytes that were written
    */ 
   public int write(ByteChannel channel) throws IOException {
      int size = length();     

      if(closed) {
         throw new PacketException("Packet is closed");              
      }
      if(size <= 0) { 
         return 0;
      }
      return write(channel, size);
   }

   /**
    * This write method will write the contents of the packet to the
    * provided byte channel. If the whole packet can be be written
    * then this will simply return the number of bytes that have. 
    * The number of bytes remaining within the packet after a write
    * can be acquired from the length method. Once all
    * of the bytes are written the packet must be closed.
    *
    * @param channel this is the channel to write the packet to
    * @param count the number of bytes to write to the channel
    *
    * @return this returns the number of bytes that were written
    */ 
   public int write(ByteChannel channel, int count) throws IOException {
      if(closed) {
         throw new PacketException("Packet is closed");              
      }           
      return write(channel, buffer);
   }

   /**
    * This write method will write the contents of the packet to the
    * provided byte channel. If the whole packet can be be written
    * then this will simply return the number of bytes that have. 
    * The number of bytes remaining within the packet after a write
    * can be acquired from the length method. Once all
    * of the bytes are written the packet must be closed.
    *
    * @param channel this is the channel to write the packet to
    * @param segment this is the segment that is to be written
    *
    * @return this returns the number of bytes that were written
    */ 
   private int write(ByteChannel channel, ByteBuffer segment) throws IOException {
      int require = segment.remaining();
      int count = 0;
      
      while(count < require) { 
         int size = channel.write(segment);

         if(size <= 0) {
            break;
         }
         count += size;
      }
      return count;

   }

   /**
    * The close method for the packet is used to ensure
    * that any resources occupied by the packet are released. This
    * can be subclassed to introduce such functionality, however the
    * current implementation does not hold any releasable resources.
    */    
   public void close() throws IOException {
      closed = true;
   }
   
   /**
    * Provides a string representation of the state of the packet. 
    * This can be useful for debugging the state transitions that a
    * packet will go through when being written and appended to.
    *
    * @return this returns a string representation for the packet
    */    
   @Override
   public String toString() {
      return String.format("%s %s", sequence, buffer);
   }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy