IOException.de

Icon

Ausgewählter Nerdkram von Informatikstudenten der Uni Ulm

Ein PubSubHubbub-Subscriber-Client für Java

Das Web ist mit HTTP fest an ein Client/Server-Modell gebunden und eine dadurch implizierte Asynchronität der Kommunikation. Requests können ausschließlich von Clients initiiert werden und immer von Servern in Form von Responses beantwortet. Ein solches Modell ist ausreichend für den Abruf von Informationen, setzt allerdings Schranken bezüglich anderer Interaktionsformen. Andere Protokolle wie XMPP, SIP oder auch Technologien wie nachrichtenbasierte Middlewaresysteme besitzen oft keine so deutliche Trennung zwischen Client/Server und erlauben weniger eingeschränkt die Kommunikation zwischen Knoten. Dadurch enstehen neben dem Request/Reply Muster weitere typischen Muster für den Austausch von Nachrichten. Ein Muster für die Benachrichtigung über Ereignisse ist das Publish/Subscribe Muster. Interessierte Knoten subskribieren sich für bestimmte Ereignisse und ereigniserzeugende Knoten publizieren diese.

Ein solches Kommunikationsmuster ist mit HTTP direkt nicht möglich, auch wenn es insbesondere für Feeds interessant wäre. Zwar bestehen mit Server Pushes / Long Polling oder dem aufkommenden WebSocket Standard vereinzelte Lösung für das prinzipielle Problem, dass HTTP keine serverinitiierte Kommunikation erlaubt, jedoch sind diese Insellösungen bisher kaum in der Breite verwendbar.

Google hat mit dem PubSubHubbub-Protokoll ein einfaches offenes Protokoll erschaffen, dass auf reinem HTTP basiert und ein solches Publish/Subscribe Muster unterstützt. Der Trick hierbei ist die Tatsache, dass alle beteiligten Knoten selbst sowohl Server wie auch Client sind und somit sowohl Requests empfangen wir auch versenden können.

Im Rahmen des diretto Projekts habe ich für unseren Client eine java-basierte Subscriber-Implementierung entwickelt. Als Feed kann jeder PubSubHubbub-fähige Atom-Feed benutzt werden. Im Falle einer Änderung des Feeds, zum Beispiel der Veröffentlichung eines neuen Eintrags, wird das “Delta” des Feeds, also der neue Teil an die Callback-Methode übergeben.

Subscriber subscriber = new SubscriberImpl("subscriber-host",8888);
Subscription subscription = subscriber.subscribe(URI.create("http://feed-host/my-push-enabled-feed.xml"));

subscription.setNotificationCallback(new NotificationCallback()
{

    @Override
    public void handle(SyndFeed feed)
    {
        //TODO: Do something more useful with the new entries
    	WireFeed inFeed = (WireFeed) feed.originalWireFeed();
    	if(inFeed instanceof Feed)
    	{
    		List<?> entries = ((Feed) inFeed).getEntries();
    		for (Object o : entries)
    		{
    			if(o instanceof Entry)
    			{
    				final Entry entry = (Entry) o;
    				System.out.println("New entry: "+entry.getId());
    			}
    		}
    	}
    }

} );

Der Client benutzt intern Rome für die Auswertung der Atom-Feeds und Jetty als leichtgewichtigen, internen Webserver. Der Subscriber muss übrigens für den Hub erreichbar sein, insofern sollte er an eine öffentliche IP und den angegebenen Port gebunden werden.

Projekt auf github: java-sub-pubsubhubbub

Atom Feeds in Java mit ROME direkt lesen

