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

org.jscsi.parser.datasegment.AbstractDataSegment Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (c) 2012, University of Konstanz, Distributed Systems Group All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 * following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of
 * conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation and/or other materials provided with the
 * distribution. * Neither the name of the University of Konstanz nor the names of its contributors may be used to
 * endorse or promote products derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package org.jscsi.parser.datasegment;


import java.nio.ByteBuffer;
import java.util.NoSuchElementException;

import org.jscsi.exception.InternetSCSIException;
import org.jscsi.parser.Constants;


/**
 * 

DataSegment

*

* This class represents a basic interface for a data segment contained in a ProtocolDataUnit object. * * @author Volker Wildi */ public abstract class AbstractDataSegment implements IDataSegment { // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * Constant, which is used to partioning the dataBuffer of this size. Typically, this is equal to the * MaxRecvDataSegmentLength. */ private final int maxChunkSize; // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * The buffer of this data segment. */ protected ByteBuffer dataBuffer; /** The number of bytes actually used by the dataBuffer. */ protected int length; // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * Constructor to create a new, empty DataSegment object with the given chunk size. * * @param initMaxChunkSize The maximum size (in bytes) of one chunk, which represents the * MaxRecvDataSegmentLength. */ public AbstractDataSegment (final int initMaxChunkSize) { maxChunkSize = initMaxChunkSize; length = 0; dataBuffer = ByteBuffer.allocate(length); } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** {@inheritDoc} */ public int serialize (final ByteBuffer dst, final int off) { if (dst == null) { throw new NullPointerException(); } dst.position(off); if (dst.remaining() % Constants.BYTES_PER_INT != 0) { throw new IllegalArgumentException("The buffer length must be a multiple of " + Constants.BYTES_PER_INT + "."); } dataBuffer.rewind(); if (dst.remaining() < dataBuffer.limit()) { throw new IllegalArgumentException("The data buffer is too small."); } dst.put(dataBuffer); return dataBuffer.limit(); } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** {@inheritDoc} */ public SettingsMap getSettings () throws InternetSCSIException { throw new UnsupportedOperationException(); } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * Returns the total length (with padding), which is needed for the given length len. * * @param len The length of the DataSegment, which want to be stored. * @return The total length. */ public static final int getTotalLength (final int len) { return len + calcPadding(len); } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * This method resizes the data buffer, if necessary. A resizing is not needed, when the neededLength * is greater than the capacity of allocated data buffer. The flag copyData indicates, if the old * buffer has to be copied into the new bigger data buffer. * * @param additionalLength The length, which is now needed to store all informations in the data buffer. * @param copyData true, if old buffer has to be copied into the new buffer. false * indicates, that the new buffer is initialized with zeros. */ protected void resizeBuffer (final int additionalLength, final boolean copyData) { if (additionalLength < 0) { throw new IllegalArgumentException("The length must be greater or equal than 0."); } dataBuffer.position(length); // reallocate a bigger dataBuffer, if needed if (length + additionalLength > dataBuffer.capacity()) { final ByteBuffer newBuffer = ByteBuffer.allocate(getTotalLength(length + additionalLength)); // copy old data... if (copyData) { dataBuffer.flip(); newBuffer.put(dataBuffer); } dataBuffer = newBuffer; dataBuffer.limit(getTotalLength(length + additionalLength)); } length += additionalLength; } /** {@inheritDoc} */ public void clear () { dataBuffer.clear().flip(); length = 0; } /** {@inheritDoc} */ public final int getLength () { return length; } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * Compares this object with another object for equality. * * @param anObject Another object. * @return true, if the anObject and this object are equal. Else false . */ public boolean equals (final Object anObject) { // check for alias if (this == anObject) { return true; } if (anObject instanceof AbstractDataSegment) { final AbstractDataSegment anotherDS = (AbstractDataSegment) anObject; if (length != anotherDS.length) { return false; } dataBuffer.rewind(); anotherDS.dataBuffer.rewind(); return dataBuffer.equals(anotherDS.dataBuffer); } return false; } /** {@inheritDoc} */ @Override public int hashCode () { return super.hashCode(); } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** {@inheritDoc} */ public final int setDataBuffer (final ByteBuffer src, final int off, final int len) { resizeBuffer(len, false); src.position(off); int n = 0; while (src.hasRemaining() && n++ < length) { dataBuffer.put(src.get()); } dataBuffer.rewind(); return n; } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** {@inheritDoc} */ public final String toString () { final StringBuilder sb = new StringBuilder(); sb.append("Length: "); sb.append(length); sb.append(", MaxChunkSize: "); sb.append(maxChunkSize); sb.append(", dataBuffer: "); sb.append(dataBuffer); return sb.toString(); } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** {@inheritDoc} */ public final DataSegmentIterator iterator () { return new DataSegmentIterator(); } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * This methods calculates the number of padding bytes of the given length. This number of the padding bytes is in * the range of 0, ..., BYTES_PER_INT. * * @param len The length for which the padding bytes are calculated. * @return The number of padding bytes. */ protected static final int calcPadding (final int len) { if (len < 0) { throw new IllegalArgumentException("Length must be a positive number"); } final int rest = len % Constants.BYTES_PER_INT; if (rest > 0) { return Constants.BYTES_PER_INT - rest; } else { return 0; } } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- /** * Iterator through the chunks of a DataSegment. *

* This class is not resistant against changes to the dataBuffer . */ private final class DataSegmentIterator implements IDataSegmentIterator { /** The actual position of the iterator. */ private int cursor; /** The data of a chunk. */ private final ByteBuffer data; /** * Constructor to create an iterator through the chunks. */ private DataSegmentIterator () { cursor = dataBuffer.position(); data = ByteBuffer.allocate(maxChunkSize); } /** {@inheritDoc} */ public final boolean hasNext () { return cursor < dataBuffer.limit(); } /** {@inheritDoc} */ public final IDataSegmentChunk next (final int chunkSize) { if (!hasNext()) { throw new NoSuchElementException(); } if (chunkSize < 0 && chunkSize > maxChunkSize) { throw new IllegalArgumentException(); } final int pos = dataBuffer.position(); dataBuffer.position(cursor); data.position(0).limit(chunkSize); while (data.hasRemaining() && dataBuffer.hasRemaining()) { data.put(dataBuffer.get()); } final int dataSegmentLength = data.position(); final int totalLength = dataSegmentLength + calcPadding(dataSegmentLength); // set limit to the next nearest bound (with padding) data.limit(totalLength); data.rewind(); dataBuffer.position(pos); // cursor += chunkSize; cursor += totalLength; return new DataSegmentChunk(dataSegmentLength, totalLength); } // ---------------------------------------------------------------------- // ---- // ---------------------------------------------------------------------- // ---- // ---------------------------------------------------------------------- // ---- // ---------------------------------------------------------------------- // ---- /** *

DataSegmentChunk

*

* This is a chunk of a data segment. * * @author Volker Wildi */ private final class DataSegmentChunk implements IDataSegmentChunk { /** The real length (in bytes) of this chunk (excluding padding). */ private final int usedLength; /** * The length (in bytes), which is needed by this chunk (including padding). */ private final int totalLength; /** * Constructor to create a new, empty DataSegmentChunk instance with a given length and a total * length of this data segment chunk. * * @param initLength The used length (in bytes) of this new DataSegmentChunk instance. * @param initTotalLength The total length (in bytes) of this new DataSegmentChunk instance. */ private DataSegmentChunk (final int initLength, final int initTotalLength) { usedLength = initLength; totalLength = initTotalLength; } /** {@inheritDoc} */ public ByteBuffer getData () { return data; } /** {@inheritDoc} */ public int getLength () { return usedLength; } /** {@inheritDoc} */ public int getTotalLength () { return totalLength; } } } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy