or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-mail-operations.mdevent-handling-system.mdindex.mdinternet-mail-mime.mdmessage-search-filtering.mdstore-folder-management.mdutility-classes-streams.md

utility-classes-streams.mddocs/

0

# Utility Classes and Streams

1

2

Jakarta Mail utility classes provide helper functionality for data sources, shared streams, stream providers, and mail-specific utilities that support the core mail operations.

3

4

## Data Source Classes

5

6

### Byte Array Data Source

7

8

The ByteArrayDataSource class provides a DataSource implementation backed by a byte array, commonly used for in-memory content.

9

10

```java { .api }

11

public class ByteArrayDataSource implements DataSource {

12

// Constructors

13

public ByteArrayDataSource(byte[] data, String type);

14

public ByteArrayDataSource(InputStream is, String type) throws IOException;

15

public ByteArrayDataSource(String data, String type);

16

17

// DataSource interface methods

18

public InputStream getInputStream() throws IOException;

19

public OutputStream getOutputStream() throws IOException;

20

public String getContentType();

21

public String getName();

22

23

// Additional methods

24

public void setName(String name);

25

}

26

```

27

28

### Byte Array Data Source Usage Example

29

30

```java

31

import jakarta.mail.util.ByteArrayDataSource;

32

import jakarta.mail.internet.*;

33

import jakarta.mail.*;

34

35

// Create data source from byte array

36

byte[] pdfData = loadPdfFile(); // Your PDF data

37

ByteArrayDataSource dataSource = new ByteArrayDataSource(pdfData, "application/pdf");

38

dataSource.setName("document.pdf");

39

40

// Use in MIME body part

41

MimeBodyPart attachment = new MimeBodyPart();

42

attachment.setDataHandler(new DataHandler(dataSource));

43

attachment.setFileName("document.pdf");

44

attachment.setDisposition(Part.ATTACHMENT);

45

46

// Create from string content

47

String htmlContent = "<html><body><h1>Hello World</h1></body></html>";

48

ByteArrayDataSource htmlSource = new ByteArrayDataSource(htmlContent, "text/html");

49

50

MimeBodyPart htmlPart = new MimeBodyPart();

51

htmlPart.setDataHandler(new DataHandler(htmlSource));

52

53

// Create from input stream

54

InputStream imageStream = getImageInputStream();

55

ByteArrayDataSource imageSource = new ByteArrayDataSource(imageStream, "image/png");

56

imageSource.setName("logo.png");

57

58

MimeBodyPart imagePart = new MimeBodyPart();

59

imagePart.setDataHandler(new DataHandler(imageSource));

60

imagePart.setDisposition(Part.INLINE);

61

imagePart.setHeader("Content-ID", "<logo>");

62

```

63

64

## Shared Input Stream Classes

65

66

Shared input streams allow multiple concurrent readers to access the same underlying data source efficiently.

67

68

### Shared Input Stream Interface

69

70

```java { .api }

71

public interface SharedInputStream {

72

// Create new stream for specified range

73

public InputStream newStream(long start, long end);

74

75

// Get current position in stream

76

public long getPosition();

77

}

78

```

79

80

### Shared File Input Stream

81

82

```java { .api }

83

public class SharedFileInputStream extends BufferedInputStream implements SharedInputStream {

84

// Constructors

85

public SharedFileInputStream(File file) throws IOException;

86

public SharedFileInputStream(File file, int size) throws IOException;

87

public SharedFileInputStream(String file) throws IOException;

88

public SharedFileInputStream(String file, int size) throws IOException;

89

90

// SharedInputStream interface methods

91

public InputStream newStream(long start, long end);

92

public long getPosition();

93

94

// File access methods

95

protected void finalize() throws Throwable;

96

}

97

```

98

99

### Shared Byte Array Input Stream

100

101

```java { .api }

102

public class SharedByteArrayInputStream extends ByteArrayInputStream implements SharedInputStream {

103

// Constructors

104

public SharedByteArrayInputStream(byte[] buf);

105

public SharedByteArrayInputStream(byte[] buf, int offset, int length);

106

107

// SharedInputStream interface methods

108

public InputStream newStream(long start, long end);

109

public long getPosition();

110

}

111

```

112

113

### Shared Stream Usage Example

114

115