Für die Interaktion mit Feeds gibt es in Java die weit verbreitete ROME-Library. Diese Library unterstützt sowohl RSS als auch ATOM in den verschiedenen Versionen. Außerdem bietet es eine Abstraktion an, die den Umgang mit den verschiedenen Feedarten vereinfachen soll. Ihre sogenannten Syndication Feeds bieten eine einheitliche Schnittstelle an, und sind unabhängig vom darunter liegenden Format. Dies mag allgemein sehr hilfreich sein und für viele Fälle auch ausreichen. Typische Operationen sind somit entkoppelt vom Format und können wiederverwendet werden, oder das konkrete Format kann problemlos ausgetauscht werden.

Der Nachteil hierbei ist, dass bei dieser Abstraktion Besonderheiten der einzelnen Formate verborgen werden. Problematisch wird es zum Beispiel, wenn man explizit ein bestimmtes Format lesen möchte, um auf bestimmte Elemente zuzugreifen. So muss in Atom jeder Feed und Einträg ein ID Element besitzen, in RSS existiert dies jedoch nicht. Leider existiert nun auch keine Methode, ein solches Feld in einem Syndication Feed direkt abzufragen.

Nach einigem Suchen bin ich nun auf die Lösung gestoßen. Beim Einlesen des Feeds muss explizit ein Flag aktiviert werden, dass das zugrunde liegende Format ebenfalls mitgespeichert werden soll. Erst wenn dieses Flag gesetzt ist, lässt sich später der Feed im Originalformat (WireFeed) abrufen:

InputSource source = new InputSource(...);
SyndFeedInput feedInput = new SyndFeedInput();
feedInput.setPreserveWireFeed(true);
SyndFeed feed = feedInput.build(source);

Später bietet dann der Syndication Feed Zugriff auf den konkreten Feed:

WireFeed wireFeed = (WireFeed) feed.originalWireFeed();
if(wireFeed instanceof com.sun.syndication.feed.atom.Feed)
{
   String feedId = ((Feed) wireFeed).getId()
}

LRU-Cache in Java

Caches dienen in der Informatik als Methode, Zugriffe auf bestimmte Daten zu beschleunigen, in dem diese vorgelagert/gepuffert werden. Sie sind in verschiedensten Bereichen zu finden, unter anderem auf Prozessoren, in Festplatten, aber auch in Technologien wie dem Web. Verschiedene Verdrängungsstrategien ermöglichen es, die beschränkte Kapazität eines Caches zu berücksichtigen, so dass nur wichtige Werte im Cache gelagert werden. Least Recently Used (LRU), ist eine solche Strategie, die häufig angewandt wird. Sie sortiert die Werte im Cache nach der letzten Nutzung. Wird auf ein Element über einen längeren Zeitraum nicht mehr zugegriffen, so wird es aus dem Cache verdrängt.

In Java lässt sich ein solcher LRU-Cache besonders einfach implementieren, da die Klasse java.util.LinkedHashMap bereits die wesentlichen Mechanismen unterstützt. Eine HashMap ist eine Hash-Tabelle, die Zugriffe auf Werte über ihre Schlüssel regelt. Zusätzlich verkettet die LinkedHashMap aber die Werte noch in einer Liste, womit auch eine Traversierung in Einfügereihenfolge ermöglicht wird. Mithilfe eines Flags in einem der Konstruktoren kann dieses Verhalten geändert werden, so dass bei jedem Zugriff das angesprochene Element neu in diese Liste eingereiht wird. Damit verwaltet die Liste die Zugriffe und ist Basis für die LRU-Strategie.

Die Methode removeEldestEntry() der LinkedHashMap wird bei jedem Schreibezugriff auf die Map, also nach Einfügeoperationen über put() oder putAll() automatisch aufgerufen und bietet die Möglichkeit, durch Überschreiben der Methode die Verdrängungsstrategie zu implementieren. Diese Methode gibt ein boolean zurück, ob der älteste Eintrag gelöscht werden soll. Es ist auch möglich, innerhalb der Methode selbst die Liste zu manipulieren, dann sollte allerdings die Methode immer false zurückgeben. Für den LRU-Cache reicht es aus, die Größe der Map mit dem gewünschten Maximum zu vergleichen. Ist der Inhalt der Map zu groß, so soll das letzte Element gelöscht werden.

