From 0e1643c19d7febbe2a9b6087498e416d41fc8539 Mon Sep 17 00:00:00 2001
From: Gabriel Landais <glandais@kereval.com>
Date: Tue, 26 Apr 2011 07:42:30 +0000
Subject: [PATCH] Adding DICOM filtering

git-svn-id: https://scm.gforge.inria.fr/authscm/ycadoret/svn/gazelle/Maven/gazelle-proxy/trunk@21543 356b4b1a-1d2b-0410-8bf1-ffa24008f01e
---
 .../proxy/dao/MessageFilterStandard.java      | 38 +++++++++++
 .../proxy/model/message/AbstractMessage.java  |  8 +--
 .../proxy/model/message/DicomMessage.java     | 37 ++++++++--
 .../proxy/model/message/HTTPMessage.java      |  3 +-
 .../src/main/resources/prefs.properties       |  1 +
 .../proxy/action/ChannelManagerBean.java      | 17 ++---
 .../ihe/gazelle/proxy/action/MessageBean.java | 32 +++++++--
 .../gazelle/proxy/action/MessagesBean.java    | 64 +++++++++++++++++
 .../ihe/gazelle/proxy/action/ProxyBean.java   | 14 ++--
 .../ihe/gazelle/proxy/action/ProxyLocal.java  |  3 +-
 .../proxy/listeners/DicomEventListener.java   | 68 ++++++++++---------
 .../proxy/listeners/HL7EventListener.java     | 15 ++--
 .../proxy/listeners/SyslogEventListener.java  | 15 ++--
 .../net/ihe/gazelle/proxy/ws/ProxyForTM.java  |  2 +-
 .../src/main/webapp/messageList.xhtml         |  2 +-
 .../src/main/webapp/messages.xhtml            | 44 ++++++------
 pom.xml                                       | 26 ++++---
 17 files changed, 281 insertions(+), 108 deletions(-)