```java

116

import jakarta.mail.util.*;

117

import java.io.*;

118

119

// Create shared file input stream for large files

120

File largeFile = new File("large-attachment.zip");

121

SharedFileInputStream sharedFile = new SharedFileInputStream(largeFile);

122

123

// Multiple readers can access different parts concurrently

124

InputStream reader1 = sharedFile.newStream(0, 1024); // First 1KB

125

InputStream reader2 = sharedFile.newStream(1024, 2048); // Second 1KB

126

InputStream reader3 = sharedFile.newStream(2048, -1); // Rest of file

127

128

// Read concurrently without blocking

129

CompletableFuture<Void> task1 = CompletableFuture.runAsync(() -> {

130

try {

131

processStream(reader1);

132

} catch (IOException e) {

133

e.printStackTrace();

134

}

135

});

136

137

CompletableFuture<Void> task2 = CompletableFuture.runAsync(() -> {

138

try {

139

processStream(reader2);

140

} catch (IOException e) {

141

e.printStackTrace();

142

}

143

});

144

145

// Shared byte array for in-memory data

146

byte[] data = loadLargeData();

147

SharedByteArrayInputStream sharedBytes = new SharedByteArrayInputStream(data);

148

149

// Create multiple streams from same data

150

InputStream stream1 = sharedBytes.newStream(0, 100);

151

InputStream stream2 = sharedBytes.newStream(100, 200);

152

153

// Each stream is independent

154

int data1 = stream1.read(); // Reads from position 0

155

int data2 = stream2.read(); // Reads from position 100

156

```

157

158

## Line-Oriented Stream Interfaces

159

160

### Line Input Stream Interface

161

162

```java { .api }

163

public interface LineInputStream {

164

// Read a line of text, null if end of stream

165

public String readLine() throws IOException;

166

}

167

```

168

169

### Line Output Stream Interface

170

171

```java { .api }

172

public interface LineOutputStream {

173

// Write a line of text followed by line terminator

174

public void writeln(String s) throws IOException;

175

176

// Write line terminator only

177

public void writeln() throws IOException;

178

}

179

```

180

181

### Line Stream Usage Example

182

183

```java

184

import jakarta.mail.util.*;

185

import java.io.*;

186

187

// Implement line-oriented processing

188

public class MailHeaderProcessor {

189

190

public void processHeaders(InputStream input) throws IOException {

191

if (input instanceof LineInputStream) {

192

LineInputStream lineInput = (LineInputStream) input;

193

String line;

194

195

while ((line = lineInput.readLine()) != null) {

196

if (line.trim().isEmpty()) {

197

break; // End of headers

198

}

199

processHeaderLine(line);

200

}

201

} else {

202

// Wrap in BufferedReader for line reading

203

BufferedReader reader = new BufferedReader(new InputStreamReader(input));

204

String line;

205

206

while ((line = reader.readLine()) != null) {

207

if (line.trim().isEmpty()) {

208

break;

209

}

210

processHeaderLine(line);

211

}

212

}

213

}

214

215

public void writeHeaders(OutputStream output, Map<String, String> headers) throws IOException {

216

if (output instanceof LineOutputStream) {

217

LineOutputStream lineOutput = (LineOutputStream) output;

218

219

for (Map.Entry<String, String> header : headers.entrySet()) {

220

lineOutput.writeln(header.getKey() + ": " + header.getValue());

221

}

222

lineOutput.writeln(); // Empty line to end headers

223

} else {

224

PrintWriter writer = new PrintWriter(output);

225

226

for (Map.Entry<String, String> header : headers.entrySet()) {

227

writer.println(header.getKey() + ": " + header.getValue());

228

}

229

writer.println();

230

writer.flush();

231

}

232

}

233

234

private void processHeaderLine(String line) {

235

System.out.println("Processing header: " + line);

236

}

237

}

238

```

239

240

## Stream Provider Interface

241

242

The StreamProvider interface allows for pluggable stream implementations.

243

244

```java { .api }

245

public interface StreamProvider {

246

// Get input stream for reading

247

public InputStream getInputStream() throws IOException;

248

249

// Get output stream for writing

250

public OutputStream getOutputStream() throws IOException;

251

}

252

```

253

254

### Stream Provider Usage Example

255

256