Im Folgenden nun der Code dazu. Zu beachten ist noch, dass es sich um eine threadsichere Klasse handelt, da die Map explizit synchronisiert wird.

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * A thread-safe LRU cache implementation based on internal LinkedHashMap.
 *
 * @author Benjamin Erb
 *
 * @param <K> Entry Key Type
 * @param <V> Entry Value Type
 */
public class LRUCache<K, V>
{
	public static final int DEFAULT_MAX_SIZE = 1000;

	private final Map<K, V> internalMap;

	public LRUCache()
	{
		this(DEFAULT_MAX_SIZE);
	}

	public LRUCache(final int maxSize)
	{
		this.internalMap = (Map<K, V>) Collections.synchronizedMap(new LinkedHashMap<K, V>(maxSize + 1, .75F, true)
		{
			private static final long serialVersionUID = 5369285290965670135L;

			@Override
			protected boolean removeEldestEntry(Map.Entry<K, V> eldest)
			{
				return size() > maxSize;
			}
		});
	}

	public V put(K key, V value)
	{
		return internalMap.put(key, value);
	}

	public V get(K key)
	{
		return internalMap.get(key);
	}

}

Mehrere Werte in Java-Methoden typsicher zurückgeben

Anders als manch andere imperative Programmiersprachen, unterstützt Java nur die Rückgabe eines Wertes bei einem Methodenaufruf. Jedoch ist es häufig interessant, mehrere Werte zurückzugeben. Grundsätzlich lassen sich hier zwei Szenarien unterscheiden. Bei der Rückgabe von mehreren gleichartigen Typen wird meist eine Klasse des Collections-Frameworks verwendet, wie zum Beispiel List oder ein Array. Manchmal will man aber auch völlig verschiedene Typen gemeinsam zurückgeben. Gängige Praxis ist es hier, ein Object-Array zurückzugeben und dann quasi beim Implementieren festzulegen, von welchem Typ die einzelnen Werte sind und entsprechen zurückzucasten. Dies ist leider weder typsicher, noch lässt sich die vorherige Festlegung im Code erzwingen. Abhilfe schafft hier eine generische Holder-Klasse, die einzelnen Werte typsicher kapselt und als einziger Rückgabewert verwendet werden kann.

Hier ein Beispiel für die Rückgabe über ein Object-Array:

private Object[] doItUnchecked()
{
	String s = "foo";
	Date d = new Date();

	return new Object[] { s, d };
}

Aufruf:

// unchecked variant: dangerous!
Object[] returnValues = t.doItUnchecked();
String s = (String) returnValues[0];
Date d = (Date) returnValues[1];

Eine generische Holderklasse (hier: immutable):

/**
 * Immutable holder type for two values.
 *
 * @author Benjamin Erb
 *
 * @param <F> type of first value
 * @param <S> type of second value
 */
public class PairHolder<F, S>
{
	private final F first;
	private final S second;

	public PairHolder(F first, S second)
	{
		this.first = first;
		this.second = second;
	}

	public F getFirst()
	{
		return first;
	}

	public S getSecond()
	{
		return second;
	}
}

Verwendung in Methode:

private PairHolder<String, Date> doItChecked()
{
	String s = "foo";
	Date d = new Date();

	return new PairHolder<String, Date>(s, d);
}

Aufruf:

// check variant: safe already at compile-time
PairHolder<String, Date> h = t.doItChecked();
String s = h.getFirst();
Date d = h.getSecond();

Die Holderklasse lässt sich auch noch beliebig erweitern, um Tripel, Quadrupel etc. zu halten. Wer für 2-Tupel keine eigene Klasse implementieren möchte, kann übrigens auf AbstractMap.SimpleEntry oder AbstractMap.SimpleImmutableEntry zurückgreifen.

Typotisch

Typotisch – 1 from David L on Vimeo.

