CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-squareup-okio--okio-jvm

A modern I/O library that complements java.io and java.nio to make it much easier to access, store, and process your data.

Pending
Overview
Eval results
Files

jvm-extensions.mddocs/

JVM Extensions

Okio provides extensive JVM-specific extensions for interoperability with Java I/O, NIO, security APIs, and other JVM libraries. These extensions make it easy to integrate Okio with existing Java codebases.

Capabilities

Java I/O Interoperability

Convert between Java I/O streams and Okio Sources/Sinks.

/**
 * Converts an OutputStream to a Sink
 * @return Sink that writes to this OutputStream
 */
fun OutputStream.sink(): Sink

/**
 * Converts an InputStream to a Source  
 * @return Source that reads from this InputStream
 */
fun InputStream.source(): Source

/**
 * Converts a Socket's OutputStream to a Sink with timeout support
 * @return Sink that writes to the socket with timeout handling
 */
fun Socket.sink(): Sink

/**
 * Converts a Socket's InputStream to a Source with timeout support
 * @return Source that reads from the socket with timeout handling
 */
fun Socket.source(): Source

/**
 * Converts a File to a Source for reading
 * @return Source that reads from this file
 * @throws FileNotFoundException if file doesn't exist
 * @throws IOException if an I/O error occurs
 */
@Throws(IOException::class)
fun File.source(): Source

/**
 * Converts a File to a Sink for writing
 * @param append If true, append to existing file; if false, overwrite
 * @return Sink that writes to this file
 * @throws IOException if an I/O error occurs
 */
@Throws(IOException::class)
fun File.sink(append: Boolean = false): Sink

/**
 * Converts a File to an appending Sink
 * @return Sink that appends to this file
 * @throws IOException if an I/O error occurs
 */
@Throws(IOException::class)
fun File.appendingSink(): Sink

Usage Examples:

import java.io.*
import java.net.Socket

// File I/O
val file = File("/tmp/example.txt")
val source = file.source().buffer()
val content = source.readUtf8()
source.close()

val sink = file.sink().buffer()
sink.writeUtf8("Hello from Okio!")
sink.close()

// Stream conversion
val byteArrayOutputStream = ByteArrayOutputStream()
val sink = byteArrayOutputStream.sink().buffer()
sink.writeUtf8("Data")
sink.close()
val bytes = byteArrayOutputStream.toByteArray()

val byteArrayInputStream = ByteArrayInputStream(bytes)
val source = byteArrayInputStream.source().buffer()
val data = source.readUtf8()

// Socket I/O with timeout
val socket = Socket("example.com", 80)
socket.soTimeout = 5000 // 5 second timeout

val socketSource = socket.source().buffer()
val socketSink = socket.sink().buffer()

socketSink.writeUtf8("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n")
socketSink.flush()

val response = socketSource.readUtf8Line()
println(response)
socket.close()

NIO Interoperability

Work with Java NIO Path and Channel APIs.

/**
 * Converts a NIO Path to a Source for reading
 * @param options OpenOption instances to control how file is opened
 * @return Source that reads from the path
 * @throws IOException if an I/O error occurs
 */
@Throws(IOException::class)
fun java.nio.file.Path.source(vararg options: OpenOption): Source

/**
 * Converts a NIO Path to a Sink for writing
 * @param options OpenOption instances to control how file is opened
 * @return Sink that writes to the path
 * @throws IOException if an I/O error occurs
 */
@Throws(IOException::class)
fun java.nio.file.Path.sink(vararg options: OpenOption): Sink

Usage Examples:

import java.nio.file.Paths
import java.nio.file.StandardOpenOption.*

val nioPath = Paths.get("/tmp/nio-example.txt")

// Write using NIO path
val sink = nioPath.sink(CREATE, WRITE, TRUNCATE_EXISTING).buffer()
sink.writeUtf8("NIO Path example")
sink.close()

// Read using NIO path
val source = nioPath.source(READ).buffer()
val content = source.readUtf8()
source.close()
println(content)

// Append to file
val appendSink = nioPath.sink(CREATE, WRITE, APPEND).buffer()
appendSink.writeUtf8("\nAppended line")
appendSink.close()

Cryptographic Extensions

Integrate with Java security APIs for encryption and authentication.

/**
 * Wraps a Sink with cipher encryption
 * @param cipher Initialized Cipher instance for encryption
 * @return CipherSink that encrypts data before writing
 */
fun Sink.cipherSink(cipher: Cipher): CipherSink

/**
 * Wraps a Source with cipher decryption
 * @param cipher Initialized Cipher instance for decryption
 * @return CipherSource that decrypts data while reading
 */
fun Source.cipherSource(cipher: Cipher): CipherSource

