or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

calendar-management.mdcore-scheduling.mdenterprise-features.mdexception-handling.mdindex.mdjob-management.mdlisteners-events.mdmatcher-framework.mdpersistence-storage.mdschedule-builders.mdtrigger-management.mdutilities-helpers.md

utilities-helpers.mddocs/

0

# Utilities and Helpers

1

2

Utility classes for date manipulation, cron expression parsing, and other common scheduling operations in Quartz. These helpers simplify complex scheduling tasks and provide convenient methods for working with time, dates, and scheduling patterns.

3

4

## Capabilities

5

6

### Date Utilities

7

8

### DateBuilder Class

9

10

Fluent utility for creating and manipulating Date instances commonly used in scheduling.

11

12

```java { .api }

13

/**

14

* Utility for convenient creation of Date instances for scheduling

15

*/

16

class DateBuilder {

17

/**

18

* Time interval units for date calculations

19

*/

20

enum IntervalUnit {

21

MILLISECOND, SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, YEAR

22

}

23

24

// Day constants (1-based, Sunday = 1)

25

int SUNDAY = 1;

26

int MONDAY = 2;

27

int TUESDAY = 3;

28

int WEDNESDAY = 4;

29

int THURSDAY = 5;

30

int FRIDAY = 6;

31

int SATURDAY = 7;

32

33

// Month constants (0-based, January = 0)

34

int JANUARY = 0;

35

int FEBRUARY = 1;

36

int MARCH = 2;

37

int APRIL = 3;

38

int MAY = 4;

39

int JUNE = 5;

40

int JULY = 6;

41

int AUGUST = 7;

42

int SEPTEMBER = 8;

43

int OCTOBER = 9;

44

int NOVEMBER = 10;

45

int DECEMBER = 11;

46

47

/**

48

* Create a new DateBuilder instance

49

* @return new builder instance

50

*/

51

static DateBuilder newDate();

52

53

/**

54

* Create a new DateBuilder instance in specified timezone

55

* @param tz the timezone

56

* @return new builder instance

57

*/

58

static DateBuilder newDateInTimezone(TimeZone tz);

59

60

/**

61

* Create a date for today at specified time

62

* @param hour hour of day (0-23)

63

* @param minute minute of hour (0-59)

64

* @param second second of minute (0-59)

65

* @return date for today at specified time

66

*/

67

static Date todayAt(int hour, int minute, int second);

68

69

/**

70

* Create a date for tomorrow at specified time

71

* @param hour hour of day (0-23)

72

* @param minute minute of hour (0-59)

73

* @param second second of minute (0-59)

74

* @return date for tomorrow at specified time

75

*/

76

static Date tomorrowAt(int hour, int minute, int second);

77

78

/**

79

* Create a date in the future by adding interval to current time

80

* @param interval the interval value

81

* @param unit the interval unit

82

* @return future date

83

*/

84

static Date futureDate(int interval, IntervalUnit unit);

85

86

/**

87

* Get the next date that falls on the given minute base

88

* @param date starting date

89

* @param minuteBase minute to align to (0-59)

90

* @return next date aligned to minute base

91

*/

92

static Date nextGivenMinuteDate(Date date, int minuteBase);

93

94

/**

95

* Get next date with seconds set to 0

96

* @param date the date to align

97

* @return date with seconds set to 0

98

*/

99

static Date evenSecondDate(Date date);

100

101

/**

102

* Get next date with minutes and seconds set to 0

103

* @param date the date to align

104

* @return date aligned to hour boundary

105

*/

106

static Date evenMinuteDate(Date date);

107

108

/**

109

* Get next date with hours, minutes, and seconds set to 0

110

* @param date the date to align

111

* @return date aligned to hour boundary

112

*/

113

static Date evenHourDate(Date date);

114

115

/**

116

* Set the year component

117

* @param year the year

118

* @return this builder for method chaining

119

*/

120

DateBuilder atYear(int year);

121

122

/**

123

* Set the month component

124

* @param month the month (0-11, use constants)

125

* @return this builder for method chaining

126

*/

127

DateBuilder atMonth(int month);

128

129

/**

130

* Set the day of month component

131

* @param day the day of month (1-31)

132

* @return this builder for method chaining

133

*/

134

DateBuilder atDay(int day);

135

136

/**

137

* Set the hour component

138

* @param hour the hour (0-23)

139

* @return this builder for method chaining

140

*/

141

DateBuilder atHourOfDay(int hour);

142

143

/**

144

* Set the minute component

145

* @param minute the minute (0-59)

146

* @return this builder for method chaining

147

*/

148

DateBuilder atMinute(int minute);

149

150

/**

151

* Set the second component

152

* @param second the second (0-59)

153

* @return this builder for method chaining

154

*/

155

DateBuilder atSecond(int second);

156

157

/**

158

* Build the Date instance

159

* @return the configured date

160

*/

161

Date build();

162

}

163

```

164

165

**Usage Examples:**

166

167