Dieses Projekt wurde im Rahmen des Praktikums “Aesthetic Computing” geplant und umgesetzt von Nora von Egloffstein und mir. Nachfolgend mehr Informationen (siehe auch hier).
Kompletten Beitrag lesen »

SequentialMessageQueues in Java

Viele Netzwerkprotokolle teilen ihre Kommunikationsentitäten in Pakete oder Nachrichten auf. Manche Protokolle erwarten außerdem eine sequentielle Abarbeitung (z.B. TCP auf Transportebene), auch wenn die darunterliegenden Protokollschichten dass nicht unbedingt unterstützen. Für die Implementierung eines Nachrichtenpuffers für RTSP-Nachrichten, die ungeordnet ankommen können, aber sequentiell abgearbeitet werden müssen, habe ich eine entsprechende Datenstruktur in Java erstellt. RTSP-Nachrichten besitzen ein Cseq-Header-Feld, welches die einzelnen Nachrichten durchnummiert und als ordnendes Element genutzt werden kann.

Die folgende generische Implementierung erwartet, dass alle Nachrichtenelemete eindeutige und miteinander vergleichbare Identifier besitzen. Desweiteren erlaubt diese Implementierung zwar das parallele Schreiben in die Queue, allerdings sollte das Lesen durch einen einzelnen Thread realisiert werden. Ansonsten kann die Ordnung nach dem Entnehmen aus der Queue durch unterschiedlich lange Laufzeiten der Worker-Threads wieder verloren gehen. Außerdem realisiert diese Implementierung die sequentielle Ordnung eines vollständigen Nachrichtenstroms. Nachrichtenverluste oder Timeouts werden nicht behandelt. Hierfür eignen sich eher Automatic repeat request Protokolle.

Interface für MessageQueue
Eine MessageQueue bietet die grundlegenden Funktionen zum Einfügen und Entfernen von Elementen sowie Hilfsmethoden für die Größe der Queue an.

/**
 * Interface for message queues.
 *
 * @author Benjamin Erb
 *
 * @param <E>
 *            Element type
 */
public interface MessageQueue<E>
{
	/**
	 * Adds element to queue. Blocks until element can be added.
	 *
	 * @param e
	 *            new element
	 * @throws InterruptedException
	 */
	void push(E e) throws InterruptedException;

	/**
	 * Takes an element from the queue. Blocks until element becomes available.
	 *
	 * @return taken element
	 * @throws InterruptedException
	 */
	E pop() throws InterruptedException;

	/**
	 * Gets the size of the queue
	 *
	 * @return
	 */
	int size();

	/**
	 * Checks whether queue is empty or not.
	 *
	 * @return
	 */
	boolean empty();

}

Interface für speziellen Comparator
Dieses spezielel Comparator-Interface fügt Methoden hinzu für das Erfragen von vorherigen und nachfolgenden Identifiern an. Außerdem können Nachrichten, Identifier oder eine Kombination aus beidem verglichen werden.

import java.util.Comparator;

/**
 * An enhanced comparator interface for retrieving preceding and subsequent identifiers.
 *
 * @author Benjamin Erb
 *
 * @param <E> Element type
 * @param <T> Element identifier
 */
/**
 */
public interface SequentialComparator<E, T extends Comparable<T>> extends Comparator<E>
{
	/**
	 * Returns the subsequent identifier of a given entity.
	 *
	 * @param t
	 *            entity
	 * @return subsequent identifier
	 */
	T getNext(E e);

	/**
	 * Returns the preceding identifier of a given entity.
	 *
	 * @param t
	 *            entity
	 * @return preceding identifier
	 */
	T getPrevious(E e);

	/**
	 * Compares two entities.
	 *
	 * @param t1
	 *            entity 1
	 * @param t2
	 *            entity 2
	 * @return a negative integer, zero, or a positive integer as the first
	 *         argument is less than, equal to, or greater than the second.
	 */
	int compare(T t1, T t2);

