From 03f3abb85fa23de235201126d4dbde99d30ddd41 Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Tue, 13 Nov 2012 17:36:56 +0100
Subject: [PATCH] OO-407: view portrait, try to cache the session id, test
 different configuration for session ids, save settings in course building
 block, default settings by copy...

---
 .../OpenMeetingsEditController.java           |  63 ++++++-
 .../OpenMeetingsEditFormController.java       |  13 +-
 .../manager/OpenMeetingsException.java        |  24 ++-
 .../manager/OpenMeetingsManager.java          |  48 +++++-
 .../manager/OpenMeetingsManagerImpl.java      | 154 ++++++++++--------
 .../restapi/OpenMeetingsWebService.java       | 100 ++++++++++++
 ...penMeetingsAdminRoomMembersController.java |   5 +-
 .../ui/OpenMeetingsRecordingsController.java  |   2 +-
 .../ui/OpenMeetingsRoomEditController.java    |  33 ++--
 .../ui/OpenMeetingsRunController.java         |   6 +-
 .../ui/_i18n/LocalStrings_de.properties       |   1 +
 .../olat/restapi/_spring/restApiContext.xml   |   1 +
 .../restapi/security/RestApiLoginFilter.java  |   1 +
 src/main/resources/ehcache.xml                |   7 +
 14 files changed, 365 insertions(+), 93 deletions(-)
 create mode 100644 src/main/java/org/olat/modules/openmeetings/restapi/OpenMeetingsWebService.java

diff --git a/src/main/java/org/olat/course/nodes/openmeetings/OpenMeetingsEditController.java b/src/main/java/org/olat/course/nodes/openmeetings/OpenMeetingsEditController.java
index a32f1a16898..0dc7b5ebb33 100644
--- a/src/main/java/org/olat/course/nodes/openmeetings/OpenMeetingsEditController.java
+++ b/src/main/java/org/olat/course/nodes/openmeetings/OpenMeetingsEditController.java
@@ -37,7 +37,9 @@ import org.olat.course.condition.ConditionEditController;
 import org.olat.course.editor.NodeEditController;
 import org.olat.course.nodes.OpenMeetingsCourseNode;
 import org.olat.course.run.userview.UserCourseEnvironment;
+import org.olat.modules.ModuleConfiguration;
 import org.olat.modules.openmeetings.manager.OpenMeetingsException;