```java

168

// Quick date creation

169

Date now = new Date();

170

Date in5Minutes = DateBuilder.futureDate(5, DateBuilder.IntervalUnit.MINUTE);

171

Date in2Hours = DateBuilder.futureDate(2, DateBuilder.IntervalUnit.HOUR);

172

Date tomorrow9AM = DateBuilder.tomorrowAt(9, 0, 0);

173

Date today2PM = DateBuilder.todayAt(14, 0, 0);

174

175

// Date alignment

176

Date alignedToMinute = DateBuilder.evenSecondDate(now);

177

Date alignedToHour = DateBuilder.evenMinuteDate(now);

178

Date nextHourMark = DateBuilder.evenHourDate(now);

179

180

// Next occurrence of minute mark (e.g., :15, :30, :45)

181

Date next15MinuteMark = DateBuilder.nextGivenMinuteDate(now, 15);

182

183

// Complex date building

184

Date specificDate = DateBuilder.newDate()

185

.atYear(2024)

186

.atMonth(DateBuilder.DECEMBER)

187

.atDay(25)

188

.atHourOfDay(9)

189

.atMinute(30)

190

.atSecond(0)

191

.build();

192

193

// Timezone-aware date building

194

Date utcDate = DateBuilder.newDateInTimezone(TimeZone.getTimeZone("UTC"))

195

.atYear(2024)

196

.atMonth(DateBuilder.JANUARY)

197

.atDay(1)

198

.atHourOfDay(0)

199

.atMinute(0)

200

.atSecond(0)

201

.build();

202

203

// Using in trigger creation

204

Trigger trigger = newTrigger()

205

.withIdentity("delayedStart")

206

.startAt(DateBuilder.futureDate(30, DateBuilder.IntervalUnit.SECOND))

207

.endAt(DateBuilder.futureDate(1, DateBuilder.IntervalUnit.HOUR))

208

.withSchedule(simpleSchedule()

209

.withIntervalInMinutes(10)

210

.repeatForever())

211

.build();

212

```

213

214

### TimeOfDay Class

215

216

Represents a specific time of day for use with daily scheduling patterns.

217

218

```java { .api }

219

/**

220

* Represents a time of day (hour, minute, second)

221

*/

222

class TimeOfDay implements Serializable, Comparable<TimeOfDay> {

223

/**

224

* Create time from hour and minute (second defaults to 0)

225

* @param hour hour of day (0-23)

226

* @param minute minute of hour (0-59)

227

* @return TimeOfDay instance

228

*/

229

static TimeOfDay hourAndMinuteOfDay(int hour, int minute);

230

231

/**

232

* Create time from hour, minute, and second

233

* @param hour hour of day (0-23)

234

* @param minute minute of hour (0-59)

235

* @param second second of minute (0-59)

236

* @return TimeOfDay instance

237

*/

238

static TimeOfDay hourMinuteAndSecondOfDay(int hour, int minute, int second);

239

240

/**

241

* Get the hour component

242

* @return hour (0-23)

243

*/

244

int getHour();

245

246

/**

247

* Get the minute component

248

* @return minute (0-59)

249

*/

250

int getMinute();

251

252

/**

253

* Get the second component

254

* @return second (0-59)

255

*/

256

int getSecond();

257

258

/**

259

* Check if this time is before another time

260

* @param timeOfDay the other time

261

* @return true if this time is before the other

262

*/

263

boolean before(TimeOfDay timeOfDay);

264

265

/**

266

* Check if this time is after another time

267

* @param timeOfDay the other time

268

* @return true if this time is after the other

269

*/

270

boolean after(TimeOfDay timeOfDay);

271

272

/**

273

* Get seconds since midnight

274

* @return total seconds since start of day

275

*/

276

int getSecondOfDay();

277

278

/**

279

* Create TimeOfDay from seconds since midnight

280

* @param secondOfDay seconds since start of day

281

* @return TimeOfDay instance

282

*/

283

static TimeOfDay secondOfDay(int secondOfDay);

284

}

285

```

286

287

**Usage Examples:**

288

289

```java

290

// Creating time instances

291

TimeOfDay morning = TimeOfDay.hourAndMinuteOfDay(9, 0); // 9:00 AM

292

TimeOfDay lunch = TimeOfDay.hourAndMinuteOfDay(12, 30); // 12:30 PM

293

TimeOfDay precise = TimeOfDay.hourMinuteAndSecondOfDay(15, 45, 30); // 3:45:30 PM

294

295

// Time comparisons

296

if (morning.before(lunch)) {

297

System.out.println("Morning comes before lunch");

298

}

299

300

// Working with seconds

301

int totalSeconds = lunch.getSecondOfDay(); // Seconds since midnight

302

TimeOfDay reconstructed = TimeOfDay.secondOfDay(totalSeconds);

303

304

// Using in daily time interval schedules

305

Trigger businessHours = newTrigger()

306

.withSchedule(dailyTimeIntervalSchedule()

307

.onMondayThroughFriday()

308

.startingDailyAt(TimeOfDay.hourAndMinuteOfDay(9, 0))

309

.endingDailyAt(TimeOfDay.hourAndMinuteOfDay(17, 0))

310

.withIntervalInMinutes(30))

311

.build();

312

```

