001    /*
002    @license.text@
003     */
004    
005    package biz.hammurapi.util;
006    
007    import java.util.LinkedList;
008    
009    /**
010     * Has internal invocation queue and pumps all invocation to be made 
011     * from a single thread. A workaround to use thread-unsafe classes in
012     * multithreaded environment.
013     * @author Pavel Vlasov 
014     * @version $Revision: 1.3 $
015     */
016    public class InvocationPump {
017            private LinkedList queue=new LinkedList();
018            
019            protected abstract class Command {
020                    private Object returnValue;
021                    private Throwable exception;
022                    
023                    /**
024                     * Put single-threaded functionality here
025                     */
026                    protected abstract Object execute() throws Throwable;
027                    
028                    /**
029                     * Posts the command to the queue and waits
030                     * until it is executed
031                     */
032                    public synchronized Object post() throws Throwable {
033                            synchronized (queue) {
034                                    queue.add(this);
035                                    queue.notifyAll();
036                            }
037                            
038                            wait();
039                            
040                            if (exception!=null) {
041                                    throw exception;
042                            }
043                            
044                            return returnValue;
045                    }
046            }
047            
048            public void pump() {
049                    synchronized (queue) {
050                            if (!queue.isEmpty()) {
051                                    Command command=(Command) queue.removeFirst();
052                                    try {
053                                            command.returnValue=command.execute();
054                                    } catch (Throwable th) {
055                                            command.exception=th;
056                                    }
057                                    
058                                    synchronized(command) {
059                                            command.notifyAll();
060                                    }
061                            }
062                    }
063            }
064    }