+import org.olat.modules.openmeetings.model.OpenMeetingsRoom;
 
 /**
  * 
@@ -51,19 +53,25 @@ public class OpenMeetingsEditController extends ActivateableTabbableDefaultContr
 	public static final String PANE_TAB_VCCONFIG = "pane.tab.vcconfig";
 	final static String[] paneKeys = { PANE_TAB_VCCONFIG, PANE_TAB_ACCESSIBILITY };
 
+	public static final String CONFIG_ROOM_NAME = "roomName";
+	public static final String CONFIG_ROOM_SIZE = "roomSize";
+	public static final String CONFIG_ROOM_MODERATION = "roomModeration";
+	public static final String CONFIG_ROOM_RECORDING = "roomRecording";
+	public static final String CONFIG_ROOM_COMMENT = "roomComment";
+	public static final String CONFIG_ROOM_TYPE = "roomType";
+
 	private VelocityContainer editVc;
 	private ConditionEditController accessibilityCondContr;
 	private TabbedPane tabPane;
+	private OpenMeetingsEditFormController editForm;
 
 	private final OpenMeetingsCourseNode courseNode;
-	
 
 	public OpenMeetingsEditController(UserRequest ureq, WindowControl wControl, OpenMeetingsCourseNode courseNode,
 			ICourse course, UserCourseEnvironment userCourseEnv) {
 		super(ureq, wControl);
 		this.courseNode = courseNode;
 
-
 		Condition accessCondition = courseNode.getPreConditionAccess();
 		accessibilityCondContr = new ConditionEditController(ureq, wControl, course.getCourseEnvironment().getCourseGroupManager(),
 				accessCondition, "accessabilityConditionForm", AssessmentHelper.getAssessableNodes(course.getEditorTreeModel(), courseNode),
@@ -73,7 +81,9 @@ public class OpenMeetingsEditController extends ActivateableTabbableDefaultContr
 		editVc = createVelocityContainer("edit");
 		try {
 			OLATResourceable ores = OresHelper.createOLATResourceableInstance(course.getResourceableTypeName(), course.getResourceableId());
-			Controller editForm = new OpenMeetingsEditFormController(ureq, getWindowControl(), ores, courseNode, course.getCourseTitle());
+			OpenMeetingsRoom defaultSettings = getDefaultValues();
+			editForm = new OpenMeetingsEditFormController(ureq, getWindowControl(), ores, courseNode, course.getCourseTitle(), defaultSettings);
+			listenTo(editForm);
 			editVc.put("editRooms", editForm.getInitialComponent());
 		} catch (OpenMeetingsException e) {
 			editVc.contextPut("error", e.getType().i18nKey());
@@ -108,6 +118,22 @@ public class OpenMeetingsEditController extends ActivateableTabbableDefaultContr
 				courseNode.setPreConditionAccess(cond);
 				fireEvent(ureq, NodeEditController.NODECONFIG_CHANGED_EVENT);
 			}
+		} else if (source == editForm) { // config form action
+			if (event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) {
+				OpenMeetingsRoom room = editForm.getRoom();
+				if(room != null) {
+					ModuleConfiguration moduleConfiguration = courseNode.getModuleConfiguration();
+					moduleConfiguration.set(CONFIG_ROOM_NAME, room.getName());
+					moduleConfiguration.set(CONFIG_ROOM_SIZE, new Long(room.getSize()));
+					moduleConfiguration.set(CONFIG_ROOM_MODERATION, new Boolean(room.isModerated()));
+					moduleConfiguration.set(CONFIG_ROOM_RECORDING, new Boolean(room.isRecordingAllowed()));
+					moduleConfiguration.set(CONFIG_ROOM_COMMENT, room.getComment());
+					moduleConfiguration.set(CONFIG_ROOM_TYPE, new Long(room.getType()));
+				}
+			}
+			if (event == Event.DONE_EVENT) {
+				fireEvent(ureq, NodeEditController.NODECONFIG_CHANGED_EVENT);
+			}
 		}
 	}
 
@@ -117,5 +143,36 @@ public class OpenMeetingsEditController extends ActivateableTabbableDefaultContr
 				accessibilityCondContr.getWrappedDefaultAccessConditionVC(translate("condition.accessibility.title")));
 		tabbedPane.addTab(translate(PANE_TAB_VCCONFIG), editVc);
 	}
+	
+	private OpenMeetingsRoom getDefaultValues() {
+		OpenMeetingsRoom room = new OpenMeetingsRoom();
+		ModuleConfiguration moduleConfiguration = courseNode.getModuleConfiguration();
+		Object name = moduleConfiguration.get(CONFIG_ROOM_NAME);
+		if(name instanceof String) {
+			room.setName((String)name);
+		}
 
+		Object size = moduleConfiguration.get(CONFIG_ROOM_SIZE);
+		if(size instanceof Long) {
+			room.setSize(((Long)size).longValue());
+		}
+		Object moderated = moduleConfiguration.get(CONFIG_ROOM_MODERATION);
+		if(moderated instanceof Boolean) {
+			room.setModerated(((Boolean)moderated).booleanValue());
+		}
+		Object recording = moduleConfiguration.get(CONFIG_ROOM_RECORDING);
+		if(recording instanceof Boolean) {
+			room.setRecordingAllowed(((Boolean)recording).booleanValue());
+		}
+		Object comment = moduleConfiguration.get(CONFIG_ROOM_COMMENT);
+		if(comment instanceof String) {
+			room.setComment((String)comment);
+		}
+		
+		Object type = moduleConfiguration.get(CONFIG_ROOM_TYPE);
+		if(type instanceof Long) {
+			room.setType(((Long)type).longValue());
+		}
+		return room;
+	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/nodes/openmeetings/OpenMeetingsEditFormController.java b/src/main/java/org/olat/course/nodes/openmeetings/OpenMeetingsEditFormController.java
index abe52ccd1b1..5736e27396a 100644
--- a/src/main/java/org/olat/course/nodes/openmeetings/OpenMeetingsEditFormController.java
+++ b/src/main/java/org/olat/course/nodes/openmeetings/OpenMeetingsEditFormController.java
@@ -58,15 +58,17 @@ public class OpenMeetingsEditFormController extends FormBasicController {
 	private final OpenMeetingsManager openMeetingsManager;
 	
 	private OpenMeetingsRoom room;
+	private OpenMeetingsRoom defaultSettings;
 
 	public OpenMeetingsEditFormController(UserRequest ureq, WindowControl wControl, OLATResourceable course,
-			OpenMeetingsCourseNode courseNode, String courseTitle)
+			OpenMeetingsCourseNode courseNode, String courseTitle, OpenMeetingsRoom defaultSettings)
 	    throws OpenMeetingsException{
 		super(ureq, wControl);
 		
 		this.course = course;
 		this.courseNode = courseNode;
 		this.courseTitle = courseTitle;
+		this.defaultSettings = defaultSettings;
 		openMeetingsManager = CoreSpringFactory.getImpl(OpenMeetingsManager.class);
 
 		room = openMeetingsManager.getRoom(null, course, courseNode.getIdent());
@@ -84,6 +86,10 @@ public class OpenMeetingsEditFormController extends FormBasicController {
 		editLink = uifactory.addFormLink(key, buttonContainer, Link.BUTTON);	
 	}
 	
+	public OpenMeetingsRoom getRoom() {
+		return room;
+	}
+	
 	private void updateUI() {
 		String name = room == null ? "" : room.getName();
 		roomNameEl.setValue(name);
@@ -101,9 +107,10 @@ public class OpenMeetingsEditFormController extends FormBasicController {
 		if(source == cmc) {
 			cleanupPopups();
 		} else if(source == editController) {
-			if(event == Event.CHANGED_EVENT) {
+			if(event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) {
 				room = editController.getRoom();
 				updateUI();
+				fireEvent(ureq, event);
 			}
 			cmc.deactivate();
 			cleanupPopups();
@@ -135,7 +142,7 @@ public class OpenMeetingsEditFormController extends FormBasicController {
 	protected void doEditRoom(UserRequest ureq) {
 		try {
 			cleanupPopups();
-			editController = new OpenMeetingsRoomEditController(ureq, getWindowControl(), null, course, courseNode.getIdent(), courseTitle, true);
+			editController = new OpenMeetingsRoomEditController(ureq, getWindowControl(), null, course, courseNode.getIdent(), courseTitle, defaultSettings,  true);
 			listenTo(editController);
 
 			cmc = new CloseableModalController(getWindowControl(), translate("close"), editController.getInitialComponent(), true, translate("edit.room"));
diff --git a/src/main/java/org/olat/modules/openmeetings/manager/OpenMeetingsException.java b/src/main/java/org/olat/modules/openmeetings/manager/OpenMeetingsException.java
index 34e54ec62c7..8988f8d6dca 100644
--- a/src/main/java/org/olat/modules/openmeetings/manager/OpenMeetingsException.java
+++ b/src/main/java/org/olat/modules/openmeetings/manager/OpenMeetingsException.java
@@ -40,6 +40,10 @@ public class OpenMeetingsException extends Exception {
 		this.type = type;
 	}
 	
+	public OpenMeetingsException(long code) {
+		this.type = Type.get(code);
+	}
+	
 	public OpenMeetingsException(String message, Type type) {
 		super(message);
 		this.type = type;
@@ -60,17 +64,31 @@ public class OpenMeetingsException extends Exception {
 	}
 
 	public enum Type {
-		unkown("error.unkown"),
-		serverNotAvailable("error.notAvailable");
+		unkown("error.unkown", 0),
+		serverNotAvailable("error.notAvailable", 0)
+		
+		;
+		
 
 		private final String i18nKey;
+		private final long code;
 		
-		private Type(String i18nKey) {
+		private Type(String i18nKey, long code) {
 			this.i18nKey = i18nKey;
+			this.code = code;
 		}
 		
 		public String i18nKey() {
 			return i18nKey;
 		}
+		
+		public static Type get(long code) {
+			for(Type t:Type.values()) {
+				if(t.code == code) {
+					return t;
+				}
+			}
+			return unkown;
+		}
 	}
 }
diff --git a/src/main/java/org/olat/modules/openmeetings/manager/OpenMeetingsManager.java b/src/main/java/org/olat/modules/openmeetings/manager/OpenMeetingsManager.java
index 83ab43568bf..add83f43da9 100644
--- a/src/main/java/org/olat/modules/openmeetings/manager/OpenMeetingsManager.java
+++ b/src/main/java/org/olat/modules/openmeetings/manager/OpenMeetingsManager.java
@@ -37,15 +37,45 @@ import org.olat.modules.openmeetings.model.OpenMeetingsUser;
  */
 public interface OpenMeetingsManager {
 	
+	/**
+	 * 
+	 * @return A string which identity rooms and users created by this OpenOLAT instance
+	 */
 	public String getOpenOLATExternalType();
 	
-	
+	/**
+	 * Create the URL to open a room
+	 * @param identity
+	 * @param roomId
+	 * @param securedHash
+	 * @param language
+	 * @return
+	 */
 	public String getURL(Identity identity, long roomId, String securedHash, Locale language);
 	
+	/**
+	 * Set a temporary user on the OpenMeetings server, this user is a regular OpenOLAT
+	 * user.
+	 * @param identity
+	 * @param roomId
+	 * @param moderator
+	 * @param sessionId
+	 * @return
+	 * @throws OpenMeetingsException
+	 */
 	public String setUserToRoom(Identity identity, long roomId, boolean moderator)
 	throws OpenMeetingsException;
 	
-	public String setGuestUserToRoom(String firstName, String lastName, long roomId, boolean moderator)
+	/**
+	 * Set a temporary user on the OpenMeetings server, this user is a guest in OpenOLAT.
+	 * @param firstName
+	 * @param lastName
+	 * @param roomId
+	 * @param moderator
+	 * @return
+	 * @throws OpenMeetingsException
+	 */
+	public String setGuestUserToRoom(String firstName, String lastName, long roomId)
 	throws OpenMeetingsException;
 	
 	public Long getRoomId(BusinessGroup group, OLATResourceable ores, String subIdentifier);
@@ -87,8 +117,20 @@ public interface OpenMeetingsManager {
 	 */
 	public String getRecordingURL(OpenMeetingsRecording recording, String sid);
 	
+	/**
+	 * A UUID mapped to the identity is saved in a cache
+	 * @param token
+	 * @return
+	 */
+	public Long getIdentityKey(String token);
 	
-	public List<OpenMeetingsUser> getUsersOf(OpenMeetingsRoom room);
+	/**
+	 * 
+	 * @param room
+	 * @return
+	 */
+	public List<OpenMeetingsUser> getUsersOf(OpenMeetingsRoom room)
+			throws OpenMeetingsException;
 	
 	/**
 	 * Kick all users from a room
diff --git a/src/main/java/org/olat/modules/openmeetings/manager/OpenMeetingsManagerImpl.java b/src/main/java/org/olat/modules/openmeetings/manager/OpenMeetingsManagerImpl.java
index a8e0fd951a3..c4aa604aa10 100644
--- a/src/main/java/org/olat/modules/openmeetings/manager/OpenMeetingsManagerImpl.java
+++ b/src/main/java/org/olat/modules/openmeetings/manager/OpenMeetingsManagerImpl.java
@@ -19,8 +19,11 @@
  */
 package org.olat.modules.openmeetings.manager;
 
+import java.io.File;
+import java.io.Serializable;
 import java.io.StringWriter;
 import java.net.ConnectException;
+import java.rmi.RemoteException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -42,6 +45,8 @@ import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.WebappHelper;
+import org.olat.core.util.cache.n.CacheWrapper;
+import org.olat.core.util.coordinate.CoordinatorManager;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.core.util.xml.XStreamHelper;
 import org.olat.group.BusinessGroup;
@@ -52,6 +57,7 @@ import org.olat.modules.openmeetings.model.OpenMeetingsUser;
 import org.olat.modules.openmeetings.model.RoomReturnInfo;
 import org.olat.properties.Property;
 import org.olat.properties.PropertyManager;
+import org.olat.user.DisplayPortraitManager;
 import org.olat.user.UserDataDeletable;
 import org.openmeetings.app.conference.session.xsd.RoomClient;
 import org.openmeetings.app.persistence.beans.flvrecord.xsd.FlvRecording;
@@ -68,6 +74,7 @@ import org.openmeetings.axis.services.GetRoomById;
 import org.openmeetings.axis.services.GetRoomByIdResponse;
 import org.openmeetings.axis.services.GetRoomWithClientObjectsById;
 import org.openmeetings.axis.services.GetRoomWithClientObjectsByIdResponse;
+import org.openmeetings.axis.services.GetRoomWithCurrentUsersByIdResponse;
 import org.openmeetings.axis.services.GetRoomsWithCurrentUsersByListAndType;
 import org.openmeetings.axis.services.GetRoomsWithCurrentUsersByListAndTypeResponse;
 import org.openmeetings.axis.services.GetSession;
@@ -113,8 +120,11 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 	private PropertyManager propertyManager;
 	@Autowired
 	private UserDeletionManager userDeletionManager;
+	@Autowired
+	private CoordinatorManager coordinator;
 
 	private XStream xStream;
+	private CacheWrapper sessionCache;
 	private OpenMeetingsLanguages languagesMapping;
 	
 	@PostConstruct
@@ -128,6 +138,8 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 		
 		languagesMapping = new OpenMeetingsLanguages();
 		languagesMapping.read();
+
+		sessionCache = coordinator.getCoordinator().getCacher().getOrCreateCache(OpenMeetingsManager.class, "session");
 	}
 
 	@Override
@@ -246,25 +258,7 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 		try {
 			UserServiceStub userWs = getUserWebService();
 			String adminSessionId = adminLogin();
-/*
-			SetUserObjectAndGenerateRoomHashByURL userObj = new SetUserObjectAndGenerateRoomHashByURL();
-			userObj.setBecomeModeratorAsInt(moderator ? 1 : 0);
-			userObj.setEmail(identity.getUser().getProperty(UserConstants.EMAIL, null));
-			userObj.setExternalUserId(getOpenOLATUserExternalId(identity));
-			userObj.setExternalUserType(getOpenOLATExternalType());
-			userObj.setFirstname(identity.getUser().getProperty(UserConstants.FIRSTNAME, null));
-			userObj.setLastname(identity.getUser().getProperty(UserConstants.LASTNAME, null));
-			userObj.setProfilePictureUrl("");
-			userObj.setRoom_id(roomId);
-			userObj.setShowAudioVideoTestAsInt(0);
-			userObj.setSID(adminSessionId);
-			userObj.setUsername(identity.getName());
-			
-			SetUserObjectAndGenerateRoomHashByURLResponse response = userWs.setUserObjectAndGenerateRoomHashByURL(userObj);
-			String hashedUrl = response.get_return();
-			*/
-			
-			
+
 			SetUserObjectAndGenerateRoomHashByURLAndRecFlag userObj = new SetUserObjectAndGenerateRoomHashByURLAndRecFlag();
 			userObj.setBecomeModeratorAsInt(moderator ? 1 : 0);
 			userObj.setEmail(identity.getUser().getProperty(UserConstants.EMAIL, null));
@@ -272,7 +266,7 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 			userObj.setExternalUserType(getOpenOLATExternalType());
 			userObj.setFirstname(identity.getUser().getProperty(UserConstants.FIRSTNAME, null));
 			userObj.setLastname(identity.getUser().getProperty(UserConstants.LASTNAME, null));
-			userObj.setProfilePictureUrl("");
+			userObj.setProfilePictureUrl(getPortraitURL(identity));
 			userObj.setRoom_id(roomId);
 			userObj.setShowAudioVideoTestAsInt(0);
 			userObj.setSID(adminSessionId);
@@ -282,13 +276,6 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 			SetUserObjectAndGenerateRoomHashByURLAndRecFlagResponse response = userWs.setUserObjectAndGenerateRoomHashByURLAndRecFlag(userObj);
 			String hashedUrl = response.get_return();
 			
-			
-			
-			
-			
-			
-			
-			
 			return hashedUrl;
 		} catch (Exception e) {
 			log.error("", e);
@@ -296,8 +283,35 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 		}
 	}
 	
