/*
** This file is part of Filius, a network construction and simulation software.
**
** Originally created at the University of Siegen, Institute "Didactics of
** Informatics and E-Learning" by a students' project group:
** members (2006-2007):
** André Asschoff, Johannes Bade, Carsten Dittich, Thomas Gerding,
** Nadja Haßler, Ernst Johannes Klebert, Michell Weyer
** supervisors:
** Stefan Freischlad (maintainer until 2009), Peer Stechert
** Project is maintained since 2010 by Christian Eibl <filius@c.fameibl.de>
** and Stefan Freischlad
** Filius is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) version 3.
**
** Filius 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Filius. If not, see <http://www.gnu.org/licenses/>.
*/
package filius.software.clientserver;
import filius.Main;
import filius.rahmenprogramm.I18n;
import filius.software.transportschicht.Socket;
import filius.software.transportschicht.TCPSocket;
import filius.exception.VerbindungsException;
/** Diese Klasse implementiert einen Thread, der von einem Server fuer
* eine eingegangene Verbindungsanfrage erzeugt wird. Damit wird der
* neu erstellte Socket ueberwacht.
*
*/
public abstract class ServerMitarbeiter extends Thread implements I18n {
/** Die Server-Anwendung, die diesen Mitarbeiter verwaltet */
protected ServerAnwendung server;
/** der Socket, der fuer den Datenaustausch verwendet wird */
protected Socket socket;
/** Dieses Attribut zeigt an, ob der Thread laeuft. */
protected boolean running = false;
/**
* Konstruktor, in dem die zugehoerige ServerAnwendung und der Socket fuer
* den Datenaustausch implementiert werden.
*
* @param server
* @param socket
*/
public ServerMitarbeiter(ServerAnwendung server, Socket socket) {
Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (ServerMitarbeiter), constr: ServerMitarbeiter("+server+","+socket+")");
this.server = server;
this.socket = socket;
}
/**
* Mit dieser Methode werden eingehende Nachrichten verarbeitet. Sie
* enthaelt also die eigentliche Anwendungslogik und muss daher von den
* Unterklassen implementiert werden.
*
* @param nachricht
*/
protected abstract void verarbeiteNachricht(String nachricht);
/**
* Mit dieser Methode werden Nachrichten versendet und wenn dies ohne
* Ausnahme (Exception) stattgefunden hat, an Beobachter der
* Server-Anwendung weiter gegeben. <br />
* Diese Methode ist <b>blockierend</b>
*
* @param nachricht
*/
protected void sendeNachricht(String nachricht) {
Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (ServerMitarbeiter), sendeNachricht("+nachricht+")");
try {
socket.senden(nachricht);
server.benachrichtigeBeobachter("<<" + nachricht);
}
catch (Exception e) {
server.benachrichtigeBeobachter(e.getMessage());
e.printStackTrace(Main.debug);
}
}
/**
* Hier wird auf eingehende Nachrichten gewartet und diese zum einen an
* Beobachter der Server-Anwendung und zum anderen zur Verarbeitung an die
* Methode verarbeitenNachricht() weiter gegeben.
*/
public void run() {
Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (ServerMitarbeiter), run()");
String nachricht = null;
while (running) {
try {
if(socket.istVerbunden()) {
nachricht = socket.empfangen();
}
if (nachricht != null) {
server.benachrichtigeBeobachter(">>" + nachricht);
verarbeiteNachricht(nachricht);
nachricht = null;
}
else if (socket != null){
socket.schliessen();
server.benachrichtigeBeobachter(messages.getString("sw_servermitarbeiter_msg1")+" "
+ socket.holeZielIPAdresse() + ":"
+ socket.holeZielPort() + " "+ messages.getString("sw_servermitarbeiter_msg2"));
running = false;
}
}
catch (VerbindungsException e) {
e.printStackTrace(Main.debug);
server.benachrichtigeBeobachter(e.getMessage());
socket.schliessen();
running = false;
server.entferneMitarbeiter(this);
}
catch (Exception e) {
e.printStackTrace(Main.debug);
server.benachrichtigeBeobachter(e.getMessage());
socket.schliessen();
running = false;
server.entferneMitarbeiter(this);
}
}
}
/**
* Methode zum Starten des Threads beim Wechsel vom Entwurfs- in den
* Aktionsmodus. Wenn sich der Thread noch in einem wartenden oder
* blockierten Zustand wird kein neuer Thread gestartet, sondern lediglich
* gewaehrleistet, dass der Thread nicht beendet wird.
*/
public void starten() {
Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (ServerMitarbeiter), starten()");
if (!running) {
running = true;
if (getState().equals(State.WAITING)
|| getState().equals(State.BLOCKED)) {
//Main.debug.println(getClass()
//+"\n\tServerMitarbeiter: Thread laeuft bereits.");
}
else {
start();
//Main.debug.println(getClass()
//+"\n\tServerMitarbeiter: wurde gestartet ");
}
}
}
/**
* Methode zum Beenden des Threads. Wenn der Thread noch in einem wartenden
* oder blockierten Zustand ist, wird interrupt() aufgerufen, um die
* Verarbeitung fortzusetzen, damit der Thread dann beendet werden kann.
*/
public void beenden() {
Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (ServerMitarbeiter), beenden()");
running = false;
if (socket != null) socket.beenden();
if (getState().equals(State.WAITING)
|| getState().equals(State.BLOCKED)) {
interrupt();
}
}
}