```java

257

import jakarta.mail.util.StreamProvider;

258

import java.io.*;

259

import java.util.ServiceLoader;

260

261

// Custom stream provider implementation

262

public class CustomStreamProvider implements StreamProvider {

263

private final File dataFile;

264

265

public CustomStreamProvider(File dataFile) {

266

this.dataFile = dataFile;

267

}

268

269

@Override

270

public InputStream getInputStream() throws IOException {

271

return new BufferedInputStream(new FileInputStream(dataFile));

272

}

273

274

@Override

275

public OutputStream getOutputStream() throws IOException {

276

return new BufferedOutputStream(new FileOutputStream(dataFile));

277

}

278

}

279

280

// Load stream providers via ServiceLoader

281

ServiceLoader<StreamProvider> providers = ServiceLoader.load(StreamProvider.class);

282

for (StreamProvider provider : providers) {

283

try (InputStream is = provider.getInputStream()) {

284

// Use stream from provider

285

processStream(is);

286

}

287

}

288

289

// Use custom provider

290

StreamProvider customProvider = new CustomStreamProvider(new File("data.txt"));

291

try (OutputStream os = customProvider.getOutputStream()) {

292

os.write("Hello World".getBytes());

293

}

294

```

295

296

## Factory Finder Utility

297

298

The FactoryFinder class provides service loading capabilities for mail-related factories.

299

300

```java { .api }

301

public class FactoryFinder {

302

// Find factory implementation by factory ID

303

public static Object find(String factoryId) throws FactoryConfigurationError;

304

public static Object find(String factoryId, String fallbackClassName) throws FactoryConfigurationError;

305

306

// Find factory with specific class loader

307

public static Object find(String factoryId, String fallbackClassName, ClassLoader cl) throws FactoryConfigurationError;

308

309

// Create new instance of factory

310

public static Object newInstance(String className) throws FactoryConfigurationError;

311

public static Object newInstance(String className, ClassLoader cl) throws FactoryConfigurationError;

312

}

313

```

314

315

### Factory Finder Usage Example

316

317

```java

318

import jakarta.mail.util.FactoryFinder;

319

320

// Find mail transport factory

321

try {

322

Object transportFactory = FactoryFinder.find("jakarta.mail.Transport",

323

"com.sun.mail.smtp.SMTPTransport");

324

System.out.println("Found transport factory: " + transportFactory.getClass().getName());

325

} catch (FactoryConfigurationError e) {

326

System.err.println("Failed to find transport factory: " + e.getMessage());

327

}

328

329

// Find store factory with fallback

330

try {

331

Object storeFactory = FactoryFinder.find("jakarta.mail.Store",

332

"com.sun.mail.imap.IMAPStore");

333

System.out.println("Found store factory: " + storeFactory.getClass().getName());

334

} catch (FactoryConfigurationError e) {

335

System.err.println("Failed to find store factory: " + e.getMessage());

336

}

337

338

// Create instance directly

339

try {

340

Object instance = FactoryFinder.newInstance("com.example.CustomMailProcessor");

341

if (instance instanceof MailProcessor) {

342

MailProcessor processor = (MailProcessor) instance;

343

processor.process();

344

}

345

} catch (FactoryConfigurationError e) {

346

System.err.println("Failed to create instance: " + e.getMessage());

347

}

348

```

349

350

## Mail Logger Utility

351

352

The MailLogger class provides logging functionality specifically designed for mail operations.

353

354

```java { .api }

355

public class MailLogger {

356

// Constructors

357

public MailLogger(String name, String defaultDebug, boolean debug, PrintStream out);

358

public MailLogger(String name, String defaultDebug, Session session);

359

360

// Logging methods

361

public void log(Level level, String msg);

362

public void log(Level level, String msg, Object param1);

363

public void log(Level level, String msg, Object... params);

364

365

// Configuration access

366

public boolean isLoggable(Level level);

367

public void config(String msg);

368

public void fine(String msg);

369

public void finer(String msg);

370

public void finest(String msg);

371

372

// Session-based logging

373

public static MailLogger getLogger(String name, String defaultDebug, Session session);

374

public static MailLogger getLogger(String name, String defaultDebug, String debug, boolean debugOut, PrintStream out);

375

}

376

```

377

378

### Mail Logger Usage Example

379

380

```java

381

import jakarta.mail.MailLogger;

382

import jakarta.mail.Session;

383

import java.util.logging.Level;

384

385

// Create logger for mail session

386

Properties props = new Properties();

387

props.put("mail.debug", "true");

388

Session session = Session.getInstance(props);

389

390

MailLogger logger = MailLogger.getLogger("jakarta.mail.transport", "mail.debug", session);

391

392

// Log mail operations

393

logger.fine("Connecting to SMTP server");

394

logger.config("Using SSL connection");

395

logger.log(Level.INFO, "Message sent successfully to {0} recipients", 5);

396

397

// Check if logging is enabled

398

if (logger.isLoggable(Level.FINE)) {

399

logger.fine("Detailed connection information: " + getConnectionDetails());

400

}

401

402

// Different log levels

403

logger.finest("Trace level message");

404

logger.finer("Debug level message");

405

logger.fine("Fine level message");

406

logger.config("Configuration message");

407

logger.log(Level.INFO, "Info level message");

408

logger.log(Level.WARNING, "Warning message");

409

logger.log(Level.SEVERE, "Error message");

410

```