+	private String getPortraitURL(Identity identity) {
+		File portrait = DisplayPortraitManager.getInstance().getBigPortrait(identity);
+		if(portrait == null || !portrait.exists()) {
+			return "";
+		}
+		
+		String key = UUID.randomUUID().toString().replace("-", "");
+		sessionCache.put(key, identity.getKey());
+		
+		StringBuilder sb = new StringBuilder();
+		sb.append(Settings.getServerContextPathURI())
+		  .append("/restapi/openmeetings/")
+		  .append(key)
+		  .append("/portrait");
+
+		return sb.toString();
+	}
+	
+	@Override
+	public Long getIdentityKey(String token) {
+		Serializable obj = sessionCache.get(token);
+		if(obj instanceof Long) {
+			return (Long)obj;
+		}
+		return null;
+	}
+	
 	@Override
-	public String setGuestUserToRoom(String firstName, String lastName, long roomId, boolean moderator)
+	public String setGuestUserToRoom(String firstName, String lastName, long roomId)
 	throws OpenMeetingsException {
 		try {
 			UserServiceStub userWs = getUserWebService();
@@ -305,7 +319,7 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 			
 			String username = UUID.randomUUID().toString().replace("-", "");
 			SetUserObjectAndGenerateRoomHashByURL userObj = new SetUserObjectAndGenerateRoomHashByURL();
-			userObj.setBecomeModeratorAsInt(moderator ? 1 : 0);
+			userObj.setBecomeModeratorAsInt(0);
 			userObj.setEmail("");
 			userObj.setExternalUserId(getOpenOLATUserExternalId(username));
 			userObj.setExternalUserType(getOpenOLATExternalType());
@@ -414,6 +428,9 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 			
 			CloseRoomResponse closeResponse = roomWs.closeRoom(closeRoom);
 			responseCode = closeResponse.get_return();
+			if(responseCode < 0) {
+				throw new OpenMeetingsException(responseCode);
+			}
 		} catch (Exception e) {
 			log.error("", e);
 			throw translateException(e, responseCode);
@@ -584,7 +601,8 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 	}
 
 	@Override
-	public List<OpenMeetingsUser> getUsersOf(OpenMeetingsRoom room) {
+	public List<OpenMeetingsUser> getUsersOf(OpenMeetingsRoom room)
+	throws OpenMeetingsException {
 		try {
 			String adminSID = adminLogin();
 			RoomServiceStub roomWs = getRoomWebService();
@@ -600,8 +618,7 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 			}
 			return Collections.emptyList();
 		} catch (Exception e) {
-			log.error("", e);
-			return Collections.emptyList();
+			throw translateException(e, 0);
 		}
 	}
 	
@@ -628,30 +645,6 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 		user.setLastName(client.getLastname());
 		return user;
 	}
