/**
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this software; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF
* site: http://www.fsf.org.
*/
package org.ut.biolab.medsavant;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.ut.biolab.medsavant.shared.model.exception.LockException;
/**
* Maintains a thread to dequeue items from the method invocation queue and
* invoke them. If the queue is empty, the thread will block. If the queue has
* an item but the MedSavant server is locked, the item will be dequeued and
* the thread will sleep for POLL_INTERVAL milliseconds before trying again.
* It will keep trying indefinitely.
*
* If the queue processing thread is not already alive, it is started when
* an item is enqueued.
*
*/
public class BlockingQueueManager {
private static final BlockingQueue<MethodInvocation> queue = new LinkedBlockingQueue<MethodInvocation>();
private static Thread queueProcessor = null;
private static final long POLL_INTERVAL = 30000;
private static final Log LOG = LogFactory.getLog(BlockingQueueManager.class);
private static class QueueProcessor extends Thread{
@Override
public void run() {
MethodInvocation mi = null;
while (true) {
try {
mi = queue.take(); //blocks until something available.
} catch (InterruptedException ie) {
LOG.error("Queue interrupted while waiting for work");
return;
}
boolean locked = false;
do {
try {
mi.invoke(true);
} catch (LockException le) {
//Database is locked (e.g. someone else is modifying
//the database). Try again in POLL_INTERVAL ms.
locked = true;
try{
Thread.sleep(POLL_INTERVAL);
} catch(InterruptedException iex){
LOG.error("Queue interrupted while sleeping. Waiting job will be pushed back.");
queue.add(mi);
return;
}
}
} while (locked);
}
}
};
public static synchronized void enqueue(MethodInvocation mi) {
queue.add(mi);
if(queueProcessor == null || !queueProcessor.isAlive()){
LOG.info("No active queue to execute method "+mi.getName()+" - starting new thread");
queueProcessor = new QueueProcessor();
queueProcessor.start();
}
}
}