	/**
	 * Compares an entity and an identifier.
	 *
	 * @param t1
	 *            entity
	 * @param e2
	 *            identifier
	 * @return a negative integer, zero, or a positive integer as the first
	 *         argument is less than, equal to, or greater than the second.
	 */
	int compare(T t1, E e2);

	/**
	 * Compares an identifier and an entity.
	 *
	 * @param e1
	 *            identifier
	 * @param t2
	 *            entity
	 * @return a negative integer, zero, or a positive integer as the first
	 *         argument is less than, equal to, or greater than the second.
	 */
	int compare(E e1, T t2);
}

SequentialMessageQueue Implementierung
Die eigentliche Queue-Implementierung greift intern auf eine PriorityBlockingQueue zurück, allerdings wird durch die Kapselung sichergestellt, dass nur das nächste zu erwartende Element entnommen werden kann.

import java.util.concurrent.PriorityBlockingQueue;

/**
 * A message queue for sequential message processing. This queue orders incoming
 * messages entities by their identifiers and outputs entites in-order. This
 * queue supports more than one writing thread. However, it is designed for one
 * reading/consuming thread in order to prevent out-of-order processing by
 * multiple threads.
 *
 * @author Benjamin Erb
 *
 * @param <E>
 *            Message entity
 * @param <T>
 *            Message identifier
 */
public class SequentialMessageQueue<E, T extends Comparable<T>> implements MessageQueue<E>
{
	/**
	 * Lock object for queueing
	 */
	private final Object lock = new Object();

	/**
	 * internal queue
	 */
	private final PriorityBlockingQueue<E> internalQueue;
	/**
	 * comparator
	 */
	private final SequentialComparator<E, T> comparator;

	/**
	 * Represents the identifier of the next expected entity
	 */
	private T expectedIdentifier;

	public SequentialMessageQueue(SequentialComparator<E, T> comparator, T initialIdentifier)
	{
		this.internalQueue = new PriorityBlockingQueue<E>(16, comparator);
		this.comparator = comparator;
		this.expectedIdentifier = initialIdentifier;
	}

	@Override
	public boolean empty()
	{
		return internalQueue.isEmpty();
	}

	@Override
	public E pop() throws InterruptedException
	{
		synchronized (lock)
		{
			E firstElement;
			while ((firstElement = internalQueue.peek()) == null || comparator.compare(firstElement, expectedIdentifier) != 0)
			{
				lock.wait();
			}
			internalQueue.remove();
			expectedIdentifier = comparator.getNext(firstElement);
			return firstElement;
		}
	}

	@Override
	public void push(E e) throws InterruptedException
	{
		synchronized (lock)
		{
			internalQueue.put(e);
			lock.notifyAll();
		}

	}

	@Override
	public int size()
	{
		return internalQueue.size();
	}

	/**
	 * Returns the used comparator
	 *
	 * @return
	 */
	protected SequentialComparator<E, T> getSequentialComparator()
	{
		return comparator;
	}

}

Schnelle Quellcode-Navigation in Eclipse