-	
-	private List<OpenMeetingsUser> convert(RoomClient[] clients) {
-		List<OpenMeetingsUser> users = new ArrayList<OpenMeetingsUser>();
-		for(RoomClient client:clients) {
-			OpenMeetingsUser user = convert(client);
-			if(user != null) {
-				users.add(user);
-			}
-		}
-		return users;
-	}
-	
-	private OpenMeetingsUser convert(RoomClient client) {
-		if(client == null) {
-			return null;
-		}
-		OpenMeetingsUser user = new OpenMeetingsUser();
-		user.setPublicSID(client.getPublicSID());
-		user.setFirstName(client.getFirstname());
-		user.setLastName(client.getLastname());
-		user.setExternalUserID(client.getExternalUserId());
-		user.setExternalUserType(client.getExternalUserType());
-		return user;
-	}
 
 	@Override
 	public boolean removeUser(String publicSID) {
@@ -696,23 +689,54 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 			return null;
 		}
 	}
+	
+	private String adminSID;
+	private long adminSIDCreationTime;
+	
 
 	private String adminLogin() {
 		try {
-			String sessionId = getSessionID() ;
-			LoginUser adminUser = new LoginUser();
-			adminUser.setSID(sessionId);
-			adminUser.setUsername(openMeetingsModule.getAdminLogin());
-			adminUser.setUserpass(openMeetingsModule.getAdminPassword());
-			LoginUserResponse loginResponse = getUserWebService().loginUser(adminUser);
-			long login = loginResponse.get_return();
-			return login > 0 ? sessionId : null;
+			synchronized(this) {
+				if(isAdminSIDValid()) {
+					return adminSID;
+				}
+				adminSID = adminLoginInternal();
+				adminSIDCreationTime = System.currentTimeMillis();
+			}
+			return adminSID;
 		} catch (Exception e) {
 			log.error("", e);
 			return null;
 		}
 	}
 	
