/** * Instantiate a Builder to be able to create a {@link QuartzDeadlineManager}. * <p> * The {@link TransactionManager} is defaulted to an {@link NoTransactionManager}, and the {@link Serializer} to a * {@link XStreamSerializer}. The {@link Scheduler} and {@link ScopeAwareProvider} are <b>hard requirements</b> and * as such should be provided. * * @return a Builder to be able to create a {@link QuartzDeadlineManager} */ public static Builder builder() { return new Builder(); }
/** * Initializes a {@link QuartzDeadlineManager} as specified through this Builder. * * @return a {@link QuartzDeadlineManager} as specified through this Builder */ public QuartzDeadlineManager build() { return new QuartzDeadlineManager(this); }
@Override public String schedule(Duration triggerDuration, String deadlineName, Object messageOrPayload, ScopeDescriptor deadlineScope) { return schedule(Instant.now().plus(triggerDuration), deadlineName, messageOrPayload, deadlineScope); }
@Override public String schedule(Instant triggerDateTime, String deadlineName, Object messageOrPayload, ScopeDescriptor deadlineScope) { DeadlineMessage<Object> deadlineMessage = asDeadlineMessage(deadlineName, messageOrPayload); String deadlineId = JOB_NAME_PREFIX + deadlineMessage.getIdentifier(); runOnPrepareCommitOrNow(() -> { DeadlineMessage interceptedDeadlineMessage = processDispatchInterceptors(deadlineMessage); try { JobDetail jobDetail = buildJobDetail(interceptedDeadlineMessage, deadlineScope, new JobKey(deadlineId, deadlineName)); scheduler.scheduleJob(jobDetail, buildTrigger(triggerDateTime, jobDetail.getKey())); } catch (SchedulerException e) { throw new DeadlineException("An error occurred while setting a timer for a deadline", e); } }); return deadlineId; }
/** * Extracts a {@link DeadlineMessage} from provided {@code jobDataMap}. * * <b>Note</b> that this function is able to retrieve two different formats of DeadlineMessage. The first being * a now deprecated solution which used to serialized the entire {@link DeadlineMessage} into the * {@link JobDataMap}. This is only kept for backwards compatibility. The second is the new solution which * stores all the required deadline fields separately, only de-/serializing the payload and metadata of a * DeadlineMessage instead of the entire message. * * @param serializer the {@link Serializer} used to deserialize the contents of the given {@code} jobDataMap} * into a {@link DeadlineMessage} * @param jobDataMap the {@link JobDataMap} which should contain a {@link DeadlineMessage} * @return the {@link DeadlineMessage} pulled from the {@code jobDataMap} */ public static DeadlineMessage deadlineMessage(Serializer serializer, JobDataMap jobDataMap) { if (jobDataMap.containsKey(SERIALIZED_DEADLINE_MESSAGE)) { SimpleSerializedObject<byte[]> serializedDeadlineMessage = new SimpleSerializedObject<>( (byte[]) jobDataMap.get(SERIALIZED_DEADLINE_MESSAGE), byte[].class, (String) jobDataMap.get(SERIALIZED_DEADLINE_MESSAGE_CLASS_NAME), null ); return serializer.deserialize(serializedDeadlineMessage); } return new GenericDeadlineMessage<>((String) jobDataMap.get(DEADLINE_NAME), (String) jobDataMap.get(MESSAGE_ID), deserializeDeadlinePayload(serializer, jobDataMap), deserializeDeadlineMetaData(serializer, jobDataMap), retrieveDeadlineTimestamp(jobDataMap)); }
@Override public void cancelSchedule(String deadlineName, String scheduleId) { runOnPrepareCommitOrNow(() -> cancelSchedule(jobKey(scheduleId, deadlineName))); }
schedulerContext.get(HANDLER_INTERCEPTORS); DeadlineMessage<?> deadlineMessage = deadlineMessage(serializer, jobData); ScopeDescriptor deadlineScope = deadlineScope(serializer, jobData); handlerInterceptors, interceptedDeadlineMessage -> { executeScheduledDeadline(scopeAwareComponents, interceptedDeadlineMessage, deadlineScope);
/** * Serializes the provided {@code deadlineMessage} and {@code deadlineScope} and puts them in a {@link * JobDataMap}. * * @param serializer the {@link Serializer} used to serialize the given {@code deadlineMessage} and {@code * deadlineScope} * @param deadlineMessage the {@link DeadlineMessage} to be handled * @param deadlineScope the {@link ScopeDescriptor} of the {@link org.axonframework.messaging.Scope} the * {@code deadlineMessage} should go to. * @return a {@link JobDataMap} containing the {@code deadlineMessage} and {@code deadlineScope} */ public static JobDataMap toJobData(Serializer serializer, DeadlineMessage deadlineMessage, ScopeDescriptor deadlineScope) { JobDataMap jobData = new JobDataMap(); putDeadlineMessage(jobData, deadlineMessage, serializer); putDeadlineScope(jobData, deadlineScope, serializer); return jobData; }
@Override public DeadlineManager buildDeadlineManager(Configuration configuration) { try { Scheduler scheduler = new StdSchedulerFactory().getScheduler(); QuartzDeadlineManager quartzDeadlineManager = QuartzDeadlineManager.builder() .scheduler(scheduler) .scopeAwareProvider(new ConfigurationScopeAwareProvider(configuration)) .build(); scheduler.start(); return quartzDeadlineManager; } catch (SchedulerException e) { throw new AxonConfigurationException("Unable to configure quartz scheduler", e); } } }
/** * Instantiate a {@link QuartzDeadlineManager} based on the fields contained in the {@link Builder}. * <p> * Will assert that the {@link Scheduler}, {@link ScopeAwareProvider}, {@link TransactionManager} and * {@link Serializer} are not {@code null}, and will throw an {@link AxonConfigurationException} if any of them is * {@code null}. * The TransactionManager, ScopeAwareProvider and Serializer will be tied to the Scheduler's context. If this * initialization step fails, this will too result in an AxonConfigurationException. * * @param builder the {@link Builder} used to instantiate a {@link QuartzDeadlineManager} instance */ protected QuartzDeadlineManager(Builder builder) { builder.validate(); this.scheduler = builder.scheduler; this.scopeAwareProvider = builder.scopeAwareProvider; this.transactionManager = builder.transactionManager; this.serializer = builder.serializer; try { initialize(); } catch (SchedulerException e) { throw new AxonConfigurationException("Unable to initialize QuartzDeadlineManager", e); } }
private JobDetail buildJobDetail(DeadlineMessage deadlineMessage, ScopeDescriptor deadlineScope, JobKey jobKey) { JobDataMap jobData = DeadlineJob.DeadlineJobDataBinder.toJobData(serializer, deadlineMessage, deadlineScope); return JobBuilder.newJob(DeadlineJob.class) .withDescription(deadlineMessage.getPayloadType().getName()) .withIdentity(jobKey) .usingJobData(jobData) .build(); }
@Override public void cancelAll(String deadlineName) { runOnPrepareCommitOrNow(() -> { try { scheduler.getJobKeys(GroupMatcher.groupEquals(deadlineName)) .forEach(this::cancelSchedule); } catch (SchedulerException e) { throw new DeadlineException("An error occurred while cancelling a timer for a deadline manager", e); } }); }
private void initialize() throws SchedulerException { scheduler.getContext().put(DeadlineJob.TRANSACTION_MANAGER_KEY, transactionManager); scheduler.getContext().put(DeadlineJob.SCOPE_AWARE_RESOLVER, scopeAwareProvider); scheduler.getContext().put(DeadlineJob.JOB_DATA_SERIALIZER, serializer); scheduler.getContext().put(DeadlineJob.HANDLER_INTERCEPTORS, handlerInterceptors()); }
@Override public void cancelSchedule(String deadlineName, String scheduleId) { runOnPrepareCommitOrNow(() -> cancelSchedule(jobKey(scheduleId, deadlineName))); }
/** * Instantiate a {@link QuartzDeadlineManager} based on the fields contained in the {@link Builder}. * <p> * Will assert that the {@link Scheduler}, {@link ScopeAwareProvider}, {@link TransactionManager} and * {@link Serializer} are not {@code null}, and will throw an {@link AxonConfigurationException} if any of them is * {@code null}. * The TransactionManager, ScopeAwareProvider and Serializer will be tied to the Scheduler's context. If this * initialization step fails, this will too result in an AxonConfigurationException. * * @param builder the {@link Builder} used to instantiate a {@link QuartzDeadlineManager} instance */ protected QuartzDeadlineManager(Builder builder) { builder.validate(); this.scheduler = builder.scheduler; this.scopeAwareProvider = builder.scopeAwareProvider; this.transactionManager = builder.transactionManager; this.serializer = builder.serializer; try { initialize(); } catch (SchedulerException e) { throw new AxonConfigurationException("Unable to initialize QuartzDeadlineManager", e); } }
@Override public void schedule(Duration triggerDuration, String deadlineName, Object messageOrPayload, ScopeDescriptor deadlineScope, String scheduleId) { schedule(Instant.now().plus(triggerDuration), deadlineName, messageOrPayload, deadlineScope, scheduleId); }
/** * Instantiate a Builder to be able to create a {@link QuartzDeadlineManager}. * <p> * The {@link TransactionManager} is defaulted to an {@link NoTransactionManager}, and the {@link Serializer} to a * {@link XStreamSerializer}. The {@link Scheduler} and {@link ScopeAwareProvider} are <b>hard requirements</b> and * as such should be provided. * * @return a Builder to be able to create a {@link QuartzDeadlineManager} */ public static Builder builder() { return new Builder(); }
/** * Initializes a {@link QuartzDeadlineManager} as specified through this Builder. * * @return a {@link QuartzDeadlineManager} as specified through this Builder */ public QuartzDeadlineManager build() { return new QuartzDeadlineManager(this); }
@Override public void cancelSchedule(String deadlineName, String scheduleId) { runOnPrepareCommitOrNow(() -> cancelSchedule(jobKey(scheduleId, deadlineName))); }
@Override public String schedule(Duration triggerDuration, String deadlineName, Object messageOrPayload, ScopeDescriptor deadlineScope) { return schedule(Instant.now().plus(triggerDuration), deadlineName, messageOrPayload, deadlineScope); }