Bei der Entwicklung größerer Java-Projekte kann schnell die Übersicht verloren gehen. Zum Glück bietet Eclipse eine Vielzahl von Shortcuts und Funktionen, um sich auch noch bei einer Vielzahl von Klassen zurecht zu finden.

  • Strg + 3
    Öffnet den intelligenten Quick Access Dialog.
  • Strg + Shift + R
    Öffnet einen Schnelldialog zum Öffnen einer Ressource. Ist insbesondere hilfreich, um eine Datei mit bekanntem Dateinamen direkt zu öffnen, ohne im Package Explorer zu suchen.
  • Strg + Shift + T
    Öffnet einen Schnelldialog zum Öffnen einer Java-Ressource. In der Auswahl kann der Name der Klasse/Interface/etc. direkt eingegeben werden.
  • Strg + Linksklick auf Klassenname
    Sprung zum Quelltext der Klasse, auf die im Editor geklickt wird.
  • Strg + T
    Übersicht der Vererbungshierarchie der Klasse, die sich im Fokus des Editors befindet. Nochmaliges Drücken von Strg + T dreht die Hierarchierichtung (Superklassen/Subklassen) um.
  • Strg + O
    Übersicht der Membervariablen und Methoden der aktuellen Klasse. Nochmaliges Drücken von Strg + O zeigt zusätzlich geerbte Member an.
  • Strg + Shift + G
    Sucht nach Verwendungen der Methode im Fokus des Editors in alles Klassen der Workspaces.
  • Strg + . und Strg + '+'
    Sprung durch die Quelltextzeilen mit Warnungen
  • Strg + L
    Öffnet Dialog für einen Sprung in eine bestimmte Codezeile.
  • Strg + E
    Zeigt Liste aller offenen Editors-Tabs an und ermöglicht Direktauswahl eines offenen Editorstabs per Texteingabe.
  • Strg + Bild Auf und Strg + Bild Ab
    Springen durch die offenen Editor-Tabs.
  • Alt + ← und Alt + →
    Springen durch die Historie der geöffneten Tabs.

Statische Code-Analyse für Java mit FindBugs

findbugs1FindBugs ist ein Open-Source Tool zur statischen Quellcode-Analyse für Java. Es sucht in Java-Code nach typischen Fehlermustern – hierbei wird lediglich der Java Bytecode betrachtet, der Code wird nicht ausgeführt. Hierfür besitzt FindBugs eine reichhaltige Sammlung von typischen Bugs. Diese basieren hauptsächlich auf schwierigen Sprachfeatures (z.B. fehleranfälliger Umgang mit intrinsischen Condition Queueswait/notify/notifyAll), häufig missverstandenen API Funktionen (z.B. Start eines Threads durch Aufruf der run()-Methode anstatt start() ) und markanten Fehlern wie Typos, falschen Vergleichsoperationen (Stringvergleiche mit == anstatt equals) etc. Auch Korrektheit und Korrektheit bei nebenläufigen Programmen sowie Performance- und Sicherheitsaspekte werden beachtet. Eine komplette Liste aller bekannter Fehlermuster gibt es auf der FindBugs Bug Descriptions Seite.

Ein solches Tool kann nie sorgfältiges Design & Implementierung, noch ausgebieges Testen und Debuggen ersetzen, jedoch ist es als weiteres Werkzeug bei der Suche nach Fehlern insbesondere in größeren Projekten sehr hilfreich. Neben einer Kommandozeilenvariante und einer GUI existiert außerdem ein Eclipse-Plugin, womit sich FindBugs vollständig in Eclipse integrieren lässt. Über den Package Explorer lassen sich Analyseprozesse starten, gefunden Fehlermuster werden sowohl in einem Bux Explorer als auch inline im Editor angezeigt.

Java VisualVM

jvisualvm1Seit Version 6 Update 7 besitzt das Java Development Kit ein weiteres hilfreiches Entwicklungstool, nämlich VisualVM. Die Anwendung ermöglicht das Überwachen und Profiling laufender Java-Anwendungen (auch entfernter) virtueller Maschinen. Neben Merkmalen wie dem aktuellen Verbrauch an Speicher, der Größe des Heaps, Anzahl von Threads und geladener Klassen laufender Prozesse lassen sich zusätzlich aus einem erzeugbaren Heapdump zur Laufzeit Informationen über instanziierte Objekte erfragen, wie es vom Eclipse-Debugger bekannt ist. Auch die Garbage Collection kann hier manuell ausgelöst werden. Threads werden inklusive ihrer Zustände chronologisch visualisiert. Dies ist insbesondere beim Debugging von Anwendungen interessant, die intensiv Gebrauch von Multithreading machen. Durch die Anzeige der Zustände der Threads werden Monitore (Locks) sichtbar gemacht. Außerdem können über einen Threadump die einzelnen Callstacks der Threads inspiziert werden.

