net.i2p.data

## Class SimpleDataStructure

- java.lang.Object
- - net.i2p.data.SimpleDataStructure

- All Implemented Interfaces:
    DataStructure
  Direct Known Subclasses:
    EncryptedBuildRecord, Hash, Hash384, Hash512, NodeInfo, PrivateKey, PublicKey, SessionKey, SHA1Hash, Signature, SigningPrivateKey, SigningPublicKey

      public abstract class SimpleDataStructure
      extends Object
      implements DataStructure

  Base class for I2P data structures containing a single fixed-length byte array.

  SimpleDataStructure provides efficient storage and caching for fixed-size data:

  - Fixed Length: Each subclass defines exact byte array size
  - Caching Support: Built-in LRU caching for frequently used objects
  - Immutability: Data becomes immutable after first non-null assignment
  - Memory Efficient: Optimized for high-performance scenarios

  Key Features:

  - Length Specification: Abstract `length()` method defines size
  - Data Access: Direct byte array access via `getData()`
  - Serialization: Standard read/write operations for streams
  - Encoding: Base64 and byte array conversions

  Caching System:

  - LRU Cache: Least-recently-used caching with size limits
  - Static Factories: `create()` methods for cache access
  - Efficient Lookup: First 4 bytes used as cache index
  - Memory Management: Automatic cache size adjustment based on memory

  Immutability Model:

  - Initial State: Can be created with null data
  - First Assignment: setData(), readBytes(), fromByteArray(), fromBase64()
  - Immutable After: Once non-null data is set, cannot be changed
  - Protection: Subsequent modifications throw `RuntimeException`

  Usage Patterns:

  - Creation: Use static factory methods for cache efficiency
  - Comparison: Efficient equals() and hashCode() implementations
  - Storage: Minimal memory footprint for large collections
  - Network: Fast serialization for protocol messages

  Performance Optimizations:

  - No DataStructureImpl: As of 0.9.48, extends DataStructure directly
  - Byte Caching: Shared byte arrays via SimpleByteCache
  - Reduced Overhead: Minimal object size and memory usage
  - Fast Hashing: Optimized hashCode() for collections

  Common Subclasses:

  - `Hash` - 32-byte SHA-256 hashes
  - `PublicKey` - Variable-length encryption keys
  - `PrivateKey` - Variable-length decryption keys
  - `SigningPublicKey` - Variable-length signing keys
  - `SigningPrivateKey` - Variable-length signing private keys
  - `SessionKey` - 32-byte session encryption keys
  - `Signature` - Variable-length digital signatures

  Thread Safety:

  - Immutable Data: Thread-safe after data is set
  - Static Caches: Thread-safe LRU cache implementation
  - Factory Methods: Thread-safe object creation

  Evolution:

  - 0.8.2: Initial implementation with retrofitted classes
  - 0.8.3: Added caching support and immutability
  - 0.9.48: Removed DataStructureImpl inheritance for space savings

- - ### Field Summary

    Fields
    Modifier and Type | Field and Description
    --- | ---
    `protected byte[]` | `_data`

  - ### Constructor Summary

    Constructors
    Constructor and Description
    `SimpleDataStructure()` A new instance with the data set to null.
    `SimpleDataStructure(byte[] data)`

  - ### Method Summary

    All Methods Instance Methods Abstract Methods Concrete Methods
    Modifier and Type | Method and Description
    --- | ---
    `Hash` | `calculateHash()` Calculate the SHA256 value of this object (useful for a few scenarios)
    `boolean` | `equals(Object obj)` Warning - this returns true for two different classes with the same size and same data, e.g.
    `void` | `fromBase64(String data)` Sets the data.
    `void` | `fromByteArray(byte[] data)` Does the same thing as setData() but null not allowed.
    `byte[]` | `getData()` Get the data reference (not a copy)
    `int` | `hashCode()` We assume the data has enough randomness in it, so use the first 4 bytes for speed.
    `abstract int` | `length()` The legal length of the byte array in this data structure
    `protected int` | `read(InputStream in, byte[] target)` Repeated reads until the buffer is full or IOException is thrown
    `void` | `readBytes(InputStream in)` Sets the data.
    `void` | `setData(byte[] data)` Sets the data.
    `String` | `toBase64()` render the structure into modified base 64 notation
    `byte[]` | `toByteArray()` Convert the structure to a byte array.
    `String` | `toString()`
    `void` | `writeBytes(OutputStream out)` Write out the data structure to the stream, using the format defined in the I2P data structure specification.

    - ### Methods inherited from class java.lang.Object

      `clone, finalize, getClass, notify, notifyAll, wait, wait, wait`

