Titel | Autor | Date |
---|---|---|
###Title### | Andreas Willinger -- Jakob Klepp | 13.02.2014 |
Implementieren Sie eine Chatapplikation mit Hilfe des Java Message Service. Verwenden Sie Apache ActiveMQ (http://activemq.apache.org) als Message Broker Ihrer Applikation. Das Programm soll folgende Funktionen beinhalten:
- Benutzer meldet sich mit einem Benutzernamen und dem Namen des Chatrooms an. Beispiel für einen Aufruf:
vsdbchat <ip_message_broker> <benutzername> <chatroom>
- Der Benutzer kann in dem Chatroom (JMS Topic) Nachrichten an alle Teilnehmer eine Nachricht senden und empfangen. Die Nachricht erscheint in folgendem Format:
<benutzername> [<ip_des_benutzers>]: <Nachricht>
- Zusätzlich zu dem Chatroom kann jedem Benutzer eine Nachricht in einem persönlichen Postfach (JMS Queue) hinterlassen werden. Der Name des Postfachs ist die IP Adresse des Benutzers (Eindeutigkeit).
- Nachricht an das Postfach senden:
MAIL <ip_des_benutzers> <nachricht>
- Eignes Postfach abfragen:
MAILBOX
- Der Chatraum wird mit den Schlüsselwort EXIT verlassen. Der Benutzer verlaesst den Chatraum, die anderen Teilnehmer sind davon nicht betroffen.
Gruppenarbeit: Die Arbeit ist in einer 2er-Gruppe zu lösen und über das Netzwerk zu testen! Abnahmen, die nur auf localhost basieren sind unzulässig und werden mit 6 Minuspunkten benotet!
GUI
- Großes Textfeld (mitte, oben) für alle Nachrichten in diesem Topic
- Einzeiliges Textfeld unten für Benutzereingabe
- Button rechts von Eingabefeld zum Absenden
Channel (JMS-Topic)
- Sender & Receiver laufen in einem extra Thread, um die GUI nicht zu blockieren
- Verwendung des Observer Patterns mithilfe von onMessage (bei MessageConsumer) Wenn Nachricht ankommt: Aktualisierung des großen Textfeldes in der GUI
- Extra Thread stellt Methode zum Senden von Nachrichten zur Verfügung, Controller hat Referenz auf dessen Objekt
Mailbox (JMS-Queue)
- Sender & Receiver laufen wie bei Topic in einem extra Thread
- Wenn eine neue Nachricht (über onMessage) empfangen wurde, wird diese in einer ArrayList abgelegt
- Bei Abfrage der Mailbox (mithilfe des Kommandos "MAILBOX" in der GUI), wird die ArrayList ausgelesen und deren Inhalt im großen Textfeld farbig hinterlegt angezeigt.
- Da es auf einer IP auch mehrere Benutzer geben kann, muss der Benutzername beim Senden einer Nachricht mit angegeben werden.
Aufruf demnach: MAIL <benutzername>@<ip_des_benutzers> <nachricht>
Beenden
Beim Beenden müssen alle offenen Verbindungen in den jeweiligen Threads geschlossen werden, anschließend kann erst das Programm beendet werden.
Arbeitspaket | Geplante Zeit | Aufwand | Wer |
---|---|---|---|
[H:MM] | |||
UML | 1:30 | Mittel | Jakob Klepp |
GUI | 1:00 | Gering | Andreas Willinger |
Chat Befehle | 0:30 | Gering | Andreas Willinger |
Channel (JMS-Topic) | 2:00 | Mittel | Andreas Willinger |
Option parsing | 0:40 | Gering | Jakob Klepp |
Mailbox (JMS-Queue) | 2:00 | Mittel | Jakob Klepp |
Testing | 0:30 | Gering | Jakob Klepp / Andreas Willinger |
Arbeitspaket | Datum | Start | Ende | Dauer | Wer |
---|---|---|---|---|---|
[YYYY-MM-DD] | [HH:MM] | [HH:MM] | [H:MM] | ||
UML | 2014-02-11 | 13:00 | 13:40 | 0:40 | Jakob Klepp |
UML überarbeitet | 2014-02-11 | 13:40 | 14:30 | 0:40 | Jakob Klepp |
UML überarbeitet | 2014-02-11 | 13:40 | 14:30 | 0:40 | Andreas Willinger |
Importing stuff from Astah | 2014-02-11 | 15:10 | 15:35 | 0:25 | Jakob Klepp |
Junit stubs | 2014-02-11 | 15:35 | 16:00 | 0:25 | Jakob Klepp |
Argumentparser | 2014-02-11 | 16:00 | 17:20 | 1:20 | Jakob Klepp |
GUI | 2014-02-11 | 17:00 | 17:30 | 0:30 | Andreas Willinger |
Ant Buildfile | 2014-02-11 | 17:40 | 18:40 | 1:20 | Jakob Klepp |
Channel(JMS-Topic) | 2014-02-11 | 17:40 | 18:00 | 0:20 | Andreas Willinger |
Channel(JMS-Topic) | 2014-02-11 | 18:05 | 18:30 | 0:30 | Andreas Willinger |
Chat Befehle (Topic) | 2014-02-11 | 18:30 | 18:35 | 0:05 | Andreas Willinger |
Channel(JMS-Topic) | 2014-02-12 | 09:35 | 09:55 | 0:20 | Andreas Willinger |
Channel(JMS-Topic)/GUI | 2014-02-12 | 11:20 | 11:35 | 0:15 | Andreas Willinger |
Mail system | 2014-02-11 | 17:40 | 18:00 | 0:20 | Jakob Klepp |
Testing | 2014-02-12 | 17:10 | 18:00 | 0:50 | Andreas Willinger |
Mail system | 2014-02-12 | 21:50 | 24:00 | 1:10 | Jakob Klepp |
Mail system | 2014-02-13 | 00:00 | 00:15 | 0:15 | Jakob Klepp |
Channel/Mail/GUI (fixing) | 2014-02-13 | 07:55 | 08:50 | 0:55 | Andreas Willinger |
UML | 2014-02-13 | 13:55 | 14:10 | 0:15 | Andreas Willinger |
Testing | 2014-02-13 | 20:00 | 20:30 | 0:30 | Andreas Willinger |
Testing | 2014-02-13 | 20:00 | 20:30 | 0:30 | Jakob Klepp |
Wir verwenden als Host für ActiveMQ einen von uns gemieteten vServer in Deutschland, da das Schulnetzwerk bei VMs sehr unzuverlässig ist.
Zu aller erst muss Java installiert werden:
apt-get install openjdk-7-jre-headless
Nun kann ActiveMQ heruntergeladen & entpackt werden. Wir verwenden die bereits vorkompilierte (binäre) Variante.
mkdir /root/activemq && cd /root/activemq
wget http://tweedo.com/mirror/apache/activemq/apache-activemq/5.9.0/apache-activemq-5.9.0-bin.tar.gz
tar xfvz apache-activemq-5.9.0-bin.tar.gz
Anschließend wird noch die Standard Konfigurationsdatei angelegt und wie folgt bearbeitet: Dies wird benötigt, da Java standardmäßig IPv6 benutzt, falls es verfügbar ist.
cd apache-activemq-5.9.0/bin/
./activemq setup /etc/default/activemq
vim /etc/default/activemq
[..]
ACTIVEMQ_OPTS="$ACTIVEMQ_OPTS -Djava.net.preferIPv4Stack=true"
[..]
Zum Schluss kann ActiveMQ gestartet werden:
./activemq start
Ausgabe:
INFO: Loading '/etc/default/activemq'
INFO: Using java '/usr/bin/java'
INFO: Starting - inspect logfiles specified in logging.properties and log4j.properties to get details
INFO: pidfile created : '/root/activemq/apache-activemq-5.9.0/data/activemq-mail.f-o-g.eu.pid' (pid '2136')
INFO: Loading '/etc/default/activemq'
INFO: Using java '/usr/bin/java'
ActiveMQ is running (pid '2136')
Da wir zwei verschiedene Threads für den Chatroom selbst und die Mailbox verwenden und diese auf dasselbe JMSModel zugreifen, müssen wir eine Thread-safe Collection verwenden.
Unsere Wahl fiel dazu auf eine Synchronized ArrayList, welche wie folgt (ähnlich zu einer normalen ArrayList) deklariert & initialisert werden kann:
public List<String> myList = Collections.synchronizedList(new ArrayList<String>());
Anschließend kann myList ganz normal wir eine ArrayList verwendet werden, mit dem Unterschied, dass alle Abfragen (einfügen, löschen, abrufen) synchronized (d.h. blocking) ablaufen.
Zum parsen von Kommandozeilen Argumenten verwenden wir JCommander. Die Entscheidung fiel auf JCommander da er noch aktiv weiter entwickelt wird und die einbindung nur eine Minimale menge Code benötigt.
Verwendungsbeispiel aus der offiziellen Dokumentation _[10]
Argumentparser
public class JCommanderTest {
@Parameter
public List<String> parameters = Lists.newArrayList();
@Parameter(names = { "-log", "-verbose" }, description = "Level of verbosity")
public Integer verbose = 1;
@Parameter(names = "-groups", description = "Comma-separated list of group names to be run")
public String groups;
@Parameter(names = "-debug", description = "Debug mode")
public boolean debug = false;
@DynamicParameter(names = "-D", description = "Dynamic parameters go here")
public Map<String, String> dynamicParams = new HashMap<String, String>();
}
Verwendung des Parsers
JCommanderTest jct = new JCommanderTest();
String[] argv = { "-log", "2", "-groups", "unit1,unit2,unit3",
"-debug", "-Doption=value", "a", "b", "c" };
new JCommander(jct, argv);
Assert.assertEquals(2, jct.verbose.intValue());
Assert.assertEquals("unit1,unit2,unit3", jct.groups);
Assert.assertEquals(true, jct.debug);
Assert.assertEquals("value", jct.dynamicParams.get("option"));
Assert.assertEquals(Arrays.asList("a", "b", "c"), jct.parameters);
Im Laufe der Entwicklung haben wir festgestellt, dass das schließend (via EXIT) ein kleines Redesign benötigt. Dazu verwenden wir nun einen WindowListener (bzw. WindowAdapater, da wir nur eine Methode benötigen) um das windowClosing Event zu verarbeiten. Außerdem wurde das Text Interface (welches vom JMSView implementiert wird) erweitert, um clearText() und close() Methoden hinzuzufügen.
Bei Aufruf der close() Methode wird ein windowClosing Event manuell ausgelöst, dadurch werden die stop() Methoden in der Channel und Mailbox Klasse aufgerufen. Anschließend wird das Fenster geschlossen. Beide Klassen werden außerdem in Threads ausgeführt, um das Programm selbst nicht zu behindern.
Die clearText() Methode löscht einfach das Kommandofeld.
Da wir ja einen VPS im Internet verwenden, haben wir das Testen von zu Hause aus durchgeführt. Der Grund dahinter ist, dass die Schul-Firewall den Port 61616 sperrt und dieser nur über einen SSH Tunnel erreichbar wäre. Dadurch hätten wir beide auch die selbe Ip (MAILBOX Test wäre aufgrund dessen nicht aussagekräftig).
Zugewiesene IPs (obwohl die benutzernamen relativ eindeutig sein sollten):
213.47.167.184 - Andreas Willinger
62.178.207.178 - Jakob Klepp
Der Aufruf zum starten ist bei beiden beinahe der selbe, mit dem Unterschied, dass die Benutzernamen unterschiedlich sind. Anschließend wird direkt eine Nachricht an alle bereits vorhandenen Teilnehmer gesendet, um den neuen Teilnehmer anzukündigen:
Nun kann freudig losgechattet werden und sobald einer den Raum wieder verlässt, wird dies auch angekündigt:
Es können auch Nachrichten direkt an einen anderen Benutzer gesandt werden:
Absender
Empfänger
Der Chat kann auch verlassen werden, ohne die anderen Teilnehmer zu beeinträchtigen (Nachrichten an die Mailbox können später abgerufen werden): (für Beweis, siehe 2. Punkt)
Statstiken im Webinterface:
Queues
Topics
- [1] Homepage ActiveMQ
- http://activemq.apache.org/index.html zuletzt besucht am:
- [2]
- http://www.academictutorials.com/jms/jms-introduction.asp zuletzt besucht am:
- [3]
- http://docs.oracle.com/javaee/1.4/tutorial/doc/JMS.html#wp84181 zuletzt besucht am:
- [4]
- http://www.openlogic.com/wazi/bid/188010/How-to-Get-Started-with-ActiveMQ zuletzt besucht am:
- [5]
- http://jmsexample.zcage.com/index2.html zuletzt besucht am:
- [6] http://www.onjava.com/pub/a/onjava/excerpt/jms_ch2/index.html
- zuletzt besucht am:
- [7] http://www.oracle.com/technetwork/systems/middleware/jms-basics-jsp-135286.html
- zuletzt besucht am:
- [8] Java JMS With A Queue Programming Reference and Examples
- http://www.fluffycat.com/Java/JMS-With-A-Queue/ zuletzt besucht am: 10.02.2014
- [9] Java Message Service: Chapter 2: Developing a Simple Example
- http://oreilly.com/catalog/javmesser/chapter/ch02.html zuletzt besucht am: 10.02.2014
- [10] JCommander
- http://www.jcommander.org/ zuletzt besucht am: 11.02.2014
###Page### / ###Total###