/**
 * Wraps a Sink with MAC computation
 * @param mac Initialized Mac instance
 * @return HashingSink that computes MAC while writing
 */
fun Sink.hashingSink(mac: Mac): HashingSink

/**
 * Wraps a Source with MAC computation
 * @param mac Initialized Mac instance
 * @return HashingSource that computes MAC while reading
 */
fun Source.hashingSource(mac: Mac): HashingSource

/**
 * Wraps a Sink with MessageDigest computation
 * @param digest MessageDigest instance
 * @return HashingSink that computes digest while writing
 */
fun Sink.hashingSink(digest: MessageDigest): HashingSink

/**
 * Wraps a Source with MessageDigest computation
 * @param digest MessageDigest instance
 * @return HashingSource that computes digest while reading
 */
fun Source.hashingSource(digest: MessageDigest): HashingSource

Usage Examples:

import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
import java.security.MessageDigest

// AES encryption
val key = SecretKeySpec("MySecretKey12345".toByteArray(), "AES")
val encryptCipher = Cipher.getInstance("AES/ECB/PKCS5Padding")
encryptCipher.init(Cipher.ENCRYPT_MODE, key)

val file = File("/tmp/encrypted.dat")
val encryptedSink = file.sink().cipherSink(encryptCipher).buffer()
encryptedSink.writeUtf8("Secret message")
encryptedSink.close()

// AES decryption
val decryptCipher = Cipher.getInstance("AES/ECB/PKCS5Padding")
decryptCipher.init(Cipher.DECRYPT_MODE, key)

val decryptedSource = file.source().cipherSource(decryptCipher).buffer()
val decryptedMessage = decryptedSource.readUtf8()
decryptedSource.close()
println("Decrypted: $decryptedMessage")

// HMAC computation
val hmacKey = SecretKeySpec("hmac-secret".toByteArray(), "HmacSHA256")
val mac = Mac.getInstance("HmacSHA256")
mac.init(hmacKey)

val hmacSink = blackholeSink().hashingSink(mac)
hmacSink.write(Buffer().writeUtf8("data to authenticate"), 19)
hmacSink.flush()
println("HMAC: ${hmacSink.hash.hex()}")

// MessageDigest computation
val sha256 = MessageDigest.getInstance("SHA-256")
val digestSink = blackholeSink().hashingSink(sha256)
digestSink.write(Buffer().writeUtf8("data to hash"), 12)
digestSink.flush()
println("SHA-256: ${digestSink.hash.hex()}")

Resource FileSystem

Access classpath resources as a FileSystem.

/**
 * Creates a FileSystem that reads from classpath resources
 * @return FileSystem for accessing classpath resources
 */
fun ClassLoader.asResourceFileSystem(): FileSystem

/**
 * CipherSink encrypts data using a Cipher before writing to underlying sink
 */
class CipherSink(
    private val sink: BufferedSink,
    private val cipher: Cipher
) : Sink {
    /**
     * The cipher being used for encryption
     */
    val cipher: Cipher
}

/**
 * CipherSource decrypts data using a Cipher while reading from underlying source
 */
class CipherSource(
    private val source: BufferedSource,
    private val cipher: Cipher
) : Source {
    /**
     * The cipher being used for decryption
     */
    val cipher: Cipher
}

Usage Examples:

// Access classpath resources
val classLoader = Thread.currentThread().contextClassLoader
val resourceFs = classLoader.asResourceFileSystem()

// Read a resource file
val configPath = "config/application.properties".toPath()
if (resourceFs.exists(configPath)) {
    val config = resourceFs.read(configPath) {
        readUtf8()
    }
    println("Config: $config")
}

// List resources in a directory
val resourceDir = "static/css".toPath()
resourceFs.listOrNull(resourceDir)?.forEach { path ->
    println("Resource: $path")
}

Async Timeout

Background thread timeout implementation for non-blocking operations.

/**
 * Timeout implementation using a background thread
 * Provides asynchronous timeout functionality
 */
class AsyncTimeout : Timeout() {
    /**
     * Enters this timeout, starting the timeout timer
     */
    fun enter()
    
    /**
     * Exits this timeout, stopping the timeout timer
     * @return true if the timeout was triggered, false otherwise
     */
    fun exit(): Boolean
    
    /**
     * Cancels this timeout, preventing it from firing
     */
    fun cancel()
    
    /**
     * Wraps a Sink with this timeout
     * @param sink Sink to wrap with timeout
     * @return Sink that respects this timeout
     */
    fun sink(sink: Sink): Sink
    
    /**
     * Wraps a Source with this timeout
     * @param source Source to wrap with timeout
     * @return Source that respects this timeout
     */
    fun source(source: Source): Source
    
    /**
     * Executes a block with this timeout applied
     * @param block Block to execute with timeout
     * @return Result of the block execution
     * @throws IOException if timeout occurs
     */
    @Throws(IOException::class)
    fun <T> withTimeout(block: () -> T): T
    