313

314

### Cron Expression Utilities

315

316

### CronExpression Class

317

318

Utility for parsing, validating, and evaluating cron expressions.

319

320

```java { .api }

321

/**

322

* Represents and evaluates cron expressions for complex scheduling patterns

323

*/

324

class CronExpression implements Serializable, Cloneable {

325

/**

326

* Create a cron expression from string

327

* @param cronExpression the cron expression string

328

* @throws ParseException if expression is invalid

329

*/

330

CronExpression(String cronExpression) throws ParseException;

331

332

/**

333

* Validate a cron expression string

334

* @param cronExpression the expression to validate

335

* @return true if expression is valid

336

*/

337

static boolean isValidExpression(String cronExpression);

338

339

/**

340

* Get the cron expression string

341

* @return the cron expression

342

*/

343

String getCronExpression();

344

345

/**

346

* Check if the given date satisfies the cron expression

347

* @param date the date to check

348

* @return true if date matches the cron pattern

349

*/

350

boolean isSatisfiedBy(Date date);

351

352

/**

353

* Get the next valid time after the given date

354

* @param date the starting date

355

* @return next date matching the cron expression

356

*/

357

Date getNextValidTimeAfter(Date date);

358

359

/**

360

* Get the next invalid time after the given date

361

* @param date the starting date

362

* @return next date not matching the cron expression

363

*/

364

Date getNextInvalidTimeAfter(Date date);

365

366

/**

367

* Get the time zone for this cron expression

368

* @return the time zone

369

*/

370

TimeZone getTimeZone();

371

372

/**

373

* Set the time zone for this cron expression

374

* @param timeZone the time zone

375

*/

376

void setTimeZone(TimeZone timeZone);

377

378

/**

379

* Get a human-readable summary of the cron expression

380

* @return description of when the expression fires

381

*/

382

String getExpressionSummary();

383

}

384

```

385

386

**Usage Examples:**

387

388

```java

389

try {

390

// Create and validate cron expressions

391

String cronString = "0 0 12 * * ?"; // Daily at noon

392

393

if (CronExpression.isValidExpression(cronString)) {

394

CronExpression cron = new CronExpression(cronString);

395

396

// Set timezone

397

cron.setTimeZone(TimeZone.getTimeZone("America/New_York"));

398

399

// Check if current time matches

400

Date now = new Date();

401

if (cron.isSatisfiedBy(now)) {

402

System.out.println("Current time matches cron expression");

403

}

404

405

// Find next execution times

406

Date nextRun = cron.getNextValidTimeAfter(now);

407

System.out.println("Next execution: " + nextRun);

408

409

Date secondNext = cron.getNextValidTimeAfter(nextRun);

410

System.out.println("Following execution: " + secondNext);

411

412

// Get human-readable description

413

System.out.println("Schedule: " + cron.getExpressionSummary());

414

}

415

416

// Complex cron expressions

417

CronExpression businessHours = new CronExpression("0 */15 9-17 ? * MON-FRI");

418

CronExpression monthlyReport = new CronExpression("0 0 9 1 * ?");

419

CronExpression quarterlyMeeting = new CronExpression("0 0 14 1 1,4,7,10 ?");

420

421

// Calculate execution schedule

422

Date start = new Date();

423

Date end = DateBuilder.futureDate(30, DateBuilder.IntervalUnit.DAY);

424

List<Date> executions = new ArrayList<>();

425

426

Date next = businessHours.getNextValidTimeAfter(start);

427

while (next != null && next.before(end)) {

428

executions.add(next);

429

next = businessHours.getNextValidTimeAfter(next);

430

}

431

432

System.out.println("Found " + executions.size() + " executions in next 30 days");

433

434

} catch (ParseException e) {

435

System.err.println("Invalid cron expression: " + e.getMessage());

436

}

437

438

// Using with cron triggers

439

try {

440

CronExpression cronExpr = new CronExpression("0 30 8 ? * MON-FRI");

441

cronExpr.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));

442

443

Trigger cronTrigger = newTrigger()

444

.withSchedule(cronSchedule(cronExpr))

445

.build();

446

447

} catch (ParseException e) {

448

// Handle invalid expression

449

}

450

```

451

452

### TriggerUtils Class

453

454

Utility methods for working with triggers and calculating firing times.

455

456

