package javacodebook.thread.wait_notify;

import java.util.Vector;

/**
 * Eine Message-Queue. Jede Nachricht wird in einem Vector gespeichert. Der
 * Empfang einer Nachricht und das Senden einer Nachricht können nicht gleich-
 * zeitig erfolgen, da die einzelnen Blöcke synchronisiert sind. Ist die 
 * Queue voll bzw. leer, müssen sendende bzw. lesende Threads warten.
 *
 * @author Mark Donnermeyer
 */
public class MessageQueue {
    Vector queue;
    int maxSize;
    
    public MessageQueue(int size) {
        this.maxSize = size;
        queue = new Vector(size);
    }
    
    /**
     * Fügt eine neue Nachricht an das Ender der Message-Queue an. Nur ein
     * Thread kann gleichzeitig eine Nachricht anfügen. In dieser Zeit kann
     * auch kein Thread eine Nachricht aus der Queue lesen. Die Queue hat
     * eine max. Grösse. Bei erreichen dieser Grössen müssen Threads, die 
     * Nachrichten in die Queue schreiben möchen, warten, bis mind. eine 
     * Nachricht aus der Queue gelesen und damit entfernt wurde.
     */
    public synchronized void send(Object obj) {
        // Solange warten, bis die Queue nicht mehr voll ist.
        while (queue.size() == maxSize) {
            System.out.println(
                Thread.currentThread().getName() +
                ": Queue ist voll. Thread muss warten"
            );
            try {
                wait();
            }
            catch (Exception e) {}
        }
        
        System.out.println(
            Thread.currentThread().getName() +
            ": schreibt Nachricht in die Queue."
        );

        // Nachricht in die Queue schreiben
        queue.addElement(obj);
        notify();
    }
    
    /**
     * Liest die älteste Nachricht aus der Message-Queue aus. Nur ein Thread
     * kann gleichzeitig eine Nachricht lesen. In dieser Zeit kann auch kein
     * Thread eine neue Nachricht an die Queue anhängen. Ist die Queue leer
     * müssen Threads solange warten, bis mind. eine Nachricht in die Queue
     * geschrieben wurde.
     */
    public synchronized Object recv() {
        // Solange warten, bis mind. eine Nachricht in der Queue bereitsteht
        while (queue.size() == 0) {
            System.out.println(
                Thread.currentThread().getName() +
                ": Queue ist leer. Thread muss warten"
            );
            try {
                wait();
            }
            catch (Exception e) {}
        }
        
        System.out.println(
            Thread.currentThread().getName() +
            ": liest Nachricht aus der Queue."
        );
        
        // Nachricht aus der Queue lesen.
        Object obj = queue.firstElement();
        queue.removeElementAt(0);
        notify();
        return obj;
    }
}