    /**
     * Called when timeout occurs (override to customize behavior)
     * Default implementation does nothing
     */
    protected open fun timedOut()
    
    /**
     * Creates an exception for timeout scenarios
     * @param cause Optional underlying cause
     * @return IOException to throw on timeout
     */
    protected open fun newTimeoutException(cause: IOException?): IOException
}

Usage Examples:

import java.util.concurrent.TimeUnit

// Create timeout for network operations
val timeout = AsyncTimeout()
timeout.timeout(30, TimeUnit.SECONDS) // 30 second timeout

try {
    val result = timeout.withTimeout {
        // Simulate long-running network operation
        val socket = Socket("slow-server.com", 80)
        val source = socket.source().buffer()
        val sink = socket.sink().buffer()
        
        sink.writeUtf8("GET / HTTP/1.1\r\nHost: slow-server.com\r\n\r\n")
        sink.flush()
        
        val response = source.readUtf8Line()
        socket.close()
        response
    }
    println("Response: $result")
} catch (e: IOException) {
    println("Operation timed out or failed: ${e.message}")
}

// Custom timeout behavior
class CustomTimeout : AsyncTimeout() {
    override fun timedOut() {
        println("Custom timeout triggered!")
    }
    
    override fun newTimeoutException(cause: IOException?): IOException {
        return IOException("Custom timeout exceeded", cause)
    }
}

Compression and Decompression

Work with compressed data streams.

/**
 * Sink that compresses data using Deflater before writing
 */
class DeflaterSink(
    private val sink: Sink,
    private val deflater: Deflater
) : Sink {
    /**
     * The deflater used for compression
     */
    val deflater: Deflater
}

/**
 * Source that decompresses data using Inflater while reading
 */
class InflaterSource(
    private val source: Source,
    private val inflater: Inflater
) : Source {
    /**
     * The inflater used for decompression
     */
    val inflater: Inflater
    
    /**
     * Attempts to read or inflate data
     * @param sink Buffer to read into
     * @param byteCount Number of bytes to attempt to read
     * @return Number of bytes read, or -1 if exhausted
     */
    fun readOrInflate(sink: Buffer, byteCount: Long): Long
    
    /**
     * Refills the inflater with more compressed data
     * @return true if more data was available
     */
    fun refill(): Boolean
}

/**
 * Creates a pipe for connecting a source and sink with buffering
 * @param maxBufferSize Maximum buffer size for the pipe
 * @return Pipe instance with source and sink properties
 */
class Pipe(maxBufferSize: Long) {
    /**
     * Sink for writing data to the pipe
     */
    val sink: Sink
    
    /**
     * Source for reading data from the pipe
     */
    val source: Source
    
    /**
     * Folds the pipe buffer into the provided sink
     * @param sink Sink to receive buffered data
     */
    fun fold(sink: Sink)
    
    /**
     * Cancels the pipe, preventing further operations
     */
    fun cancel()
}

Usage Examples:

import java.util.zip.Deflater
import java.util.zip.Inflater

// Compress data
val originalData = "This is data to compress. ".repeat(100)
val deflater = Deflater(Deflater.BEST_COMPRESSION)
val compressedBuffer = Buffer()
val deflaterSink = DeflaterSink(compressedBuffer, deflater)
val bufferedSink = deflaterSink.buffer()

bufferedSink.writeUtf8(originalData)
bufferedSink.close()

println("Original size: ${originalData.length}")
println("Compressed size: ${compressedBuffer.size}")

// Decompress data
val inflater = Inflater()
val inflaterSource = InflaterSource(compressedBuffer, inflater)
val bufferedSource = inflaterSource.buffer()

val decompressedData = bufferedSource.readUtf8()
bufferedSource.close()

println("Decompressed matches original: ${decompressedData == originalData}")

// Use Pipe for producer-consumer pattern
val pipe = Pipe(8192) // 8KB buffer

// Producer thread
Thread {
    val sink = pipe.sink.buffer()
    try {
        for (i in 1..100) {
            sink.writeUtf8("Message $i\n")
            Thread.sleep(10) // Simulate work
        }
    } finally {
        sink.close()
    }
}.start()

// Consumer thread
Thread {
    val source = pipe.source.buffer()
    try {
        while (!source.exhausted()) {
            val message = source.readUtf8Line()
            if (message != null) {
                println("Received: $message")
            }
        }
    } finally {
        source.close()
    }
}.start()

Install with Tessl CLI

npx tessl i tessl/maven-com-squareup-okio--okio-jvm

docs

buffer.md

bytestring.md

filesystem.md

hashing.md

index.md

jvm-extensions.md

sources-sinks.md

tile.json