411

412

## MIME Utilities (Additional Functions)

413

414

Beyond the core MimeUtility class, there are additional utility functions for MIME handling.

415

416

### MIME Utility Extensions

417

418

```java

419

public class MimeUtilityExtensions {

420

421

// Content type utilities

422

public static boolean isMultipart(String contentType) {

423

return contentType != null && contentType.toLowerCase().startsWith("multipart/");

424

}

425

426

public static boolean isText(String contentType) {

427

return contentType != null && contentType.toLowerCase().startsWith("text/");

428

}

429

430

public static String extractBoundary(String contentType) {

431

if (contentType == null) return null;

432

433

int boundaryIndex = contentType.toLowerCase().indexOf("boundary=");

434

if (boundaryIndex == -1) return null;

435

436

String boundary = contentType.substring(boundaryIndex + 9);

437

if (boundary.startsWith("\"") && boundary.endsWith("\"")) {

438

boundary = boundary.substring(1, boundary.length() - 1);

439

}

440

441

return boundary;

442

}

443

444

// Charset utilities

445

public static String getCharset(String contentType, String defaultCharset) {

446

if (contentType == null) return defaultCharset;

447

448

int charsetIndex = contentType.toLowerCase().indexOf("charset=");

449

if (charsetIndex == -1) return defaultCharset;

450

451

String charset = contentType.substring(charsetIndex + 8);

452

int semicolonIndex = charset.indexOf(';');

453

if (semicolonIndex != -1) {

454

charset = charset.substring(0, semicolonIndex);

455

}

456

457

charset = charset.trim();

458

if (charset.startsWith("\"") && charset.endsWith("\"")) {

459

charset = charset.substring(1, charset.length() - 1);

460

}

461

462

return charset;

463

}

464

465

// File extension to MIME type mapping

466

public static String getContentTypeForFile(String filename) {

467

if (filename == null) return "application/octet-stream";

468

469

String extension = getFileExtension(filename).toLowerCase();

470

471

switch (extension) {

472

case "txt": return "text/plain";

473

case "html": case "htm": return "text/html";

474

case "pdf": return "application/pdf";

475

case "doc": return "application/msword";

476

case "docx": return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";

477

case "xls": return "application/vnd.ms-excel";

478

case "xlsx": return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

479

case "jpg": case "jpeg": return "image/jpeg";

480

case "png": return "image/png";

481

case "gif": return "image/gif";

482

case "zip": return "application/zip";

483

case "json": return "application/json";

484

case "xml": return "application/xml";

485

default: return "application/octet-stream";

486

}

487

}

488

489

private static String getFileExtension(String filename) {

490

int lastDot = filename.lastIndexOf('.');

491

return lastDot == -1 ? "" : filename.substring(lastDot + 1);

492

}

493

}

494

```

495

496

## Stream Processing Utilities

497

498

### Stream Copying and Processing

499

500