```java { .api }

457

/**

458

* Utility methods for working with triggers

459

*/

460

class TriggerUtils {

461

/**

462

* Get the next N fire times for a trigger

463

* @param trigger the trigger to analyze

464

* @param cal optional calendar to exclude times

465

* @param numTimes number of fire times to calculate

466

* @return list of next fire times

467

*/

468

static List<Date> computeFireTimes(OperableTrigger trigger, Calendar cal, int numTimes);

469

470

/**

471

* Get fire times between two dates

472

* @param trigger the trigger to analyze

473

* @param cal optional calendar to exclude times

474

* @param from start date

475

* @param to end date

476

* @return list of fire times in range

477

*/

478

static List<Date> computeFireTimesBetween(OperableTrigger trigger, Calendar cal, Date from, Date to);

479

480

/**

481

* Get the final fire time for a trigger

482

* @param trigger the trigger to analyze

483

* @return final fire time or null if infinite

484

*/

485

static Date computeFinalFireTime(OperableTrigger trigger);

486

}

487

```

488

489

**Usage Examples:**

490

491

```java

492

// Analyze trigger firing schedule

493

Trigger trigger = newTrigger()

494

.withSchedule(cronSchedule("0 0 9-17 * * MON-FRI")) // Hourly 9-5, weekdays

495

.startNow()

496

.endAt(DateBuilder.futureDate(30, DateBuilder.IntervalUnit.DAY))

497

.build();

498

499

OperableTrigger operableTrigger = (OperableTrigger) trigger;

500

501

// Get next 10 fire times

502

List<Date> next10 = TriggerUtils.computeFireTimes(operableTrigger, null, 10);

503

System.out.println("Next 10 executions:");

504

for (Date fireTime : next10) {

505

System.out.println(" " + fireTime);

506

}

507

508

// Get fire times for this week

509

Date weekStart = DateBuilder.todayAt(0, 0, 0);

510

Date weekEnd = DateBuilder.futureDate(7, DateBuilder.IntervalUnit.DAY);

511

List<Date> thisWeek = TriggerUtils.computeFireTimesBetween(

512

operableTrigger, null, weekStart, weekEnd);

513

System.out.println("Executions this week: " + thisWeek.size());

514

515

// Check if trigger has finite schedule

516

Date finalFire = TriggerUtils.computeFinalFireTime(operableTrigger);

517

if (finalFire != null) {

518

System.out.println("Final execution: " + finalFire);

519

} else {

520

System.out.println("Trigger runs indefinitely");

521

}

522

```

523

524

### Scheduler Metadata

525

526

### SchedulerMetaData Class

527

528

Provides information about scheduler instance capabilities and status.

529

530

```java { .api }

531

/**

532

* Provides metadata about a scheduler instance

533

*/

534

class SchedulerMetaData {

535

/**

536

* Get the scheduler instance name

537

* @return scheduler name

538

*/

539

String getSchedulerName();

540

541

/**

542

* Get the scheduler instance ID

543

* @return unique instance identifier

544

*/

545

String getSchedulerInstanceId();

546

547

/**

548

* Get the scheduler class being used

549

* @return scheduler implementation class

550

*/

551

Class<?> getSchedulerClass();

552

553

/**

554

* Get the Quartz version

555

* @return version string

556

*/

557

String getVersion();

558

559

/**

560

* Check if scheduler is started

561

* @return true if scheduler is running

562

*/

563

boolean isStarted();

564

565

/**

566

* Check if scheduler is in standby mode

567

* @return true if in standby

568

*/

569

boolean isInStandbyMode();

570

571

/**

572

* Check if scheduler has been shutdown

573

* @return true if shutdown

574

*/

575

boolean isShutdown();

576

577

/**

578

* Get the time when scheduler was started

579

* @return start time or null if not started

580

*/

581

Date getRunningSince();

582

583

/**

584

* Get the number of jobs executed since startup

585

* @return executed job count

586

*/

587

int getNumberOfJobsExecuted();

588

589

/**

590

* Get the job store class being used

591

* @return job store implementation class

592

*/

593

Class<?> getJobStoreClass();

594

595

/**

596

* Check if job store supports persistence

597

* @return true if jobs are persisted

598

*/

599

boolean isJobStoreSupportsPersistence();

600

601

/**

602

* Check if job store is clustered

603

* @return true if clustering is enabled

604

*/

605

boolean isJobStoreClustered();

606

607

/**

608

* Get the thread pool class being used

609

* @return thread pool implementation class

610

*/

611

Class<?> getThreadPoolClass();

612

613

/**

614

* Get the thread pool size

615

* @return number of threads available for job execution

616

*/

617

int getThreadPoolSize();

618

}

619

```

620

621

**Usage Examples:**

622

623

