package org.ff4j.audit; /* * #%L * ff4j-core * %% * Copyright (C) 2013 - 2014 Ff4J * %% * 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. * #L% */ import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.ff4j.audit.repository.EventRepository; import org.ff4j.audit.repository.InMemoryEventRepository; /** * Default implementation of repository. * * @author Cedrick Lunven (@clunven) */ public class EventPublisher { /** DEFAULT. */ public static final int DEFAULT_QUEUE_CAPACITY = 100; /** DEFAULT. */ public static final int DEFAULT_POOL_SIZE = 4; /** 2s to save the event other wize skip. */ public static final long timeout = 2000L; /** Executor for item writer. */ private ExecutorService executor; /** Repository to save events. */ private EventRepository repository; /** the amount of time to wait after submitting for the task to complete. */ private final long submitTimeout; /** flag to shiutdown executor on failure. */ private final boolean shutdownExecutor; /** * Default constructor. */ public EventPublisher() { this(DEFAULT_QUEUE_CAPACITY, DEFAULT_POOL_SIZE, new InMemoryEventRepository()); } /** * Default constructor. */ public EventPublisher(EventRepository er) { this(DEFAULT_QUEUE_CAPACITY, DEFAULT_POOL_SIZE, er); } /** * Default constructor. */ public EventPublisher(int queueCapacity, int poolSize, EventRepository er) { this(queueCapacity, poolSize, er, timeout); } /** * Default constructor. */ public EventPublisher(int queueCapacity, int poolSize, EventRepository er, long submitTimeout) { // Initializing queue final BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(queueCapacity); // Executor with worker to process threads RejectedExecutionHandler rej = new EventRejectedExecutionHandler(); ThreadFactory tFactorty = new PublisherThreadFactory(); this.executor = new ThreadPoolExecutor(poolSize, poolSize, 0L, TimeUnit.MILLISECONDS, queue, tFactorty, rej); // Override repository this.repository = er; this.submitTimeout = submitTimeout; this.shutdownExecutor = true; } /** * @param er the event repository to use * @param executorService the executor service */ public EventPublisher(EventRepository er, ExecutorService executorService) { this(er, executorService, timeout); } /** * @param er the event repository to use * @param executorService the executor service * @param submitTimeout */ public EventPublisher(EventRepository er, ExecutorService executorService, long submitTimeout) { repository = er; executor = executorService; this.submitTimeout = submitTimeout; this.shutdownExecutor = false; } /** * Publish event to repository * * @param e * event. */ public void publish(Event e) { try { EventWorker ew = new EventWorker(e, repository); final Future<Boolean> check = executor.submit(ew); check.get(submitTimeout, TimeUnit.MILLISECONDS); } catch (Exception e1) { // Do not propagate error, it's monitoring (aside business logic) System.err.println("Cannot publish event " + e1.getMessage()); } } /** * Stops the event publisher. If we started an executor service, it will * be shutdown here. */ public void stop() { if (this.shutdownExecutor) { this.executor.shutdownNow(); } } /** * Setter accessor for attribute 'repository'. * * @param repository * new value for 'repository ' */ public void setRepository(EventRepository repository) { this.repository = repository; } /** * Getter accessor for attribute 'repository'. * * @return current value of 'repository' */ public EventRepository getRepository() { return repository; } }