```java

501

public class StreamUtils {

502

503

// Copy stream with progress tracking

504

public static long copyStream(InputStream input, OutputStream output,

505

ProgressCallback callback) throws IOException {

506

byte[] buffer = new byte[8192];

507

long totalBytes = 0;

508

int bytesRead;

509

510

while ((bytesRead = input.read(buffer)) != -1) {

511

output.write(buffer, 0, bytesRead);

512

totalBytes += bytesRead;

513

514

if (callback != null) {

515

callback.onProgress(totalBytes);

516

}

517

}

518

519

return totalBytes;

520

}

521

522

// Read stream to byte array with size limit

523

public static byte[] readStreamToBytes(InputStream input, int maxSize) throws IOException {

524

ByteArrayOutputStream buffer = new ByteArrayOutputStream();

525

byte[] temp = new byte[1024];

526

int totalRead = 0;

527

int bytesRead;

528

529

while ((bytesRead = input.read(temp)) != -1) {

530

if (totalRead + bytesRead > maxSize) {

531

throw new IOException("Stream size exceeds maximum allowed: " + maxSize);

532

}

533

534

buffer.write(temp, 0, bytesRead);

535

totalRead += bytesRead;

536

}

537

538

return buffer.toByteArray();

539

}

540

541

// Create tee stream that writes to multiple outputs

542

public static OutputStream createTeeStream(OutputStream... outputs) {

543

return new OutputStream() {

544

@Override

545

public void write(int b) throws IOException {

546

for (OutputStream output : outputs) {

547

output.write(b);

548

}

549

}

550

551

@Override

552

public void write(byte[] b, int off, int len) throws IOException {

553

for (OutputStream output : outputs) {

554

output.write(b, off, len);

555

}

556

}

557

558

@Override

559

public void flush() throws IOException {

560

for (OutputStream output : outputs) {

561

output.flush();

562

}

563

}

564

565

@Override

566

public void close() throws IOException {

567

for (OutputStream output : outputs) {

568

output.close();

569

}

570

}

571

};

572

}

573

574

public interface ProgressCallback {

575

void onProgress(long bytesProcessed);

576

}

577

}

578

```

579

580

### Stream Usage Example

581

582

```java

583

import java.io.*;

584

585

// Copy large file with progress tracking

586

FileInputStream input = new FileInputStream("large-file.dat");

587

FileOutputStream output = new FileOutputStream("copy.dat");

588

589

StreamUtils.copyStream(input, output, bytesProcessed -> {

590

System.out.println("Copied " + bytesProcessed + " bytes");

591

});

592

593

// Read attachment with size limit (10MB max)

594

try {

595

byte[] attachmentData = StreamUtils.readStreamToBytes(attachmentStream, 10 * 1024 * 1024);

596

// Process attachment data

597

} catch (IOException e) {

598

System.err.println("Attachment too large: " + e.getMessage());

599

}

600

601

// Write to multiple destinations simultaneously

602

FileOutputStream file1 = new FileOutputStream("backup1.dat");

603

FileOutputStream file2 = new FileOutputStream("backup2.dat");

604

OutputStream teeStream = StreamUtils.createTeeStream(file1, file2);

605

606

// Data written to teeStream goes to both files

607

teeStream.write("Hello World".getBytes());

608

teeStream.close(); // Closes both underlying streams

609

```

610

611

## Exception Handling for Utilities

612

613

### Utility Exception Types

614

615

```java { .api }

616

// Configuration errors in factory finding

617

public class FactoryConfigurationError extends Error {

618

public FactoryConfigurationError();

619

public FactoryConfigurationError(String msg);

620

public FactoryConfigurationError(Exception e);

621

public FactoryConfigurationError(String msg, Exception e);

622

623

public Exception getException();

624

}

625

```

626

627

### Error Handling Example

628

629

```java

630

import jakarta.mail.util.*;

631

632

public class SafeUtilityUsage {

633

634

public void safeFactoryLookup() {

635

try {

636

Object factory = FactoryFinder.find("com.example.MailFactory");

637

// Use factory

638

} catch (FactoryConfigurationError e) {

639

System.err.println("Factory configuration error: " + e.getMessage());

640

if (e.getException() != null) {

641

System.err.println("Underlying cause: " + e.getException().getMessage());

642

}

643

// Use fallback implementation

644

useDefaultFactory();

645

}

646

}

647

648

public void safeStreamOperations() {

649

SharedFileInputStream sharedStream = null;

650

try {

651

sharedStream = new SharedFileInputStream("data.txt");

652

653

// Create multiple readers safely

654

InputStream reader1 = sharedStream.newStream(0, 1024);

655

processStreamSafely(reader1);

656

657

} catch (IOException e) {

658

System.err.println("Stream operation failed: " + e.getMessage());

659

} finally {

660

if (sharedStream != null) {

661

try {

662

sharedStream.close();

663

} catch (IOException e) {

664

System.err.println("Error closing stream: " + e.getMessage());

665

}

666

}

667

}

668

}

669

670

private void processStreamSafely(InputStream stream) {

671

try (stream) { // Auto-close

672

byte[] buffer = new byte[1024];

673

int bytesRead = stream.read(buffer);

674

// Process data

675

} catch (IOException e) {

676

System.err.println("Error processing stream: " + e.getMessage());

677

}

678

}

679

680

private void useDefaultFactory() {

681

// Fallback implementation

682

System.out.println("Using default factory implementation");

683

}

684

}

685

```