```java

624

// Get scheduler information

625

Scheduler scheduler = new StdSchedulerFactory().getScheduler();

626

SchedulerMetaData metaData = scheduler.getMetaData();

627

628

// Display basic information

629

System.out.println("Scheduler Information:");

630

System.out.println(" Name: " + metaData.getSchedulerName());

631

System.out.println(" Instance ID: " + metaData.getSchedulerInstanceId());

632

System.out.println(" Version: " + metaData.getVersion());

633

System.out.println(" Started: " + metaData.isStarted());

634

635

if (metaData.getRunningSince() != null) {

636

System.out.println(" Running since: " + metaData.getRunningSince());

637

System.out.println(" Jobs executed: " + metaData.getNumberOfJobsExecuted());

638

}

639

640

// Display configuration information

641

System.out.println("\nConfiguration:");

642

System.out.println(" Scheduler class: " + metaData.getSchedulerClass().getSimpleName());

643

System.out.println(" Job store: " + metaData.getJobStoreClass().getSimpleName());

644

System.out.println(" Persistent: " + metaData.isJobStoreSupportsPersistence());

645

System.out.println(" Clustered: " + metaData.isJobStoreClustered());

646

System.out.println(" Thread pool: " + metaData.getThreadPoolClass().getSimpleName());

647

System.out.println(" Thread count: " + metaData.getThreadPoolSize());

648

649

// Health check based on metadata

650

public boolean isSchedulerHealthy(Scheduler scheduler) throws SchedulerException {

651

SchedulerMetaData metaData = scheduler.getMetaData();

652

653

// Check if scheduler is running

654

if (!metaData.isStarted() || metaData.isShutdown()) {

655

return false;

656

}

657

658

// Check if it's been running for reasonable time

659

Date runningSince = metaData.getRunningSince();

660

if (runningSince != null) {

661

long runningTime = System.currentTimeMillis() - runningSince.getTime();

662

if (runningTime < 1000) { // Less than 1 second

663

return false; // Might still be starting up

664

}

665

}

666

667

// Check thread pool size

668

if (metaData.getThreadPoolSize() < 1) {

669

return false;

670

}

671

672

return true;

673

}

674

```

675

676

### Context Classes

677

678

### SchedulerContext Class

679

680

Container for sharing application data across jobs within a scheduler instance.

681

682

```java { .api }

683

/**

684

* Holds application context data for scheduler instance

685

* Extends Map for convenient data access

686

*/

687

class SchedulerContext extends StringKeyDirtyFlagMap {

688

/**

689

* Create empty scheduler context

690

*/

691

SchedulerContext();

692

693

/**

694

* Create scheduler context with initial data

695

* @param map initial context data

696

*/

697

SchedulerContext(Map<?, ?> map);

698

699

// Inherits all Map methods for data manipulation

700

// Plus type-safe accessors similar to JobDataMap

701

}

702

```

703

704

**Usage Examples:**

705

706

```java

707

// Setting up scheduler context

708

Scheduler scheduler = new StdSchedulerFactory().getScheduler();

709

SchedulerContext context = scheduler.getContext();

710

711

// Store application-wide configuration

712

context.put("applicationVersion", "2.1.0");

713

context.put("environment", "production");

714

context.put("databaseUrl", "jdbc:postgresql://db.example.com/app");

715

context.put("maxRetries", 3);

716

context.put("emailService", emailServiceInstance);

717

718

// Jobs can access scheduler context

719

public class ReportJob implements Job {

720

public void execute(JobExecutionContext context) throws JobExecutionException {

721

// Access scheduler context

722

SchedulerContext schedulerContext = context.getScheduler().getContext();

723

724

String version = (String) schedulerContext.get("applicationVersion");

725

String environment = (String) schedulerContext.get("environment");

726

EmailService emailService = (EmailService) schedulerContext.get("emailService");

727

728

// Use shared resources

729

generateReport(version, environment, emailService);

730

}

731

732

private void generateReport(String version, String env, EmailService emailService) {

733

// Implementation using shared context

734

}

735

}

736

737

// Updating context at runtime

738

public void updateConfiguration(Scheduler scheduler, String newDbUrl) throws SchedulerException {

739

SchedulerContext context = scheduler.getContext();

740

context.put("databaseUrl", newDbUrl);

741

742

// All subsequently executed jobs will see the new value

743

}

744

```

745

746

### Key Utility Classes

747

748

### Key Base Class

749

750

Base class for JobKey and TriggerKey providing identity and comparison functionality.

751

752

```java { .api }

753

/**

754

* Base class for keys that identify jobs and triggers

755

*/

756

abstract class Key<T> implements Serializable, Comparable<Key<T>> {

757

String DEFAULT_GROUP = "DEFAULT";

758

759

/**

760

* Get the key name

761

* @return the name component of the key

762

*/

763

String getName();

764

765

/**

766

* Get the key group

767

* @return the group component of the key

768

*/

769

String getGroup();

770

771

/**

772

* Compare keys for ordering

773

* @param other the other key

774

* @return comparison result

775

*/

776

int compareTo(Key<T> other);

777

778

/**

779

* Check equality with another key

780

* @param obj the other object

781

* @return true if keys are equal

782

*/

783

boolean equals(Object obj);

784

785

/**

786

* Get hash code for the key

787

* @return hash code based on name and group

788

*/

789

int hashCode();

790

791

/**

792

* Get string representation

793

* @return formatted string with group and name

794

*/

795

String toString();

796

}

797

```

798

799

**Usage Examples:**

800

801

