Java tutorial
/* * Copyright (c) 2010-2014. Axon Framework * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.axonframework.eventhandling.scheduling.java; import org.axonframework.common.Assert; import org.axonframework.domain.EventMessage; import org.axonframework.domain.GenericEventMessage; import org.axonframework.domain.IdentifierFactory; import org.axonframework.eventhandling.EventBus; import org.axonframework.eventhandling.scheduling.EventScheduler; import org.axonframework.eventhandling.scheduling.ScheduleToken; import org.axonframework.unitofwork.DefaultUnitOfWorkFactory; import org.axonframework.unitofwork.UnitOfWork; import org.axonframework.unitofwork.UnitOfWorkFactory; import org.joda.time.DateTime; import org.joda.time.Duration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; /** * An {@link EventScheduler} implementation that uses Java's ScheduledExecutorService as scheduling and triggering * mechanism. * <p/> * Note that this mechanism is non-persistent. Scheduled tasks will be lost when the JVM is shut down, unless special * measures have been taken to prevent that. For more flexible and powerful scheduling options, see {@link * org.axonframework.eventhandling.scheduling.quartz.QuartzEventScheduler}. * * @author Allard Buijze * @see org.axonframework.eventhandling.scheduling.quartz.QuartzEventScheduler * @since 0.7 */ public class SimpleEventScheduler implements EventScheduler { private static final Logger logger = LoggerFactory.getLogger(SimpleEventScheduler.class); private final ScheduledExecutorService executorService; private final EventBus eventBus; private final UnitOfWorkFactory unitOfWorkFactory; private final Map<String, Future<?>> tokens = new ConcurrentHashMap<String, Future<?>>(); /** * Initialize the SimpleEventScheduler using the given <code>executorService</code> as trigger and execution * mechanism, and publishes events to the given <code>eventBus</code>. * * @param executorService The backing ScheduledExecutorService * @param eventBus The Event Bus on which Events are to be published */ public SimpleEventScheduler(ScheduledExecutorService executorService, EventBus eventBus) { this(executorService, eventBus, new DefaultUnitOfWorkFactory()); } /** * Initialize the SimpleEventScheduler using the given <code>executorService</code> as trigger and execution * mechanism, and publishes events to the given <code>eventBus</code>. The <code>eventTriggerCallback</code> is * invoked just before and after publication of a scheduled event. * * @param executorService The backing ScheduledExecutorService * @param eventBus The Event Bus on which Events are to be published * @param unitOfWorkFactory The factory that creates the Unit of Work to manage transactions */ public SimpleEventScheduler(ScheduledExecutorService executorService, EventBus eventBus, UnitOfWorkFactory unitOfWorkFactory) { Assert.notNull(executorService, "executorService may not be null"); Assert.notNull(eventBus, "eventBus may not be null"); Assert.notNull(unitOfWorkFactory, "unitOfWorkFactory may not be null"); this.executorService = executorService; this.eventBus = eventBus; this.unitOfWorkFactory = unitOfWorkFactory; } @Override public ScheduleToken schedule(DateTime triggerDateTime, Object event) { return schedule(new Duration(null, triggerDateTime), event); } @Override public ScheduleToken schedule(Duration triggerDuration, Object event) { String tokenId = IdentifierFactory.getInstance().generateIdentifier(); ScheduledFuture<?> future = executorService.schedule(new PublishEventTask(event, tokenId), triggerDuration.getMillis(), TimeUnit.MILLISECONDS); tokens.put(tokenId, future); return new SimpleScheduleToken(tokenId); } @Override public void cancelSchedule(ScheduleToken scheduleToken) { if (!SimpleScheduleToken.class.isInstance(scheduleToken)) { throw new IllegalArgumentException("The given ScheduleToken was not provided by this scheduler."); } Future<?> future = tokens.remove(((SimpleScheduleToken) scheduleToken).getTokenId()); if (future != null) { future.cancel(false); } } private class PublishEventTask implements Runnable { private final Object event; private final String tokenId; public PublishEventTask(Object event, String tokenId) { this.event = event; this.tokenId = tokenId; } @SuppressWarnings("unchecked") @Override public void run() { EventMessage<?> eventMessage = createMessage(); if (logger.isInfoEnabled()) { logger.info("Triggered the publication of event [{}]", eventMessage.getPayloadType().getSimpleName()); } UnitOfWork unitOfWork = unitOfWorkFactory.createUnitOfWork(); try { unitOfWork.publishEvent(eventMessage, eventBus); unitOfWork.commit(); } finally { tokens.remove(tokenId); } } /** * Creates a new message for the scheduled event. This ensures that a new identifier and timestamp will always * be generated, so that the timestamp will reflect the actual moment the trigger occurred. * * @return the message to publish */ private EventMessage<?> createMessage() { EventMessage<?> eventMessage; if (event instanceof EventMessage) { eventMessage = new GenericEventMessage<Object>(((EventMessage) event).getPayload(), ((EventMessage) event).getMetaData()); } else { eventMessage = new GenericEventMessage<Object>(event); } return eventMessage; } } }