diff --git a/gazelle-proxy-datamodel/src/main/java/net/ihe/gazelle/proxy/dao/MessageFilterStandard.java b/gazelle-proxy-datamodel/src/main/java/net/ihe/gazelle/proxy/dao/MessageFilterStandard.java
index 9eead767..e29179f3 100644
--- a/gazelle-proxy-datamodel/src/main/java/net/ihe/gazelle/proxy/dao/MessageFilterStandard.java
+++ b/gazelle-proxy-datamodel/src/main/java/net/ihe/gazelle/proxy/dao/MessageFilterStandard.java
@@ -28,6 +28,10 @@ public class MessageFilterStandard implements MessageFilter {
 
 	private ProxySide proxySide = null;
 
+	private String dicomAffectedSopClassUID;
+	private String dicomRequestedSopClassUID;
+	private String dicomCommandField;
+
 	public String getInitiatorIP() {
 		return initiatorIP;
 	}
@@ -108,6 +112,30 @@ public class MessageFilterStandard implements MessageFilter {
 		this.connectionId = connectionId;
 	}
 
+	public String getDicomAffectedSopClassUID() {
+		return dicomAffectedSopClassUID;
+	}
+
+	public void setDicomAffectedSopClassUID(String dicomAffectedSopClassUID) {
+		this.dicomAffectedSopClassUID = dicomAffectedSopClassUID;
+	}
+
+	public String getDicomRequestedSopClassUID() {
+		return dicomRequestedSopClassUID;
+	}
+
+	public void setDicomRequestedSopClassUID(String dicomRequestedSopClassUID) {
+		this.dicomRequestedSopClassUID = dicomRequestedSopClassUID;
+	}
+
+	public String getDicomCommandField() {
+		return dicomCommandField;
+	}
+
+	public void setDicomCommandField(String dicomCommandField) {
+		this.dicomCommandField = dicomCommandField;
+	}
+
 	public void reset() {
 		messageType = ChannelType.HTTP;
 		initiatorIP = null;
@@ -119,6 +147,10 @@ public class MessageFilterStandard implements MessageFilter {
 		dateTo = null;
 		connectionId = null;
 		proxySide = null;
+
+		dicomAffectedSopClassUID = null;
+		dicomRequestedSopClassUID = null;
+		dicomCommandField = null;
 	}
 
 	public void appendFilters(Criteria criteria) {
@@ -141,6 +173,12 @@ public class MessageFilterStandard implements MessageFilter {
 		if (dateTo != null) {
 			criteria.add(Restrictions.le("dateReceived", dateTo));
 		}
+
+		if (messageType == ChannelType.DICOM) {
+			addEq(criteria, "affectedSopClassUID", dicomAffectedSopClassUID);
+			addEq(criteria, "requestedSopClassUID", dicomRequestedSopClassUID);
+			addEq(criteria, "commandField", dicomCommandField);
+		}
 	}
 
 	private void addEq(Criteria criteria, String parameterName, Object value) {
diff --git a/gazelle-proxy-datamodel/src/main/java/net/ihe/gazelle/proxy/model/message/AbstractMessage.java b/gazelle-proxy-datamodel/src/main/java/net/ihe/gazelle/proxy/model/message/AbstractMessage.java
index e395fd73..ceb27b93 100644
--- a/gazelle-proxy-datamodel/src/main/java/net/ihe/gazelle/proxy/model/message/AbstractMessage.java
+++ b/gazelle-proxy-datamodel/src/main/java/net/ihe/gazelle/proxy/model/message/AbstractMessage.java
@@ -44,6 +44,7 @@ import net.ihe.gazelle.proxy.model.Channel;
 import org.apache.commons.httpclient.methods.multipart.ByteArrayPartSource;
 import org.apache.commons.httpclient.methods.multipart.PartSource;
 import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.lang.StringEscapeUtils;
 import org.apache.commons.lang.WordUtils;
 import org.hibernate.validator.NotNull;
 
@@ -141,11 +142,10 @@ public abstract class AbstractMessage {
 
 	public String getInfoGUI() {
 		String sToUse = getMessageReceivedAsString();
-		if (sToUse.length() < 20) {
-			return sToUse;
-		} else {
-			return sToUse.substring(0, 20) + "...";
+		if (sToUse.length() > 20) {
+			sToUse = sToUse.substring(0, 20) + "...";
 		}
+		return StringEscapeUtils.escapeHtml(sToUse);
 	}
 
 	public Date getDateReceived() {
diff --git a/gazelle-proxy-datamodel/src/main/java/net/ihe/gazelle/proxy/model/message/DicomMessage.java b/gazelle-proxy-datamodel/src/main/java/net/ihe/gazelle/proxy/model/message/DicomMessage.java
index 5ad0d16f..93948750 100644
--- a/gazelle-proxy-datamodel/src/main/java/net/ihe/gazelle/proxy/model/message/DicomMessage.java
+++ b/gazelle-proxy-datamodel/src/main/java/net/ihe/gazelle/proxy/model/message/DicomMessage.java
@@ -46,6 +46,7 @@ import net.ihe.gazelle.proxy.util.Preferences;
 
 import org.apache.commons.httpclient.methods.multipart.FilePartSource;
 import org.apache.commons.httpclient.methods.multipart.PartSource;
+import org.apache.commons.lang.StringEscapeUtils;
 import org.hibernate.annotations.CollectionOfElements;
 import org.hibernate.annotations.IndexColumn;
 import org.jboss.seam.annotations.Name;
@@ -110,7 +111,7 @@ public class DicomMessage extends AbstractMessage implements java.io.Serializabl
 
 	// Constructors
 
-	private static Map<String, String> getMapOfDicomUID(EntityManager entityManager) {
+	public static Map<String, String> getMapOfDicomUID(EntityManager entityManager) {
 		if (_mapOfDicomUID == null) {
 			synchronized (_mapOfDicomUIDSync) {
 				if (_mapOfDicomUID == null) {
@@ -127,7 +128,7 @@ public class DicomMessage extends AbstractMessage implements java.io.Serializabl
 		return _mapOfDicomUID;
 	}
 
-	private static Map<Integer, String> getMapOfCommandFields(EntityManager entityManager) {
+	public static Map<Integer, String> getMapOfCommandFields(EntityManager entityManager) {
 		if (_mapOfCommandFields == null) {
 			synchronized (_mapOfCommandFieldsSync) {
 				if (_mapOfCommandFields == null) {
@@ -296,11 +297,31 @@ public class DicomMessage extends AbstractMessage implements java.io.Serializabl
 		super(channel, fromIP, localPort, proxyPort, toIP, remotePort, channelId, proxySide);
 	}
 
+	public static String humanReadableByteCount(long bytes, boolean si) {
+		int unit = si ? 1000 : 1024;
+		if (bytes < unit)
+			return bytes + " B";
+		int exp = (int) (Math.log(bytes) / Math.log(unit));
+		String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i");
+		return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
+	}
+
 	@Override
 	public String getInfoGUI() {
-		StringBuilder sb = new StringBuilder(affectedSopClassUID);
-		sb.append(" - ").append(commandField);
-		return sb.toString();
+		StringBuilder sb = new StringBuilder("");
+		sb.append("Aff. ").append(affectedSopClassUID).append("\n");
+		// sb.append("Req. ").append(requestedSopClassUID).append("\n");
+		sb.append("Cmd. ").append(commandField).append("\n");
+		int messageLength = getMessageLength();
+		if (messageLength > 0) {
+			sb.append(humanReadableByteCount(messageLength, true));
+		}
+
+		String sToUse = sb.toString();
+		sToUse = StringEscapeUtils.escapeHtml(sToUse);
+		sToUse = sToUse.replaceAll("\n", "<br \\>");
+
+		return sToUse;
 	}
 
 	@Override
@@ -368,7 +389,11 @@ public class DicomMessage extends AbstractMessage implements java.io.Serializabl
 
 	@Override
 	public int getMessageLength() {
-		return (int) getFile().length();
+		try {
+			return (int) getFile().length();
+		} catch (Throwable e) {
+			return 0;
+		}
 	}
 
 	@Override
diff --git a/gazelle-proxy-datamodel/src/main/java/net/ihe/gazelle/proxy/model/message/HTTPMessage.java b/gazelle-proxy-datamodel/src/main/java/net/ihe/gazelle/proxy/model/message/HTTPMessage.java
index 7d64f0fa..3c6a7e47 100644
--- a/gazelle-proxy-datamodel/src/main/java/net/ihe/gazelle/proxy/model/message/HTTPMessage.java
+++ b/gazelle-proxy-datamodel/src/main/java/net/ihe/gazelle/proxy/model/message/HTTPMessage.java
@@ -10,6 +10,7 @@ import net.ihe.gazelle.proxy.enums.ChannelType;
 import net.ihe.gazelle.proxy.enums.ProxySide;
 import net.ihe.gazelle.proxy.model.Channel;
 
+import org.apache.commons.lang.StringEscapeUtils;
 import org.jboss.seam.annotations.Name;
 
 @Entity
@@ -79,7 +80,7 @@ public class HTTPMessage extends AbstractMessage {
 
 	@Override
 	public String getInfoGUI() {
-		return messageType;
+		return StringEscapeUtils.escapeHtml(messageType);
 	}
 
 	public ChannelType getChannelType() {
diff --git a/gazelle-proxy-datamodel/src/main/resources/prefs.properties b/gazelle-proxy-datamodel/src/main/resources/prefs.properties
index f1a512f4..06160c78 100644
--- a/gazelle-proxy-datamodel/src/main/resources/prefs.properties
+++ b/gazelle-proxy-datamodel/src/main/resources/prefs.properties
@@ -1,2 +1,3 @@
 evsclient.url=${evsclient.url}
 storage.dicom=${storage.dicom}
+storage.tmp=${storage.tmp}
diff --git a/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/ChannelManagerBean.java b/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/ChannelManagerBean.java
index 3bf35198..67cded5f 100644
--- a/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/ChannelManagerBean.java
+++ b/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/ChannelManagerBean.java
@@ -132,9 +132,9 @@ public class ChannelManagerBean implements Serializable {
 	}
 
 	private String createAndStartChannel(String name, Integer localPort, String remoteAddress, Integer remotePort,
-			ChannelType channelType, Object config) {
+			ChannelType channelType, TlsConfig tlsConfig, Object config) {
 		try {
-			proxyBean.startChannel(name, localPort, remoteAddress, remotePort, channelType, config);
+			proxyBean.startChannel(name, localPort, remoteAddress, remotePort, channelType, tlsConfig, config);
 			FacesMessages.instance().add(StatusMessage.Severity.INFO, "Channel successfully created");
 			return "/home.xhtml";
 		} catch (Throwable e) {
@@ -233,9 +233,9 @@ public class ChannelManagerBean implements Serializable {
 		this.certificateServer = certificateServer;
 	}
 
-	public SelectItem[] getCertificates() {			
-		List<Certificate> list = ProxyDAO.getCertificatesForSigning(identity.getCredentials()
-				.getUsername());;
+	public SelectItem[] getCertificates() {
+		List<Certificate> list = ProxyDAO.getCertificatesForSigning(identity.getCredentials().getUsername());
+		;
 		Collections.sort(list, new Comparator<Certificate>() {
 
 			public int compare(Certificate o1, Certificate o2) {
@@ -348,11 +348,12 @@ public class ChannelManagerBean implements Serializable {
 
 	public void startChannel() {
 		if (identity.hasRole("admin_role")) {
-			Object config = null;
+			TlsConfig tlsConfig = null;
 			if (secured) {
-				config = getTlsConfig();
+				tlsConfig = getTlsConfig();
 			}
-			createAndStartChannel("", getProxyPort(), getResponderIP(), getResponderPort(), getMessageType(), config);
+			createAndStartChannel("", getProxyPort(), getResponderIP(), getResponderPort(), getMessageType(),
+					tlsConfig, null);
 		} else {
 			FacesMessages.instance().add("Wrong role");
 		}
diff --git a/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/MessageBean.java b/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/MessageBean.java
index 2ee288e2..f8012416 100644
--- a/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/MessageBean.java
+++ b/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/MessageBean.java
@@ -12,8 +12,10 @@ import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import net.ihe.gazelle.proxy.action.dao.ProxyDAO;
 import net.ihe.gazelle.proxy.enums.ChannelType;
 import net.ihe.gazelle.proxy.model.message.AbstractMessage;
+import net.ihe.gazelle.proxy.model.message.DicomMessage;
 import net.ihe.gazelle.proxy.model.message.HL7Message;
 import net.ihe.gazelle.proxy.model.message.HTTPMessage;
 import net.ihe.gazelle.proxy.model.message.SyslogMessage;
@@ -35,6 +37,7 @@ import org.jboss.seam.annotations.In;
 import org.jboss.seam.annotations.Name;
 import org.jboss.seam.annotations.Scope;
 import org.jboss.seam.faces.FacesMessages;
+import org.jboss.seam.faces.Redirect;
 import org.jboss.seam.international.StatusMessage;
 
 @Name("messageBean")
@@ -67,18 +70,39 @@ public class MessageBean {
 	}
 
 	public void retrieveMessage(String channelType) {
-		ChannelType type = ChannelType.valueOf(channelType);
-
 		Map<String, String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
 		String messageId = params.get("id");
 		if (messageId == null || messageId.trim().length() < 1)
 			return;
 		try {
-			Integer i = new Integer(messageId);
-			message = entityManager.find(type.getMessageClass(), i);
+			int i = Integer.valueOf(messageId);
+			message = ProxyDAO.getMessageByID(i, entityManager);
 		} catch (Exception e) {
 			message = null;
 		}
+
+		ChannelType type = ChannelType.valueOf(channelType);
+		if (message.getChannelType() != type) {
+			Redirect redirect = Redirect.instance();
+			redirect.setParameter("id", messageId);
+
+			String viewId = "";
+			if (message instanceof HL7Message) {
+				viewId = "/messages/hl7.xhtml";
+			}
+			if (message instanceof DicomMessage) {
+				viewId = "/messages/dicom.xhtml";
+			}
+			if (message instanceof SyslogMessage) {
+				viewId = "/messages/syslog.xhtml";
+			}
+			if (message instanceof HTTPMessage) {
+				viewId = "/messages/http.xhtml";
+			}
+
+			redirect.setViewId(viewId);
+			redirect.execute();
+		}
 	}
 
 	public Boolean linkedRendered() {
diff --git a/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/MessagesBean.java b/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/MessagesBean.java
index 632f35e2..d741e395 100644
--- a/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/MessagesBean.java
+++ b/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/MessagesBean.java
@@ -1,12 +1,18 @@
 package net.ihe.gazelle.proxy.action;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
 
 import javax.ejb.Remove;
 import javax.faces.context.FacesContext;
+import javax.faces.model.SelectItem;
 import javax.persistence.EntityManager;
 
 import net.ihe.gazelle.jsf.datatable.HibernateDataModel;
@@ -120,6 +126,64 @@ public class MessagesBean {
 		return messageFilterStandard.getResponderPort();
 	}
 
+	public boolean isDICOM() {
+		return messageFilterStandard.getMessageType() == ChannelType.DICOM;
+	}
+
+	public String getDicomAffectedSopClassUID() {
+		return messageFilterStandard.getDicomAffectedSopClassUID();
+	}
+
+	public void setDicomAffectedSopClassUID(String dicomAffectedSopClassUID) {
+		messageFilterStandard.setDicomAffectedSopClassUID(dicomAffectedSopClassUID);
+	}
+
+	public SelectItem[] getDicomAffectedSopClassUIDs() {
+		Map<String, String> mapOfDicomUID = DicomMessage.getMapOfDicomUID(entityManager);
+		List<String> result = new ArrayList<String>(mapOfDicomUID.values());
+		Collections.sort(result);
+		return getSelectItems(result);
+	}
+
+	private SelectItem[] getSelectItems(List<String> list) {
+		SelectItem[] result = new SelectItem[list.size() + 1];
+		int i = 0;
+		result[i] = new SelectItem(null, "--");
+		i++;
+		for (String option : list) {
+			result[i] = new SelectItem(option, option);
+			i++;
+		}
+		return result;
+	}
+
+	public String getDicomRequestedSopClassUID() {
+		return messageFilterStandard.getDicomRequestedSopClassUID();
+	}
+
+	public void setDicomRequestedSopClassUID(String dicomRequestedSopClassUID) {
+		messageFilterStandard.setDicomRequestedSopClassUID(dicomRequestedSopClassUID);
+	}
+
+	public SelectItem[] getDicomRequestedSopClassUIDs() {
+		return getDicomAffectedSopClassUIDs();
+	}
+
+	public String getDicomCommandField() {
+		return messageFilterStandard.getDicomCommandField();
+	}
+
+	public void setDicomCommandField(String dicomCommandField) {
+		messageFilterStandard.setDicomCommandField(dicomCommandField);
+	}
+
+	public SelectItem[] getDicomCommandFields() {
+		Map<Integer, String> mapOfCommandFields = DicomMessage.getMapOfCommandFields(entityManager);
+		List<String> result = new ArrayList<String>(mapOfCommandFields.values());
+		Collections.sort(result);
+		return getSelectItems(result);
+	}
+
 	public boolean isFilterDates() {
 		return messageFilterStep.isFilterDates();
 	}
diff --git a/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/ProxyBean.java b/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/ProxyBean.java
index 4f5d07aa..b2e905af 100644
--- a/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/ProxyBean.java
+++ b/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/ProxyBean.java
@@ -24,6 +24,7 @@ import net.ihe.gazelle.proxy.netty.protocols.http.HttpProxy;
 import net.ihe.gazelle.proxy.netty.protocols.syslog.SyslogProxy;
 import net.ihe.gazelle.proxy.netty.protocols.tls.TlsConfig;
 import net.ihe.gazelle.proxy.util.HibernateUtilProxy;
+import net.ihe.gazelle.proxy.util.Preferences;
 
 import org.apache.log4j.Logger;
 import org.jboss.seam.ScopeType;
@@ -98,7 +99,7 @@ public class ProxyBean implements ProxyLocal {
 	}
 
 	public Channel startChannel(String name, Integer localPort, String remoteAddress, Integer remotePort,
-			ChannelType channelType, Object config) {
+			ChannelType channelType, TlsConfig tlsConfig, Object config) {
 		Channel channel = new Channel();
 		channel.setProxyPort(localPort);
 		if (name != null)
@@ -112,7 +113,7 @@ public class ProxyBean implements ProxyLocal {
 		channel.setStartDate(new Date());
 		channel.setStarted(Boolean.TRUE);
 
-		ProxyChannel proxyChannel = createProxyChannel(channel, config);
+		ProxyChannel proxyChannel = createProxyChannel(channel, tlsConfig, config);
 		proxyChannel.proxy.start();
 		listOfProxies.add(proxyChannel);
 
@@ -127,13 +128,9 @@ public class ProxyBean implements ProxyLocal {
 		return channel;
 	}
 
-	private ProxyChannel createProxyChannel(Channel channel, Object config) {
+	private ProxyChannel createProxyChannel(Channel channel, TlsConfig tlsConfig, Object config) {
 		ProxyChannel proxyChannel = new ProxyChannel();
 		proxyChannel.channel = channel;
-		TlsConfig tlsConfig = null;
-		if (config != null && config instanceof TlsConfig) {
-			tlsConfig = (TlsConfig) config;
-		}
 		switch (channel.getChannelType()) {
 		case HL7:
 			proxyChannel.proxy = new HL7Proxy(new HL7EventListener(channel), channel.getProxyPort(),
@@ -143,7 +140,10 @@ public class ProxyBean implements ProxyLocal {
 			String path = "/tmp";
 			if (config != null && config instanceof String) {
 				path = (String) config;
+			} else {
+				path = Preferences.getProperty("storage.tmp");
 			}
+			path = null;
 			proxyChannel.proxy = new DicomProxy(new DicomEventListener(channel), channel.getProxyPort(),
 					channel.getRemoteAddress(), channel.getRemotePort(), path, tlsConfig);
 			break;
diff --git a/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/ProxyLocal.java b/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/ProxyLocal.java
index ca390824..8f5008ed 100644
--- a/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/ProxyLocal.java
+++ b/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/ProxyLocal.java
@@ -4,12 +4,13 @@ import javax.ejb.Local;
 
 import net.ihe.gazelle.proxy.enums.ChannelType;
 import net.ihe.gazelle.proxy.model.Channel;
+import net.ihe.gazelle.proxy.netty.protocols.tls.TlsConfig;
 
 @Local
 public interface ProxyLocal {
 
 	public Channel startChannel(String name, Integer localPort, String remoteAddress, Integer remotePort,
-			ChannelType channelType, Object config);
+			ChannelType channelType, TlsConfig tlsConfig, Object config);
 
 	public void stopChannel(Integer localPort);
 
diff --git a/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/listeners/DicomEventListener.java b/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/listeners/DicomEventListener.java
index 2396f93f..c6569280 100644
--- a/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/listeners/DicomEventListener.java
+++ b/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/listeners/DicomEventListener.java
@@ -56,48 +56,52 @@ public class DicomEventListener extends SameEventListener<DimseMessage> {
 
 	protected void saveMessage(DimseMessage dicom, String requesterIp, int requesterPort, String responderIp,
 			int responderPort, int channelId, ProxySide side) {
-		EntityManager em = getEntityManager();
-
-		DicomMessage messageToStore = new DicomMessage(channelUsed, requesterIp, requesterPort, proxyPort, responderIp,
-				responderPort, channelId, convertProxySide(side));
-		if (dicom.getDataSet() != null) {
-			try {
-				String storageDicom = Preferences.getProperty("storage.dicom");
-				File storageDicomFolder = new File(storageDicom);
-
-				String fileName = Long.toHexString(System.nanoTime());
-				if (fileName.length() < 3) {
-					fileName = "000" + fileName;
-				}
+		// Messages are coming from different threads!
+		synchronized (this) {
+			EntityManager em = getEntityManager();
+
+			DicomMessage messageToStore = new DicomMessage(channelUsed, requesterIp, requesterPort, proxyPort,
+					responderIp, responderPort, channelId, convertProxySide(side));
+			if (dicom.getDataSet() != null) {
+				try {
+					String storageDicom = Preferences.getProperty("storage.dicom");
+					File storageDicomFolder = new File(storageDicom);
+
+					String fileName = Long.toHexString(System.nanoTime());
+					if (fileName.length() < 3) {
+						fileName = "000" + fileName;
+					}
 
-				File targetFolder1 = new File(storageDicomFolder, fileName.substring(0, 1));
-				File targetFolder2 = new File(targetFolder1, fileName.substring(1, 2));
-				File targetFolder3 = new File(targetFolder2, fileName.substring(2, 3));
+					int l = fileName.length();
+					File targetFolder1 = new File(storageDicomFolder, fileName.substring(l - 3, l - 2));
+					File targetFolder2 = new File(targetFolder1, fileName.substring(l - 2, l - 1));
+					File targetFolder3 = new File(targetFolder2, fileName.substring(l - 1, l));
 
-				targetFolder3.mkdirs();
+					targetFolder3.mkdirs();
 
-				File targetFile = new File(targetFolder3, fileName);
+					File targetFile = new File(targetFolder3, fileName);
 
-				File sourceFile = new File(dicom.getDataSet().getCanonicalPath());
+					File sourceFile = new File(dicom.getDataSet().getCanonicalPath());
 
-				FileUtils.copyFile(sourceFile, targetFile);
+					FileUtils.copyFile(sourceFile, targetFile);
 
-				String pathToStore = targetFile.getAbsolutePath();
-				pathToStore = pathToStore.replace(storageDicom, "");
+					String pathToStore = targetFile.getAbsolutePath();
+					pathToStore = pathToStore.replace(storageDicom, "");
 
-				messageToStore.setMessageReceived(pathToStore.getBytes(UTF_8));
+					messageToStore.setMessageReceived(pathToStore.getBytes(UTF_8));
 
-				sourceFile.delete();
-			} catch (IOException e) {
-				e.printStackTrace();
+					sourceFile.delete();
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
 			}
-		}
-		if (dicom.getCommandSet() != null && dicom.getCommandSet().length > 0)
-			messageToStore.setFileCommandSet(em, dicom.getCommandSet());
-		messageToStore.setFileTransfertSyntax(dicom.getTransferSyntax());
+			if (dicom.getCommandSet() != null && dicom.getCommandSet().length > 0)
+				messageToStore.setFileCommandSet(em, dicom.getCommandSet());
+			messageToStore.setFileTransfertSyntax(dicom.getTransferSyntax());
 
-		synchronized (em) {
-			writeMessage(em, messageToStore);
+			synchronized (em) {
+				writeMessage(em, messageToStore);
+			}
 		}
 	}
 
diff --git a/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/listeners/HL7EventListener.java b/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/listeners/HL7EventListener.java
index 62e7985c..50e70d07 100644
--- a/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/listeners/HL7EventListener.java
+++ b/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/listeners/HL7EventListener.java
@@ -14,12 +14,15 @@ public class HL7EventListener extends SameEventListener<String> {
 
 	protected void saveMessage(String message, String requesterIp, int requesterPort, String responderIp,
 			int responderPort, int channelId, ProxySide side) {
-		HL7Message hl7message = new HL7Message(channelUsed, requesterIp, requesterPort, proxyPort, responderIp,
-				responderPort, channelId, convertProxySide(side));
-		hl7message.setMessageReceivedAsString(message);
-		EntityManager em = getEntityManager();
-		synchronized (em) {
-			writeMessage(em, hl7message);
+		// Messages are coming from different threads!
+		synchronized (this) {
+			HL7Message hl7message = new HL7Message(channelUsed, requesterIp, requesterPort, proxyPort, responderIp,
+					responderPort, channelId, convertProxySide(side));
+			hl7message.setMessageReceivedAsString(message);
+			EntityManager em = getEntityManager();
+			synchronized (em) {
+				writeMessage(em, hl7message);
+			}
 		}
 	}
 
diff --git a/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/listeners/SyslogEventListener.java b/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/listeners/SyslogEventListener.java
index bca0aeec..8bf40163 100644
--- a/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/listeners/SyslogEventListener.java
+++ b/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/listeners/SyslogEventListener.java
@@ -14,12 +14,15 @@ public class SyslogEventListener extends SameEventListener<String> {
 
 	protected void saveMessage(String message, String requesterIp, int requesterPort, String responderIp,
 			int responderPort, int channelId, ProxySide side) {
-		SyslogMessage syslogMessage = new SyslogMessage(channelUsed, requesterIp, requesterPort, proxyPort,
-				responderIp, responderPort, channelId, convertProxySide(side));
-		syslogMessage.setMessageReceivedAsString(message);
-		EntityManager em = getEntityManager();
-		synchronized (em) {
-			writeMessage(em, syslogMessage);
+		// Messages are coming from different threads!
+		synchronized (this) {
+			SyslogMessage syslogMessage = new SyslogMessage(channelUsed, requesterIp, requesterPort, proxyPort,
+					responderIp, responderPort, channelId, convertProxySide(side));
+			syslogMessage.setMessageReceivedAsString(message);
+			EntityManager em = getEntityManager();
+			synchronized (em) {
+				writeMessage(em, syslogMessage);
+			}
 		}
 	}
 
diff --git a/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/ws/ProxyForTM.java b/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/ws/ProxyForTM.java
index 988cf0c3..8265ac93 100644
--- a/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/ws/ProxyForTM.java
+++ b/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/ws/ProxyForTM.java
@@ -93,7 +93,7 @@ public class ProxyForTM implements IProxyForTM {
 			String remoteAddress = configuration.getHost();
 			Integer remotePort = configuration.getPort();
 			ChannelType channelType = configuration.getType();
-			proxyBean.startChannel(name, localPort, remoteAddress, remotePort, channelType, null);
+			proxyBean.startChannel(name, localPort, remoteAddress, remotePort, channelType, null, null);
 		}
 	}
 
diff --git a/gazelle-proxy-war/src/main/webapp/messageList.xhtml b/gazelle-proxy-war/src/main/webapp/messageList.xhtml
index b30329af..6d29c52b 100644
--- a/gazelle-proxy-war/src/main/webapp/messageList.xhtml
+++ b/gazelle-proxy-war/src/main/webapp/messageList.xhtml
@@ -109,7 +109,7 @@
 			<f:facet name="header">
 				<h:outputText value="Info" />
 			</f:facet>
-			<h:outputText value="#{message.getInfoGUI()}" />
+			<h:outputText value="#{message.getInfoGUI()}" escape="false" />
 		</rich:column>
 
 		<f:facet name="footer">
diff --git a/gazelle-proxy-war/src/main/webapp/messages.xhtml b/gazelle-proxy-war/src/main/webapp/messages.xhtml
index e70505b1..0ade31cf 100644
--- a/gazelle-proxy-war/src/main/webapp/messages.xhtml
+++ b/gazelle-proxy-war/src/main/webapp/messages.xhtml
@@ -10,8 +10,7 @@
 		<a4j:form>
 			<rich:simpleTogglePanel switchType="client" id="search"
 				label="Search criteria">
-				<h:panelGrid columns="3">
-
+				<h:panelGrid columns="2">
 					<s:decorate id="messageTypeDeco" template="/layout/edit.xhtml">
 						<ui:define name="label">Message type</ui:define>
 						<h:selectOneMenu id="messageTypeBox"
@@ -22,7 +21,6 @@
 						</h:selectOneMenu>
 					</s:decorate>
 					<s:decorate></s:decorate>
-					<s:decorate></s:decorate>
 
 					<s:decorate id="initiatorIPDeco" template="/layout/edit.xhtml">
 						<ui:define name="label">Initiator's IP</ui:define>
@@ -38,7 +36,6 @@
 							<a4j:support event="onchange" reRender="search,panelOfMessages" />
 						</h:inputText>
 					</s:decorate>
-					<s:decorate></s:decorate>
 
 					<s:decorate id="responderIPDeco" template="/layout/edit.xhtml">
 						<ui:define name="label">Responder's IP</ui:define>
@@ -54,7 +51,6 @@
 							<a4j:support event="onchange" reRender="search,panelOfMessages" />
 						</h:inputText>
 					</s:decorate>
-					<s:decorate></s:decorate>
 
 					<s:decorate id="proxyPortDeco" template="/layout/edit.xhtml">
 						<ui:define name="label">Proxy's port</ui:define>
@@ -62,23 +58,7 @@
 							<a4j:support event="onchange" reRender="search,panelOfMessages" />
 						</h:inputText>
 					</s:decorate>
-
 					<s:decorate></s:decorate>
-					<!--					<s:decorate id="connectionIdDeco" template="/layout/edit.xhtml">-->
-					<!--						<ui:define name="label">Connection id</ui:define>-->
-					<!--						<h:inputText id="connectionId" value="#{messagesBean.connectionId}" />-->
-					<!--					</s:decorate>-->
-
-					<s:decorate></s:decorate>
-					<!--					<s:decorate id="proxySideDeco" template="/layout/edit.xhtml">-->
-					<!--						<ui:define name="label">Type</ui:define>-->
-					<!--						<h:selectOneMenu id="proxySideBox"-->
-					<!--							value="#{messagesBean.proxySide}">-->
-					<!--							<s:selectItems value="#{messagesBean.getProxySides()}"-->
-					<!--								noSelectionLabel="BOTH" var="cmdField"-->
-					<!--								label="#{cmdField.toString()}" />-->
-					<!--						</h:selectOneMenu>-->
-					<!--					</s:decorate>-->
 
 					<s:decorate id="dateFromDeco" template="/layout/edit.xhtml">
 						<ui:define name="label">Date from</ui:define>
@@ -96,8 +76,28 @@
 							<a4j:support event="onchange" reRender="search,panelOfMessages" />
 						</rich:calendar>
 					</s:decorate>
-					<s:decorate></s:decorate>
 				</h:panelGrid>
+
+				<h:panelGrid columns="1" rendered="#{messagesBean.isDICOM()}">
+
+					<s:decorate template="/layout/edit.xhtml">
+						<ui:define name="label">DICOM Affected Sop Class UID</ui:define>
+						<h:selectOneMenu value="#{messagesBean.dicomAffectedSopClassUID}">
+							<f:selectItems
+								value="#{messagesBean.getDicomAffectedSopClassUIDs()}" />
+							<a4j:support event="onchange" reRender="search,panelOfMessages" />
+						</h:selectOneMenu>
+					</s:decorate>
+					<s:decorate template="/layout/edit.xhtml">
+						<ui:define name="label">Dicom Command Field</ui:define>
+						<h:selectOneMenu value="#{messagesBean.dicomCommandField}">
+							<f:selectItems value="#{messagesBean.getDicomCommandFields()}" />
+							<a4j:support event="onchange" reRender="search,panelOfMessages" />
+						</h:selectOneMenu>
+					</s:decorate>
+
+				</h:panelGrid>
+
 				<a4j:commandButton actionListener="#{messagesBean.clearFilter()}"
 					reRender="search,panelOfMessages" value="Reset"
 					styleClass="commandButton" />
diff --git a/pom.xml b/pom.xml
index 277083e2..79c58c44 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,15 +30,17 @@
 
 	<repositories>
 		<repository>
-			<id>repository.jboss.org</id>
-			<name>JBoss Maven Repository</name>
-			<url>http://repository.jboss.org/maven2</url>
-			<snapshots>
-				<enabled>false</enabled>
-			</snapshots>
+			<id>irisa-sumo</id>
+			<name>Sumo Irisa Public Maven Repository Group</name>
+			<url>http://gazelle.ihe.net/nexus/content/groups/public/</url>
+			<layout>default</layout>
 			<releases>
 				<enabled>true</enabled>
+				<updatePolicy>never</updatePolicy>
 			</releases>
+			<snapshots>
+				<enabled>true</enabled>
+			</snapshots>
 		</repository>
 	</repositories>
 
@@ -203,7 +205,8 @@
 				<cas.service>http://127.0.0.1:8080/proxy/</cas.service>
 				<evsclient.url>http://127.0.0.1:8080/EVSClient/</evsclient.url>
 
-				<dicom.storage>/tmp</dicom.storage>
+				<dicom.storage>/tmp/DICOM</dicom.storage>
+				<storage.tmp>/tmp</storage.tmp>
 
 				<!-- development mode (disable in production) -->
 				<seam.debug>true</seam.debug>
@@ -252,6 +255,7 @@
 				<evsclient.url>http://jumbo-2.irisa.fr:8080/EVSClient/</evsclient.url>
 
 				<dicom.storage>/opt/proxy/DICOM</dicom.storage>
+				<storage.tmp>/opt/proxy/tmp</storage.tmp>
 
 				<!-- development mode (disable in production) -->
 				<seam.debug>false</seam.debug>
@@ -296,11 +300,14 @@
 			</activation>
 
 			<properties>
-				<!-- <cas.service>http://131.114.254.7:8080/proxy/</cas.service> -->
-				<cas.service>http://surimi.irisa.fr:8080/proxy/</cas.service>
+				<cas.service>http://131.114.254.7:8080/proxy/</cas.service>
+				<!-- <cas.service>http://surimi.irisa.fr:8080/proxy/</cas.service> -->
 
 				<evsclient.url>http://jumbo-2.irisa.fr:8080/EVSClient/</evsclient.url>
+				<!-- <storage.dicom>/Volumes/My\ Book/proxy/DICOM</storage.dicom> -->
+				<!-- <storage.tmp>/Volumes/My\ Book/proxy/tmp</storage.tmp> -->
 				<storage.dicom>/opt/proxy/DICOM</storage.dicom>
+				<storage.tmp>/opt/proxy/tmp</storage.tmp>
 
 				<!-- development mode (disable in production) -->
 				<seam.debug>false</seam.debug>
@@ -338,6 +345,7 @@
 		</profile>
 
 	</profiles>
+
 	<modules>
 		<module>gazelle-proxy-netty</module>
 		<module>gazelle-proxy-datamodel</module>
-- 
GitLab