```java

802

// Key comparison and sorting

803

List<JobKey> jobKeys = Arrays.asList(

804

jobKey("jobA", "group1"),

805

jobKey("jobB", "group1"),

806

jobKey("jobA", "group2")

807

);

808

809

// Sort keys (by group first, then name)

810

Collections.sort(jobKeys);

811

812

// Key equality

813

JobKey key1 = jobKey("myJob", "myGroup");

814

JobKey key2 = jobKey("myJob", "myGroup");

815

System.out.println(key1.equals(key2)); // true

816

817

// Using keys in collections

818

Set<JobKey> uniqueKeys = new HashSet<>();

819

uniqueKeys.add(key1);

820

uniqueKeys.add(key2); // Won't add duplicate

821

822

Map<JobKey, JobDetail> jobMap = new HashMap<>();

823

jobMap.put(key1, jobDetail);

824

825

// Key string representation

826

System.out.println(key1.toString()); // "myGroup.myJob"

827

```

828

829

### Additional Utility Classes

830

831

### TriggerUtils Class

832

833

Utility methods for working with triggers and trigger calculations.

834

835

```java { .api }

836

/**

837

* Utility class for trigger-related operations

838

*/

839

class TriggerUtils {

840

/**

841

* Get the next N fire times for a trigger

842

* @param trigger the trigger to calculate for

843

* @param cal optional calendar for exclusions

844

* @param numTimes number of fire times to calculate

845

* @return list of future fire times

846

*/

847

static List<Date> computeFireTimes(OperableTrigger trigger, Calendar cal, int numTimes);

848

849

/**

850

* Get fire times between two dates

851

* @param trigger the trigger to calculate for

852

* @param cal optional calendar for exclusions

853

* @param from start date

854

* @param to end date

855

* @return list of fire times in the range

856

*/

857

static List<Date> computeFireTimesBetween(OperableTrigger trigger, Calendar cal, Date from, Date to);

858

859

/**

860

* Get the final fire time for a trigger

861

* @param trigger the trigger

862

* @return the final fire time, or null if infinite

863

*/

864

static Date computeEndTimeToAllowParticularNumberOfFirings(OperableTrigger trigger, Calendar cal, int numTimes);

865

866

/**

867

* Make a trigger that will fire at specific times

868

* @param fireTimes list of times when trigger should fire

869

* @return a SimpleTrigger configured for the fire times

870

*/

871

static OperableTrigger makeEvenlySpacedDateTrigger(Date[] fireTimes);

872

}

873

```

874

875

### PropertiesParser Class

876

877

Utility for parsing configuration properties with type conversion.

878

879

```java { .api }

880

/**

881

* Utility for parsing configuration properties

882

*/

883

class PropertiesParser {

884

/**

885

* Create parser for properties

886

* @param props the properties to parse

887

*/

888

PropertiesParser(Properties props);

889

890

/**

891

* Get string property with optional default

892

* @param name property name

893

* @param defaultValue default if not found

894

* @return property value or default

895

*/

896

String getStringProperty(String name, String defaultValue);

897

898

/**

899

* Get required string property

900

* @param name property name

901

* @return property value

902

* @throws SchedulerException if property not found

903

*/

904

String getStringProperty(String name) throws SchedulerException;

905

906

/**

907

* Get boolean property

908

* @param name property name

909

* @param defaultValue default if not found

910

* @return boolean value

911

*/

912

boolean getBooleanProperty(String name, boolean defaultValue);

913

914

/**

915

* Get integer property

916

* @param name property name

917

* @param defaultValue default if not found

918

* @return integer value

919

*/

920

int getIntProperty(String name, int defaultValue);

921

922

/**

923

* Get long property

924

* @param name property name

925

* @param defaultValue default if not found

926

* @return long value

927

*/

928

long getLongProperty(String name, long defaultValue);

929

930

/**

931

* Get float property

932

* @param name property name

933

* @param defaultValue default if not found

934

* @return float value

935

*/

936

float getFloatProperty(String name, float defaultValue);

937

938

/**

939

* Get double property

940

* @param name property name

941

* @param defaultValue default if not found

942

* @return double value

943

*/

944

double getDoubleProperty(String name, double defaultValue);

945

946

/**

947

* Get property names with a given prefix

948

* @param prefix the prefix to match

949

* @return array of matching property names

950

*/

951

String[] getPropertyNames(String prefix);

952

953

/**

954

* Get properties with a given prefix as a new Properties object

955

* @param prefix the prefix to match

956

* @return Properties containing matching entries

957

*/

958

Properties getPropertyGroup(String prefix);

959

960

/**

961

* Get properties with prefix, removing the prefix from keys

962

* @param prefix the prefix to match and remove

963

* @param stripPrefix whether to remove prefix from keys

964

* @return Properties with prefix removed from keys

965

*/

966

Properties getPropertyGroup(String prefix, boolean stripPrefix);

967

}

968

```

969

970

### ClassUtils Class

971

