Index: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/EventGenerator.java
===================================================================
--- trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/EventGenerator.java	(revision 51)
+++ 	(revision )
@@ -1,738 +1,0 @@
-package de.ugoe.cs.eventbench;
-
-import java.io.IOException;
-import java.security.InvalidParameterException;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Map;
-import java.util.NoSuchElementException;
-
-import org.jdom.Document;
-import org.jdom.Element;
-import org.jdom.JDOMException;
-import org.jdom.Namespace;
-import org.jdom.input.SAXBuilder;
-
-import de.ugoe.cs.eventbench.data.Event;
-import de.ugoe.cs.eventbench.data.ReplayableEvent;
-import de.ugoe.cs.eventbench.data.WindowTree;
-import de.ugoe.cs.eventbench.data.WindowTreeNode;
-import de.ugoe.cs.eventbench.data.WindowsMessage;
-import de.ugoe.cs.util.console.Console;
-
-/**
- * <p>
- * Translates sequences of windows messages into events that can be used by the
- * Logalyzer core libraries for usage analysis.
- * </p>
- * 
- * @author Steffen Herbold
- * 
- */
-public class EventGenerator {
-
-	/**
-	 * <p>
-	 * Helper method that fetches the document node of an XML file.
-	 * </p>
-	 * 
-	 * @param filename
-	 *            name of the XML file
-	 * @return the document node
-	 */
-	private static Document getDocument(String filename) {
-		SAXBuilder builder = new SAXBuilder();
-		Document doc = null;
-
-		try {
-			doc = builder.build(filename);
-			rulesNamespace = Namespace.getNamespace("ul:rules");
-		} catch (JDOMException e) {
-			System.err.println("Invalid rules file.");
-			e.printStackTrace();
-		} catch (IOException e) {
-			System.err.println("Invalid rules file.");
-			e.printStackTrace();
-		}
-
-		return doc;
-	}
-
-	/**
-	 * <p>
-	 * Name and path of the XML files containing the rules.
-	 * </p>
-	 */
-	private String rulesFile;
-
-	/**
-	 * <p>
-	 * Iterator used for the current sequence.
-	 * </p>
-	 */
-	private ListIterator<WindowsMessage> sequenceIterator;
-
-	/**
-	 * <p>
-	 * Token that is currently being generated.
-	 * </p>
-	 */
-	private ReplayableEvent<WindowsMessage> currentToken;
-
-	/**
-	 * <p>
-	 * Reference to the ul:rules namespace.
-	 * </p>
-	 */
-	private static Namespace rulesNamespace;
-
-	/**
-	 * <p>
-	 * The name of the rule that is currently being evaluated.
-	 * </p>
-	 */
-	private String currentRuleName;
-
-	/**
-	 * <p>
-	 * Internal message storage. Used to implement the
-	 * <code>{@literal <store>}</code> and <code>{@literal <storeSeq>}</code>
-	 * tags.
-	 * </p>
-	 */
-	private Map<String, Object> messageStorage;
-
-	/**
-	 * <p>
-	 * Creates a new EventGenerator. Sets "rules/rules.xml" as default file for
-	 * the rules.
-	 * </p>
-	 */
-	public EventGenerator() {
-		rulesFile = "rules/rules.xml";
-	}
-
-	/**
-	 * <p>
-	 * Tries to match the rules to the given sequence to generate an
-	 * {@link Event}.
-	 * </p>
-	 * <p>
-	 * The rules are matched the order, in which they are defined in the XML
-	 * file. Therefore, the order of the rules in the file defines priorities,
-	 * when multiple rules could be matched to the same sequence.
-	 * </p>
-	 * 
-	 * @param sequence
-	 *            sequence of message for which an event will be generated
-	 * @return event that matches the messages; null, if no rule can be matched
-	 */
-	@SuppressWarnings("unchecked")
-	public Event<WindowsMessage> generateEvent(List<WindowsMessage> sequence) {
-		Document rulesDoc = getDocument(rulesFile);
-		Element rulesRoot = rulesDoc.getRootElement();
-
-		List<Element> ruleElements = rulesRoot.getChildren("rule",
-				rulesNamespace);
-
-		boolean isMatch = false;
-
-		for (int ruleIndex = 0; ruleIndex < ruleElements.size() && !isMatch; ruleIndex++) {
-			Element currentRule = ruleElements.get(ruleIndex);
-			currentRuleName = currentRule.getAttributeValue("name");
-			currentToken = new ReplayableEvent<WindowsMessage>(currentRuleName);
-			isMatch = true;
-			messageStorage = new HashMap<String, Object>();
-			sequenceIterator = sequence.listIterator();
-			List<Element> ruleChildrenMsg = currentRule.getChildren("msg",
-					rulesNamespace);
-
-			int i = 0;
-			while (isMatch && i < ruleChildrenMsg.size()) {
-				Element messageElement = ruleChildrenMsg.get(i);
-				if ("true".equals(messageElement.getAttributeValue("multiple"))) {
-					Element nextMessageElement = null;
-					if (i + 1 < ruleChildrenMsg.size()) {
-						nextMessageElement = ruleChildrenMsg.get(i + 1);
-					}
-					try {
-						isMatch = matchMultipleMessages(messageElement,
-								nextMessageElement);
-					} catch (InvalidParameterException e) {
-						Console.printerrln(e.getMessage());
-					}
-				} else {
-					try {
-						isMatch = matchSingleMessage(messageElement);
-					} catch (InvalidParameterException e) {
-						Console.printerrln(e.getMessage());
-					}
-				}
-				i++;
-			}
-			if (isMatch) {
-				List<Element> ruleChildren = currentRule.getChildren();
-				for (Element genMsgElement : ruleChildren) {
-					if (genMsgElement.getName().equals("genMsg")) {
-						try {
-							generateReplayMessage(genMsgElement);
-						} catch (InvalidParameterException e) {
-							Console.printerrln(e.getMessage());
-							currentToken.invalidateReplay();
-						}
-					} else if (genMsgElement.getName().equals("genMsgSeq")) {
-						try {
-							generateReplaySequence(genMsgElement);
-							currentToken.invalidateReplay();
-						} catch (InvalidParameterException e) {
-							Console.printerrln(e.getMessage());
-							currentToken.invalidateReplay();
-						}
-					}
-				}
-				Element idinfoElement = currentRule.getChild("idinfo",
-						rulesNamespace);
-				if (idinfoElement != null) {
-					// cannot be empty if document is valid
-					List<Element> valueElements = idinfoElement.getChildren();
-					currentToken.setIdInfo(getTermValue(null,
-							valueElements.get(0)));
-				}
-				Console.traceln(currentRule.getAttributeValue("name")
-						+ currentToken.getIdInfo() + " matched");
-			} else {
-				currentToken = null;
-			}
-		}
-		if (!isMatch) {
-			Console.traceln("no match found for sequence: "
-					+ sequence.toString());
-		}
-		return currentToken;
-	}
-
-	private boolean createSequenceLParam(
-			List<WindowsMessage> generatedMessageSeq, boolean msgsGenerated,
-			int constMsgType, Element termElement)
-			throws NoSuchElementException {
-		Iterator<WindowsMessage> seqIterator = generatedMessageSeq.iterator();
-		if (termElement.getName().equals("seqValue")) {
-			String obj = termElement.getAttributeValue("seqObj");
-			List<WindowsMessage> seqVar = getStoredSeqVariable(obj);
-			if (msgsGenerated && seqVar.size() != generatedMessageSeq.size()) {
-				throw new InvalidParameterException(
-						"Failure generating replay sequence for rule "
-								+ currentRuleName
-								+ ": One or more of the sequence variables used to generate a sequence have different lenghts.");
-			}
-			for (WindowsMessage msg : seqVar) {
-				WindowsMessage currentSeqMsg = getCurrentSeqMsg(
-						generatedMessageSeq, msgsGenerated, constMsgType,
-						seqIterator);
-				String paramValueStr = msg.getParameter(termElement
-						.getAttributeValue("param"));
-				int paramValue = 0;
-				try {
-					paramValue = Integer.parseInt(paramValueStr);
-					currentSeqMsg.setLPARAM(paramValue);
-				} catch (NumberFormatException e) {
-					currentSeqMsg.setLPARAMasWindowDesc(paramValueStr);
-				}
-			}
-			if (seqIterator.hasNext()) {
-				// the first seq-var has a different number of elements than the
-				// current one
-				throw new NoSuchElementException();
-			}
-			msgsGenerated = true;
-		} else { // const value
-			int paramValue = Integer.parseInt(getTermValue(null, termElement));
-			while (seqIterator.hasNext()) {
-				seqIterator.next().setLPARAM(paramValue);
-			}
-		}
-		return msgsGenerated;
-	}
-
-	private boolean createSequenceTarget(
-			List<WindowsMessage> generatedMessageSeq, boolean msgsGenerated,
-			int constMsgType, Element termElement)
-			throws NoSuchElementException {
-		Iterator<WindowsMessage> seqIterator = generatedMessageSeq.iterator();
-		if (termElement.getName().equals("seqValue")) {
-			String obj = termElement.getAttributeValue("seqObj");
-			List<WindowsMessage> seqVar = getStoredSeqVariable(obj);
-			if (msgsGenerated && seqVar.size() != generatedMessageSeq.size()) {
-				throw new InvalidParameterException(
-						"Failure generating replay sequence for rule "
-								+ currentRuleName
-								+ ": One or more of the sequence variables used to generate a sequence have different lenghts.");
-			}
-			for (WindowsMessage msg : seqVar) {
-				WindowsMessage currentSeqMsg = getCurrentSeqMsg(
-						generatedMessageSeq, msgsGenerated, constMsgType,
-						seqIterator);
-				String targetString = msg.getParameter(termElement
-						.getAttributeValue("param"));
-				currentSeqMsg.setXmlWindowDescription(targetString);
-			}
-			msgsGenerated = true;
-		} else { // const value
-			throw new AssertionError("target must be a sequence variable!");
-			/*
-			 * If target would not be a variable, the message-elements could not
-			 * yet be created and the whole sequence might be broken. If this is
-			 * to be changed, createSequenceLParam and createSequenceWParam need
-			 * to be addepted, too.
-			 */
-		}
-		return msgsGenerated;
-	}
-
-	private boolean createSequenceWParam(
-			List<WindowsMessage> generatedMessageSeq, boolean msgsGenerated,
-			int constMsgType, Element termElement)
-			throws NoSuchElementException {
-		Iterator<WindowsMessage> seqIterator = generatedMessageSeq.iterator();
-		if (termElement.getName().equals("seqValue")) {
-			String obj = termElement.getAttributeValue("seqObj");
-			List<WindowsMessage> seqVar = getStoredSeqVariable(obj);
-			if (msgsGenerated && seqVar.size() != generatedMessageSeq.size()) {
-				throw new InvalidParameterException(
-						"Failure generating replay sequence for rule "
-								+ currentRuleName
-								+ ": One or more of the sequence variables used to generate a sequence have different lenghts.");
-			}
-			for (WindowsMessage msg : seqVar) {
-				WindowsMessage currentSeqMsg = getCurrentSeqMsg(
-						generatedMessageSeq, msgsGenerated, constMsgType,
-						seqIterator);
-				String paramValueStr = msg.getParameter(termElement
-						.getAttributeValue("param"));
-				int paramValue = 0;
-				try {
-					paramValue = Integer.parseInt(paramValueStr);
-					currentSeqMsg.setWPARAM(paramValue);
-				} catch (NumberFormatException e) {
-					currentSeqMsg.setWPARAMasWindowDesc(paramValueStr);
-				}
-			}
-			if (seqIterator.hasNext()) {
-				// the first seq-var has a different number of elements than the
-				// current one
-				throw new NoSuchElementException();
-			}
-			msgsGenerated = true;
-		} else { // const value
-			int paramValue = Integer.parseInt(getTermValue(null, termElement));
-			while (seqIterator.hasNext()) {
-				seqIterator.next().setWPARAM(paramValue);
-			}
-		}
-		return msgsGenerated;
-	}
-
-	@SuppressWarnings("unchecked")
-	private boolean evalEqualRestrictions(WindowsMessage currentMessage,
-			Element messageElement) {
-		boolean isMatch = true;
-		for (Element childElement : (List<Element>) messageElement.getChildren(
-				"equals", rulesNamespace)) {
-			List<Element> termElements = childElement.getChildren();
-			// the size 2 of termElements is guaranteed by the XML schema
-			String value1 = getTermValue(currentMessage, termElements.get(0));
-			String value2 = getTermValue(currentMessage, termElements.get(1));
-			if (value1 == null || value2 == null) {
-				isMatch = false;
-			} else {
-				isMatch = isMatch && value1.equals(value2);
-			}
-		}
-		for (Element childElement : (List<Element>) messageElement.getChildren(
-				"equalsSeq", rulesNamespace)) {
-			List<Element> termElements = childElement.getChildren();
-			List<String> values1 = getTermValueSeq(currentMessage,
-					termElements.get(0));
-			List<String> values2 = getTermValueSeq(currentMessage,
-					termElements.get(0));
-			if (values1 == null || values2 == null) {
-				isMatch = false;
-			} else {
-				isMatch = isMatch && values1.equals(values2);
-			}
-		}
-		return isMatch;
-	}
-
-	@SuppressWarnings("unchecked")
-	private void generateReplayMessage(Element genMsgElement) {
-		List<Element> genMsgChildren = genMsgElement.getChildren();
-		WindowsMessage generatedMessage = null;
-		if (genMsgChildren.size() == 1) { // replay stored message without
-											// change
-			String obj = genMsgChildren.get(0).getAttributeValue("obj");
-			generatedMessage = getStoredMessageVariable(null, obj);
-		} else { // generate message according to the rule
-			for (Element genMsgChild : genMsgChildren) {
-				Element termElement = (Element) genMsgChild.getChildren()
-						.get(0);
-				if (genMsgChild.getName().equals("type")) {
-					try {
-						int msgType = Integer.parseInt(getTermValue(null,
-								termElement));
-						generatedMessage = new WindowsMessage(msgType);
-					} catch (NumberFormatException e) {
-						throw new InvalidParameterException(
-								"Failure generating replay sequence for rule "
-										+ currentRuleName
-										+ ": Defined type is not an integer.");
-					}
-				} else if (genMsgChild.getName().equals("target")) {
-					String targetString = getTermValue(null, termElement);
-					generatedMessage.setXmlWindowDescription(targetString);
-				} else if (genMsgChild.getName().equals("LPARAM")) {
-					String paramValueStr = getTermValue(null, termElement);
-					long paramValue = 0;
-					Element loword = genMsgChild.getChild("LOWORD", rulesNamespace);
-					if( loword!=null ) {
-						paramValue = loHiWord(genMsgChild);
-						generatedMessage.setLPARAM(paramValue);
-					} else {
-						try {
-							paramValue = Integer.parseInt(paramValueStr);
-							generatedMessage.setLPARAM(paramValue);
-						} catch (NumberFormatException e) {
-							generatedMessage.setLPARAMasWindowDesc(paramValueStr);
-						}
-					}
-				} else if (genMsgChild.getName().equals("WPARAM")) {
-					String paramValueStr = getTermValue(null, termElement);
-					long paramValue = 0;
-					Element loword = genMsgChild.getChild("LOWORD", rulesNamespace);
-					if( loword!=null ) {
-						paramValue = loHiWord(genMsgChild);
-						generatedMessage.setWPARAM(paramValue);
-					} else {
-						try {
-							paramValue = Integer.parseInt(paramValueStr);
-							generatedMessage.setWPARAM(paramValue);
-						} catch (NumberFormatException e) {
-							generatedMessage.setWPARAMasWindowDesc(paramValueStr);
-						}
-					}
-				}
-			}
-		}
-		if (generatedMessage != null) {
-			int delay = Integer.parseInt(genMsgElement
-					.getAttributeValue("delay"));
-			generatedMessage.setDelay(delay);
-		} else {
-			currentToken.invalidateReplay();
-		}
-		currentToken.addReplayEvent(generatedMessage);
-	}
-
-	@SuppressWarnings("unchecked")
-	private void generateReplaySequence(Element genMsgElement) {
-		List<Element> genMsgSeqChildren = genMsgElement.getChildren();
-		List<WindowsMessage> generatedMessageSeq = new LinkedList<WindowsMessage>();
-		if (genMsgSeqChildren.size() == 1) {
-			String obj = genMsgSeqChildren.get(0).getAttributeValue("seqObj");
-			generatedMessageSeq = getStoredSeqVariable(obj);
-		} else {
-			boolean msgsGenerated = false;
-			int constMsgType = 0;
-			for (Element genMsgSeqChild : genMsgSeqChildren) {
-				Element termElement = (Element) genMsgSeqChild.getChildren()
-						.get(0);
-				if (genMsgSeqChild.getName().equals("type")) {
-					// note: cannot easily be extracted because of mulitple
-					// return values
-					if (termElement.getName().equals("seqValue")) {
-						String obj = termElement.getAttributeValue("seqObj");
-						List<WindowsMessage> seqVar = getStoredSeqVariable(obj);
-						for (WindowsMessage msg : seqVar) {
-							generatedMessageSeq.add(new WindowsMessage(msg
-									.getType()));
-						}
-						msgsGenerated = true;
-					} else { // constValue type
-						constMsgType = Integer.parseInt(getTermValue(null,
-								termElement));
-					}
-				} else if (genMsgSeqChild.getName().equals("target")) {
-					msgsGenerated = createSequenceTarget(generatedMessageSeq,
-							msgsGenerated, constMsgType, termElement);
-				} else if (genMsgSeqChild.getName().equals("LPARAM")) {
-					msgsGenerated = createSequenceLParam(generatedMessageSeq,
-							msgsGenerated, constMsgType, termElement);
-				} else if (genMsgSeqChild.getName().equals("WPARAM")) {
-					msgsGenerated = createSequenceWParam(generatedMessageSeq,
-							msgsGenerated, constMsgType, termElement);
-				}
-			}
-		}
-		currentToken.addReplaySequence(generatedMessageSeq);
-	}
-
-	private WindowsMessage getCurrentSeqMsg(
-			List<WindowsMessage> generatedMessageSeq, boolean msgsGenerated,
-			int constMsgType, Iterator<WindowsMessage> seqIterator) {
-		WindowsMessage currentSeqMsg = null;
-		if (msgsGenerated) {
-			currentSeqMsg = seqIterator.next();
-		} else {
-			currentSeqMsg = new WindowsMessage(constMsgType);
-			generatedMessageSeq.add(currentSeqMsg);
-		}
-		return currentSeqMsg;
-	}
-
-	private WindowsMessage getStoredMessageVariable(
-			WindowsMessage currentMessage, String obj)
-			throws InvalidParameterException {
-		WindowsMessage varMessage = null;
-		if (obj.equals("this")) {
-			if (currentMessage == null) {
-				throw new InvalidParameterException(
-						"Failure obtaining term value for rule "
-								+ currentRuleName
-								+ ": \"this\" is not a valid name for generating runtime messages.");
-			}
-			varMessage = currentMessage;
-		} else {
-			Object tmp = messageStorage.get(obj);
-			if (tmp instanceof WindowsMessage) {
-				varMessage = (WindowsMessage) tmp;
-			} else {
-				throw new InvalidParameterException(
-						"Failure obtaining term value for rule "
-								+ currentRuleName + ": No message \"" + obj
-								+ "\" stored.");
-			}
-		}
-		return varMessage;
-	}
-
-	@SuppressWarnings("unchecked")
-	private List<WindowsMessage> getStoredSeqVariable(String obj)
-			throws InvalidParameterException {
-		List<WindowsMessage> varMsgSeq = null;
-		Object tmp = messageStorage.get(obj);
-		if (tmp instanceof List<?>) {
-			varMsgSeq = (List<WindowsMessage>) tmp;
-		} else {
-			throw new InvalidParameterException(
-					"Failure obtaining term value for rule " + currentRuleName
-							+ ": No sequence \"" + obj + "\" store.");
-		}
-		return varMsgSeq;
-	}
-
-	private String getTermValue(WindowsMessage currentMessage,
-			Element termElement) {
-		String value = null;
-		WindowsMessage varMessage = null;
-		if (termElement.getName().equals("constValue")) {
-			value = termElement.getAttributeValue("value");
-		} else if (termElement.getName().equals("paramValue")) {
-			String objectName = termElement.getAttributeValue("obj");
-			varMessage = getStoredMessageVariable(currentMessage, objectName);
-			if (varMessage != null) {
-				String param = termElement.getAttributeValue("param");
-				value = varMessage.getParameter(param);
-			}
-		} else if (termElement.getName().equals("winInfoValue")) {
-			String objectName = termElement.getAttributeValue("obj");
-			varMessage = getStoredMessageVariable(currentMessage, objectName);
-			if (varMessage != null) {
-				String paramString = termElement.getAttributeValue("winParam");
-				if (paramString.equals("class")) {
-					value = varMessage.getWindowClass();
-				} else if (paramString.equals("resourceId")) {
-					value = "" + varMessage.getWindowResourceId();
-				} else if (paramString.equals("hwnd")) {
-					value = "" + varMessage.getHwnd();
-				} else if (paramString.equals("parentTarget")) {
-					String target = varMessage.getXmlWindowDescription();
-					int index = target.lastIndexOf("<");
-					if( index==0 ) {
-						Console.println("Trying to adress parent of top-level window! Replay probably invalid!");
-					}
-					value = target.substring(0, index);
-				}
-			}
-		} else if (termElement.getName().equals("msgInfoValue")) {
-			String objectName = termElement.getAttributeValue("obj");
-			varMessage = getStoredMessageVariable(currentMessage, objectName);
-			if (varMessage != null) {
-				String paramString = termElement.getAttributeValue("msgParam");
-				if (paramString.equals("type")) {
-					value = "" + varMessage.getType();
-				} else if (paramString.equals("target")) {
-					value = varMessage.getXmlWindowDescription();
-				}
-			}
-		}
-		return value;
-	}
-
-	private List<String> getTermValueSeq(WindowsMessage currentMessage,
-			Element termElement) {
-		List<String> values = new LinkedList<String>();
-		if (termElement.getName().equals("seqValue")) {
-			String obj = termElement.getAttributeValue("seqObj");
-			String param = termElement.getAttributeValue("param");
-			List<WindowsMessage> seqVar = getStoredSeqVariable(obj);
-
-			for (WindowsMessage msg : seqVar) {
-				// msg.getParameter returns null, if parameter is not found,
-				// therefore the List can contain null-values
-				values.add(msg.getParameter(param));
-			}
-		}
-		return values;
-	}
-
-	@SuppressWarnings("unchecked")
-	private void handleStorage(Element messageElement,
-			WindowsMessage currentMessage) {
-		for (Element childElement : (List<Element>) messageElement.getChildren(
-				"store", rulesNamespace)) {
-			String identifier = childElement.getAttributeValue("var");
-			messageStorage.put(identifier, currentMessage);
-			resolveHwnd(currentMessage, childElement);
-		}
-		for (Element childElement : (List<Element>) messageElement.getChildren(
-				"storeSeq", rulesNamespace)) {
-			String identifier = childElement.getAttributeValue("varSeq");
-			Object tmp = messageStorage.get(identifier);
-			List<WindowsMessage> storedSequence;
-			if (tmp == null || tmp instanceof WindowsMessage) {
-				storedSequence = new LinkedList<WindowsMessage>();
-				storedSequence.add(currentMessage);
-				messageStorage.put(identifier, storedSequence);
-			} else if (tmp instanceof List<?>) {
-				storedSequence = (List<WindowsMessage>) tmp;
-				storedSequence.add(currentMessage);
-				messageStorage.put(identifier, storedSequence);
-			}
-			resolveHwnd(currentMessage, childElement);
-		}
-	}
-
-	private boolean matchMultipleMessages(Element messageElement,
-			Element nextMessageElement) {
-		boolean isMatch = false;
-		boolean isCurrentMatch = false;
-		boolean nextMatchFound = false;
-		WindowsMessage currentMessage = null;
-		WindowsMessage nextMessage = null;
-
-		int type = Integer.parseInt(messageElement.getAttributeValue("type"));
-
-		int nextType = -1;
-		if (nextMessageElement != null) {
-			nextType = Integer.parseInt(nextMessageElement
-					.getAttributeValue("type"));
-		}
-
-		while (!nextMatchFound && sequenceIterator.hasNext()) {
-			currentMessage = sequenceIterator.next();
-			if (type == currentMessage.getType()) {
-				isCurrentMatch = evalEqualRestrictions(currentMessage,
-						messageElement);
-				isMatch = isMatch || isCurrentMatch;
-
-				if (isCurrentMatch) {
-					handleStorage(messageElement, currentMessage);
-					currentToken.setTarget(currentMessage
-							.getXmlWindowDescription());
-					currentToken
-							.setTargetShort(currentMessage.getParentNames());
-				}
-			}
-			if (nextMessageElement != null && isMatch) {
-				// peek next message to check if the sequence ends and the next
-				// match is found
-				if (!sequenceIterator.hasNext()) {
-					return false; // sequence is over, but not all messages are
-									// found
-				}
-				nextMessage = sequenceIterator.next();
-				sequenceIterator.previous();
-
-				if (nextType == nextMessage.getType()) {
-					nextMatchFound = evalEqualRestrictions(nextMessage,
-							nextMessageElement);
-				}
-
-			}
-		}
-
-		return isMatch;
-	}
-
-	private boolean matchSingleMessage(Element messageElement) {
-		boolean isMatch = false;
-		WindowsMessage currentMessage = null;
-
-		int type = Integer.parseInt(messageElement.getAttributeValue("type"));
-
-		while (!isMatch && sequenceIterator.hasNext()) {
-			// traverses the messages from the current position forward till a
-			// message with the correct type is found
-			currentMessage = sequenceIterator.next();
-			if (type == currentMessage.getType()) {
-				// message with the correct type found
-				// eval child nodes for further matching/storing
-				isMatch = evalEqualRestrictions(currentMessage, messageElement);
-
-				// in case the message is a match, eval storage children
-				if (isMatch) {
-					handleStorage(messageElement, currentMessage);
-					currentToken.setTarget(currentMessage
-							.getXmlWindowDescription());
-					currentToken
-							.setTargetShort(currentMessage.getParentNames());
-				}
-			}
-		}
-
-		return isMatch;
-	}
-
-	@SuppressWarnings("unchecked")
-	private void resolveHwnd(WindowsMessage currentMessage, Element childElement) {
-		List<Element> resolveElements = childElement.getChildren("resolveHwnd",
-				rulesNamespace);
-		for (Element resolveElement : resolveElements) {
-			String param = resolveElement.getAttributeValue("param");
-			String storeParam = resolveElement.getAttributeValue("storeParam");
-			int paramHwnd = Integer
-					.parseInt(currentMessage.getParameter(param));
-			WindowTreeNode node = WindowTree.getInstance().find(paramHwnd);
-			if (node != null) {
-				currentMessage.addParameter(storeParam,
-						node.xmlRepresentation());
-			}
-		}
-	}
-	
-	private long loHiWord(Element param) {
-		Element loword = param.getChild("LOWORD", rulesNamespace);
-		Element hiword = param.getChild("HIWORD", rulesNamespace);
-		String lowordStr = getTermValue(null, (Element) loword.getChildren().get(0));
-		String hiwordStr = getTermValue(null, (Element) hiword.getChildren().get(0));
-		return MAKEPARAM(Short.parseShort(lowordStr), Short.parseShort(hiwordStr));
-	}
-	
-	private static int MAKEPARAM(short loword, short hiword) {
-		return loword| ((int) hiword) << Short.SIZE;
-	}
-
-}
Index: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/LogParser.java
===================================================================
--- trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/LogParser.java	(revision 51)
+++ 	(revision )
@@ -1,183 +1,0 @@
-package de.ugoe.cs.eventbench;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.UnsupportedEncodingException;
-import java.security.InvalidParameterException;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXParseException;
-import org.xml.sax.helpers.DefaultHandler;
-
-import de.ugoe.cs.eventbench.data.Event;
-import de.ugoe.cs.eventbench.data.WindowTree;
-import de.ugoe.cs.eventbench.data.WindowsMessage;
-import de.ugoe.cs.eventbench.messagehandler.HandlerCreate;
-import de.ugoe.cs.eventbench.messagehandler.HandlerDestroy;
-import de.ugoe.cs.eventbench.messagehandler.HandlerSetText;
-import de.ugoe.cs.eventbench.messagehandler.MessageHandler;
-import de.ugoe.cs.eventbench.windowsdefs.MessageDefs;
-import de.ugoe.cs.util.StringTools;
-import de.ugoe.cs.util.console.Console;
-
-public class LogParser extends DefaultHandler {
-	
-	private MessageHandler currentHandler;
-	
-	private WindowsMessage currentMessage;
-	
-	private SequenceSplitter sequenceSplitter;
-	
-	private List<List<Event<WindowsMessage>>> sequences;
-	
-	private SortedMap<Integer, Integer> typeCounter;
-	
-	private boolean countMessageOccurences;
-	
-	public LogParser() {
-		this(false);
-	}
-	
-	public LogParser(boolean countMessageOccurences) {
-		sequenceSplitter = new SequenceSplitter();
-		sequences = new LinkedList<List<Event<WindowsMessage>>>();
-		currentHandler = null;
-		this.countMessageOccurences = countMessageOccurences;
-		if( countMessageOccurences) {
-			typeCounter = new TreeMap<Integer, Integer>();
-		}
-		
-	}
-	
-	public List<List<Event<WindowsMessage>>> getSequences() {
-		return sequences;
-	}
-	
-	@Override
-	public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
-		if( qName.equals("session") ) {
-			Console.traceln("start of session");
-			sequenceSplitter = new SequenceSplitter();
-		}
-		else if( qName.equals("msg") ) {
-			String msgType = atts.getValue("type");
-			int msgInt = -1;
-			try {
-				msgInt = Integer.parseInt(msgType);
-				
-				if( countMessageOccurences ) {
-					Integer currentCount = typeCounter.get(msgInt);
-					if( currentCount==null ) {
-						typeCounter.put(msgInt, 1);
-					} else {
-						typeCounter.put(msgInt, currentCount+1);
-					}
-				}
-				
-				if( msgInt==MessageDefs.WM_CREATE ) {
-					currentHandler = new HandlerCreate();
-					currentHandler.onStartElement();
-				}
-				else if( msgInt==MessageDefs.WM_DESTROY ) {
-					currentHandler = new HandlerDestroy();
-					currentHandler.onStartElement();
-				}
-				else if( msgInt==MessageDefs.WM_SETTEXT ) {
-					currentHandler = new HandlerSetText();
-					currentHandler.onStartElement();
-				} else {
-					currentMessage = new WindowsMessage(msgInt);
-				}
-			} catch(NumberFormatException e) {
-				Console.printerrln("Invalid message type: type not a number");
-				e.printStackTrace();
-			}
-		}
-		else if( qName.equals("param") ) {
-			if( currentHandler!=null ) {
-				currentHandler.onParameter(atts.getValue("name"), atts.getValue("value"));
-			} else {
-				currentMessage.addParameter(atts.getValue("name"), atts.getValue("value"));
-			}
-		}
-	}
-	
-	@Override
-	public void endElement(String uri, String localName, String qName) throws SAXException {
-		if( qName.equals("msg") ) {
-			if( currentHandler!=null ) {
-				currentHandler.onEndElement();
-				currentHandler = null;
-			} else {
-				try {
-					currentMessage.setTarget(WindowTree.getInstance());
-					sequenceSplitter.addMessage(currentMessage);
-				} catch (InvalidParameterException e) {
-					Console.traceln(e.getMessage() + " WindowsMessage " + currentMessage + " ignored.");
-				}				
-			}
-		}
-		else if(qName.equals("session")) {
-			sequenceSplitter.endSession();
-			sequences.add(sequenceSplitter.getSequence());
-			Console.traceln("end of session");
-		}
-	}
-	
-	public void parseFile(String filename) {
-		if( filename==null ) {
-			throw new InvalidParameterException("filename must not be null");
-		}
-		
-		SAXParserFactory spf = SAXParserFactory.newInstance();
-		spf.setValidating(true);
-		
-		SAXParser saxParser = null;
-		InputSource inputSource = null;
-		try {
-			saxParser = spf.newSAXParser();
-			inputSource = new InputSource(new InputStreamReader(new FileInputStream(filename), "UTF-16"));
-		} catch (UnsupportedEncodingException e) {
-			e.printStackTrace();
-		} catch (ParserConfigurationException e) {
-			e.printStackTrace();
-		} catch (SAXException e) {
-			e.printStackTrace();
-		} catch (FileNotFoundException e) {
-			e.printStackTrace();
-		}
-		if( inputSource!=null ) {
-	        inputSource.setSystemId("file://" + new File(filename).getAbsolutePath());
-	        try {
-	        	if( saxParser==null) {
-	        		throw new RuntimeException("SAXParser creation failed");
-	        	}
-				saxParser.parse(inputSource, this);
-	        } catch (SAXParseException e) {
-	        	Console.printerrln("Failure parsing file in line " + e.getLineNumber() + ", column " + e.getColumnNumber() +".");
-	        	e.printStackTrace();
-			} catch (SAXException e) {
-				e.printStackTrace();
-			} catch (IOException e) {
-				e.printStackTrace();
-			}
-		}
-		if( countMessageOccurences ) {
-			Console.println("Message statistics:");
-			Console.println(typeCounter.toString().replace(" ", StringTools.ENDLINE).replaceAll("[\\{\\}]",""));
-		}
-	}
-}
Index: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/LogPreprocessor.java
===================================================================
--- trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/LogPreprocessor.java	(revision 51)
+++ 	(revision )
@@ -1,128 +1,0 @@
-package de.ugoe.cs.eventbench;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-
-import org.apache.commons.codec.binary.Base64;
-
-import de.ugoe.cs.util.StringTools;
-import de.ugoe.cs.util.console.Console;
-
-public class LogPreprocessor {
-	
-	private boolean sessionOpen = false;
-	private boolean msgIncomplete = false;
-	
-	private boolean base64;
-	
-	public LogPreprocessor() {
-		this(false);
-	}
-	
-	public LogPreprocessor(boolean base64) {
-		this.base64 = base64;
-	}
-	
-	public void convertToXml(String source, String target) throws IOException, FileNotFoundException {
-		OutputStreamWriter targetFile = new OutputStreamWriter(new FileOutputStream(target), "UTF-16");
-		targetFile.write("<?xml version=\"1.0\" encoding=\"UTF-16\"?>" + StringTools.ENDLINE);
-		targetFile.write("<log>" + StringTools.ENDLINE);
-		processFile(source, targetFile);
-		if( sessionOpen ) {
-			targetFile.write(" </session>" + StringTools.ENDLINE);
-		}
-		targetFile.write("</log>");
-		targetFile.close();
-	}
-	
-	
-	public void convertDirToXml(String path, String target) throws IOException, FileNotFoundException {
-		OutputStreamWriter targetFile = new OutputStreamWriter(new FileOutputStream(target), "UTF-16");
-		targetFile.write("<?xml version=\"1.0\" encoding=\"UTF-16\"?>" + StringTools.ENDLINE);
-		targetFile.write("<log>" + StringTools.ENDLINE);
-		File folder = new File(path);
-		if( !folder.isDirectory() ) {
-			throw new IOException(path + " is not a directory");
-		}
-		String absolutPath = folder.getAbsolutePath();
-		for( String filename : folder.list() ) {
-			String source = absolutPath + "/" + filename;
-			Console.traceln("Processing file: " + source);
-			processFile(source, targetFile);
-		}
-		
-		if( sessionOpen ) {
-			targetFile.write(" </session>" + StringTools.ENDLINE);
-		}
-		targetFile.write("</log>");
-		targetFile.close();
-	}
-
-	private void processFile(String source, OutputStreamWriter targetFile)
-			throws FileNotFoundException, IOException {
-		File f = new File(source);
-		FileReader reader = new FileReader(f);
-		char[] buffer = new char[(int) f.length()];
-		reader.read(buffer);
-		reader.close();
-		String[] lines = (new String(buffer)).split("\n");
-		String incompleteLine = "";
-		// Open source and read line by line
-		for( String currentLine : lines ) {
-			if( currentLine.contains("UL: <session>")) {
-				if( sessionOpen) {
-					targetFile.write(" </session>" + StringTools.ENDLINE);
-					targetFile.write(" <session>" + StringTools.ENDLINE);
-				} else {
-					targetFile.write(" <session>" + StringTools.ENDLINE);
-					sessionOpen = true;
-				}
-			} else if( currentLine.contains("UL: </session>")) {
-				if( sessionOpen) {
-					targetFile.write(" </session>" + StringTools.ENDLINE);
-					sessionOpen = false;
-				}
-			} else if( msgIncomplete || currentLine.contains("UL: ")) {
-				
-				String currentContent;
-				String actualLine;
-				if( msgIncomplete ) {
-					actualLine = currentLine;
-				} else {
-					String[] splitResult = currentLine.split("UL: ");
-					actualLine = splitResult[1];
-				}
-				if( base64 ) {
-					Base64 decoder = new Base64();
-					byte[] decoded = decoder.decode(actualLine);
-					currentContent = new String(decoded, "UTF-16LE");
-					currentContent = currentContent.substring(0, currentContent.length()-1);
-				} else {
-					currentContent = actualLine;
-				}
-				if( msgIncomplete ) {
-					incompleteLine += currentContent;
-					if( incompleteLine.contains("</msg>") ) {
-						msgIncomplete = false;
-						targetFile.write(incompleteLine + StringTools.ENDLINE);
-						incompleteLine = "";
-					}
-				} else {
-					if( currentContent.contains("<msg") && sessionOpen ) {
-						if( currentContent.contains("</msg>") ) {
-							targetFile.write("  " + currentContent + StringTools.ENDLINE);
-						} else {
-							msgIncomplete = true;
-							incompleteLine += currentContent;
-						}
-					}
-				}
-			}
-		}
-	}
-
-}
Index: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/Runner.java
===================================================================
--- trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/Runner.java	(revision 51)
+++ trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/Runner.java	(revision 52)
@@ -11,4 +11,5 @@
 	public static void main(String[] args) {
 		CommandExecuter.getInstance().addCommandPackage("de.ugoe.cs.eventbench.commands");
+		CommandExecuter.getInstance().addCommandPackage("de.ugoe.cs.eventbench.windows.commands");
 		CommandExecuter.getInstance().addCommandPackage("de.ugoe.cs.eventbench.web.commands");
 		TextConsole textConsole = new TextConsole();
Index: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/SequenceSplitter.java
===================================================================
--- trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/SequenceSplitter.java	(revision 51)
+++ 	(revision )
@@ -1,155 +1,0 @@
-package de.ugoe.cs.eventbench;
-
-import java.util.LinkedList;
-import java.util.List;
-
-import de.ugoe.cs.eventbench.data.Event;
-import de.ugoe.cs.eventbench.data.WindowsMessage;
-import de.ugoe.cs.eventbench.windowsdefs.MessageDefs;
-import de.ugoe.cs.util.console.Console;
-
-public class SequenceSplitter {
-
-	private List<WindowsMessage> currentSequence;
-	
-	private int openDowns;
-	
-	private boolean initMessages;
-	
-	private EventGenerator tokenGenerator;
-	
-	private List<Event<WindowsMessage>> actionSequence;
-	
-	public SequenceSplitter() {
-		currentSequence = new LinkedList<WindowsMessage>();
-		openDowns = 0;
-		initMessages = true;
-		tokenGenerator = new EventGenerator();
-		actionSequence = new LinkedList<Event<WindowsMessage>>();
-	}
-	
-	public void addMessage(WindowsMessage msg) {
-		if( startOfSequence(msg) ) {
-			if( !initMessages ) {
-				Event<WindowsMessage> currentAction = tokenGenerator.generateEvent(currentSequence);
-				if( currentAction!=null ) {
-					actionSequence.add(currentAction);
-				}
-				if( isKeyMessage(msg.getType()) && openDowns>0 ) {
-					Console.traceln("Key message found with open down mouse messages - will probabably result in a faulty sequence.");
-				}
-			} else {
-				initMessages = false;
-			}
-			currentSequence = new LinkedList<WindowsMessage>();
-		} 
-		if( isUpMessage(msg.getType()) ) {
-			if( openDowns>0 ) { 
-				openDowns--;
-			}
-		}
-		currentSequence.add(msg);
-	}
-	
-	public List<Event<WindowsMessage>> getSequence() {
-		return actionSequence;
-	}
-	
-	public void endSession() {
-		Event<WindowsMessage> currentAction = tokenGenerator.generateEvent(currentSequence);
-		if( currentAction!=null ) {
-			actionSequence.add(currentAction);
-		}
-	}
-
-	private boolean startOfSequence(WindowsMessage msg) {
-		boolean isStart = false;
-		int msgType = msg.getType();
-		if( isKeyMessage(msgType) ) {
-			isStart = true;
-		}
-		if( isDownMessage(msgType) ) {
-			openDowns++;
-			if( openDowns==1 ) {
-				isStart = true;
-			}
-		}
-		if( isDblclkMessage(msgType) ) {
-			openDowns++;
-		}
-		return isStart;
-	}
-
-	private boolean isKeyMessage(int msgType) {
-		boolean isKeyMsg = false;
-		switch (msgType) {
-			case MessageDefs.WM_KEYDOWN:
-			case MessageDefs.WM_KEYUP:
-			case MessageDefs.WM_SYSKEYDOWN:
-			case MessageDefs.WM_SYSKEYUP:
-				isKeyMsg = true;
-				break;
-			default:
-					break;
-		}
-		return isKeyMsg;
-	}
-	
-	private boolean isDownMessage(int msgType) {
-		boolean isDownMsg = false;
-		switch (msgType) {
-			case MessageDefs.WM_LBUTTONDOWN:
-			case MessageDefs.WM_RBUTTONDOWN:
-			case MessageDefs.WM_MBUTTONDOWN:
-			case MessageDefs.WM_XBUTTONDOWN:
-			case MessageDefs.WM_NCLBUTTONDOWN:
-			case MessageDefs.WM_NCRBUTTONDOWN:
-			case MessageDefs.WM_NCMBUTTONDOWN:
-			case MessageDefs.WM_NCXBUTTONDOWN:
-				isDownMsg = true;
-				break;
-			default:
-				break;
-		}
-		return isDownMsg;
-	}
-
-	private boolean isDblclkMessage(int msgType) {
-		boolean isDblclkMsg = false;
-		switch (msgType) {
-			case MessageDefs.WM_LBUTTONDBLCLK:
-			case MessageDefs.WM_RBUTTONDBLCLK:
-			case MessageDefs.WM_MBUTTONDBLCLK:
-			case MessageDefs.WM_XBUTTONDBLCLK:
-			case MessageDefs.WM_NCLBUTTONDBLCLK:
-			case MessageDefs.WM_NCRBUTTONDBLCLK:
-			case MessageDefs.WM_NCMBUTTONDBLCLK:
-			case MessageDefs.WM_NCXBUTTONDBLCLK:
-				isDblclkMsg = true;
-				break;
-			default:
-				break;
-		}
-		return isDblclkMsg;
-	}
-	
-	private boolean isUpMessage(int msgType) {
-		boolean isUpMsg = false;
-		switch (msgType) {
-			case MessageDefs.WM_LBUTTONUP:
-			case MessageDefs.WM_RBUTTONUP:
-			case MessageDefs.WM_MBUTTONUP:
-			case MessageDefs.WM_XBUTTONUP:
-			case MessageDefs.WM_NCLBUTTONUP:
-			case MessageDefs.WM_NCRBUTTONUP:
-			case MessageDefs.WM_NCMBUTTONUP:
-			case MessageDefs.WM_NCXBUTTONUP:
-				isUpMsg = true;
-				break;
-			default:
-				break;
-		}
-		return isUpMsg;
-	}
-	
-}
Index: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/commands/CMDconvertDirToXml.java
===================================================================
--- trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/commands/CMDconvertDirToXml.java	(revision 51)
+++ 	(revision )
@@ -1,41 +1,0 @@
-package de.ugoe.cs.eventbench.commands;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.security.InvalidParameterException;
-import java.util.List;
-
-import de.ugoe.cs.eventbench.LogPreprocessor;
-import de.ugoe.cs.util.console.Command;
-import de.ugoe.cs.util.console.Console;
-
-public class CMDconvertDirToXml implements Command {
-
-	@Override
-	public void help() {
-		Console.println("Usage: convertToXml <sourceFolder> <targetFile> {<base64>}");
-	}
-
-	@Override
-	public void run(List<Object> parameters) {
-		if( parameters.size() < 2 ) {
-			throw new InvalidParameterException();
-		}
-		String path = (String) parameters.get(0);
-		String target = (String) parameters.get(1);
-		boolean base64 = false;
-		if( parameters.size() == 3 ) {
-			base64 = Boolean.parseBoolean((String) parameters.get(2));
-		}
-		
-		try {
-			new LogPreprocessor(base64).convertDirToXml(path, target);
-		} catch (FileNotFoundException e) {
-			Console.println(e.getMessage());
-		} catch (IOException e) {
-			Console.println(e.getMessage());
-		}
-		
-	}
-
-}
Index: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/commands/CMDconvertToXml.java
===================================================================
--- trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/commands/CMDconvertToXml.java	(revision 51)
+++ 	(revision )
@@ -1,41 +1,0 @@
-package de.ugoe.cs.eventbench.commands;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.security.InvalidParameterException;
-import java.util.List;
-
-import de.ugoe.cs.eventbench.LogPreprocessor;
-import de.ugoe.cs.util.console.Command;
-import de.ugoe.cs.util.console.Console;
-
-public class CMDconvertToXml implements Command {
-
-	@Override
-	public void help() {
-		Console.println("Usage: convertToXml <sourceFile> <targetFile> {<base64>}");
-	}
-
-	@Override
-	public void run(List<Object> parameters) {
-		if( parameters.size() < 2 ) {
-			throw new InvalidParameterException();
-		}
-		String source = (String) parameters.get(0);
-		String target = (String) parameters.get(1);
-		boolean base64 = false;
-		if( parameters.size() == 3 ) {
-			base64 = Boolean.parseBoolean((String) parameters.get(2));
-		}
-		
-		try {
-			new LogPreprocessor(base64).convertToXml(source, target);
-		} catch (FileNotFoundException e) {
-			Console.println(e.getMessage());
-		} catch (IOException e) {
-			Console.println(e.getMessage());
-		}
-		
-	}
-
-}
Index: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/commands/CMDparseXML.java
===================================================================
--- trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/commands/CMDparseXML.java	(revision 51)
+++ 	(revision )
@@ -1,42 +1,0 @@
-package de.ugoe.cs.eventbench.commands;
-
-import java.security.InvalidParameterException;
-import java.util.List;
-
-import de.ugoe.cs.eventbench.LogParser;
-import de.ugoe.cs.eventbench.data.Event;
-import de.ugoe.cs.eventbench.data.GlobalDataContainer;
-import de.ugoe.cs.eventbench.data.WindowsMessage;
-import de.ugoe.cs.util.console.Command;
-import de.ugoe.cs.util.console.Console;
-
-public class CMDparseXML implements Command {
-
-	@Override
-	public void help() {
-		Console.println("Usage: parseXML <filename> {<countMessageOccurences}");
-	}
-
-	@Override
-	public void run(List<Object> parameters) {
-		String filename;
-		boolean countMessageOccurences = false;
-		
-		try {
-			filename = (String) parameters.get(0);
-			if( parameters.size()==2 ) {
-				countMessageOccurences = Boolean.parseBoolean((String) parameters.get(1));
-			}
-		} catch (Exception e) {
-			throw new InvalidParameterException();
-		}
-		
-		LogParser parser = new LogParser(countMessageOccurences);
-		parser.parseFile(filename);
-		
-		List<List<Event<WindowsMessage>>> sequences = parser.getSequences();
-		
-		GlobalDataContainer.getInstance().addData("sequences", sequences);		
-	}
-
-}
Index: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/data/WindowTree.java
===================================================================
--- trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/data/WindowTree.java	(revision 51)
+++ 	(revision )
@@ -1,163 +1,0 @@
-package de.ugoe.cs.eventbench.data;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * <p>
- * This class provides an the interfaces for window trees.
- * </p>
- * <p>
- * The window tree represents the hierarchical structure of the windows
- * "as it is" currently during a session. It may change during the session due
- * to creation and destruction of windows.
- * </p>
- * <p>
- * The class is implemented as a singleton. The rational behind implementing
- * this class as a singleton is to ease the access of all class that may request
- * information about the windows during the parsing of a session. As the tree
- * may change during the session, it does not make sense to preserve it after a
- * session. Thus, it can just be deleted. Therefore, as long as only one session
- * is parsed at a time, a single instance is sufficient.
- * </p>
- * 
- * @author Steffen Herbold
- */
-public class WindowTree {
-
-	/**
-	 * <p>
-	 * Handle to the window instance.
-	 * </p>
-	 */
-	private static WindowTree theInstance = null;
-
-	/**
-	 * <p>
-	 * Obtain a handle to the window instance.
-	 * </p>
-	 * 
-	 * @return
-	 */
-	public static WindowTree getInstance() {
-		if (theInstance == null) {
-			theInstance = new WindowTree();
-		}
-		return theInstance;
-	}
-
-	/**
-	 * <p>
-	 * Resets the tree. Should be used between sessions.
-	 * </p>
-	 */
-	public static void resetTree() {
-		theInstance = null;
-	}
-
-	/**
-	 * <p>
-	 * Map of all windows that are part of the tree for efficient searching. The
-	 * keys of the map are the hwnd's of the windows.
-	 * </p>
-	 */
-	private Map<Integer, WindowTreeNode> nodes;
-
-	/**
-	 * <p>
-	 * Creates a new WindowTree.
-	 * </p>
-	 * <p>
-	 * Private, as the class is a singleton.
-	 * </p>
-	 */
-	private WindowTree() {
-		nodes = new HashMap<Integer, WindowTreeNode>();
-	}
-
-	/**
-	 * <p>
-	 * Adds a new window to the tree.
-	 * </p>
-	 * 
-	 * @param parentHwnd
-	 *            hwnd of the parent window
-	 * @param childHwnd
-	 *            hwnd of the window to be created
-	 * @param childWindowName
-	 *            resource id of the window to be created
-	 * @param resourceId
-	 *            resource id of the window to be created
-	 * @param className
-	 *            class name of the window to be created
-	 */
-	public void add(int parentHwnd, int childHwnd, String childWindowName,
-			int resourceId, String className, boolean isModal) {
-		WindowTreeNode parent = nodes.get(parentHwnd);
-		WindowTreeNode child = nodes.get(childHwnd);
-		if (child == null) {
-			if (parent != null) {
-				child = parent.addChild(childHwnd, childWindowName, resourceId,
-						className, isModal);
-			} else {
-				child = new WindowTreeNode(childHwnd, null, childWindowName,
-						resourceId, className, isModal);
-			}
-			nodes.put(childHwnd, child);
-		}
-	}
-
-	/**
-	 * <p>
-	 * Removes a window (defined by its hwnd) from the tree. All children of the
-	 * window will be removed recursively.
-	 * </p>
-	 * 
-	 * @param hwnd
-	 *            hwnd of the window to be removed
-	 * @return number of windows that were removed
-	 */
-	public int remove(int hwnd) {
-		int removedCounter = 0;
-		WindowTreeNode node = nodes.get(hwnd);
-		if (node != null) {
-			List<WindowTreeNode> nodesToBeRemoved = node.remove();
-			for (int i = 0; i < nodesToBeRemoved.size(); i++) {
-				WindowTreeNode nodeToBeRemoved = nodesToBeRemoved.get(i);
-				nodesToBeRemoved.addAll(nodeToBeRemoved.getChildren());
-				nodes.remove(nodeToBeRemoved.getHwnd());
-				removedCounter++;
-			}
-			nodes.remove(hwnd);
-			removedCounter++;
-		}
-		return removedCounter;
-	}
-
-	/**
-	 * <p>
-	 * Searches the tree for a window with the specified hwnd and returns its
-	 * {@link WindowTreeNode}.
-	 * </p>
-	 * 
-	 * @param hwnd
-	 *            hwnd that is looked for
-	 * @return {@link WindowTreeNode} of the window with the given hwnd if
-	 *         found, null otherwise
-	 */
-	public WindowTreeNode find(int hwnd) {
-		return nodes.get(hwnd);
-	}
-	
-	/**
-	 * <p>
-	 * Returns the number of nodes contained in the WindowTree.
-	 * </p>
-	 * 
-	 * @return number of nodes
-	 */
-	public int size() {
-		return nodes.size();
-	}
-}
Index: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/data/WindowTreeNode.java
===================================================================
--- trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/data/WindowTreeNode.java	(revision 51)
+++ 	(revision )
@@ -1,280 +1,0 @@
-package de.ugoe.cs.eventbench.data;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import de.ugoe.cs.util.StringTools;
-
-/**
- * <p>
- * This class implements a node in the {@link WindowTree} that is maintained
- * during parsing a session.
- * </p>
- * <p>
- * The window tree is structure that contains the hierarchy of the windows of a
- * application as well as basic information about each window: the hwnd; its
- * name; its resource id; its class name.
- * </p>
- * 
- * @author Steffen Herbold
- */
-public class WindowTreeNode {
-
-	/**
-	 * <p>
-	 * Name of the window. May change over time.
-	 * </p>
-	 */
-	private String windowName;
-
-	/**
-	 * <p>
-	 * Handle of the window. Used as unique identifier during its existence.
-	 * </p>
-	 */
-	private final int hwnd;
-
-	/**
-	 * <p>
-	 * Resource id of the window.
-	 * </p>
-	 */
-	private final int resourceId;
-
-	/**
-	 * <p>
-	 * Class name of the window.
-	 * </p>
-	 */
-	private final String className;
-
-	/**
-	 * <p>
-	 * True, if the window is modal.
-	 * </p>
-	 */
-	private final boolean isModal;
-
-	/**
-	 * <p>
-	 * Parent of the window. <code>null</code> if the window has no parent.
-	 * </p>
-	 */
-	private WindowTreeNode parent;
-
-	/**
-	 * <p>
-	 * List of the windows children. May be empty.
-	 * </p>
-	 */
-	private List<WindowTreeNode> children;
-	
-	/**
-	 * <p>
-	 * Creates a new WindowTreeNode.
-	 * </p>
-	 * <p>
-	 * The constructor is protected WindowTreeNode may only be created from the
-	 * WindowTree.
-	 * </p>
-	 * 
-	 * @param hwnd
-	 *            hwnd of the window
-	 * @param parent
-	 *            reference to the parent's WindowTreeNode
-	 * @param windowName
-	 *            name of the window
-	 * @param resourceId
-	 *            resource id of the window
-	 * @param className
-	 *            class name of the window
-	 * @param isModal
-	 *            modality of the window
-	 */
-	protected WindowTreeNode(int hwnd, WindowTreeNode parent,
-			String windowName, int resourceId, String className, boolean isModal) {
-		this.hwnd = hwnd;
-		this.parent = parent;
-		this.windowName = windowName;
-		this.resourceId = resourceId;
-		this.className = className;
-		this.isModal = isModal;
-		children = new ArrayList<WindowTreeNode>();
-	}
-
-	/**
-	 * <p>
-	 * Returns a reference to the WindowTreeNode of the parent.
-	 * </p>
-	 * 
-	 * @return WindowTreeNode of the parent
-	 */
-	public WindowTreeNode getParent() {
-		return parent;
-	}
-
-	/**
-	 * <p>
-	 * Returns the list of the windows children.
-	 * </p>
-	 * 
-	 * @return list of the windows children
-	 */
-	public List<WindowTreeNode> getChildren() {
-		return children;
-	}
-
-	/**
-	 * <p>
-	 * Returns the name of the window.
-	 * </p>
-	 * 
-	 * @return name of the window
-	 */
-	public String getName() {
-		return windowName;
-	}
-
-	/**
-	 * <p>
-	 * Returns the hwnd of the window.
-	 * </p>
-	 * 
-	 * @return hwnd of the window
-	 */
-	public int getHwnd() {
-		return hwnd;
-	}
-
-	/**
-	 * <p>
-	 * Returns the resource id of the window.
-	 * </p>
-	 * 
-	 * @return resource id of the window
-	 */
-	public int getResourceId() {
-		return resourceId;
-	}
-
-	/**
-	 * <p>
-	 * Returns the class name of the window.
-	 * </p>
-	 * 
-	 * @return
-	 */
-	public String getClassName() {
-		return className;
-	}
-
-	/**
-	 * <p>
-	 * Sets the name of the window.
-	 * </p>
-	 * 
-	 * @param text
-	 *            new name of the window
-	 */
-	public void setName(String text) {
-		windowName = text;
-	}
-
-	/**
-	 * <p>
-	 * Removes a the window and all its children from the {@link WindowTree}.
-	 * </p>
-	 * 
-	 * @return list of the children of the window for further clean up.
-	 */
-	public List<WindowTreeNode> remove() {
-		if (parent != null) {
-			parent.removeChild(this);
-		}
-		return children;
-	}
-
-	/**
-	 * <p>
-	 * Removes a child window.
-	 * </p>
-	 * 
-	 * @param child
-	 *            reference to the child window to be removed
-	 */
-	public void removeChild(WindowTreeNode child) {
-		children.remove(child);
-	}
-
-	/**
-	 * <p>
-	 * Adds a new child window and creates WindowTreeNode for it.
-	 * </p>
-	 * 
-	 * @param childHwnd
-	 *            hwnd of the child window
-	 * @param childWindowName
-	 *            name of the child window
-	 * @param resourceId
-	 *            resource id of the child window
-	 * @param className
-	 *            class name of the child window
-	 * @param isModal
-	 *            modality of the child window
-	 * @return reference to the WindowTreeNode created for the child window
-	 */
-	public WindowTreeNode addChild(int childHwnd, String childWindowName,
-			int resourceId, String className, boolean isModal) {
-		WindowTreeNode child = new WindowTreeNode(childHwnd, this,
-				childWindowName, resourceId, className, isModal);
-		children.add(child);
-		return child;
-	}
-
-	/**
-	 * <p>
-	 * Returns a string identfier of the window:<br>
-	 * {@code [resourceId;"windowName";"className";modality]}
-	 * </p>
-	 * 
-	 * @return identifier string of the window
-	 */
-	@Override
-	public String toString() {
-		return "[" + resourceId + ";\"" + windowName + "\";\"" + className
-				+ "\";" + isModal + "]";
-	}
-
-	/**
-	 * <p>
-	 * Returns an XML representation of the window, including its parents. It is
-	 * defined as follows:<br>
-	 * <code>
-	 * parent#xmlRepresentation()<br>
-	 * &lt;window name="this.windowname" class="this.className" resourceId="this.resourceId" isModal="this.isModel"/&gt;
-	 * </code>
-	 * </p>
-	 * 
-	 * @return xml representation of the window
-	 */
-	public String xmlRepresentation() {
-		String xmlString = "";
-		if (parent != null) {
-			xmlString = parent.xmlRepresentation();
-		}
-		xmlString += "<window name=\"" + StringTools.xmlEntityReplacement(windowName) + "\" class=\""
-				+ StringTools.xmlEntityReplacement(className) + "\" resourceId=\"" + resourceId + "\" isModal=\""
-				+ isModal + "\"/>";
-		return xmlString;
-	}
-	
-	public String getParentNames() {
-		String parentNames = "";
-		if (parent != null ) {
-			parentNames = parent.getParentNames()+".";
-		}
-		parentNames += windowName;
-		return parentNames;
-	}
-
-}
Index: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/data/WindowsMessage.java
===================================================================
--- trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/data/WindowsMessage.java	(revision 51)
+++ 	(revision )
@@ -1,204 +1,0 @@
-package de.ugoe.cs.eventbench.data;
-
-import java.security.InvalidParameterException;
-import java.util.HashMap;
-import java.util.Map;
-
-import de.ugoe.cs.eventbench.data.IReplayable;
-import de.ugoe.cs.util.StringTools;
-
-public class WindowsMessage implements IReplayable {
-	final int type;
-	private String windowClass = "";
-	private int resourceId = 0;
-	private String xmlWindowDescription = "";
-	private String parentNames = null;
-
-	private long LPARAM = 0;
-	private long WPARAM = 0;
-
-	private String LPARAMasWindowDesc = null;
-	private String WPARAMasWindowDesc = null;
-
-	private int delay = 0;
-	
-	private Map<String, String> params = new HashMap<String, String>();
-
-	public WindowsMessage(int type) {
-		this.type = type;
-	}
-
-	public void addParameter(String type, String value) {
-		params.put(type, value);
-		if (type.equals("LPARAM")) {
-			LPARAM = Long.parseLong(value);
-		} else if (type.equals("WPARAM")) {
-			WPARAM = Long.parseLong(value);
-		}
-	}
-
-	public int getType() {
-		return type;
-	}
-
-	public String getParameter(String type) {
-		return params.get(type);
-	}
-
-	public String getWindowClass() {
-		return windowClass;
-	}
-
-	public int getHwnd() {
-		int hwnd = -1;
-		String hwndString = getParameter("window.hwnd"); // possible, as
-															// "window.hwnd" is
-															// mandatory
-		if (hwndString != null) {
-			hwnd = Integer.parseInt(hwndString);
-		}
-		return hwnd;
-	}
-
-	public int getWindowResourceId() {
-		return resourceId;
-	}
-
-	@Override
-	public boolean equals(Object other) {
-		if( other==this) {
-			return true;
-		}
-		boolean isEqual = false;
-		if (other instanceof WindowsMessage) {
-			isEqual = ((WindowsMessage) other).type == this.type
-					&& ((WindowsMessage) other).xmlWindowDescription
-							.equals(this.xmlWindowDescription)
-					&& ((WindowsMessage) other).params.equals(this.params);
-		}
-		return isEqual;
-	}
-
-	@Override
-	public int hashCode() {
-		int multiplier = 17;
-		int hash = 42;
-
-		hash = multiplier * hash + type;
-		hash = multiplier * hash + xmlWindowDescription.hashCode();
-		hash = multiplier * hash + params.hashCode();
-
-		return hash;
-	}
-
-	@Override
-	public String toString() {
-		return "msg[target=" + getParameter("window.hwnd") + ";type=" + type
-				+ "]";
-	}
-
-	public void setTarget(WindowTree windowTree)
-			throws InvalidParameterException {
-		int hwnd = Integer.parseInt(getParameter("window.hwnd"));
-		WindowTreeNode node = windowTree.find(hwnd);
-		if (node == null) {
-			throw new InvalidParameterException("No window with HWND " + hwnd
-					+ " found in window tree!");
-		} else {
-			windowClass = node.getClassName();
-			resourceId = node.getResourceId();
-			xmlWindowDescription = node.xmlRepresentation();
-			parentNames = node.getParentNames();
-		}
-	}
-
-	public void setLPARAM(long paramValue) {
-		LPARAM = paramValue;
-	}
-
-	public void setWPARAM(long paramValue) {
-		WPARAM = paramValue;
-	}
-
-	public long getLPARAM() {
-		return LPARAM;
-	}
-
-	public long getWPARAM() {
-		return WPARAM;
-	}
-
-	public void setLPARAMasWindowDesc(String windowDesc) {
-		LPARAMasWindowDesc = windowDesc;
-	}
-
-	public void setWPARAMasWindowDesc(String windowDesc) {
-		WPARAMasWindowDesc = windowDesc;
-	}
-
-	public String getLPARAMasWindowDesc() {
-		return LPARAMasWindowDesc;
-	}
-
-	public String getWPARAMasWindowDesc() {
-		return WPARAMasWindowDesc;
-	}
-
-	public String getXmlWindowDescription() {
-		return xmlWindowDescription;
-	}
-
-	public void setXmlWindowDescription(String xmlWindowDescription) {
-		this.xmlWindowDescription = xmlWindowDescription;
-	}
-
-	public int getDelay() {
-		return delay;
-	}
-
-	public void setDelay(int delay) {
-		this.delay = delay;
-	}
-
-	public String getParentNames() {
-		return parentNames;
-	}
-
-	public int getNumParams() {
-		return params.size();
-	}
-	
-	public String getReplayXml() {
-		StringBuilder currentMsgStr = new StringBuilder(400);
-		currentMsgStr.append("  <msg type=\""+type+"\" ");
-		currentMsgStr.append("LPARAM=\""+LPARAM+"\" ");
-		currentMsgStr.append("WPARAM=\""+WPARAM+"\" ");
-		currentMsgStr.append("delay=\""+delay+"\">");
-		if( LPARAMasWindowDesc!=null ) {
-			currentMsgStr.append(StringTools.ENDLINE);
-			currentMsgStr.append("   <LPARAM>");
-			currentMsgStr.append(StringTools.ENDLINE);
-			currentMsgStr.append(LPARAMasWindowDesc);
-			currentMsgStr.append(StringTools.ENDLINE);
-			currentMsgStr.append("</LPARAM>");
-		} 
-		if( WPARAMasWindowDesc!=null ) {
-			currentMsgStr.append(StringTools.ENDLINE);
-			currentMsgStr.append("   <WPARAM>");
-			currentMsgStr.append(StringTools.ENDLINE);
-			currentMsgStr.append(WPARAMasWindowDesc);
-			currentMsgStr.append(StringTools.ENDLINE);
-			currentMsgStr.append("   </WPARAM>");
-		}
-		currentMsgStr.append(StringTools.ENDLINE);
-		currentMsgStr.append(xmlWindowDescription);
-		currentMsgStr.append(StringTools.ENDLINE);
-		currentMsgStr.append("  </msg>");
-		currentMsgStr.append(StringTools.ENDLINE);
-		return currentMsgStr.toString();
-	}
-	
-	public String getTarget() {
-		return xmlWindowDescription;
-	}
-}
Index: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/messagehandler/HandlerCreate.java
===================================================================
--- trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/messagehandler/HandlerCreate.java	(revision 51)
+++ trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/messagehandler/HandlerCreate.java	(revision 52)
@@ -1,5 +1,5 @@
 package de.ugoe.cs.eventbench.messagehandler;
 
-import de.ugoe.cs.eventbench.data.WindowTree;
+import de.ugoe.cs.eventbench.windows.data.WindowTree;
 
 public class HandlerCreate extends MessageHandler {
Index: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/messagehandler/HandlerDestroy.java
===================================================================
--- trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/messagehandler/HandlerDestroy.java	(revision 51)
+++ trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/messagehandler/HandlerDestroy.java	(revision 52)
@@ -1,5 +1,5 @@
 package de.ugoe.cs.eventbench.messagehandler;
 
-import de.ugoe.cs.eventbench.data.WindowTree;
+import de.ugoe.cs.eventbench.windows.data.WindowTree;
 
 public class HandlerDestroy extends MessageHandler {
Index: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/messagehandler/HandlerSetText.java
===================================================================
--- trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/messagehandler/HandlerSetText.java	(revision 51)
+++ trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/messagehandler/HandlerSetText.java	(revision 52)
@@ -1,6 +1,6 @@
 package de.ugoe.cs.eventbench.messagehandler;
 
-import de.ugoe.cs.eventbench.data.WindowTree;
-import de.ugoe.cs.eventbench.data.WindowTreeNode;
+import de.ugoe.cs.eventbench.windows.data.WindowTree;
+import de.ugoe.cs.eventbench.windows.data.WindowTreeNode;
 
 public class HandlerSetText extends MessageHandler {
Index: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/EventGenerator.java
===================================================================
--- trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/EventGenerator.java	(revision 52)
+++ trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/EventGenerator.java	(revision 52)
@@ -0,0 +1,738 @@
+package de.ugoe.cs.eventbench.windows;
+
+import java.io.IOException;
+import java.security.InvalidParameterException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.JDOMException;
+import org.jdom.Namespace;
+import org.jdom.input.SAXBuilder;
+
+import de.ugoe.cs.eventbench.data.Event;
+import de.ugoe.cs.eventbench.data.ReplayableEvent;
+import de.ugoe.cs.eventbench.windows.data.WindowTree;
+import de.ugoe.cs.eventbench.windows.data.WindowTreeNode;
+import de.ugoe.cs.eventbench.windows.data.WindowsMessage;
+import de.ugoe.cs.util.console.Console;
+
+/**
+ * <p>
+ * Translates sequences of windows messages into events that can be used by the
+ * Logalyzer core libraries for usage analysis.
+ * </p>
+ * 
+ * @author Steffen Herbold
+ * 
+ */
+public class EventGenerator {
+
+	/**
+	 * <p>
+	 * Helper method that fetches the document node of an XML file.
+	 * </p>
+	 * 
+	 * @param filename
+	 *            name of the XML file
+	 * @return the document node
+	 */
+	private static Document getDocument(String filename) {
+		SAXBuilder builder = new SAXBuilder();
+		Document doc = null;
+
+		try {
+			doc = builder.build(filename);
+			rulesNamespace = Namespace.getNamespace("ul:rules");
+		} catch (JDOMException e) {
+			System.err.println("Invalid rules file.");
+			e.printStackTrace();
+		} catch (IOException e) {
+			System.err.println("Invalid rules file.");
+			e.printStackTrace();
+		}
+
+		return doc;
+	}
+
+	/**
+	 * <p>
+	 * Name and path of the XML files containing the rules.
+	 * </p>
+	 */
+	private String rulesFile;
+
+	/**
+	 * <p>
+	 * Iterator used for the current sequence.
+	 * </p>
+	 */
+	private ListIterator<WindowsMessage> sequenceIterator;
+
+	/**
+	 * <p>
+	 * Token that is currently being generated.
+	 * </p>
+	 */
+	private ReplayableEvent<WindowsMessage> currentToken;
+
+	/**
+	 * <p>
+	 * Reference to the ul:rules namespace.
+	 * </p>
+	 */
+	private static Namespace rulesNamespace;
+
+	/**
+	 * <p>
+	 * The name of the rule that is currently being evaluated.
+	 * </p>
+	 */
+	private String currentRuleName;
+
+	/**
+	 * <p>
+	 * Internal message storage. Used to implement the
+	 * <code>{@literal <store>}</code> and <code>{@literal <storeSeq>}</code>
+	 * tags.
+	 * </p>
+	 */
+	private Map<String, Object> messageStorage;
+
+	/**
+	 * <p>
+	 * Creates a new EventGenerator. Sets "rules/rules.xml" as default file for
+	 * the rules.
+	 * </p>
+	 */
+	public EventGenerator() {
+		rulesFile = "rules/rules.xml";
+	}
+
+	/**
+	 * <p>
+	 * Tries to match the rules to the given sequence to generate an
+	 * {@link Event}.
+	 * </p>
+	 * <p>
+	 * The rules are matched the order, in which they are defined in the XML
+	 * file. Therefore, the order of the rules in the file defines priorities,
+	 * when multiple rules could be matched to the same sequence.
+	 * </p>
+	 * 
+	 * @param sequence
+	 *            sequence of message for which an event will be generated
+	 * @return event that matches the messages; null, if no rule can be matched
+	 */
+	@SuppressWarnings("unchecked")
+	public Event<WindowsMessage> generateEvent(List<WindowsMessage> sequence) {
+		Document rulesDoc = getDocument(rulesFile);
+		Element rulesRoot = rulesDoc.getRootElement();
+
+		List<Element> ruleElements = rulesRoot.getChildren("rule",
+				rulesNamespace);
+
+		boolean isMatch = false;
+
+		for (int ruleIndex = 0; ruleIndex < ruleElements.size() && !isMatch; ruleIndex++) {
+			Element currentRule = ruleElements.get(ruleIndex);
+			currentRuleName = currentRule.getAttributeValue("name");
+			currentToken = new ReplayableEvent<WindowsMessage>(currentRuleName);
+			isMatch = true;
+			messageStorage = new HashMap<String, Object>();
+			sequenceIterator = sequence.listIterator();
+			List<Element> ruleChildrenMsg = currentRule.getChildren("msg",
+					rulesNamespace);
+
+			int i = 0;
+			while (isMatch && i < ruleChildrenMsg.size()) {
+				Element messageElement = ruleChildrenMsg.get(i);
+				if ("true".equals(messageElement.getAttributeValue("multiple"))) {
+					Element nextMessageElement = null;
+					if (i + 1 < ruleChildrenMsg.size()) {
+						nextMessageElement = ruleChildrenMsg.get(i + 1);
+					}
+					try {
+						isMatch = matchMultipleMessages(messageElement,
+								nextMessageElement);
+					} catch (InvalidParameterException e) {
+						Console.printerrln(e.getMessage());
+					}
+				} else {
+					try {
+						isMatch = matchSingleMessage(messageElement);
+					} catch (InvalidParameterException e) {
+						Console.printerrln(e.getMessage());
+					}
+				}
+				i++;
+			}
+			if (isMatch) {
+				List<Element> ruleChildren = currentRule.getChildren();
+				for (Element genMsgElement : ruleChildren) {
+					if (genMsgElement.getName().equals("genMsg")) {
+						try {
+							generateReplayMessage(genMsgElement);
+						} catch (InvalidParameterException e) {
+							Console.printerrln(e.getMessage());
+							currentToken.invalidateReplay();
+						}
+					} else if (genMsgElement.getName().equals("genMsgSeq")) {
+						try {
+							generateReplaySequence(genMsgElement);
+							currentToken.invalidateReplay();
+						} catch (InvalidParameterException e) {
+							Console.printerrln(e.getMessage());
+							currentToken.invalidateReplay();
+						}
+					}
+				}
+				Element idinfoElement = currentRule.getChild("idinfo",
+						rulesNamespace);
+				if (idinfoElement != null) {
+					// cannot be empty if document is valid
+					List<Element> valueElements = idinfoElement.getChildren();
+					currentToken.setIdInfo(getTermValue(null,
+							valueElements.get(0)));
+				}
+				Console.traceln(currentRule.getAttributeValue("name")
+						+ currentToken.getIdInfo() + " matched");
+			} else {
+				currentToken = null;
+			}
+		}
+		if (!isMatch) {
+			Console.traceln("no match found for sequence: "
+					+ sequence.toString());
+		}
+		return currentToken;
+	}
+
+	private boolean createSequenceLParam(
+			List<WindowsMessage> generatedMessageSeq, boolean msgsGenerated,
+			int constMsgType, Element termElement)
+			throws NoSuchElementException {
+		Iterator<WindowsMessage> seqIterator = generatedMessageSeq.iterator();
+		if (termElement.getName().equals("seqValue")) {
+			String obj = termElement.getAttributeValue("seqObj");
+			List<WindowsMessage> seqVar = getStoredSeqVariable(obj);
+			if (msgsGenerated && seqVar.size() != generatedMessageSeq.size()) {
+				throw new InvalidParameterException(
+						"Failure generating replay sequence for rule "
+								+ currentRuleName
+								+ ": One or more of the sequence variables used to generate a sequence have different lenghts.");
+			}
+			for (WindowsMessage msg : seqVar) {
+				WindowsMessage currentSeqMsg = getCurrentSeqMsg(
+						generatedMessageSeq, msgsGenerated, constMsgType,
+						seqIterator);
+				String paramValueStr = msg.getParameter(termElement
+						.getAttributeValue("param"));
+				int paramValue = 0;
+				try {
+					paramValue = Integer.parseInt(paramValueStr);
+					currentSeqMsg.setLPARAM(paramValue);
+				} catch (NumberFormatException e) {
+					currentSeqMsg.setLPARAMasWindowDesc(paramValueStr);
+				}
+			}
+			if (seqIterator.hasNext()) {
+				// the first seq-var has a different number of elements than the
+				// current one
+				throw new NoSuchElementException();
+			}
+			msgsGenerated = true;
+		} else { // const value
+			int paramValue = Integer.parseInt(getTermValue(null, termElement));
+			while (seqIterator.hasNext()) {
+				seqIterator.next().setLPARAM(paramValue);
+			}
+		}
+		return msgsGenerated;
+	}
+
+	private boolean createSequenceTarget(
+			List<WindowsMessage> generatedMessageSeq, boolean msgsGenerated,
+			int constMsgType, Element termElement)
+			throws NoSuchElementException {
+		Iterator<WindowsMessage> seqIterator = generatedMessageSeq.iterator();
+		if (termElement.getName().equals("seqValue")) {
+			String obj = termElement.getAttributeValue("seqObj");
+			List<WindowsMessage> seqVar = getStoredSeqVariable(obj);
+			if (msgsGenerated && seqVar.size() != generatedMessageSeq.size()) {
+				throw new InvalidParameterException(
+						"Failure generating replay sequence for rule "
+								+ currentRuleName
+								+ ": One or more of the sequence variables used to generate a sequence have different lenghts.");
+			}
+			for (WindowsMessage msg : seqVar) {
+				WindowsMessage currentSeqMsg = getCurrentSeqMsg(
+						generatedMessageSeq, msgsGenerated, constMsgType,
+						seqIterator);
+				String targetString = msg.getParameter(termElement
+						.getAttributeValue("param"));
+				currentSeqMsg.setXmlWindowDescription(targetString);
+			}
+			msgsGenerated = true;
+		} else { // const value
+			throw new AssertionError("target must be a sequence variable!");
+			/*
+			 * If target would not be a variable, the message-elements could not
+			 * yet be created and the whole sequence might be broken. If this is
+			 * to be changed, createSequenceLParam and createSequenceWParam need
+			 * to be addepted, too.
+			 */
+		}
+		return msgsGenerated;
+	}
+
+	private boolean createSequenceWParam(
+			List<WindowsMessage> generatedMessageSeq, boolean msgsGenerated,
+			int constMsgType, Element termElement)
+			throws NoSuchElementException {
+		Iterator<WindowsMessage> seqIterator = generatedMessageSeq.iterator();
+		if (termElement.getName().equals("seqValue")) {
+			String obj = termElement.getAttributeValue("seqObj");
+			List<WindowsMessage> seqVar = getStoredSeqVariable(obj);
+			if (msgsGenerated && seqVar.size() != generatedMessageSeq.size()) {
+				throw new InvalidParameterException(
+						"Failure generating replay sequence for rule "
+								+ currentRuleName
+								+ ": One or more of the sequence variables used to generate a sequence have different lenghts.");
+			}
+			for (WindowsMessage msg : seqVar) {
+				WindowsMessage currentSeqMsg = getCurrentSeqMsg(
+						generatedMessageSeq, msgsGenerated, constMsgType,
+						seqIterator);
+				String paramValueStr = msg.getParameter(termElement
+						.getAttributeValue("param"));
+				int paramValue = 0;
+				try {
+					paramValue = Integer.parseInt(paramValueStr);
+					currentSeqMsg.setWPARAM(paramValue);
+				} catch (NumberFormatException e) {
+					currentSeqMsg.setWPARAMasWindowDesc(paramValueStr);
+				}
+			}
+			if (seqIterator.hasNext()) {
+				// the first seq-var has a different number of elements than the
+				// current one
+				throw new NoSuchElementException();
+			}
+			msgsGenerated = true;
+		} else { // const value
+			int paramValue = Integer.parseInt(getTermValue(null, termElement));
+			while (seqIterator.hasNext()) {
+				seqIterator.next().setWPARAM(paramValue);
+			}
+		}
+		return msgsGenerated;
+	}
+
+	@SuppressWarnings("unchecked")
+	private boolean evalEqualRestrictions(WindowsMessage currentMessage,
+			Element messageElement) {
+		boolean isMatch = true;
+		for (Element childElement : (List<Element>) messageElement.getChildren(
+				"equals", rulesNamespace)) {
+			List<Element> termElements = childElement.getChildren();
+			// the size 2 of termElements is guaranteed by the XML schema
+			String value1 = getTermValue(currentMessage, termElements.get(0));
+			String value2 = getTermValue(currentMessage, termElements.get(1));
+			if (value1 == null || value2 == null) {
+				isMatch = false;
+			} else {
+				isMatch = isMatch && value1.equals(value2);
+			}
+		}
+		for (Element childElement : (List<Element>) messageElement.getChildren(
+				"equalsSeq", rulesNamespace)) {
+			List<Element> termElements = childElement.getChildren();
+			List<String> values1 = getTermValueSeq(currentMessage,
+					termElements.get(0));
+			List<String> values2 = getTermValueSeq(currentMessage,
+					termElements.get(0));
+			if (values1 == null || values2 == null) {
+				isMatch = false;
+			} else {
+				isMatch = isMatch && values1.equals(values2);
+			}
+		}
+		return isMatch;
+	}
+
+	@SuppressWarnings("unchecked")
+	private void generateReplayMessage(Element genMsgElement) {
+		List<Element> genMsgChildren = genMsgElement.getChildren();
+		WindowsMessage generatedMessage = null;
+		if (genMsgChildren.size() == 1) { // replay stored message without
+											// change
+			String obj = genMsgChildren.get(0).getAttributeValue("obj");
+			generatedMessage = getStoredMessageVariable(null, obj);
+		} else { // generate message according to the rule
+			for (Element genMsgChild : genMsgChildren) {
+				Element termElement = (Element) genMsgChild.getChildren()
+						.get(0);
+				if (genMsgChild.getName().equals("type")) {
+					try {
+						int msgType = Integer.parseInt(getTermValue(null,
+								termElement));
+						generatedMessage = new WindowsMessage(msgType);
+					} catch (NumberFormatException e) {
+						throw new InvalidParameterException(
+								"Failure generating replay sequence for rule "
+										+ currentRuleName
+										+ ": Defined type is not an integer.");
+					}
+				} else if (genMsgChild.getName().equals("target")) {
+					String targetString = getTermValue(null, termElement);
+					generatedMessage.setXmlWindowDescription(targetString);
+				} else if (genMsgChild.getName().equals("LPARAM")) {
+					String paramValueStr = getTermValue(null, termElement);
+					long paramValue = 0;
+					Element loword = genMsgChild.getChild("LOWORD", rulesNamespace);
+					if( loword!=null ) {
+						paramValue = loHiWord(genMsgChild);
+						generatedMessage.setLPARAM(paramValue);
+					} else {
+						try {
+							paramValue = Integer.parseInt(paramValueStr);
+							generatedMessage.setLPARAM(paramValue);
+						} catch (NumberFormatException e) {
+							generatedMessage.setLPARAMasWindowDesc(paramValueStr);
+						}
+					}
+				} else if (genMsgChild.getName().equals("WPARAM")) {
+					String paramValueStr = getTermValue(null, termElement);
+					long paramValue = 0;
+					Element loword = genMsgChild.getChild("LOWORD", rulesNamespace);
+					if( loword!=null ) {
+						paramValue = loHiWord(genMsgChild);
+						generatedMessage.setWPARAM(paramValue);
+					} else {
+						try {
+							paramValue = Integer.parseInt(paramValueStr);
+							generatedMessage.setWPARAM(paramValue);
+						} catch (NumberFormatException e) {
+							generatedMessage.setWPARAMasWindowDesc(paramValueStr);
+						}
+					}
+				}
+			}
+		}
+		if (generatedMessage != null) {
+			int delay = Integer.parseInt(genMsgElement
+					.getAttributeValue("delay"));
+			generatedMessage.setDelay(delay);
+		} else {
+			currentToken.invalidateReplay();
+		}
+		currentToken.addReplayEvent(generatedMessage);
+	}
+
+	@SuppressWarnings("unchecked")
+	private void generateReplaySequence(Element genMsgElement) {
+		List<Element> genMsgSeqChildren = genMsgElement.getChildren();
+		List<WindowsMessage> generatedMessageSeq = new LinkedList<WindowsMessage>();
+		if (genMsgSeqChildren.size() == 1) {
+			String obj = genMsgSeqChildren.get(0).getAttributeValue("seqObj");
+			generatedMessageSeq = getStoredSeqVariable(obj);
+		} else {
+			boolean msgsGenerated = false;
+			int constMsgType = 0;
+			for (Element genMsgSeqChild : genMsgSeqChildren) {
+				Element termElement = (Element) genMsgSeqChild.getChildren()
+						.get(0);
+				if (genMsgSeqChild.getName().equals("type")) {
+					// note: cannot easily be extracted because of mulitple
+					// return values
+					if (termElement.getName().equals("seqValue")) {
+						String obj = termElement.getAttributeValue("seqObj");
+						List<WindowsMessage> seqVar = getStoredSeqVariable(obj);
+						for (WindowsMessage msg : seqVar) {
+							generatedMessageSeq.add(new WindowsMessage(msg
+									.getType()));
+						}
+						msgsGenerated = true;
+					} else { // constValue type
+						constMsgType = Integer.parseInt(getTermValue(null,
+								termElement));
+					}
+				} else if (genMsgSeqChild.getName().equals("target")) {
+					msgsGenerated = createSequenceTarget(generatedMessageSeq,
+							msgsGenerated, constMsgType, termElement);
+				} else if (genMsgSeqChild.getName().equals("LPARAM")) {
+					msgsGenerated = createSequenceLParam(generatedMessageSeq,
+							msgsGenerated, constMsgType, termElement);
+				} else if (genMsgSeqChild.getName().equals("WPARAM")) {
+					msgsGenerated = createSequenceWParam(generatedMessageSeq,
+							msgsGenerated, constMsgType, termElement);
+				}
+			}
+		}
+		currentToken.addReplaySequence(generatedMessageSeq);
+	}
+
+	private WindowsMessage getCurrentSeqMsg(
+			List<WindowsMessage> generatedMessageSeq, boolean msgsGenerated,
+			int constMsgType, Iterator<WindowsMessage> seqIterator) {
+		WindowsMessage currentSeqMsg = null;
+		if (msgsGenerated) {
+			currentSeqMsg = seqIterator.next();
+		} else {
+			currentSeqMsg = new WindowsMessage(constMsgType);
+			generatedMessageSeq.add(currentSeqMsg);
+		}
+		return currentSeqMsg;
+	}
+
+	private WindowsMessage getStoredMessageVariable(
+			WindowsMessage currentMessage, String obj)
+			throws InvalidParameterException {
+		WindowsMessage varMessage = null;
+		if (obj.equals("this")) {
+			if (currentMessage == null) {
+				throw new InvalidParameterException(
+						"Failure obtaining term value for rule "
+								+ currentRuleName
+								+ ": \"this\" is not a valid name for generating runtime messages.");
+			}
+			varMessage = currentMessage;
+		} else {
+			Object tmp = messageStorage.get(obj);
+			if (tmp instanceof WindowsMessage) {
+				varMessage = (WindowsMessage) tmp;
+			} else {
+				throw new InvalidParameterException(
+						"Failure obtaining term value for rule "
+								+ currentRuleName + ": No message \"" + obj
+								+ "\" stored.");
+			}
+		}
+		return varMessage;
+	}
+
+	@SuppressWarnings("unchecked")
+	private List<WindowsMessage> getStoredSeqVariable(String obj)
+			throws InvalidParameterException {
+		List<WindowsMessage> varMsgSeq = null;
+		Object tmp = messageStorage.get(obj);
+		if (tmp instanceof List<?>) {
+			varMsgSeq = (List<WindowsMessage>) tmp;
+		} else {
+			throw new InvalidParameterException(
+					"Failure obtaining term value for rule " + currentRuleName
+							+ ": No sequence \"" + obj + "\" store.");
+		}
+		return varMsgSeq;
+	}
+
+	private String getTermValue(WindowsMessage currentMessage,
+			Element termElement) {
+		String value = null;
+		WindowsMessage varMessage = null;
+		if (termElement.getName().equals("constValue")) {
+			value = termElement.getAttributeValue("value");
+		} else if (termElement.getName().equals("paramValue")) {
+			String objectName = termElement.getAttributeValue("obj");
+			varMessage = getStoredMessageVariable(currentMessage, objectName);
+			if (varMessage != null) {
+				String param = termElement.getAttributeValue("param");
+				value = varMessage.getParameter(param);
+			}
+		} else if (termElement.getName().equals("winInfoValue")) {
+			String objectName = termElement.getAttributeValue("obj");
+			varMessage = getStoredMessageVariable(currentMessage, objectName);
+			if (varMessage != null) {
+				String paramString = termElement.getAttributeValue("winParam");
+				if (paramString.equals("class")) {
+					value = varMessage.getWindowClass();
+				} else if (paramString.equals("resourceId")) {
+					value = "" + varMessage.getWindowResourceId();
+				} else if (paramString.equals("hwnd")) {
+					value = "" + varMessage.getHwnd();
+				} else if (paramString.equals("parentTarget")) {
+					String target = varMessage.getXmlWindowDescription();
+					int index = target.lastIndexOf("<");
+					if( index==0 ) {
+						Console.println("Trying to adress parent of top-level window! Replay probably invalid!");
+					}
+					value = target.substring(0, index);
+				}
+			}
+		} else if (termElement.getName().equals("msgInfoValue")) {
+			String objectName = termElement.getAttributeValue("obj");
+			varMessage = getStoredMessageVariable(currentMessage, objectName);
+			if (varMessage != null) {
+				String paramString = termElement.getAttributeValue("msgParam");
+				if (paramString.equals("type")) {
+					value = "" + varMessage.getType();
+				} else if (paramString.equals("target")) {
+					value = varMessage.getXmlWindowDescription();
+				}
+			}
+		}
+		return value;
+	}
+
+	private List<String> getTermValueSeq(WindowsMessage currentMessage,
+			Element termElement) {
+		List<String> values = new LinkedList<String>();
+		if (termElement.getName().equals("seqValue")) {
+			String obj = termElement.getAttributeValue("seqObj");
+			String param = termElement.getAttributeValue("param");
+			List<WindowsMessage> seqVar = getStoredSeqVariable(obj);
+
+			for (WindowsMessage msg : seqVar) {
+				// msg.getParameter returns null, if parameter is not found,
+				// therefore the List can contain null-values
+				values.add(msg.getParameter(param));
+			}
+		}
+		return values;
+	}
+
+	@SuppressWarnings("unchecked")
+	private void handleStorage(Element messageElement,
+			WindowsMessage currentMessage) {
+		for (Element childElement : (List<Element>) messageElement.getChildren(
+				"store", rulesNamespace)) {
+			String identifier = childElement.getAttributeValue("var");
+			messageStorage.put(identifier, currentMessage);
+			resolveHwnd(currentMessage, childElement);
+		}
+		for (Element childElement : (List<Element>) messageElement.getChildren(
+				"storeSeq", rulesNamespace)) {
+			String identifier = childElement.getAttributeValue("varSeq");
+			Object tmp = messageStorage.get(identifier);
+			List<WindowsMessage> storedSequence;
+			if (tmp == null || tmp instanceof WindowsMessage) {
+				storedSequence = new LinkedList<WindowsMessage>();
+				storedSequence.add(currentMessage);
+				messageStorage.put(identifier, storedSequence);
+			} else if (tmp instanceof List<?>) {
+				storedSequence = (List<WindowsMessage>) tmp;
+				storedSequence.add(currentMessage);
+				messageStorage.put(identifier, storedSequence);
+			}
+			resolveHwnd(currentMessage, childElement);
+		}
+	}
+
+	private boolean matchMultipleMessages(Element messageElement,
+			Element nextMessageElement) {
+		boolean isMatch = false;
+		boolean isCurrentMatch = false;
+		boolean nextMatchFound = false;
+		WindowsMessage currentMessage = null;
+		WindowsMessage nextMessage = null;
+
+		int type = Integer.parseInt(messageElement.getAttributeValue("type"));
+
+		int nextType = -1;
+		if (nextMessageElement != null) {
+			nextType = Integer.parseInt(nextMessageElement
+					.getAttributeValue("type"));
+		}
+
+		while (!nextMatchFound && sequenceIterator.hasNext()) {
+			currentMessage = sequenceIterator.next();
+			if (type == currentMessage.getType()) {
+				isCurrentMatch = evalEqualRestrictions(currentMessage,
+						messageElement);
+				isMatch = isMatch || isCurrentMatch;
+
+				if (isCurrentMatch) {
+					handleStorage(messageElement, currentMessage);
+					currentToken.setTarget(currentMessage
+							.getXmlWindowDescription());
+					currentToken
+							.setTargetShort(currentMessage.getParentNames());
+				}
+			}
+			if (nextMessageElement != null && isMatch) {
+				// peek next message to check if the sequence ends and the next
+				// match is found
+				if (!sequenceIterator.hasNext()) {
+					return false; // sequence is over, but not all messages are
+									// found
+				}
+				nextMessage = sequenceIterator.next();
+				sequenceIterator.previous();
+
+				if (nextType == nextMessage.getType()) {
+					nextMatchFound = evalEqualRestrictions(nextMessage,
+							nextMessageElement);
+				}
+
+			}
+		}
+
+		return isMatch;
+	}
+
+	private boolean matchSingleMessage(Element messageElement) {
+		boolean isMatch = false;
+		WindowsMessage currentMessage = null;
+
+		int type = Integer.parseInt(messageElement.getAttributeValue("type"));
+
+		while (!isMatch && sequenceIterator.hasNext()) {
+			// traverses the messages from the current position forward till a
+			// message with the correct type is found
+			currentMessage = sequenceIterator.next();
+			if (type == currentMessage.getType()) {
+				// message with the correct type found
+				// eval child nodes for further matching/storing
+				isMatch = evalEqualRestrictions(currentMessage, messageElement);
+
+				// in case the message is a match, eval storage children
+				if (isMatch) {
+					handleStorage(messageElement, currentMessage);
+					currentToken.setTarget(currentMessage
+							.getXmlWindowDescription());
+					currentToken
+							.setTargetShort(currentMessage.getParentNames());
+				}
+			}
+		}
+
+		return isMatch;
+	}
+
+	@SuppressWarnings("unchecked")
+	private void resolveHwnd(WindowsMessage currentMessage, Element childElement) {
+		List<Element> resolveElements = childElement.getChildren("resolveHwnd",
+				rulesNamespace);
+		for (Element resolveElement : resolveElements) {
+			String param = resolveElement.getAttributeValue("param");
+			String storeParam = resolveElement.getAttributeValue("storeParam");
+			int paramHwnd = Integer
+					.parseInt(currentMessage.getParameter(param));
+			WindowTreeNode node = WindowTree.getInstance().find(paramHwnd);
+			if (node != null) {
+				currentMessage.addParameter(storeParam,
+						node.xmlRepresentation());
+			}
+		}
+	}
+	
+	private long loHiWord(Element param) {
+		Element loword = param.getChild("LOWORD", rulesNamespace);
+		Element hiword = param.getChild("HIWORD", rulesNamespace);
+		String lowordStr = getTermValue(null, (Element) loword.getChildren().get(0));
+		String hiwordStr = getTermValue(null, (Element) hiword.getChildren().get(0));
+		return MAKEPARAM(Short.parseShort(lowordStr), Short.parseShort(hiwordStr));
+	}
+	
+	private static int MAKEPARAM(short loword, short hiword) {
+		return loword| ((int) hiword) << Short.SIZE;
+	}
+
+}
Index: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/LogParser.java
===================================================================
--- trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/LogParser.java	(revision 52)
+++ trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/LogParser.java	(revision 52)
@@ -0,0 +1,183 @@
+package de.ugoe.cs.eventbench.windows;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.security.InvalidParameterException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import de.ugoe.cs.eventbench.data.Event;
+import de.ugoe.cs.eventbench.messagehandler.HandlerCreate;
+import de.ugoe.cs.eventbench.messagehandler.HandlerDestroy;
+import de.ugoe.cs.eventbench.messagehandler.HandlerSetText;
+import de.ugoe.cs.eventbench.messagehandler.MessageHandler;
+import de.ugoe.cs.eventbench.windows.data.WindowTree;
+import de.ugoe.cs.eventbench.windows.data.WindowsMessage;
+import de.ugoe.cs.eventbench.windowsdefs.MessageDefs;
+import de.ugoe.cs.util.StringTools;
+import de.ugoe.cs.util.console.Console;
+
+public class LogParser extends DefaultHandler {
+	
+	private MessageHandler currentHandler;
+	
+	private WindowsMessage currentMessage;
+	
+	private SequenceSplitter sequenceSplitter;
+	
+	private List<List<Event<WindowsMessage>>> sequences;
+	
+	private SortedMap<Integer, Integer> typeCounter;
+	
+	private boolean countMessageOccurences;
+	
+	public LogParser() {
+		this(false);
+	}
+	
+	public LogParser(boolean countMessageOccurences) {
+		sequenceSplitter = new SequenceSplitter();
+		sequences = new LinkedList<List<Event<WindowsMessage>>>();
+		currentHandler = null;
+		this.countMessageOccurences = countMessageOccurences;
+		if( countMessageOccurences) {
+			typeCounter = new TreeMap<Integer, Integer>();
+		}
+		
+	}
+	
+	public List<List<Event<WindowsMessage>>> getSequences() {
+		return sequences;
+	}
+	
+	@Override
+	public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
+		if( qName.equals("session") ) {
+			Console.traceln("start of session");
+			sequenceSplitter = new SequenceSplitter();
+		}
+		else if( qName.equals("msg") ) {
+			String msgType = atts.getValue("type");
+			int msgInt = -1;
+			try {
+				msgInt = Integer.parseInt(msgType);
+				
+				if( countMessageOccurences ) {
+					Integer currentCount = typeCounter.get(msgInt);
+					if( currentCount==null ) {
+						typeCounter.put(msgInt, 1);
+					} else {
+						typeCounter.put(msgInt, currentCount+1);
+					}
+				}
+				
+				if( msgInt==MessageDefs.WM_CREATE ) {
+					currentHandler = new HandlerCreate();
+					currentHandler.onStartElement();
+				}
+				else if( msgInt==MessageDefs.WM_DESTROY ) {
+					currentHandler = new HandlerDestroy();
+					currentHandler.onStartElement();
+				}
+				else if( msgInt==MessageDefs.WM_SETTEXT ) {
+					currentHandler = new HandlerSetText();
+					currentHandler.onStartElement();
+				} else {
+					currentMessage = new WindowsMessage(msgInt);
+				}
+			} catch(NumberFormatException e) {
+				Console.printerrln("Invalid message type: type not a number");
+				e.printStackTrace();
+			}
+		}
+		else if( qName.equals("param") ) {
+			if( currentHandler!=null ) {
+				currentHandler.onParameter(atts.getValue("name"), atts.getValue("value"));
+			} else {
+				currentMessage.addParameter(atts.getValue("name"), atts.getValue("value"));
+			}
+		}
+	}
+	
+	@Override
+	public void endElement(String uri, String localName, String qName) throws SAXException {
+		if( qName.equals("msg") ) {
+			if( currentHandler!=null ) {
+				currentHandler.onEndElement();
+				currentHandler = null;
+			} else {
+				try {
+					currentMessage.setTarget(WindowTree.getInstance());
+					sequenceSplitter.addMessage(currentMessage);
+				} catch (InvalidParameterException e) {
+					Console.traceln(e.getMessage() + " WindowsMessage " + currentMessage + " ignored.");
+				}				
+			}
+		}
+		else if(qName.equals("session")) {
+			sequenceSplitter.endSession();
+			sequences.add(sequenceSplitter.getSequence());
+			Console.traceln("end of session");
+		}
+	}
+	
+	public void parseFile(String filename) {
+		if( filename==null ) {
+			throw new InvalidParameterException("filename must not be null");
+		}
+		
+		SAXParserFactory spf = SAXParserFactory.newInstance();
+		spf.setValidating(true);
+		
+		SAXParser saxParser = null;
+		InputSource inputSource = null;
+		try {
+			saxParser = spf.newSAXParser();
+			inputSource = new InputSource(new InputStreamReader(new FileInputStream(filename), "UTF-16"));
+		} catch (UnsupportedEncodingException e) {
+			e.printStackTrace();
+		} catch (ParserConfigurationException e) {
+			e.printStackTrace();
+		} catch (SAXException e) {
+			e.printStackTrace();
+		} catch (FileNotFoundException e) {
+			e.printStackTrace();
+		}
+		if( inputSource!=null ) {
+	        inputSource.setSystemId("file://" + new File(filename).getAbsolutePath());
+	        try {
+	        	if( saxParser==null) {
+	        		throw new RuntimeException("SAXParser creation failed");
+	        	}
+				saxParser.parse(inputSource, this);
+	        } catch (SAXParseException e) {
+	        	Console.printerrln("Failure parsing file in line " + e.getLineNumber() + ", column " + e.getColumnNumber() +".");
+	        	e.printStackTrace();
+			} catch (SAXException e) {
+				e.printStackTrace();
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+		}
+		if( countMessageOccurences ) {
+			Console.println("Message statistics:");
+			Console.println(typeCounter.toString().replace(" ", StringTools.ENDLINE).replaceAll("[\\{\\}]",""));
+		}
+	}
+}
Index: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/LogPreprocessor.java
===================================================================
--- trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/LogPreprocessor.java	(revision 52)
+++ trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/LogPreprocessor.java	(revision 52)
@@ -0,0 +1,128 @@
+package de.ugoe.cs.eventbench.windows;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+
+import org.apache.commons.codec.binary.Base64;
+
+import de.ugoe.cs.util.StringTools;
+import de.ugoe.cs.util.console.Console;
+
+public class LogPreprocessor {
+	
+	private boolean sessionOpen = false;
+	private boolean msgIncomplete = false;
+	
+	private boolean base64;
+	
+	public LogPreprocessor() {
+		this(false);
+	}
+	
+	public LogPreprocessor(boolean base64) {
+		this.base64 = base64;
+	}
+	
+	public void convertToXml(String source, String target) throws IOException, FileNotFoundException {
+		OutputStreamWriter targetFile = new OutputStreamWriter(new FileOutputStream(target), "UTF-16");
+		targetFile.write("<?xml version=\"1.0\" encoding=\"UTF-16\"?>" + StringTools.ENDLINE);
+		targetFile.write("<log>" + StringTools.ENDLINE);
+		processFile(source, targetFile);
+		if( sessionOpen ) {
+			targetFile.write(" </session>" + StringTools.ENDLINE);
+		}
+		targetFile.write("</log>");
+		targetFile.close();
+	}
+	
+	
+	public void convertDirToXml(String path, String target) throws IOException, FileNotFoundException {
+		OutputStreamWriter targetFile = new OutputStreamWriter(new FileOutputStream(target), "UTF-16");
+		targetFile.write("<?xml version=\"1.0\" encoding=\"UTF-16\"?>" + StringTools.ENDLINE);
+		targetFile.write("<log>" + StringTools.ENDLINE);
+		File folder = new File(path);
+		if( !folder.isDirectory() ) {
+			throw new IOException(path + " is not a directory");
+		}
+		String absolutPath = folder.getAbsolutePath();
+		for( String filename : folder.list() ) {
+			String source = absolutPath + "/" + filename;
+			Console.traceln("Processing file: " + source);
+			processFile(source, targetFile);
+		}
+		
+		if( sessionOpen ) {
+			targetFile.write(" </session>" + StringTools.ENDLINE);
+		}
+		targetFile.write("</log>");
+		targetFile.close();
+	}
+
+	private void processFile(String source, OutputStreamWriter targetFile)
+			throws FileNotFoundException, IOException {
+		File f = new File(source);
+		FileReader reader = new FileReader(f);
+		char[] buffer = new char[(int) f.length()];
+		reader.read(buffer);
+		reader.close();
+		String[] lines = (new String(buffer)).split("\n");
+		String incompleteLine = "";
+		// Open source and read line by line
+		for( String currentLine : lines ) {
+			if( currentLine.contains("UL: <session>")) {
+				if( sessionOpen) {
+					targetFile.write(" </session>" + StringTools.ENDLINE);
+					targetFile.write(" <session>" + StringTools.ENDLINE);
+				} else {
+					targetFile.write(" <session>" + StringTools.ENDLINE);
+					sessionOpen = true;
+				}
+			} else if( currentLine.contains("UL: </session>")) {
+				if( sessionOpen) {
+					targetFile.write(" </session>" + StringTools.ENDLINE);
+					sessionOpen = false;
+				}
+			} else if( msgIncomplete || currentLine.contains("UL: ")) {
+				
+				String currentContent;
+				String actualLine;
+				if( msgIncomplete ) {
+					actualLine = currentLine;
+				} else {
+					String[] splitResult = currentLine.split("UL: ");
+					actualLine = splitResult[1];
+				}
+				if( base64 ) {
+					Base64 decoder = new Base64();
+					byte[] decoded = decoder.decode(actualLine);
+					currentContent = new String(decoded, "UTF-16LE");
+					currentContent = currentContent.substring(0, currentContent.length()-1);
+				} else {
+					currentContent = actualLine;
+				}
+				if( msgIncomplete ) {
+					incompleteLine += currentContent;
+					if( incompleteLine.contains("</msg>") ) {
+						msgIncomplete = false;
+						targetFile.write(incompleteLine + StringTools.ENDLINE);
+						incompleteLine = "";
+					}
+				} else {
+					if( currentContent.contains("<msg") && sessionOpen ) {
+						if( currentContent.contains("</msg>") ) {
+							targetFile.write("  " + currentContent + StringTools.ENDLINE);
+						} else {
+							msgIncomplete = true;
+							incompleteLine += currentContent;
+						}
+					}
+				}
+			}
+		}
+	}
+
+}
Index: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/SequenceSplitter.java
===================================================================
--- trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/SequenceSplitter.java	(revision 52)
+++ trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/SequenceSplitter.java	(revision 52)
@@ -0,0 +1,155 @@
+package de.ugoe.cs.eventbench.windows;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import de.ugoe.cs.eventbench.data.Event;
+import de.ugoe.cs.eventbench.windows.data.WindowsMessage;
+import de.ugoe.cs.eventbench.windowsdefs.MessageDefs;
+import de.ugoe.cs.util.console.Console;
+
+public class SequenceSplitter {
+
+	private List<WindowsMessage> currentSequence;
+	
+	private int openDowns;
+	
+	private boolean initMessages;
+	
+	private EventGenerator tokenGenerator;
+	
+	private List<Event<WindowsMessage>> actionSequence;
+	
+	public SequenceSplitter() {
+		currentSequence = new LinkedList<WindowsMessage>();
+		openDowns = 0;
+		initMessages = true;
+		tokenGenerator = new EventGenerator();
+		actionSequence = new LinkedList<Event<WindowsMessage>>();
+	}
+	
+	public void addMessage(WindowsMessage msg) {
+		if( startOfSequence(msg) ) {
+			if( !initMessages ) {
+				Event<WindowsMessage> currentAction = tokenGenerator.generateEvent(currentSequence);
+				if( currentAction!=null ) {
+					actionSequence.add(currentAction);
+				}
+				if( isKeyMessage(msg.getType()) && openDowns>0 ) {
+					Console.traceln("Key message found with open down mouse messages - will probabably result in a faulty sequence.");
+				}
+			} else {
+				initMessages = false;
+			}
+			currentSequence = new LinkedList<WindowsMessage>();
+		} 
+		if( isUpMessage(msg.getType()) ) {
+			if( openDowns>0 ) { 
+				openDowns--;
+			}
+		}
+		currentSequence.add(msg);
+	}
+	
+	public List<Event<WindowsMessage>> getSequence() {
+		return actionSequence;
+	}
+	
+	public void endSession() {
+		Event<WindowsMessage> currentAction = tokenGenerator.generateEvent(currentSequence);
+		if( currentAction!=null ) {
+			actionSequence.add(currentAction);
+		}
+	}
+
+	private boolean startOfSequence(WindowsMessage msg) {
+		boolean isStart = false;
+		int msgType = msg.getType();
+		if( isKeyMessage(msgType) ) {
+			isStart = true;
+		}
+		if( isDownMessage(msgType) ) {
+			openDowns++;
+			if( openDowns==1 ) {
+				isStart = true;
+			}
+		}
+		if( isDblclkMessage(msgType) ) {
+			openDowns++;
+		}
+		return isStart;
+	}
+
+	private boolean isKeyMessage(int msgType) {
+		boolean isKeyMsg = false;
+		switch (msgType) {
+			case MessageDefs.WM_KEYDOWN:
+			case MessageDefs.WM_KEYUP:
+			case MessageDefs.WM_SYSKEYDOWN:
+			case MessageDefs.WM_SYSKEYUP:
+				isKeyMsg = true;
+				break;
+			default:
+					break;
+		}
+		return isKeyMsg;
+	}
+	
+	private boolean isDownMessage(int msgType) {
+		boolean isDownMsg = false;
+		switch (msgType) {
+			case MessageDefs.WM_LBUTTONDOWN:
+			case MessageDefs.WM_RBUTTONDOWN:
+			case MessageDefs.WM_MBUTTONDOWN:
+			case MessageDefs.WM_XBUTTONDOWN:
+			case MessageDefs.WM_NCLBUTTONDOWN:
+			case MessageDefs.WM_NCRBUTTONDOWN:
+			case MessageDefs.WM_NCMBUTTONDOWN:
+			case MessageDefs.WM_NCXBUTTONDOWN:
+				isDownMsg = true;
+				break;
+			default:
+				break;
+		}
+		return isDownMsg;
+	}
+
+	private boolean isDblclkMessage(int msgType) {
+		boolean isDblclkMsg = false;
+		switch (msgType) {
+			case MessageDefs.WM_LBUTTONDBLCLK:
+			case MessageDefs.WM_RBUTTONDBLCLK:
+			case MessageDefs.WM_MBUTTONDBLCLK:
+			case MessageDefs.WM_XBUTTONDBLCLK:
+			case MessageDefs.WM_NCLBUTTONDBLCLK:
+			case MessageDefs.WM_NCRBUTTONDBLCLK:
+			case MessageDefs.WM_NCMBUTTONDBLCLK:
+			case MessageDefs.WM_NCXBUTTONDBLCLK:
+				isDblclkMsg = true;
+				break;
+			default:
+				break;
+		}
+		return isDblclkMsg;
+	}
+	
+	private boolean isUpMessage(int msgType) {
+		boolean isUpMsg = false;
+		switch (msgType) {
+			case MessageDefs.WM_LBUTTONUP:
+			case MessageDefs.WM_RBUTTONUP:
+			case MessageDefs.WM_MBUTTONUP:
+			case MessageDefs.WM_XBUTTONUP:
+			case MessageDefs.WM_NCLBUTTONUP:
+			case MessageDefs.WM_NCRBUTTONUP:
+			case MessageDefs.WM_NCMBUTTONUP:
+			case MessageDefs.WM_NCXBUTTONUP:
+				isUpMsg = true;
+				break;
+			default:
+				break;
+		}
+		return isUpMsg;
+	}
+	
+}
Index: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/commands/CMDconvertDirToXml.java
===================================================================
--- trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/commands/CMDconvertDirToXml.java	(revision 52)
+++ trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/commands/CMDconvertDirToXml.java	(revision 52)
@@ -0,0 +1,41 @@
+package de.ugoe.cs.eventbench.windows.commands;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.security.InvalidParameterException;
+import java.util.List;
+
+import de.ugoe.cs.eventbench.windows.LogPreprocessor;
+import de.ugoe.cs.util.console.Command;
+import de.ugoe.cs.util.console.Console;
+
+public class CMDconvertDirToXml implements Command {
+
+	@Override
+	public void help() {
+		Console.println("Usage: convertToXml <sourceFolder> <targetFile> {<base64>}");
+	}
+
+	@Override
+	public void run(List<Object> parameters) {
+		if( parameters.size() < 2 ) {
+			throw new InvalidParameterException();
+		}
+		String path = (String) parameters.get(0);
+		String target = (String) parameters.get(1);
+		boolean base64 = false;
+		if( parameters.size() == 3 ) {
+			base64 = Boolean.parseBoolean((String) parameters.get(2));
+		}
+		
+		try {
+			new LogPreprocessor(base64).convertDirToXml(path, target);
+		} catch (FileNotFoundException e) {
+			Console.println(e.getMessage());
+		} catch (IOException e) {
+			Console.println(e.getMessage());
+		}
+		
+	}
+
+}
Index: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/commands/CMDconvertToXml.java
===================================================================
--- trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/commands/CMDconvertToXml.java	(revision 52)
+++ trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/commands/CMDconvertToXml.java	(revision 52)
@@ -0,0 +1,41 @@
+package de.ugoe.cs.eventbench.windows.commands;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.security.InvalidParameterException;
+import java.util.List;
+
+import de.ugoe.cs.eventbench.windows.LogPreprocessor;
+import de.ugoe.cs.util.console.Command;
+import de.ugoe.cs.util.console.Console;
+
+public class CMDconvertToXml implements Command {
+
+	@Override
+	public void help() {
+		Console.println("Usage: convertToXml <sourceFile> <targetFile> {<base64>}");
+	}
+
+	@Override
+	public void run(List<Object> parameters) {
+		if( parameters.size() < 2 ) {
+			throw new InvalidParameterException();
+		}
+		String source = (String) parameters.get(0);
+		String target = (String) parameters.get(1);
+		boolean base64 = false;
+		if( parameters.size() == 3 ) {
+			base64 = Boolean.parseBoolean((String) parameters.get(2));
+		}
+		
+		try {
+			new LogPreprocessor(base64).convertToXml(source, target);
+		} catch (FileNotFoundException e) {
+			Console.println(e.getMessage());
+		} catch (IOException e) {
+			Console.println(e.getMessage());
+		}
+		
+	}
+
+}
Index: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/commands/CMDparseXML.java
===================================================================
--- trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/commands/CMDparseXML.java	(revision 52)
+++ trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/commands/CMDparseXML.java	(revision 52)
@@ -0,0 +1,42 @@
+package de.ugoe.cs.eventbench.windows.commands;
+
+import java.security.InvalidParameterException;
+import java.util.List;
+
+import de.ugoe.cs.eventbench.data.Event;
+import de.ugoe.cs.eventbench.data.GlobalDataContainer;
+import de.ugoe.cs.eventbench.windows.LogParser;
+import de.ugoe.cs.eventbench.windows.data.WindowsMessage;
+import de.ugoe.cs.util.console.Command;
+import de.ugoe.cs.util.console.Console;
+
+public class CMDparseXML implements Command {
+
+	@Override
+	public void help() {
+		Console.println("Usage: parseXML <filename> {<countMessageOccurences}");
+	}
+
+	@Override
+	public void run(List<Object> parameters) {
+		String filename;
+		boolean countMessageOccurences = false;
+		
+		try {
+			filename = (String) parameters.get(0);
+			if( parameters.size()==2 ) {
+				countMessageOccurences = Boolean.parseBoolean((String) parameters.get(1));
+			}
+		} catch (Exception e) {
+			throw new InvalidParameterException();
+		}
+		
+		LogParser parser = new LogParser(countMessageOccurences);
+		parser.parseFile(filename);
+		
+		List<List<Event<WindowsMessage>>> sequences = parser.getSequences();
+		
+		GlobalDataContainer.getInstance().addData("sequences", sequences);		
+	}
+
+}
Index: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/data/WindowTree.java
===================================================================
--- trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/data/WindowTree.java	(revision 52)
+++ trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/data/WindowTree.java	(revision 52)
@@ -0,0 +1,163 @@
+package de.ugoe.cs.eventbench.windows.data;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * This class provides an the interfaces for window trees.
+ * </p>
+ * <p>
+ * The window tree represents the hierarchical structure of the windows
+ * "as it is" currently during a session. It may change during the session due
+ * to creation and destruction of windows.
+ * </p>
+ * <p>
+ * The class is implemented as a singleton. The rational behind implementing
+ * this class as a singleton is to ease the access of all class that may request
+ * information about the windows during the parsing of a session. As the tree
+ * may change during the session, it does not make sense to preserve it after a
+ * session. Thus, it can just be deleted. Therefore, as long as only one session
+ * is parsed at a time, a single instance is sufficient.
+ * </p>
+ * 
+ * @author Steffen Herbold
+ */
+public class WindowTree {
+
+	/**
+	 * <p>
+	 * Handle to the window instance.
+	 * </p>
+	 */
+	private static WindowTree theInstance = null;
+
+	/**
+	 * <p>
+	 * Obtain a handle to the window instance.
+	 * </p>
+	 * 
+	 * @return
+	 */
+	public static WindowTree getInstance() {
+		if (theInstance == null) {
+			theInstance = new WindowTree();
+		}
+		return theInstance;
+	}
+
+	/**
+	 * <p>
+	 * Resets the tree. Should be used between sessions.
+	 * </p>
+	 */
+	public static void resetTree() {
+		theInstance = null;
+	}
+
+	/**
+	 * <p>
+	 * Map of all windows that are part of the tree for efficient searching. The
+	 * keys of the map are the hwnd's of the windows.
+	 * </p>
+	 */
+	private Map<Integer, WindowTreeNode> nodes;
+
+	/**
+	 * <p>
+	 * Creates a new WindowTree.
+	 * </p>
+	 * <p>
+	 * Private, as the class is a singleton.
+	 * </p>
+	 */
+	private WindowTree() {
+		nodes = new HashMap<Integer, WindowTreeNode>();
+	}
+
+	/**
+	 * <p>
+	 * Adds a new window to the tree.
+	 * </p>
+	 * 
+	 * @param parentHwnd
+	 *            hwnd of the parent window
+	 * @param childHwnd
+	 *            hwnd of the window to be created
+	 * @param childWindowName
+	 *            resource id of the window to be created
+	 * @param resourceId
+	 *            resource id of the window to be created
+	 * @param className
+	 *            class name of the window to be created
+	 */
+	public void add(int parentHwnd, int childHwnd, String childWindowName,
+			int resourceId, String className, boolean isModal) {
+		WindowTreeNode parent = nodes.get(parentHwnd);
+		WindowTreeNode child = nodes.get(childHwnd);
+		if (child == null) {
+			if (parent != null) {
+				child = parent.addChild(childHwnd, childWindowName, resourceId,
+						className, isModal);
+			} else {
+				child = new WindowTreeNode(childHwnd, null, childWindowName,
+						resourceId, className, isModal);
+			}
+			nodes.put(childHwnd, child);
+		}
+	}
+
+	/**
+	 * <p>
+	 * Removes a window (defined by its hwnd) from the tree. All children of the
+	 * window will be removed recursively.
+	 * </p>
+	 * 
+	 * @param hwnd
+	 *            hwnd of the window to be removed
+	 * @return number of windows that were removed
+	 */
+	public int remove(int hwnd) {
+		int removedCounter = 0;
+		WindowTreeNode node = nodes.get(hwnd);
+		if (node != null) {
+			List<WindowTreeNode> nodesToBeRemoved = node.remove();
+			for (int i = 0; i < nodesToBeRemoved.size(); i++) {
+				WindowTreeNode nodeToBeRemoved = nodesToBeRemoved.get(i);
+				nodesToBeRemoved.addAll(nodeToBeRemoved.getChildren());
+				nodes.remove(nodeToBeRemoved.getHwnd());
+				removedCounter++;
+			}
+			nodes.remove(hwnd);
+			removedCounter++;
+		}
+		return removedCounter;
+	}
+
+	/**
+	 * <p>
+	 * Searches the tree for a window with the specified hwnd and returns its
+	 * {@link WindowTreeNode}.
+	 * </p>
+	 * 
+	 * @param hwnd
+	 *            hwnd that is looked for
+	 * @return {@link WindowTreeNode} of the window with the given hwnd if
+	 *         found, null otherwise
+	 */
+	public WindowTreeNode find(int hwnd) {
+		return nodes.get(hwnd);
+	}
+	
+	/**
+	 * <p>
+	 * Returns the number of nodes contained in the WindowTree.
+	 * </p>
+	 * 
+	 * @return number of nodes
+	 */
+	public int size() {
+		return nodes.size();
+	}
+}
Index: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/data/WindowTreeNode.java
===================================================================
--- trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/data/WindowTreeNode.java	(revision 52)
+++ trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/data/WindowTreeNode.java	(revision 52)
@@ -0,0 +1,280 @@
+package de.ugoe.cs.eventbench.windows.data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import de.ugoe.cs.util.StringTools;
+
+/**
+ * <p>
+ * This class implements a node in the {@link WindowTree} that is maintained
+ * during parsing a session.
+ * </p>
+ * <p>
+ * The window tree is structure that contains the hierarchy of the windows of a
+ * application as well as basic information about each window: the hwnd; its
+ * name; its resource id; its class name.
+ * </p>
+ * 
+ * @author Steffen Herbold
+ */
+public class WindowTreeNode {
+
+	/**
+	 * <p>
+	 * Name of the window. May change over time.
+	 * </p>
+	 */
+	private String windowName;
+
+	/**
+	 * <p>
+	 * Handle of the window. Used as unique identifier during its existence.
+	 * </p>
+	 */
+	private final int hwnd;
+
+	/**
+	 * <p>
+	 * Resource id of the window.
+	 * </p>
+	 */
+	private final int resourceId;
+
+	/**
+	 * <p>
+	 * Class name of the window.
+	 * </p>
+	 */
+	private final String className;
+
+	/**
+	 * <p>
+	 * True, if the window is modal.
+	 * </p>
+	 */
+	private final boolean isModal;
+
+	/**
+	 * <p>
+	 * Parent of the window. <code>null</code> if the window has no parent.
+	 * </p>
+	 */
+	private WindowTreeNode parent;
+
+	/**
+	 * <p>
+	 * List of the windows children. May be empty.
+	 * </p>
+	 */
+	private List<WindowTreeNode> children;
+	
+	/**
+	 * <p>
+	 * Creates a new WindowTreeNode.
+	 * </p>
+	 * <p>
+	 * The constructor is protected WindowTreeNode may only be created from the
+	 * WindowTree.
+	 * </p>
+	 * 
+	 * @param hwnd
+	 *            hwnd of the window
+	 * @param parent
+	 *            reference to the parent's WindowTreeNode
+	 * @param windowName
+	 *            name of the window
+	 * @param resourceId
+	 *            resource id of the window
+	 * @param className
+	 *            class name of the window
+	 * @param isModal
+	 *            modality of the window
+	 */
+	protected WindowTreeNode(int hwnd, WindowTreeNode parent,
+			String windowName, int resourceId, String className, boolean isModal) {
+		this.hwnd = hwnd;
+		this.parent = parent;
+		this.windowName = windowName;
+		this.resourceId = resourceId;
+		this.className = className;
+		this.isModal = isModal;
+		children = new ArrayList<WindowTreeNode>();
+	}
+
+	/**
+	 * <p>
+	 * Returns a reference to the WindowTreeNode of the parent.
+	 * </p>
+	 * 
+	 * @return WindowTreeNode of the parent
+	 */
+	public WindowTreeNode getParent() {
+		return parent;
+	}
+
+	/**
+	 * <p>
+	 * Returns the list of the windows children.
+	 * </p>
+	 * 
+	 * @return list of the windows children
+	 */
+	public List<WindowTreeNode> getChildren() {
+		return children;
+	}
+
+	/**
+	 * <p>
+	 * Returns the name of the window.
+	 * </p>
+	 * 
+	 * @return name of the window
+	 */
+	public String getName() {
+		return windowName;
+	}
+
+	/**
+	 * <p>
+	 * Returns the hwnd of the window.
+	 * </p>
+	 * 
+	 * @return hwnd of the window
+	 */
+	public int getHwnd() {
+		return hwnd;
+	}
+
+	/**
+	 * <p>
+	 * Returns the resource id of the window.
+	 * </p>
+	 * 
+	 * @return resource id of the window
+	 */
+	public int getResourceId() {
+		return resourceId;
+	}
+
+	/**
+	 * <p>
+	 * Returns the class name of the window.
+	 * </p>
+	 * 
+	 * @return
+	 */
+	public String getClassName() {
+		return className;
+	}
+
+	/**
+	 * <p>
+	 * Sets the name of the window.
+	 * </p>
+	 * 
+	 * @param text
+	 *            new name of the window
+	 */
+	public void setName(String text) {
+		windowName = text;
+	}
+
+	/**
+	 * <p>
+	 * Removes a the window and all its children from the {@link WindowTree}.
+	 * </p>
+	 * 
+	 * @return list of the children of the window for further clean up.
+	 */
+	public List<WindowTreeNode> remove() {
+		if (parent != null) {
+			parent.removeChild(this);
+		}
+		return children;
+	}
+
+	/**
+	 * <p>
+	 * Removes a child window.
+	 * </p>
+	 * 
+	 * @param child
+	 *            reference to the child window to be removed
+	 */
+	public void removeChild(WindowTreeNode child) {
+		children.remove(child);
+	}
+
+	/**
+	 * <p>
+	 * Adds a new child window and creates WindowTreeNode for it.
+	 * </p>
+	 * 
+	 * @param childHwnd
+	 *            hwnd of the child window
+	 * @param childWindowName
+	 *            name of the child window
+	 * @param resourceId
+	 *            resource id of the child window
+	 * @param className
+	 *            class name of the child window
+	 * @param isModal
+	 *            modality of the child window
+	 * @return reference to the WindowTreeNode created for the child window
+	 */
+	public WindowTreeNode addChild(int childHwnd, String childWindowName,
+			int resourceId, String className, boolean isModal) {
+		WindowTreeNode child = new WindowTreeNode(childHwnd, this,
+				childWindowName, resourceId, className, isModal);
+		children.add(child);
+		return child;
+	}
+
+	/**
+	 * <p>
+	 * Returns a string identfier of the window:<br>
+	 * {@code [resourceId;"windowName";"className";modality]}
+	 * </p>
+	 * 
+	 * @return identifier string of the window
+	 */
+	@Override
+	public String toString() {
+		return "[" + resourceId + ";\"" + windowName + "\";\"" + className
+				+ "\";" + isModal + "]";
+	}
+
+	/**
+	 * <p>
+	 * Returns an XML representation of the window, including its parents. It is
+	 * defined as follows:<br>
+	 * <code>
+	 * parent#xmlRepresentation()<br>
+	 * &lt;window name="this.windowname" class="this.className" resourceId="this.resourceId" isModal="this.isModel"/&gt;
+	 * </code>
+	 * </p>
+	 * 
+	 * @return xml representation of the window
+	 */
+	public String xmlRepresentation() {
+		String xmlString = "";
+		if (parent != null) {
+			xmlString = parent.xmlRepresentation();
+		}
+		xmlString += "<window name=\"" + StringTools.xmlEntityReplacement(windowName) + "\" class=\""
+				+ StringTools.xmlEntityReplacement(className) + "\" resourceId=\"" + resourceId + "\" isModal=\""
+				+ isModal + "\"/>";
+		return xmlString;
+	}
+	
+	public String getParentNames() {
+		String parentNames = "";
+		if (parent != null ) {
+			parentNames = parent.getParentNames()+".";
+		}
+		parentNames += windowName;
+		return parentNames;
+	}
+
+}
Index: trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/data/WindowsMessage.java
===================================================================
--- trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/data/WindowsMessage.java	(revision 52)
+++ trunk/EventBenchConsole/src/de/ugoe/cs/eventbench/windows/data/WindowsMessage.java	(revision 52)
@@ -0,0 +1,204 @@
+package de.ugoe.cs.eventbench.windows.data;
+
+import java.security.InvalidParameterException;
+import java.util.HashMap;
+import java.util.Map;
+
+import de.ugoe.cs.eventbench.data.IReplayable;
+import de.ugoe.cs.util.StringTools;
+
+public class WindowsMessage implements IReplayable {
+	final int type;
+	private String windowClass = "";
+	private int resourceId = 0;
+	private String xmlWindowDescription = "";
+	private String parentNames = null;
+
+	private long LPARAM = 0;
+	private long WPARAM = 0;
+
+	private String LPARAMasWindowDesc = null;
+	private String WPARAMasWindowDesc = null;
+
+	private int delay = 0;
+	
+	private Map<String, String> params = new HashMap<String, String>();
+
+	public WindowsMessage(int type) {
+		this.type = type;
+	}
+
+	public void addParameter(String type, String value) {
+		params.put(type, value);
+		if (type.equals("LPARAM")) {
+			LPARAM = Long.parseLong(value);
+		} else if (type.equals("WPARAM")) {
+			WPARAM = Long.parseLong(value);
+		}
+	}
+
+	public int getType() {
+		return type;
+	}
+
+	public String getParameter(String type) {
+		return params.get(type);
+	}
+
+	public String getWindowClass() {
+		return windowClass;
+	}
+
+	public int getHwnd() {
+		int hwnd = -1;
+		String hwndString = getParameter("window.hwnd"); // possible, as
+															// "window.hwnd" is
+															// mandatory
+		if (hwndString != null) {
+			hwnd = Integer.parseInt(hwndString);
+		}
+		return hwnd;
+	}
+
+	public int getWindowResourceId() {
+		return resourceId;
+	}
+
+	@Override
+	public boolean equals(Object other) {
+		if( other==this) {
+			return true;
+		}
+		boolean isEqual = false;
+		if (other instanceof WindowsMessage) {
+			isEqual = ((WindowsMessage) other).type == this.type
+					&& ((WindowsMessage) other).xmlWindowDescription
+							.equals(this.xmlWindowDescription)
+					&& ((WindowsMessage) other).params.equals(this.params);
+		}
+		return isEqual;
+	}
+
+	@Override
+	public int hashCode() {
+		int multiplier = 17;
+		int hash = 42;
+
+		hash = multiplier * hash + type;
+		hash = multiplier * hash + xmlWindowDescription.hashCode();
+		hash = multiplier * hash + params.hashCode();
+
+		return hash;
+	}
+
+	@Override
+	public String toString() {
+		return "msg[target=" + getParameter("window.hwnd") + ";type=" + type
+				+ "]";
+	}
+
+	public void setTarget(WindowTree windowTree)
+			throws InvalidParameterException {
+		int hwnd = Integer.parseInt(getParameter("window.hwnd"));
+		WindowTreeNode node = windowTree.find(hwnd);
+		if (node == null) {
+			throw new InvalidParameterException("No window with HWND " + hwnd
+					+ " found in window tree!");
+		} else {
+			windowClass = node.getClassName();
+			resourceId = node.getResourceId();
+			xmlWindowDescription = node.xmlRepresentation();
+			parentNames = node.getParentNames();
+		}
+	}
+
+	public void setLPARAM(long paramValue) {
+		LPARAM = paramValue;
+	}
+
+	public void setWPARAM(long paramValue) {
+		WPARAM = paramValue;
+	}
+
+	public long getLPARAM() {
+		return LPARAM;
+	}
+
+	public long getWPARAM() {
+		return WPARAM;
+	}
+
+	public void setLPARAMasWindowDesc(String windowDesc) {
+		LPARAMasWindowDesc = windowDesc;
+	}
+
+	public void setWPARAMasWindowDesc(String windowDesc) {
+		WPARAMasWindowDesc = windowDesc;
+	}
+
+	public String getLPARAMasWindowDesc() {
+		return LPARAMasWindowDesc;
+	}
+
+	public String getWPARAMasWindowDesc() {
+		return WPARAMasWindowDesc;
+	}
+
+	public String getXmlWindowDescription() {
+		return xmlWindowDescription;
+	}
+
+	public void setXmlWindowDescription(String xmlWindowDescription) {
+		this.xmlWindowDescription = xmlWindowDescription;
+	}
+
+	public int getDelay() {
+		return delay;
+	}
+
+	public void setDelay(int delay) {
+		this.delay = delay;
+	}
+
+	public String getParentNames() {
+		return parentNames;
+	}
+
+	public int getNumParams() {
+		return params.size();
+	}
+	
+	public String getReplayXml() {
+		StringBuilder currentMsgStr = new StringBuilder(400);
+		currentMsgStr.append("  <msg type=\""+type+"\" ");
+		currentMsgStr.append("LPARAM=\""+LPARAM+"\" ");
+		currentMsgStr.append("WPARAM=\""+WPARAM+"\" ");
+		currentMsgStr.append("delay=\""+delay+"\">");
+		if( LPARAMasWindowDesc!=null ) {
+			currentMsgStr.append(StringTools.ENDLINE);
+			currentMsgStr.append("   <LPARAM>");
+			currentMsgStr.append(StringTools.ENDLINE);
+			currentMsgStr.append(LPARAMasWindowDesc);
+			currentMsgStr.append(StringTools.ENDLINE);
+			currentMsgStr.append("</LPARAM>");
+		} 
+		if( WPARAMasWindowDesc!=null ) {
+			currentMsgStr.append(StringTools.ENDLINE);
+			currentMsgStr.append("   <WPARAM>");
+			currentMsgStr.append(StringTools.ENDLINE);
+			currentMsgStr.append(WPARAMasWindowDesc);
+			currentMsgStr.append(StringTools.ENDLINE);
+			currentMsgStr.append("   </WPARAM>");
+		}
+		currentMsgStr.append(StringTools.ENDLINE);
+		currentMsgStr.append(xmlWindowDescription);
+		currentMsgStr.append(StringTools.ENDLINE);
+		currentMsgStr.append("  </msg>");
+		currentMsgStr.append(StringTools.ENDLINE);
+		return currentMsgStr.toString();
+	}
+	
+	public String getTarget() {
+		return xmlWindowDescription;
+	}
+}