+	private String adminLoginInternal()
+	throws AxisFault, RemoteException {
+		String sid = getSessionID() ;
+		LoginUser adminUser = new LoginUser();
+		adminUser.setSID(sid);
+		adminUser.setUsername(openMeetingsModule.getAdminLogin());
+		adminUser.setUserpass(openMeetingsModule.getAdminPassword());
+		LoginUserResponse loginResponse = getUserWebService().loginUser(adminUser);
+		long login = loginResponse.get_return();
+		return login > 0 ? sid : null;
+	}
+	
+	/**
+	 * 
+	 * @return
+	 */
+	private boolean isAdminSIDValid() {
+		if(adminSID != null) {
+			return true;
+			/*long age = System.currentTimeMillis() - adminSIDCreationTime;
+			if(age < 450000) {
+				return false;//don't cache
+			}*/
+		}
+		return false;
+	}
+	
 	@Override
 	public void deleteAll(BusinessGroup group, OLATResourceable ores, String subIdentifier)
 	 throws OpenMeetingsException {
@@ -725,7 +749,7 @@ public class OpenMeetingsManagerImpl implements OpenMeetingsManager, UserDataDel
 				}
 			}
 		} catch (OpenMeetingsException e) {
-			
+			log.error("", e);
 		}
 	}
 