972

Utility methods for class loading and reflection operations.

973

974

```java { .api }

975

/**

976

* Utility class for class loading operations

977

*/

978

class ClassUtils {

979

/**

980

* Load a class using the thread context class loader

981

* @param className fully qualified class name

982

* @return the loaded class

983

* @throws ClassNotFoundException if class not found

984

*/

985

static Class<?> loadClass(String className) throws ClassNotFoundException;

986

987

/**

988

* Load a class using a specific class loader

989

* @param className fully qualified class name

990

* @param classLoader the class loader to use

991

* @return the loaded class

992

* @throws ClassNotFoundException if class not found

993

*/

994

static Class<?> loadClass(String className, ClassLoader classLoader) throws ClassNotFoundException;

995

996

/**

997

* Create an instance of a class

998

* @param className fully qualified class name

999

* @return new instance of the class

1000

* @throws Exception if instantiation fails

1001

*/

1002

static Object instantiateClass(String className) throws Exception;

1003

1004

/**

1005

* Create an instance using a specific class loader

1006

* @param className fully qualified class name

1007

* @param classLoader the class loader to use

1008

* @return new instance of the class

1009

* @throws Exception if instantiation fails

1010

*/

1011

static Object instantiateClass(String className, ClassLoader classLoader) throws Exception;

1012

1013

/**

1014

* Check if a class is available in the classpath

1015

* @param className fully qualified class name

1016

* @return true if class can be loaded

1017

*/

1018

static boolean isClassAvailable(String className);

1019

1020

/**

1021

* Get the thread context class loader

1022

* @return the current thread's context class loader

1023

*/

1024

static ClassLoader getThreadContextClassLoader();

1025

1026

/**

1027

* Set the thread context class loader

1028

* @param classLoader the class loader to set

1029

*/

1030

static void setThreadContextClassLoader(ClassLoader classLoader);

1031

}

1032

```

1033

1034

### Data Structure Utilities

1035

1036

### DirtyFlagMap Class

1037

1038

Map implementation that tracks modifications for change detection.

1039

1040

```java { .api }

1041

/**

1042

* Map that tracks whether its contents have been modified

1043

* @param <K> key type

1044

* @param <V> value type

1045

*/

1046

class DirtyFlagMap<K, V> extends HashMap<K, V> {

1047

/**

1048

* Create empty dirty flag map

1049

*/

1050

DirtyFlagMap();

1051

1052

/**

1053

* Create dirty flag map with initial data

1054

* @param initialCapacity initial capacity

1055

*/

1056

DirtyFlagMap(int initialCapacity);

1057

1058

/**

1059

* Create dirty flag map from existing map

1060

* @param map initial data

1061

*/

1062

DirtyFlagMap(Map<? extends K, ? extends V> map);

1063

1064

/**

1065

* Check if map has been modified since last clearDirtyFlag()

1066

* @return true if map has been modified

1067

*/

1068

boolean isDirty();

1069

1070

/**

1071

* Clear the dirty flag

1072

*/

1073

void clearDirtyFlag();

1074

1075

/**

1076

* Get map of all modified entries since last clearDirtyFlag()

1077

* @return map of modified entries

1078

*/

1079

Map<K, V> getWrappedMap();

1080

1081

// Overrides all modification methods to set dirty flag

1082

}

1083

```

1084

1085

### StringKeyDirtyFlagMap Class

1086

1087

String-keyed version of DirtyFlagMap with type-safe accessors.

1088

1089

```java { .api }

1090

/**

1091

* String-keyed dirty flag map with type-safe accessors

1092

*/

1093

class StringKeyDirtyFlagMap extends DirtyFlagMap<String, Object> {

1094

/**

1095

* Create empty string key dirty flag map

1096

*/

1097

StringKeyDirtyFlagMap();

1098

1099

/**

1100

* Create from existing map

1101

* @param map initial data

1102

*/

1103

StringKeyDirtyFlagMap(Map<?, ?> map);

1104

1105

/**

1106

* Put string value

1107

* @param key the key

1108

* @param value the string value

1109

* @return previous value

1110

*/

1111

Object putAsString(String key, String value);

1112

1113

/**

1114

* Get value as string

1115

* @param key the key

1116

* @return value as string or null

1117

*/

1118

String getString(String key);

1119

1120

/**

1121

* Get boolean value

1122

* @param key the key

1123

* @return boolean value or false if not found

1124

*/

1125

boolean getBoolean(String key);

1126

1127

/**

1128

* Get boolean value with default

1129

* @param key the key

1130

* @param defaultValue default value if not found

1131

* @return boolean value or default

1132

*/

1133

boolean getBooleanValue(String key, boolean defaultValue);

1134

1135

/**

1136

* Get byte value

1137

* @param key the key

1138

* @return byte value or 0 if not found

1139

*/

1140

byte getByte(String key);

1141

1142

/**

1143

* Get character value

1144

* @param key the key

1145

* @return character value or null character if not found

1146

*/

1147

char getChar(String key);

1148

1149

/**

1150

* Get double value

1151

* @param key the key

1152

* @return double value or 0.0 if not found

1153

*/

1154

double getDouble(String key);

1155

1156

/**

1157

* Get float value

1158

* @param key the key

1159

* @return float value or 0.0f if not found

1160

*/

1161

float getFloat(String key);

1162

1163

/**

1164

* Get integer value

1165

* @param key the key

1166

* @return integer value or 0 if not found

1167

*/

1168

int getInt(String key);

1169

1170

/**

1171

* Get integer value with default

1172

* @param key the key

1173

* @param defaultValue default value if not found

1174

* @return integer value or default

1175

*/

1176

int getIntValue(String key, int defaultValue);

1177

1178

/**

1179

* Get long value

1180

* @param key the key

1181

* @return long value or 0L if not found

1182

*/

1183

long getLong(String key);

1184

1185

/**

1186

* Get long value with default

1187

* @param key the key

1188

* @param defaultValue default value if not found

1189

* @return long value or default

1190

*/

1191

long getLongValue(String key, long defaultValue);

1192

1193

/**

1194

* Get short value

1195

* @param key the key

1196

* @return short value or 0 if not found

1197

*/

1198

short getShort(String key);

1199

}

1200

```