- - ### Field Detail

    - #### _data

          protected byte[] _data

  - ### Constructor Detail

    - #### SimpleDataStructure

          public SimpleDataStructure()

      A new instance with the data set to null. Call readBytes(), setData(), or fromByteArray() after this to set the data

    - #### SimpleDataStructure

          public SimpleDataStructure(byte[] data)

      Throws:
        `IllegalArgumentException` - if data is not the legal number of bytes (but null is ok)

  - ### Method Detail

    - #### calculateHash

          public Hash calculateHash()

      Description copied from interface: `DataStructure`
      Calculate the SHA256 value of this object (useful for a few scenarios)
      Specified by:
        `calculateHash` in interface `DataStructure`
      Returns:
        the SHA256 hash of the byte array, or null if the data is null

    - #### equals

          public boolean equals(Object obj)

      Warning - this returns true for two different classes with the same size and same data, e.g. SessionKey and SessionTag, but you wouldn't put them in the same Set, would you?
      Overrides:
        `equals` in class `Object`

    - #### fromBase64

          public void fromBase64(String data)
                          throws DataFormatException

      Sets the data.
      Specified by:
        `fromBase64` in interface `DataStructure`
      Parameters:
        `data` - base64 encoded string to load from
      Throws:
        `DataFormatException` - if decoded data is not the legal number of bytes or on decoding error
        `RuntimeException` - if data already set.

    - #### fromByteArray

          public void fromByteArray(byte[] data)
                             throws DataFormatException

      Does the same thing as setData() but null not allowed.
      Specified by:
        `fromByteArray` in interface `DataStructure`
      Parameters:
        `data` - non-null
      Throws:
        `DataFormatException` - if null or wrong length
        `RuntimeException` - if data already set.

    - #### getData

          public byte[] getData()

      Get the data reference (not a copy)
      Returns:
        the byte array, or null if unset

    - #### hashCode

          public int hashCode()

      We assume the data has enough randomness in it, so use the first 4 bytes for speed. If this is not the case, override in the extending class.
      Overrides:
        `hashCode` in class `Object`

    - #### length

          public abstract int length()

      The legal length of the byte array in this data structure

    - #### read

          protected int read(InputStream in,
                             byte[] target)
                      throws IOException

      Repeated reads until the buffer is full or IOException is thrown
      Returns:
        number of bytes read (should always equal target.length)
      Throws:
        `IOException`

    - #### readBytes

          public void readBytes(InputStream in)
                         throws DataFormatException,
                                IOException

      Sets the data.
      Specified by:
        `readBytes` in interface `DataStructure`
      Parameters:
        `in` - the stream to read
      Throws:
        `RuntimeException` - if data already set.
        `DataFormatException` - if the data is improperly formatted
        `IOException` - if there was a problem reading the stream

    - #### setData

          public void setData(byte[] data)

      Sets the data.
      Parameters:
        `data` - of correct length, or null
      Throws:
        `IllegalArgumentException` - if data is not the legal number of bytes (but null is ok)
        `RuntimeException` - if data already set.

    - #### toBase64

          public String toBase64()

      Description copied from interface: `DataStructure`
      render the structure into modified base 64 notation
      Specified by:
        `toBase64` in interface `DataStructure`
      Returns:
        null on error

    - #### toByteArray

          public byte[] toByteArray()

      Description copied from interface: `DataStructure`
      Convert the structure to a byte array.
      Specified by:
        `toByteArray` in interface `DataStructure`
      Returns:
        same thing as getData()

    - #### toString

          public String toString()

      Overrides:
        `toString` in class `Object`

    - #### writeBytes

          public void writeBytes(OutputStream out)
                          throws DataFormatException,
                                 IOException

      Description copied from interface: `DataStructure`
      Write out the data structure to the stream, using the format defined in the I2P data structure specification.
      Specified by:
        `writeBytes` in interface `DataStructure`
      Parameters:
        `out` - stream to write to
      Throws:
        `DataFormatException` - if the data was incomplete or not yet ready to be written
        `IOException` - if there was a problem writing to the stream