/*
* Copyright 2009-2012 Jose Luis Martin.
*
* 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.jdal.util.concurrent;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.task.SyncTaskExecutor;
/**
* Wrapper for a BlockingQueue that dispatchs incoming objets to a Task Executor.
* You need to configure a Dispatcher or override dispatch(T t) mehod.
*
* @author Jose Luis Martin
* @param <T> Objetc type stored in Queue.
* @since 1.3
*/
public class DispatcherQueue<T> {
private static final Log log = LogFactory.getLog(DispatcherQueue.class);
private BlockingQueue<T> queue = new LinkedBlockingQueue<T>();
private Thread dispatcherThread;
/** true when dispatching messages */
private volatile boolean running = false;
/** Task executor to execute Dispatchers as Runnables */
private Executor executor = new SyncTaskExecutor();
/** Dispatcher instance */
private Dispatcher<T> dispatcher;
public DispatcherQueue() {
}
public DispatcherQueue(Dispatcher<T> dispatcher) {
this.dispatcher = dispatcher;
}
/**
* Create and start dispatcher thread
*/
public void init() {
start();
}
/**
* Dispatch incomming objects to a Executor
*/
private void dispatch() {
while (running) {
T t = null;
try {
t = queue.take();
if (log.isDebugEnabled())
log.debug("Dispatching object: " + t.toString());
dispatcher.dispatch(t);
}
catch (InterruptedException e) {
log.error(e);
break;
}
catch (Exception e) {
log.error("Dispather failed. Readding object to queue again.");
log.error(e.getMessage());
queue.offer(t);
}
}
}
/**
* Create a Runnable to dispatch incomming messages
* @param msg message to be dispatched
* @return Runnable
*/
protected Runnable createWorker(final T t) {
return new Runnable() {
public void run() {
dispatch(t);
}
};
}
/**
* Dispatch objects in Queue
* @param msg
*/
protected void dispatch(T t) {
if (dispatcher != null) {
try {
dispatcher.dispatch(t);
}
catch (Exception e) {
log.error(e);
}
}
else {
log.error("Dispatcher is null, Override default dispatch method or " +
"configure a dispatcher.");
}
}
/**
* Gets the number of messages on the queue.
* @return queue size
* @see java.util.Collection#size()
*/
public int size() {
return queue.size();
}
/**
* Insert a Object to the queue, waiting if necessary.
* @param t object to put on queue
* @see java.util.concurrent.BlockingQueue#put(java.lang.Object)
*/
public void put(T t) {
try {
queue.put(t);
} catch (InterruptedException e) {
log.error(e);
}
}
/**
* Clear all messages on the queue
* @see java.util.Collection#clear()
*/
public void clear() {
queue.clear();
}
/**
* Stop Dispatcher
*/
public void stop() {
running = false;
dispatcherThread.interrupt();
try {
dispatcherThread.join();
} catch (InterruptedException e) {
log.error(e);
}
}
public void start() {
if (running) {
log.warn("Already running");
return;
}
dispatcherThread = new Thread(new Runnable() {
public void run() {
dispatch();
}
});
running = true;
log.info("Starting dispatcher thread");
dispatcherThread.start();
}
/**
* @return the dispatcher
*/
public Dispatcher<T> getDispatcher() {
return dispatcher;
}
/**
* @param dispatcher the dispatcher to set
*/
public void setDispatcher(Dispatcher<T> dispatcher) {
this.dispatcher = dispatcher;
}
/**
* @return the queue
*/
public BlockingQueue<T> getQueue() {
return queue;
}
/**
* @param queue the queue to set
*/
public void setQueue(BlockingQueue<T> queue) {
this.queue = queue;
}
/**
* @return the running
*/
public boolean isRunning() {
return running;
}
/**
* @param running the running to set
*/
public void setRunning(boolean running) {
this.running = running;
}
/**
* @return the executor
*/
public Executor getExecutor() {
return executor;
}
/**
* @param executor the executor to set
*/
public void setExecutor(Executor executor) {
this.executor = executor;
}
public interface Dispatcher<T> {
void dispatch(T t);
}
}