1201

1202

**Usage Examples:**

1203

1204

```java

1205

// TriggerUtils usage

1206

SimpleTrigger trigger = (SimpleTrigger) newTrigger()

1207

.withSchedule(simpleSchedule()

1208

.withIntervalInHours(6)

1209

.withRepeatCount(10))

1210

.build();

1211

1212

// Calculate next 5 fire times

1213

List<Date> fireTimes = TriggerUtils.computeFireTimes(trigger, null, 5);

1214

for (Date fireTime : fireTimes) {

1215

System.out.println("Will fire at: " + fireTime);

1216

}

1217

1218

// Calculate fire times in a date range

1219

Date startDate = new Date();

1220

Date endDate = DateBuilder.futureDate(30, DateBuilder.IntervalUnit.DAY);

1221

List<Date> fireTimesInRange = TriggerUtils.computeFireTimesBetween(trigger, null, startDate, endDate);

1222

1223

// PropertiesParser usage

1224

Properties props = new Properties();

1225

props.setProperty("app.name", "MyScheduler");

1226

props.setProperty("app.threadCount", "10");

1227

props.setProperty("app.enabled", "true");

1228

props.setProperty("app.timeout", "30.5");

1229

1230

PropertiesParser parser = new PropertiesParser(props);

1231

1232

String appName = parser.getStringProperty("app.name", "DefaultApp");

1233

int threadCount = parser.getIntProperty("app.threadCount", 5);

1234

boolean enabled = parser.getBooleanProperty("app.enabled", false);

1235

double timeout = parser.getDoubleProperty("app.timeout", 60.0);

1236

1237

// Get all properties with prefix

1238

Properties appProps = parser.getPropertyGroup("app.", true);

1239

// Results in: name=MyScheduler, threadCount=10, enabled=true, timeout=30.5

1240

1241

// ClassUtils usage

1242

try {

1243

// Load class dynamically

1244

Class<?> jobClass = ClassUtils.loadClass("com.example.MyJob");

1245

1246

// Create instance

1247

Job jobInstance = (Job) ClassUtils.instantiateClass("com.example.MyJob");

1248

1249

// Check if class exists

1250

if (ClassUtils.isClassAvailable("com.optional.OptionalFeature")) {

1251

// Use optional feature

1252

}

1253

} catch (Exception e) {

1254

System.err.println("Failed to load class: " + e.getMessage());

1255

}

1256

1257

// DirtyFlagMap usage

1258

DirtyFlagMap<String, String> config = new DirtyFlagMap<>();

1259

config.put("setting1", "value1");

1260

config.put("setting2", "value2");

1261

1262

System.out.println("Is dirty: " + config.isDirty()); // true

1263

1264

config.clearDirtyFlag();

1265

System.out.println("Is dirty: " + config.isDirty()); // false

1266

1267

config.put("setting3", "value3");

1268

System.out.println("Is dirty: " + config.isDirty()); // true

1269

1270

// StringKeyDirtyFlagMap usage (like JobDataMap)

1271

StringKeyDirtyFlagMap data = new StringKeyDirtyFlagMap();

1272

data.put("count", "100");

1273

data.put("enabled", "true");

1274

data.put("rate", "3.14");

1275

1276

// Type-safe accessors

1277

int count = data.getInt("count"); // 100

1278

boolean enabled = data.getBoolean("enabled"); // true

1279

double rate = data.getDouble("rate"); // 3.14

1280

String missing = data.getString("missing"); // null

1281

1282

// With defaults

1283

int defaultCount = data.getIntValue("missingCount", 50); // 50

1284

boolean defaultEnabled = data.getBooleanValue("missingEnabled", false); // false

1285

```