diff --git a/src/main/java/org/olat/modules/openmeetings/restapi/OpenMeetingsWebService.java b/src/main/java/org/olat/modules/openmeetings/restapi/OpenMeetingsWebService.java
new file mode 100644
index 00000000000..02efab22d5c
--- /dev/null
+++ b/src/main/java/org/olat/modules/openmeetings/restapi/OpenMeetingsWebService.java
@@ -0,0 +1,100 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * 12.10.2011 by frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.openmeetings.restapi;
+
+import java.io.File;
+import java.util.Date;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.CacheControl;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Request;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.olat.basesecurity.BaseSecurityManager;
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.id.Identity;
+import org.olat.modules.openmeetings.OpenMeetingsModule;
+import org.olat.modules.openmeetings.manager.OpenMeetingsManager;
+import org.olat.user.DisplayPortraitManager;
+
+/**
+ * 
+ * Initial date: 13.11.2012<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Path("openmeetings")
+public class OpenMeetingsWebService {
+
+	public static CacheControl cc = new CacheControl();
+	
+	/**
+	 * Retrieves the portrait of an user
+	 * @response.representation.200.mediaType application/octet-stream
+	 * @response.representation.200.doc The portrait as image
+   * @response.representation.404.doc The identity or the portrait not found
+	 * @param identityToken The identity key of the user being searched
+	 * @param request The REST request
+	 * @return The image
+	 */
+	@GET
+	@Path("{identityToken}/portrait")
+	@Produces({"image/jpeg","image/jpg",MediaType.APPLICATION_OCTET_STREAM})
+	public Response getPortrait(@PathParam("identityToken") String identityToken, @Context Request request) {
+		try {
+			OpenMeetingsModule module = CoreSpringFactory.getImpl(OpenMeetingsModule.class);
+			if(!module.isEnabled()) {
+				return Response.serverError().status(Status.FORBIDDEN).build();
+			}
+
+			OpenMeetingsManager omm = CoreSpringFactory.getImpl(OpenMeetingsManager.class);
+			Long identityKey = omm.getIdentityKey(identityToken);
+			if(identityKey == null) {
+				return Response.serverError().status(Status.NOT_FOUND).build();
+			}
+			Identity identity = BaseSecurityManager.getInstance().loadIdentityByKey(identityKey, false);
+			if(identity == null) {
+				return Response.serverError().status(Status.NOT_FOUND).build();
+			}
+			
+			File portrait = DisplayPortraitManager.getInstance().getBigPortrait(identity);
+			if(portrait == null || !portrait.exists()) {
+				return Response.serverError().status(Status.NOT_FOUND).build();
+			}
+
+			Date lastModified = new Date(portrait.lastModified());
+			Response.ResponseBuilder response = request.evaluatePreconditions(lastModified);
+			if(response == null) {
+				response = Response.ok(portrait).lastModified(lastModified).cacheControl(cc);
+			}
+			return response.build();
+		} catch (Throwable e) {
+			throw new WebApplicationException(e);
+		}
+	}
+
+}
diff --git a/src/main/java/org/olat/modules/openmeetings/ui/OpenMeetingsAdminRoomMembersController.java b/src/main/java/org/olat/modules/openmeetings/ui/OpenMeetingsAdminRoomMembersController.java
index 2960c6a8899..f0b35117ba0 100644
--- a/src/main/java/org/olat/modules/openmeetings/ui/OpenMeetingsAdminRoomMembersController.java
+++ b/src/main/java/org/olat/modules/openmeetings/ui/OpenMeetingsAdminRoomMembersController.java
@@ -160,8 +160,9 @@ public class OpenMeetingsAdminRoomMembersController extends BasicController {
 			
 			long numOfFreePlaces = room.getSize() - users.size();
 			mainVC.contextPut("freePlaces", new String[]{Long.toString(numOfFreePlaces)});
-		} catch (Exception e) {
-			showError(OpenMeetingsException.SERVER_NOT_I18N_KEY);
+		} catch (OpenMeetingsException e) {
+			tableCtr.setTableDataModel(new UserToGroupDataModel());
+			showError(e.getType().i18nKey());
 		}
 	}
 