jvisualvm2Im CPU-Profiling können die Anwendungen in Echtzeit daraufhin untersucht werden, welche Methoden wie oft aufgerufen werden und wieviel CPU-Zeit sie benötigen, was bei der Suche nach möglichen Optimierungsansätzen hilfreich sein könnte. Das Memory-Profiling zeigt die Anzahl von Instanzen, den Speicherverbrauch, sowie den prozentualen Anteil am gesamten Speicherplatz von Klassen und primitiven Datentypen an sowie Informationen zur Garbage Collection.

Durch Plugins lässt sich das Programm noch um weitere Funktionen ergänzen. Entstanden ist das Projekt aus der Sun-eigenen NetBeans-IDE und basiert auch heute noch auf dessen NetBeans-RCP Framework. Zu finden ist es bei jeder JDK Installation ab 6u7 im Ordner bin/jvisualvm. Es lässt sich für ältere JDK-Versionen über einen Download von der Projektseite separat installieren .

Originalartikel: Java VisualVM

Mit Working Sets Eclipse aufräumen

Working Sets im Package ExplorerJedem Eclipse-Benutzer dürfte es bekannt vorkommen, wenn langsam die ganzen Projekte den Package Explorer füllen und dabei die Übersicht verloren geht. Natürlich besteht hier die Möglichkeit, durch verschiedene Workspaces die einzelnen Projekte oder Projektgruppen zu separieren, jedoch stellt eine Unterteilung in Workspaces eine sehr restriktive Trennung dar.
Abhilfe schaffen in Eclipse die so genannten Working Sets – wie bei allen Eclipse-Funktionen muss man halt erstmal überhaupt davon wissen. Working Sets lassen sich über New => Java => Java Working Set erstellen und erzeugen Überordner, in denen sich Projekte gruppieren lassen. Um im Package Explorer die Ansicht nach Working Sets aufzuschlüsseln, müssen diese jedoch als Top Level Elements gewählt werden.

Originalartikel: Mit Working Sets Eclipse aufräumen

ioexception.de

Benjamin Erb studiert seit 2006 Medieninformatik und interessiert sich insbesondere für Java, Web-Technologien, Ubiquitous Computing, Cloud Computing, verteilte Systeme und Informationsdesign.


Raimar Wagner studiert seit 2005 Informatik mit Anwendungsfach Medizin und interessiert sich für C++ stl, boost & Qt Programmierung, Scientific Visualization, Computer Vision und parallele Rechenkonzepte.


David Langer studiert seit 2006 Medieninformatik und interessiert sich für Web-Entwicklung, jQuery, Business Process Management und Java.


Sebastian Schimmel studiert seit 2006 Informatik mit Anwendungsfach Medizin und interessiert sich für hardwarenahe Aspekte, Robotik, webOs, C/C++ und UNIX/Linux.


Timo Müller studiert seit 2006 Medieninformatik. Er interessiert sich allen voran für Mobile and Ubiquitous Computing, systemnahe Enwticklung und verteilte Systeme, sowie Computer Vision.


Achim Strauß studiert seit 2006 Medieninformatik. Seine Interessen liegen in Themen der Mensch-Computer Interaktion sowie Webentwicklung und UNIX/Linux.


Tobias Schlecht studiert seit 2006 Medieninformatik und interessiert sich vor allem für Software Engineering, Model Driven Development, Model Driven Architecture, Requirements Engineering, Web-Technologien, UML2 und Java.


Fabian Groh studiert seit 2006 Medieninformatik. Seine Interessengebiete sind Computer Graphics, Computer Vision, Computational Photography sowie Ubiquitos Computing.

Archiv

September 2010
M D M D F S S
« Aug    
 12345
6789101112
13141516171819
20212223242526
27282930