diff --git a/src/main/java/org/olat/modules/openmeetings/ui/OpenMeetingsRecordingsController.java b/src/main/java/org/olat/modules/openmeetings/ui/OpenMeetingsRecordingsController.java
index 761514a03ac..b293bf74e7d 100644
--- a/src/main/java/org/olat/modules/openmeetings/ui/OpenMeetingsRecordingsController.java
+++ b/src/main/java/org/olat/modules/openmeetings/ui/OpenMeetingsRecordingsController.java
@@ -62,7 +62,7 @@ public class OpenMeetingsRecordingsController extends BasicController {
 		openMeetingsManager = CoreSpringFactory.getImpl(OpenMeetingsManager.class);
 
 		TableGuiConfiguration tableConfig = new TableGuiConfiguration();
-		tableConfig.setTableEmptyMessage(translate("users.empty"));
+		tableConfig.setTableEmptyMessage(translate("recordings.empty"));
 		
 		Translator trans = UserManager.getInstance().getPropertyHandlerTranslator(getTranslator());
 		tableCtr = new TableController(tableConfig, ureq, getWindowControl(), trans);
diff --git a/src/main/java/org/olat/modules/openmeetings/ui/OpenMeetingsRoomEditController.java b/src/main/java/org/olat/modules/openmeetings/ui/OpenMeetingsRoomEditController.java
index 06400ae49be..9db3444c77c 100644
--- a/src/main/java/org/olat/modules/openmeetings/ui/OpenMeetingsRoomEditController.java
+++ b/src/main/java/org/olat/modules/openmeetings/ui/OpenMeetingsRoomEditController.java
@@ -64,15 +64,17 @@ public class OpenMeetingsRoomEditController extends FormBasicController {
 	private final String subIdentifier;
 	
 	private OpenMeetingsRoom room;
+	private OpenMeetingsRoom defaultSettings;
 	private final OpenMeetingsManager openMeetingsManager;
 
 	public OpenMeetingsRoomEditController(UserRequest ureq, WindowControl wControl, BusinessGroup group, OLATResourceable ores,
-			String subIdentifier, String resourceName, boolean admin) {
+			String subIdentifier, String resourceName, OpenMeetingsRoom defaultSettings, boolean admin) {
 		super(ureq, wControl);
 		
 		this.group = group;
 		this.ores = ores;
 		this.subIdentifier = subIdentifier;
+		this.defaultSettings = defaultSettings;
 		
 		roomTypeKeys = new String[]{
 				RoomType.conference.typeStr(), RoomType.audience.typeStr(), RoomType.restricted.typeStr(), RoomType.interview.typeStr()
@@ -101,8 +103,8 @@ public class OpenMeetingsRoomEditController extends FormBasicController {
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		
-		String name = room == null ? "" : room.getName();
-		roomNameEl = uifactory.addTextElement("roomname", "room.name", 255, name, formLayout);
+		String name = room == null ? (defaultSettings == null ? null : defaultSettings.getName()) : room.getName();
+		roomNameEl = uifactory.addTextElement("roomname", "room.name", 255, name == null ? "" : name, formLayout);
 		
 		String[] roomTypeValues = new String[]{
 				translate(RoomType.conference.i18nKey()), translate(RoomType.audience.i18nKey()), translate(RoomType.restricted.i18nKey()), translate(RoomType.interview.i18nKey())
@@ -111,12 +113,18 @@ public class OpenMeetingsRoomEditController extends FormBasicController {
 		if(room != null) {
 			String type = Long.toString(room.getType());
 			roomTypeEl.select(type, true);
+		} else if(defaultSettings != null && defaultSettings.getType() > 0) {
+			String type = Long.toString(defaultSettings.getType());
+			roomTypeEl.select(type, true);
 		}
 		
 		roomSizeEl = uifactory.addDropdownSingleselect("roomsize", "room.size", formLayout, roomSizes, roomSizes, null);
 		if(room != null) {
 			String size = Long.toString(room.getSize());
 			roomSizeEl.select(size, true);
+		} else if(defaultSettings != null && defaultSettings.getSize() > 0) {
+			String size = Long.toString(defaultSettings.getSize());
+			roomSizeEl.select(size, true);
 		}
 		 
 		String[]  moderationModeValues = new String[]{ translate("room.moderation.yes"), translate("room.moderation.no") };
@@ -124,17 +132,21 @@ public class OpenMeetingsRoomEditController extends FormBasicController {
 		if(room != null) {
 			String key = room.isModerated() ? moderationModeKeys[0] : moderationModeKeys[1];
 			moderationModeEl.select(key, true);
-		};
+		} else if(defaultSettings != null) {
+			String key = defaultSettings.isModerated() ? moderationModeKeys[0] : moderationModeKeys[1];
+			moderationModeEl.select(key, true);
+		}
 
 		String[] recordingValues = new String[]{ translate("room.recording") };
 		recordingEl = uifactory.addCheckboxesHorizontal("recording", "room.recording", formLayout, recordingKeys, recordingValues, null);
 		if(room != null) {
-			String key = room.isRecordingAllowed() ? recordingKeys[0] : recordingKeys[1];
-			recordingEl.select(key, true);
-		};
+			recordingEl.select(recordingKeys[0], room.isRecordingAllowed());
+		} else if(defaultSettings != null) {
+			recordingEl.select(recordingKeys[0], defaultSettings.isRecordingAllowed());
+		}
 
-		String comment = room == null ? "" : room.getComment();
-		commentEl = uifactory.addRichTextElementForStringData("roomcomment", "room.comment", comment,
+		String comment = room == null ? (defaultSettings == null ? null : defaultSettings.getComment()) : room.getComment();
+		commentEl = uifactory.addRichTextElementForStringData("roomcomment", "room.comment", comment == null ? "" : comment,
 				10, -1, false, false, null, null, formLayout, ureq.getUserSession(), getWindowControl());
 
 		FormLayoutContainer buttonContainer = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
@@ -173,10 +185,11 @@ public class OpenMeetingsRoomEditController extends FormBasicController {
 		
 		if(room.getRoomId() > 0) {
 			room = openMeetingsManager.updateRoom(group, ores, subIdentifier, room);
+			fireEvent(ureq, Event.CHANGED_EVENT);
 		} else {
 			room = openMeetingsManager.addRoom(group, ores, subIdentifier, room);
+			fireEvent(ureq, Event.DONE_EVENT);
 		}
-		fireEvent(ureq, Event.CHANGED_EVENT);
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/modules/openmeetings/ui/OpenMeetingsRunController.java b/src/main/java/org/olat/modules/openmeetings/ui/OpenMeetingsRunController.java
index 5430c739b5f..4a6f6e481dd 100644
--- a/src/main/java/org/olat/modules/openmeetings/ui/OpenMeetingsRunController.java
+++ b/src/main/java/org/olat/modules/openmeetings/ui/OpenMeetingsRunController.java
@@ -225,7 +225,7 @@ public class OpenMeetingsRunController extends BasicController {
 	
 	private void doEdit(UserRequest ureq) {
 		cleanupPopups();
-		editController = new OpenMeetingsRoomEditController(ureq, getWindowControl(), group, ores, subIdentifier, "", true);
+		editController = new OpenMeetingsRoomEditController(ureq, getWindowControl(), group, ores, subIdentifier, "", null, true);
 		listenTo(editController);
 
 		cmc = new CloseableModalController(getWindowControl(), translate("close"), editController.getInitialComponent(), true, translate("edit"));
@@ -248,7 +248,7 @@ public class OpenMeetingsRunController extends BasicController {
 			showError("room.notfound.error");
 		} else {
 			try {
-				String securedHash = openMeetingsManager.setGuestUserToRoom(firstName, lastName, roomId, true);
+				String securedHash = openMeetingsManager.setGuestUserToRoom(firstName, lastName, roomId);
 				String url = openMeetingsManager.getURL(getIdentity(), roomId.longValue(), securedHash, getLocale());
 				DisplayOrDownloadComponent cmp = new DisplayOrDownloadComponent("openCommand", url);
 				mainVC.put("openCmd", cmp);
@@ -263,7 +263,7 @@ public class OpenMeetingsRunController extends BasicController {
 			showError("room.notfound.error");
 		} else {
 			try {
-				String securedHash = openMeetingsManager.setUserToRoom(getIdentity(), roomId, true);
+				String securedHash = openMeetingsManager.setUserToRoom(getIdentity(), roomId, admin);
 				String url = openMeetingsManager.getURL(getIdentity(), roomId.longValue(), securedHash, getLocale());
 				RedirectMediaResource redirect = new RedirectMediaResource(url);
 				ureq.getDispatchResult().setResultingMediaResource(redirect);
diff --git a/src/main/java/org/olat/modules/openmeetings/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/openmeetings/ui/_i18n/LocalStrings_de.properties
index e36833fc3d2..a2f9e72caae 100644
--- a/src/main/java/org/olat/modules/openmeetings/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/modules/openmeetings/ui/_i18n/LocalStrings_de.properties
@@ -24,6 +24,7 @@ view=Ansehen
 table.empty=Kein Raum wurde gefunden.
 recording.name=Name
 recordings=Aufzeichnungen
+recordings.empty=Dieser Raum hat noch kein Aufzeichnung
 rooms.title=Raum
 room.comment=Kommentar
 room.members=Mitglieder
diff --git a/src/main/java/org/olat/restapi/_spring/restApiContext.xml b/src/main/java/org/olat/restapi/_spring/restApiContext.xml
index 9e10d9beb83..ae1adabf3e5 100644
--- a/src/main/java/org/olat/restapi/_spring/restApiContext.xml
+++ b/src/main/java/org/olat/restapi/_spring/restApiContext.xml
@@ -44,6 +44,7 @@
 				<value>org.olat.modules.fo.restapi.ForumImportWebService</value>
 				<value>org.olat.modules.fo.restapi.ForumCourseNodeWebService</value>
 				<value>org.olat.modules.fo.restapi.MyForumsWebService</value>
+				<value>org.olat.modules.openmeetings.restapi.OpenMeetingsWebService</value>
 				<value>org.olat.catalog.restapi.CatalogWebService</value>
 				<value>org.olat.notifications.restapi.NotificationsWebService</value>
 				<value>org.olat.registration.restapi.RegistrationWebService</value>
diff --git a/src/main/java/org/olat/restapi/security/RestApiLoginFilter.java b/src/main/java/org/olat/restapi/security/RestApiLoginFilter.java
index 3add0ca0804..50bbd9f5870 100644
--- a/src/main/java/org/olat/restapi/security/RestApiLoginFilter.java
+++ b/src/main/java/org/olat/restapi/security/RestApiLoginFilter.java
@@ -329,6 +329,7 @@ public class RestApiLoginFilter implements Filter {
 			openUrls.add(context + "/application.html");
 			openUrls.add(context + "/wadl");
 			openUrls.add(context + "/registration");
+			openUrls.add(context + "/openmeetings");
 		}
 		return openUrls;
 	}
diff --git a/src/main/resources/ehcache.xml b/src/main/resources/ehcache.xml
index 48513e070b4..7f7cf307dce 100644
--- a/src/main/resources/ehcache.xml
+++ b/src/main/resources/ehcache.xml
@@ -76,6 +76,13 @@
         overflowToDisk="false"
         />
 
+	<cache name="org.olat.core.util.cache.n.impl.svm.SingleVMCacher@org.olat.modules.openmeetings.manager.OpenMeetingsManager_session__0"
+        maxElementsInMemory="10000"
+        eternal="false"
+        timeToIdleSeconds="900"
+        timeToLiveSeconds="900"
+        overflowToDisk="false"
+        />
 
 	<!-- 
 		specific OLAT caches
-- 
GitLab