You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openmeetings.apache.org by so...@apache.org on 2019/06/14 15:15:08 UTC

[openmeetings] branch OPENMEETINGS-2077-group-css created (now 73f5877)

This is an automated email from the ASF dual-hosted git repository.

solomax pushed a change to branch OPENMEETINGS-2077-group-css
in repository https://gitbox.apache.org/repos/asf/openmeetings.git.


      at 73f5877  [OPENMEETINGS-2077] external type is moved to the group (tests are broken)

This branch includes the following new commits:

     new 73f5877  [OPENMEETINGS-2077] external type is moved to the group (tests are broken)

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[openmeetings] 01/01: [OPENMEETINGS-2077] external type is moved to the group (tests are broken)

Posted by so...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

solomax pushed a commit to branch OPENMEETINGS-2077-group-css
in repository https://gitbox.apache.org/repos/asf/openmeetings.git

commit 73f5877c1b617e4e4455f3455cc12bfa4b08a776
Author: Maxim Solodovnik <so...@gmail.com>
AuthorDate: Fri Jun 14 22:14:47 2019 +0700

    [OPENMEETINGS-2077] external type is moved to the group (tests are broken)
---
 .../core/converter/DocumentConverter.java          |   2 +-
 .../core/converter/ImageConverter.java             |   2 +-
 .../core/documents/LibraryChartLoader.java         |   2 +-
 .../openmeetings/core/ldap/LdapLoginManager.java   |  40 ++++----
 .../apache/openmeetings/core/mail/MailHandler.java |   6 +-
 .../db/dao/basic/ConfigurationDao.java             |   2 +-
 .../db/dao/calendar/AppointmentDao.java            |  31 ++++---
 .../db/dao/calendar/MeetingMemberDao.java          |   2 +-
 .../openmeetings/db/dao/file/FileItemDao.java      |   2 +-
 .../openmeetings/db/dao/record/RecordingDao.java   |  53 ++++-------
 .../apache/openmeetings/db/dao/room/PollDao.java   |  19 ++--
 .../apache/openmeetings/db/dao/room/RoomDao.java   |  60 ++++--------
 .../apache/openmeetings/db/dao/room/SipDao.java    |   2 +-
 .../openmeetings/db/dao/server/LdapConfigDao.java  |   2 +-
 .../openmeetings/db/dao/server/SessiondataDao.java |   2 +-
 .../apache/openmeetings/db/dao/user/GroupDao.java  |   9 ++
 .../openmeetings/db/dao/user/UserContactDao.java   |  21 +++--
 .../apache/openmeetings/db/dao/user/UserDao.java   | 103 +++++++++------------
 .../db/dto/calendar/AppointmentDTO.java            |   8 +-
 .../db/dto/calendar/MeetingMemberDTO.java          |   9 +-
 .../openmeetings/db/dto/record/RecordingDTO.java   |  11 +++
 .../apache/openmeetings/db/dto/room/RoomDTO.java   |  17 +++-
 .../apache/openmeetings/db/dto/user/UserDTO.java   |  15 ++-
 .../openmeetings/db/entity/file/BaseFileItem.java  |  12 +++
 .../openmeetings/db/entity/file/FileItem.java      |  11 ---
 .../openmeetings/db/entity/record/Recording.java   |  55 +++++------
 .../apache/openmeetings/db/entity/room/Room.java   |  20 +++-
 .../apache/openmeetings/db/entity/user/Group.java  |  31 +++++--
 .../openmeetings/db/entity/user/GroupUser.java     |  12 +--
 .../apache/openmeetings/db/entity/user/User.java   |  35 +++++--
 .../openmeetings/db/util/ApplicationHelper.java    |   5 +-
 .../org/apache/openmeetings/db/util/DaoHelper.java |  26 ++++++
 .../apache/openmeetings/db/util/LocaleHelper.java  |   2 +-
 .../apache/openmeetings/backup/BackupExport.java   |   4 +-
 .../apache/openmeetings/backup/BackupImport.java   |  13 +--
 .../org/apache/openmeetings/cli/CleanupHelper.java |   4 +-
 .../installation/ImportInitvalues.java             |   4 +-
 .../org/apache/openmeetings/screenshare/Core.java  |  58 ++++++------
 .../screenshare/RTMPClientPublish.java             |   2 +-
 .../screenshare/gui/ScreenKeyListener.java         |   4 +-
 .../screenshare/gui/ScreenSharerFrame.java         |   4 +-
 .../openmeetings/screenshare/job/RemoteJob.java    |   4 +-
 .../service/calendar/caldav/IcalUtils.java         |   2 +-
 .../calendar/caldav/handler/EtagsHandler.java      |   9 +-
 .../calendar/caldav/methods/SyncMethod.java        |   2 +-
 .../service/room/InvitationManager.java            |   2 +-
 .../openmeetings/util/crypt/CryptProvider.java     |   2 +-
 .../apache/openmeetings/util/mail/IcalHandler.java |   6 +-
 .../openmeetings/util/process/ProcessResult.java   |   2 +-
 .../openmeetings/web/admin/groups/GroupsPanel.java |   6 +-
 .../openmeetings/web/admin/oauth/OAuthPanel.html   |   4 +-
 .../openmeetings/web/admin/rooms/RoomsPanel.html   |   4 +-
 .../apache/openmeetings/web/app/UserManager.java   |   5 +-
 .../apache/openmeetings/web/app/WebSession.java    |  12 +--
 .../web/pages/auth/ForgetPasswordDialog.java       |  31 ++++---
 .../apache/openmeetings/web/room/RoomPanel.java    |   2 +-
 .../openmeetings/web/room/sidebar/RoomSidebar.html |   2 +-
 .../web/room/sidebar/UploadDialog.java             |   1 -
 .../web/user/calendar/AppointmentDialog.java       |   2 +-
 .../web/user/calendar/CalendarDialog.java          |   2 +-
 .../web/user/calendar/CalendarPanel.java           |   2 +-
 .../user/record/RecordingResourceReference.java    |   6 +-
 openmeetings-web/src/main/webapp/css/raw-room.css  |   8 ++
 .../TestDatabaseStructureGetUserStart.java         |   2 +-
 .../apache/openmeetings/domain/TestAddGroup.java   |   3 +-
 .../apache/openmeetings/user/TestUserContact.java  |   3 +-
 .../apache/openmeetings/user/TestUserGroup.java    |   2 +-
 .../webservice/TestCalendarService.java            |   7 +-
 .../webservice/TestRecordingService.java           |   3 +-
 .../openmeetings/webservice/TestUserService.java   |   5 +-
 .../webservice/CalendarWebService.java             |   6 +-
 .../openmeetings/webservice/ErrorWebService.java   |   2 +-
 .../openmeetings/webservice/GroupWebService.java   |   2 +-
 .../webservice/RecordingWebService.java            |   6 +-
 .../openmeetings/webservice/RoomWebService.java    |  13 ++-
 .../openmeetings/webservice/UserWebService.java    |  23 ++---
 76 files changed, 489 insertions(+), 426 deletions(-)

diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/converter/DocumentConverter.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/converter/DocumentConverter.java
index 9592b61..0bc1742 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/converter/DocumentConverter.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/converter/DocumentConverter.java
@@ -60,7 +60,7 @@ public class DocumentConverter {
 		boolean fullProcessing = !sf.isPdf();
 		File original = f.getFile(sf.getExt());
 		File pdf = f.getFile(EXTENSION_PDF);
-		log.debug("fullProcessing: " + fullProcessing);
+		log.debug("fullProcessing: {}", fullProcessing);
 		if (fullProcessing) {
 			log.debug("-- running JOD --");
 			logs.add(doJodConvert(original, pdf));
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/converter/ImageConverter.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/converter/ImageConverter.java
index b33c10c..035cdfc 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/converter/ImageConverter.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/converter/ImageConverter.java
@@ -75,7 +75,7 @@ public class ImageConverter extends BaseConverter {
 		if (!sf.isPng()) {
 			File img = f.getFile(sf.getExt());
 
-			log.debug("##### convertImage destinationFile: " + png);
+			log.debug("##### convertImage destinationFile: {}", png);
 			logs.add(convertSinglePng(img, png));
 		} else if (!png.exists()){
 			copyFile(f.getFile(sf.getExt()), png);
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/documents/LibraryChartLoader.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/documents/LibraryChartLoader.java
index bc942e0..8379c25 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/documents/LibraryChartLoader.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/documents/LibraryChartLoader.java
@@ -45,7 +45,7 @@ public class LibraryChartLoader {
 		try {
 			File file = new File(dir, fileName + CHART_EXT);
 
-			log.error("filepathComplete: " + file);
+			log.error("filepathComplete: {}", file);
 
 			XStream xStream = new XStream(new XppDriver());
 			xStream.setMode(XStream.NO_REFERENCES);
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/ldap/LdapLoginManager.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/ldap/LdapLoginManager.java
index 372bf23..a018de5 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/ldap/LdapLoginManager.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/ldap/LdapLoginManager.java
@@ -18,6 +18,23 @@
  */
 package org.apache.openmeetings.core.ldap;
 
+import static org.apache.openmeetings.db.dao.user.UserDao.getNewUserInstance;
+import static org.apache.openmeetings.db.util.LocaleHelper.validateCountry;
+import static org.apache.openmeetings.db.util.TimezoneUtil.getTimeZone;
+import static org.apache.openmeetings.util.OmException.BAD_CREDENTIALS;
+import static org.apache.openmeetings.util.OmException.UNKNOWN;
+import static org.apache.openmeetings.util.OmFileHelper.loadLdapConf;
+import static org.apache.openmeetings.util.OpenmeetingsVariables.getDefaultGroup;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+
 import org.apache.directory.api.ldap.model.cursor.CursorException;
 import org.apache.directory.api.ldap.model.cursor.CursorLdapReferralException;
 import org.apache.directory.api.ldap.model.cursor.EntryCursor;
@@ -51,23 +68,6 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
-import java.io.Closeable;
-import java.io.IOException;
-import java.util.AbstractMap;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Properties;
-
-import static org.apache.openmeetings.db.dao.user.UserDao.getNewUserInstance;
-import static org.apache.openmeetings.db.util.LocaleHelper.validateCountry;
-import static org.apache.openmeetings.db.util.TimezoneUtil.getTimeZone;
-import static org.apache.openmeetings.util.OmException.BAD_CREDENTIALS;
-import static org.apache.openmeetings.util.OmException.UNKNOWN;
-import static org.apache.openmeetings.util.OmFileHelper.loadLdapConf;
-import static org.apache.openmeetings.util.OpenmeetingsVariables.getDefaultGroup;
-
 /**
  * Management of optional LDAP Login
  *
@@ -346,7 +346,7 @@ public class LdapLoginManager {
 				u.setDomainId(domainId);
 				Group g = groupDao.get(getDefaultGroup());
 				if (g != null) {
-					u.getGroupUsers().add(new GroupUser(g, u));
+					u.addGroup(g);
 				}
 				String login = getLogin(config, entry);
 				if (ldapCfg.getAddDomainToUserName()) {
@@ -410,8 +410,8 @@ public class LdapLoginManager {
 						}
 					}
 					if (!found) {
-						u.getGroupUsers().add(new GroupUser(o, u));
-						log.debug("Going to add user to group:: " + name);
+						u.addGroup(o);
+						log.debug("Going to add user to group:: {}", name);
 					}
 				}
 			}
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/mail/MailHandler.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/mail/MailHandler.java
index 04c5d0c..0d19dff 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/mail/MailHandler.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/mail/MailHandler.java
@@ -212,7 +212,7 @@ public class MailHandler {
 		msg.setSubject(m.getSubject(), UTF_8.name());
 		String replyTo = m.getReplyTo();
 		if (replyTo != null && mailAddReplyTo) {
-			log.debug("setReplyTo " + replyTo);
+			log.debug("setReplyTo {}", replyTo);
 			if (MailUtil.isValid(replyTo)) {
 				msg.setReplyTo(new InternetAddress[]{new InternetAddress(replyTo)});
 			}
@@ -242,8 +242,8 @@ public class MailHandler {
 			}
 			taskExecutor.execute(() -> {
 				log.debug("Message sending in progress");
-				log.debug("  To: " + m.getRecipients());
-				log.debug("  Subject: " + m.getSubject());
+				log.debug("  To: {}", m.getRecipients());
+				log.debug("  Subject: {}", m.getSubject());
 
 				// -- Send the message --
 				try {
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/basic/ConfigurationDao.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/basic/ConfigurationDao.java
index 3abbcb1..622a58f 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/basic/ConfigurationDao.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/basic/ConfigurationDao.java
@@ -196,7 +196,7 @@ public class ConfigurationDao implements IDataProviderDao<Configuration> {
 		List<Configuration> list = get(new String[] {key});
 
 		if (list == null || list.isEmpty() || list.get(0) == null) {
-			log.warn("Could not find key in configurations: " + key);
+			log.warn("Could not find key in configurations: {}", key);
 			return null;
 		}
 		return list.get(0);
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/calendar/AppointmentDao.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/calendar/AppointmentDao.java
index ebc2cef..fc41111 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/calendar/AppointmentDao.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/calendar/AppointmentDao.java
@@ -18,6 +18,21 @@
  */
 package org.apache.openmeetings.db.dao.calendar;
 
+import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_CALENDAR_ROOM_CAPACITY;
+import static org.apache.openmeetings.util.OpenmeetingsVariables.PARAM_USER_ID;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import javax.persistence.TypedQuery;
+
 import org.apache.openmeetings.db.dao.basic.ConfigurationDao;
 import org.apache.openmeetings.db.dao.room.IInvitationManager;
 import org.apache.openmeetings.db.dao.room.RoomDao;
@@ -32,20 +47,6 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Repository;
 import org.springframework.transaction.annotation.Transactional;
 
-import javax.persistence.EntityManager;
-import javax.persistence.PersistenceContext;
-import javax.persistence.Query;
-import javax.persistence.TypedQuery;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_CALENDAR_ROOM_CAPACITY;
-import static org.apache.openmeetings.util.OpenmeetingsVariables.PARAM_USER_ID;
-
 @Repository
 @Transactional
 public class AppointmentDao {
@@ -155,7 +156,7 @@ public class AppointmentDao {
 	}
 
 	public List<Appointment> getInRange(Long userId, Date start, Date end) {
-		log.debug("Start " + start + " End " + end);
+		log.debug("Start {} End {}", start, end);
 
 		TypedQuery<Appointment> query = em.createNamedQuery("appointmentsInRange", Appointment.class);
 		query.setParameter(PARAM_START, start);
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/calendar/MeetingMemberDao.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/calendar/MeetingMemberDao.java
index 481f058..afc0730 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/calendar/MeetingMemberDao.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/calendar/MeetingMemberDao.java
@@ -49,7 +49,7 @@ public class MeetingMemberDao {
 	}
 
 	public Set<Long> getMeetingMemberIdsByAppointment(Long appointmentId) {
-		log.debug("getMeetingMemberIdsByAppointment: " + appointmentId);
+		log.debug("getMeetingMemberIdsByAppointment: {}", appointmentId);
 
 		return new HashSet<>(em.createNamedQuery("getMeetingMemberIdsByAppointment", Long.class)
 				.setParameter("id", appointmentId)
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/file/FileItemDao.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/file/FileItemDao.java
index decbf4e..6fcef93 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/file/FileItemDao.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/file/FileItemDao.java
@@ -47,7 +47,7 @@ public class FileItemDao extends BaseFileItemDao {
 	private static final Logger log = LoggerFactory.getLogger(FileItemDao.class);
 
 	public List<FileItem> getByRoom(Long roomId) {
-		log.debug("getByRoom roomId :: " + roomId);
+		log.debug("getByRoom roomId :: {}", roomId);
 		return em.createNamedQuery("getFilesByRoom", FileItem.class).setParameter("roomId", roomId).getResultList();
 	}
 
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/record/RecordingDao.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/record/RecordingDao.java
index 86fe07a..1aeb34e 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/record/RecordingDao.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/record/RecordingDao.java
@@ -23,7 +23,6 @@ import static org.apache.openmeetings.util.OmFileHelper.EXTENSION_PNG;
 
 import java.time.Duration;
 import java.time.Instant;
-import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
@@ -65,35 +64,25 @@ public class RecordingDao extends BaseFileItemDao {
 		return bf instanceof Recording ? (Recording)bf : null;
 	}
 
-	public List<Recording> getByExternalId(String externalId, String externalType) {
-		try {
-			log.debug("getFByExternalId :externalId: {}; externalType: {}", externalId, externalType);
-
-			TypedQuery<Recording> query = em.createNamedQuery("getRecordingsByExternalUser", Recording.class);
-			query.setParameter("externalId", externalId);
-			query.setParameter("externalType", externalType);
-
-			List<Recording> recordingList = query.getResultList();
+	public List<Recording> getByExternalUser(String externalId, String externalType) {
+		log.debug("getByExternalUser :externalId: {}; externalType: {}", externalId, externalType);
 
-			log.debug("getByExternalId :: " + recordingList.size());
-
-			return recordingList;
-		} catch (Exception ex2) {
-			log.error("[getByExternalId]: ", ex2);
-		}
-		return new ArrayList<>();
+		return em.createNamedQuery("getRecordingsByExternalUser", Recording.class)
+				.setParameter("externalId", externalId)
+				.setParameter("externalType", externalType)
+				.getResultList();
 	}
+
 	public List<Recording> get() {
 		return em.createNamedQuery("getRecordingsAll", Recording.class).getResultList();
 	}
 
 	public List<Recording> getByExternalType(String externalType) {
-		log.debug("getByExternalType :externalType: " + externalType);
+		log.debug("getByExternalType :externalType: {}", externalType);
 
-		TypedQuery<Recording> query = em.createNamedQuery("getRecordingsByExternalType", Recording.class);
-		query.setParameter("externalType", externalType);
-
-		return query.getResultList();
+		return em.createNamedQuery("getRecordingsByExternalType", Recording.class)
+				.setParameter("externalType", externalType)
+				.getResultList();
 	}
 
 	public List<Recording> getRootByPublic(Long groupId) {
@@ -110,7 +99,8 @@ public class RecordingDao extends BaseFileItemDao {
 
 	public List<Recording> getByRoomId(Long roomId) {
 		return em.createNamedQuery("getRecordingsByRoom", Recording.class)
-				.setParameter("roomId", roomId).getResultList();
+				.setParameter("roomId", roomId)
+				.getResultList();
 	}
 
 	public List<Recording> getExpiring(Long groupId, int reminderDays, boolean notified) {
@@ -123,20 +113,9 @@ public class RecordingDao extends BaseFileItemDao {
 	}
 
 	public List<Recording> getByParent(Long parentId) {
-		return em.createNamedQuery("getRecordingsByParent", Recording.class).setParameter("parentId", parentId).getResultList();
-	}
-
-	public void updateEndTime(Long recordingId, Date recordEnd) {
-		try {
-
-			Recording fId = get(recordingId);
-
-			fId.setRecordEnd(recordEnd);
-
-			update(fId);
-		} catch (Exception ex2) {
-			log.error("[updateEndTime]: ", ex2);
-		}
+		return em.createNamedQuery("getRecordingsByParent", Recording.class)
+				.setParameter("parentId", parentId)
+				.getResultList();
 	}
 
 	public Recording update(Recording f) {
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/room/PollDao.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/room/PollDao.java
index 316b6ad..0210e27 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/room/PollDao.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/room/PollDao.java
@@ -18,6 +18,15 @@
  */
 package org.apache.openmeetings.db.dao.room;
 
+import static org.apache.openmeetings.util.OpenmeetingsVariables.PARAM_USER_ID;
+
+import java.util.Date;
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+
 import org.apache.openmeetings.db.entity.room.RoomPoll;
 import org.apache.openmeetings.db.entity.room.RoomPollAnswer;
 import org.slf4j.Logger;
@@ -25,14 +34,6 @@ import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Repository;
 import org.springframework.transaction.annotation.Transactional;
 
-import javax.persistence.EntityManager;
-import javax.persistence.PersistenceContext;
-import javax.persistence.Query;
-import java.util.Date;
-import java.util.List;
-
-import static org.apache.openmeetings.util.OpenmeetingsVariables.PARAM_USER_ID;
-
 @Repository
 @Transactional
 public class PollDao {
@@ -100,7 +101,7 @@ public class PollDao {
 	}
 
 	public boolean hasPoll(Long roomId) {
-		log.debug(" :: hasPoll :: " + roomId);
+		log.debug(" :: hasPoll :: {}", roomId);
 		return em.createNamedQuery("hasPoll", Long.class)
 				.setParameter(PARAM_ROOMID, roomId)
 				.setParameter("archived", false)
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/room/RoomDao.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/room/RoomDao.java
index 3aa89bd..f8a7353 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/room/RoomDao.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/room/RoomDao.java
@@ -18,7 +18,9 @@
  */
 package org.apache.openmeetings.db.dao.room;
 
+import static org.apache.openmeetings.db.util.DaoHelper.fillLazy;
 import static org.apache.openmeetings.db.util.DaoHelper.setLimits;
+import static org.apache.openmeetings.db.util.DaoHelper.single;
 import static org.apache.openmeetings.db.util.TimezoneUtil.getTimeZone;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_SIP_ROOM_PREFIX;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.PARAM_USER_ID;
@@ -38,9 +40,6 @@ import javax.persistence.EntityManager;
 import javax.persistence.PersistenceContext;
 import javax.persistence.TypedQuery;
 
-import org.apache.openjpa.persistence.OpenJPAEntityManager;
-import org.apache.openjpa.persistence.OpenJPAPersistence;
-import org.apache.openjpa.persistence.OpenJPAQuery;
 import org.apache.openmeetings.db.dao.IGroupAdminDataProviderDao;
 import org.apache.openmeetings.db.dao.basic.ConfigurationDao;
 import org.apache.openmeetings.db.dao.user.UserDao;
@@ -76,39 +75,20 @@ public class RoomDao implements IGroupAdminDataProviderDao<Room> {
 	public Room get(Long id) {
 		Room r = null;
 		if (id != null && id.longValue() > 0) {
-			OpenJPAEntityManager oem = OpenJPAPersistence.cast(em);
-			boolean qrce = oem.getFetchPlan().getQueryResultCacheEnabled();
-			try {
-				oem.getFetchPlan().setQueryResultCacheEnabled(false); //update in cache during update
-				TypedQuery<Room> q = oem.createNamedQuery("getRoomById", Room.class);
-				q.setParameter("id", id);
-				@SuppressWarnings("unchecked")
-				OpenJPAQuery<Room> kq = OpenJPAPersistence.cast(q);
-				kq.getFetchPlan().addFetchGroups("roomModerators", "roomGroups", "roomFiles");
-				List<Room> l = kq.getResultList();
-				r = l.isEmpty() ? r : l.get(0);
-			} finally {
-				oem.getFetchPlan().setQueryResultCacheEnabled(qrce);
-			}
+			r = single(fillLazy(em
+					, oem -> oem.createNamedQuery("getRoomById", Room.class)
+						.setParameter("id", id)
+					, "roomModerators", "roomGroups", "roomFiles"));
 		} else {
-			log.info("[get] " + "Info: No room id given");
+			log.info("[get]: No room id given");
 		}
 		return r;
 	}
 
 	public List<Room> get() {
-		OpenJPAEntityManager oem = OpenJPAPersistence.cast(em);
-		boolean qrce = oem.getFetchPlan().getQueryResultCacheEnabled();
-		try {
-			oem.getFetchPlan().setQueryResultCacheEnabled(false); //update in cache during update
-			TypedQuery<Room> q = oem.createNamedQuery("getBackupRooms", Room.class);
-			@SuppressWarnings("unchecked")
-			OpenJPAQuery<Room> kq = OpenJPAPersistence.cast(q);
-			kq.getFetchPlan().addFetchGroups("roomModerators", "roomGroups", "roomFiles");
-			return kq.getResultList();
-		} finally {
-			oem.getFetchPlan().setQueryResultCacheEnabled(qrce);
-		}
+		return fillLazy(em
+				, oem -> oem.createNamedQuery("getBackupRooms", Room.class)
+				, "roomModerators", "roomGroups", "roomFiles");
 	}
 
 	public List<Room> get(List<Long> ids) {
@@ -177,7 +157,7 @@ public class RoomDao implements IGroupAdminDataProviderDao<Room> {
 	}
 
 	public List<Room> getAppointedRoomsByUser(long userId) {
-		log.debug("getAppointedRoomsByUser : UserID - " + userId);
+		log.debug("getAppointedRoomsByUser : UserID - {}", userId);
 
 		TimeZone timeZone = getTimeZone(userDao.get(userId));
 
@@ -241,7 +221,7 @@ public class RoomDao implements IGroupAdminDataProviderDao<Room> {
 	}
 
 	public Room getUserRoom(Long ownerId, Room.Type type, String name) {
-		log.debug("getUserRoom : " + ownerId + " || " + type);
+		log.debug("getUserRoom : {} || {}", ownerId, type);
 		Room room = null;
 		List<Room> ll = em.createNamedQuery("getRoomByOwnerAndTypeId", Room.class).setParameter("ownerId", ownerId).setParameter("type", type).getResultList();
 		if (!ll.isEmpty()) {
@@ -249,7 +229,7 @@ public class RoomDao implements IGroupAdminDataProviderDao<Room> {
 		}
 
 		if (room == null) {
-			log.debug("Could not find room " + ownerId + " || " + type);
+			log.debug("Could not find room {} || {}", ownerId, type);
 
 			room = new Room();
 			room.setName(name);
@@ -272,13 +252,13 @@ public class RoomDao implements IGroupAdminDataProviderDao<Room> {
 	}
 
 	public Room getExternal(Type type, String externalType, String externalId) {
-		log.debug("getExternal : " + externalId + " - " + externalType + " - " + type);
-		List<Room> ll = em.createNamedQuery("getRoomByExternalId", Room.class)
-				.setParameter("externalId", externalId)
-				.setParameter("externalType", externalType)
-				.setParameter("type", type)
-				.getResultList();
-		return ll.isEmpty() ? null : ll.get(0);
+		log.debug("getExternal : {} - {}  - {}", type, externalType, externalId);
+		return single(fillLazy(em
+				, oem -> oem.createNamedQuery("getExternalRoom", Room.class)
+					.setParameter("externalId", externalId)
+					.setParameter("externalType", externalType)
+					.setParameter("type", type)
+				, "roomGroups"));
 	}
 
 	public List<Room> getRecent(Long userId) {
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/room/SipDao.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/room/SipDao.java
index 699e788..caaf97b 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/room/SipDao.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/room/SipDao.java
@@ -159,7 +159,7 @@ public class SipDao {
 		ConfbridgeListAction da = new ConfbridgeListAction(confno);
 		ResponseEvents r = execEvent(da);
 		if (r != null) {
-			log.debug("SipDao::countUsers size == " + r.getEvents().size());
+			log.debug("SipDao::countUsers size == {}", r.getEvents().size());
 			// "- 1" here means: ListComplete event
 			return r.getEvents().size() - 1;
 		}
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/server/LdapConfigDao.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/server/LdapConfigDao.java
index b339ec1..c09a4df 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/server/LdapConfigDao.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/server/LdapConfigDao.java
@@ -105,7 +105,7 @@ public class LdapConfigDao implements IDataProviderDao<LdapConfig> {
 		try {
 			TypedQuery<Long> query = em.createNamedQuery("countNondeletedLdapConfigs", Long.class);
 			List<Long> ll = query.getResultList();
-			log.debug("selectMaxFromLdapConfig" + ll.get(0));
+			log.debug("selectMaxFromLdapConfig {}", ll.get(0));
 			return ll.get(0);
 		} catch (Exception ex2) {
 			log.error("[selectMaxFromLdapConfig] ", ex2);
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/server/SessiondataDao.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/server/SessiondataDao.java
index 5927049..1ace9eb 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/server/SessiondataDao.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/server/SessiondataDao.java
@@ -103,7 +103,7 @@ public class SessiondataDao {
 			return null;
 		}
 		Sessiondata sd = sessions.get(0);
-		if (sd == null || sd.getUserId() == null || sd.getUserId().equals(new Long(0)) || !sid.equals(sd.getSessionId())) {
+		if (sd == null || sd.getUserId() == null || sd.getUserId().equals(Long.valueOf(0)) || !sid.equals(sd.getSessionId())) {
 			return null;
 		}
 		return sd;
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/user/GroupDao.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/user/GroupDao.java
index 62f1ed3..c353ce5 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/user/GroupDao.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/user/GroupDao.java
@@ -52,6 +52,15 @@ public class GroupDao implements IGroupAdminDataProviderDao<Group> {
 		return groups == null || groups.isEmpty() ? null : groups.get(0);
 	}
 
+	public Group getExternal(String name) {
+		List<Group> groups = em.createNamedQuery("getExtGroupByName", Group.class).setParameter("name", name).getResultList();
+		Group g = groups == null || groups.isEmpty() ? null : groups.get(0);
+		if (g == null) {
+			g = update(new Group().setExternal(true).setName(name), null);
+		}
+		return g;
+	}
+
 	@Override
 	public List<Group> get(long start, long count) {
 		return setLimits(em.createNamedQuery("getNondeletedGroups", Group.class), start, count)
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/user/UserContactDao.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/user/UserContactDao.java
index bbf93b3..5fdbdde 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/user/UserContactDao.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/user/UserContactDao.java
@@ -18,6 +18,16 @@
  */
 package org.apache.openmeetings.db.dao.user;
 
+import static org.apache.openmeetings.db.util.DaoHelper.setLimits;
+import static org.apache.openmeetings.util.OpenmeetingsVariables.PARAM_USER_ID;
+
+import java.util.Date;
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.TypedQuery;
+
 import org.apache.openmeetings.db.entity.user.UserContact;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -25,15 +35,6 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Repository;
 import org.springframework.transaction.annotation.Transactional;
 
-import javax.persistence.EntityManager;
-import javax.persistence.PersistenceContext;
-import javax.persistence.TypedQuery;
-import java.util.Date;
-import java.util.List;
-
-import static org.apache.openmeetings.db.util.DaoHelper.setLimits;
-import static org.apache.openmeetings.util.OpenmeetingsVariables.PARAM_USER_ID;
-
 @Repository
 @Transactional
 public class UserContactDao {
@@ -81,7 +82,7 @@ public class UserContactDao {
 				.setParameter(PARAM_USER_ID, userId)
 				.setParameter(PARAM_OWNERID, ownerId)
 				.getResultList();
-		log.info("number of contacts:: " + (ll == null ? null : ll.size()));
+		log.info("number of contacts:: {}", (ll == null ? null : ll.size()));
 		return ll != null && ll.size() == 1 ? ll.get(0) : null;
 	}
 
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/user/UserDao.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/user/UserDao.java
index bc59e19..9ee977c 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/user/UserDao.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/user/UserDao.java
@@ -19,8 +19,10 @@
 package org.apache.openmeetings.db.dao.user;
 
 import static java.util.UUID.randomUUID;
+import static org.apache.openmeetings.db.util.DaoHelper.fillLazy;
 import static org.apache.openmeetings.db.util.DaoHelper.getStringParam;
 import static org.apache.openmeetings.db.util.DaoHelper.setLimits;
+import static org.apache.openmeetings.db.util.DaoHelper.single;
 import static org.apache.openmeetings.db.util.TimezoneUtil.getTimeZone;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.PARAM_USER_ID;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.getDefaultLang;
@@ -44,9 +46,6 @@ import javax.persistence.PersistenceContext;
 import javax.persistence.TypedQuery;
 
 import org.apache.commons.lang3.StringUtils;
-import org.apache.openjpa.persistence.OpenJPAEntityManager;
-import org.apache.openjpa.persistence.OpenJPAPersistence;
-import org.apache.openjpa.persistence.OpenJPAQuery;
 import org.apache.openmeetings.db.dao.IGroupAdminDataProviderDao;
 import org.apache.openmeetings.db.dao.label.LabelDao;
 import org.apache.openmeetings.db.entity.user.Address;
@@ -79,6 +78,8 @@ public class UserDao implements IGroupAdminDataProviderDao<User> {
 	private static final Logger log = LoggerFactory.getLogger(UserDao.class);
 	private static final String PARAM_EMAIL = "email";
 	private static final String[] searchFields = {"lastname", "firstname", "login", "address.email", "address.town"};
+	public static final String FETCH_GROUP_GROUP = "groupUsers";
+	public static final String FETCH_GROUP_BACKUP = "backupexport";
 
 	@PersistenceContext
 	private EntityManager em;
@@ -277,22 +278,14 @@ public class UserDao implements IGroupAdminDataProviderDao<User> {
 	private User get(Long id, boolean force) {
 		User u = null;
 		if (id != null && id.longValue() > 0) {
-			OpenJPAEntityManager oem = OpenJPAPersistence.cast(em);
-			boolean qrce = oem.getFetchPlan().getQueryResultCacheEnabled();
-			try {
-				oem.getFetchPlan().setQueryResultCacheEnabled(false); //update in cache during update
-				TypedQuery<User> q = oem.createNamedQuery("getUserById", User.class).setParameter("id", id);
-				@SuppressWarnings("unchecked")
-				OpenJPAQuery<User> kq = OpenJPAPersistence.cast(q);
-				kq.getFetchPlan().addFetchGroup("groupUsers");
-				if (force) {
-					kq.getFetchPlan().addFetchGroup("backupexport");
-				}
-				List<User> list = kq.getResultList();
-				u = list.size() == 1 ? list.get(0) : null;
-			} finally {
-				oem.getFetchPlan().setQueryResultCacheEnabled(qrce);
+			List<String> groups = new ArrayList<>(2);
+			groups.add(FETCH_GROUP_GROUP);
+			if (force) {
+				groups.add(FETCH_GROUP_BACKUP);
 			}
+			u = single(fillLazy(em
+					, oem -> oem.createNamedQuery("getUserById", User.class).setParameter("id", id)
+					, groups.toArray(new String[groups.size()])));
 		} else {
 			log.info("[get]: No user id given");
 		}
@@ -364,23 +357,15 @@ public class UserDao implements IGroupAdminDataProviderDao<User> {
 	}
 
 	public List<User> getAllUsers() {
-		TypedQuery<User> q = em.createNamedQuery("getNondeletedUsers", User.class);
-		return q.getResultList();
+		return fillLazy(em
+				, oem -> oem.createNamedQuery("getNondeletedUsers", User.class)
+				, FETCH_GROUP_GROUP);
 	}
 
 	public List<User> getAllBackupUsers() {
-		OpenJPAEntityManager oem = OpenJPAPersistence.cast(em);
-		boolean qrce = oem.getFetchPlan().getQueryResultCacheEnabled();
-		try {
-			oem.getFetchPlan().setQueryResultCacheEnabled(false); //update in cache during update
-			TypedQuery<User> q = oem.createNamedQuery("getAllUsers", User.class);
-			@SuppressWarnings("unchecked")
-			OpenJPAQuery<User> kq = OpenJPAPersistence.cast(q);
-			kq.getFetchPlan().addFetchGroups("backupexport", "groupUsers");
-			return kq.getResultList();
-		} finally {
-			oem.getFetchPlan().setQueryResultCacheEnabled(qrce);
-		}
+		return fillLazy(em
+				, oem -> oem.createNamedQuery("getAllUsers", User.class)
+				, FETCH_GROUP_BACKUP, FETCH_GROUP_GROUP);
 	}
 
 	/**
@@ -416,21 +401,13 @@ public class UserDao implements IGroupAdminDataProviderDao<User> {
 		return !Strings.isEmpty(login) && login.length() >= getMinLoginLength();
 	}
 
-	private static User getSingle(List<User> list) {
-		User u = null;
-		if (list.size() == 1) {
-			u = list.get(0);
-			u.getGroupUsers().size(); // this will initiate lazy collection
-		}
-		return u;
-	}
-
 	public User getByLogin(String login, Type type, Long domainId) {
-		return getSingle(em.createNamedQuery("getUserByLogin", User.class)
-				.setParameter("login", login)
-				.setParameter("type", type)
-				.setParameter("domainId", domainId == null ? Long.valueOf(0) : domainId)
-				.getResultList());
+		return single(fillLazy(em
+				, oem -> oem.createNamedQuery("getUserByLogin", User.class)
+					.setParameter("login", login)
+					.setParameter("type", type)
+					.setParameter("domainId", domainId == null ? Long.valueOf(0) : domainId)
+				, FETCH_GROUP_GROUP));
 	}
 
 	public User getByEmail(String email) {
@@ -438,21 +415,23 @@ public class UserDao implements IGroupAdminDataProviderDao<User> {
 	}
 
 	public User getByEmail(String email, User.Type type, Long domainId) {
-		return getSingle(em.createNamedQuery("getUserByEmail", User.class)
-				.setParameter(PARAM_EMAIL, email)
-				.setParameter("type", type)
-				.setParameter("domainId", domainId == null ? Long.valueOf(0) : domainId)
-				.getResultList());
+		return single(fillLazy(em
+				, oem -> oem.createNamedQuery("getUserByEmail", User.class)
+					.setParameter(PARAM_EMAIL, email)
+					.setParameter("type", type)
+					.setParameter("domainId", domainId == null ? Long.valueOf(0) : domainId)
+				, FETCH_GROUP_GROUP));
 	}
 
 	public User getUserByHash(String hash) {
 		if (Strings.isEmpty(hash)) {
 			return null;
 		}
-		return getSingle(em.createNamedQuery("getUserByHash", User.class)
+		return single(fillLazy(em
+				, oem -> oem.createNamedQuery("getUserByHash", User.class)
 					.setParameter("resethash", hash)
 					.setParameter("type", User.Type.user)
-					.getResultList());
+				, FETCH_GROUP_GROUP));
 	}
 
 	/**
@@ -546,8 +525,10 @@ public class UserDao implements IGroupAdminDataProviderDao<User> {
 	 * @return user with this hash
 	 */
 	public User getByActivationHash(String hash) {
-		return getSingle(em.createQuery("SELECT u FROM User as u WHERE u.activatehash = :activatehash AND u.deleted = false", User.class)
-				.setParameter("activatehash", hash).getResultList());
+		return single(fillLazy(em
+				, oem -> oem.createQuery("SELECT u FROM User as u WHERE u.activatehash = :activatehash AND u.deleted = false", User.class)
+				.setParameter("activatehash", hash)
+				, FETCH_GROUP_GROUP));
 	}
 
 	private <T> TypedQuery<T> getUserProfileQuery(Class<T> clazz, Long userId, String text, String offers, String search, String orderBy, boolean asc) {
@@ -593,10 +574,12 @@ public class UserDao implements IGroupAdminDataProviderDao<User> {
 	}
 
 	public User getExternalUser(String extId, String extType) {
-		return getSingle(em.createNamedQuery("getExternalUser", User.class)
-				.setParameter("externalId", extId)
-				.setParameter("externalType", extType)
-				.getResultList());
+		return single(fillLazy(em
+				, oem -> oem.createNamedQuery("getExternalUser", User.class)
+					.setParameter("externalId", extId)
+					.setParameter("externalType", extType)
+					.setParameter("type", Type.external)
+				, FETCH_GROUP_GROUP));
 	}
 
 	@Override
@@ -654,7 +637,7 @@ public class UserDao implements IGroupAdminDataProviderDao<User> {
 			log.debug("Not activated: {}", u);
 			throw new OmException("error.notactivated");
 		}
-		log.debug("loginUser " + u.getGroupUsers());
+		log.debug("login user groups {}", u.getGroupUsers());
 		if (u.getGroupUsers().isEmpty()) {
 			log.debug("No Group assigned: {}", u);
 			throw new OmException("error.nogroup");
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dto/calendar/AppointmentDTO.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dto/calendar/AppointmentDTO.java
index d6ea7da..0b70ca4 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dto/calendar/AppointmentDTO.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dto/calendar/AppointmentDTO.java
@@ -31,6 +31,8 @@ import javax.xml.bind.annotation.XmlRootElement;
 
 import org.apache.openmeetings.db.dao.calendar.AppointmentDao;
 import org.apache.openmeetings.db.dao.file.BaseFileItemDao;
+import org.apache.openmeetings.db.dao.room.RoomDao;
+import org.apache.openmeetings.db.dao.user.GroupDao;
 import org.apache.openmeetings.db.dao.user.UserDao;
 import org.apache.openmeetings.db.dto.room.RoomDTO;
 import org.apache.openmeetings.db.dto.user.UserDTO;
@@ -98,7 +100,7 @@ public class AppointmentDTO implements Serializable {
 		reminderEmailSend = a.isReminderEmailSend();
 	}
 
-	public Appointment get(UserDao userDao, BaseFileItemDao fileDao, AppointmentDao appointmentDao, User u) {
+	public Appointment get(UserDao userDao, GroupDao groupDao, RoomDao roomDao, BaseFileItemDao fileDao, AppointmentDao appointmentDao, User u) {
 		Appointment a = id == null ? new Appointment() : appointmentDao.get(id);
 		a.setId(id);
 		a.setTitle(title);
@@ -111,7 +113,7 @@ public class AppointmentDTO implements Serializable {
 		a.setUpdated(updated);
 		a.setDeleted(deleted);
 		a.setReminder(reminder);
-		a.setRoom(room.get(fileDao));
+		a.setRoom(room.get(roomDao, groupDao, fileDao));
 		a.setIcalId(icalId);
 		List<MeetingMember> mml = new ArrayList<>();
 		for(MeetingMemberDTO mm : meetingMembers) {
@@ -128,7 +130,7 @@ public class AppointmentDTO implements Serializable {
 					throw new RuntimeException("Weird guest from different appointment is passed");
 				}
 			} else {
-				m = mm.get(userDao, u);
+				m = mm.get(userDao, groupDao, u);
 				m.setAppointment(a);
 			}
 			mml.add(m);
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dto/calendar/MeetingMemberDTO.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dto/calendar/MeetingMemberDTO.java
index 2678f1e..eaa4797 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dto/calendar/MeetingMemberDTO.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dto/calendar/MeetingMemberDTO.java
@@ -26,6 +26,7 @@ import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlRootElement;
 
+import org.apache.openmeetings.db.dao.user.GroupDao;
 import org.apache.openmeetings.db.dao.user.UserDao;
 import org.apache.openmeetings.db.dto.user.UserDTO;
 import org.apache.openmeetings.db.entity.calendar.MeetingMember;
@@ -50,7 +51,7 @@ public class MeetingMemberDTO implements Serializable {
 		this.user = new UserDTO(mm.getUser());
 	}
 
-	public MeetingMember get(UserDao userDao, User owner) {
+	public MeetingMember get(UserDao userDao, GroupDao groupDao, User owner) {
 		MeetingMember mm = new MeetingMember();
 		mm.setId(id);
 		if (user.getId() != null) {
@@ -70,11 +71,9 @@ public class MeetingMemberDTO implements Serializable {
 						, owner);
 			}
 			if (u == null) {
-				u = user.get(userDao);
-				u.setType(User.Type.contact);
+				user.setType(User.Type.contact);
+				u = user.get(userDao, groupDao);
 				u.getRights().clear();
-				u.setExternalId(null);
-				u.setExternalType(null);
 			}
 			if (Strings.isEmpty(u.getTimeZoneId())) {
 				u.setTimeZoneId(owner.getTimeZoneId());
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dto/record/RecordingDTO.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dto/record/RecordingDTO.java
index 5000ed8..4ccaf5c 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dto/record/RecordingDTO.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dto/record/RecordingDTO.java
@@ -44,6 +44,7 @@ public class RecordingDTO implements Serializable {
 	private Integer width;
 	private Integer height;
 	private Long ownerId;
+	private String externalType;
 
 	public RecordingDTO() {
 		//def constructor
@@ -61,6 +62,7 @@ public class RecordingDTO implements Serializable {
 		this.width = r.getWidth();
 		this.height = r.getHeight();
 		this.ownerId = r.getOwnerId();
+		this.externalType = r.getExternalType();
 	}
 
 	public Long getId() {
@@ -151,6 +153,15 @@ public class RecordingDTO implements Serializable {
 		this.ownerId = ownerId;
 	}
 
+	public String getExternalType() {
+		return externalType;
+	}
+
+	public RecordingDTO setExternalType(String externalType) {
+		this.externalType = externalType;
+		return this;
+	}
+
 	public static List<RecordingDTO> list(List<Recording> l) {
 		List<RecordingDTO> list = new ArrayList<>();
 		if (l != null) {
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dto/room/RoomDTO.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dto/room/RoomDTO.java
index c019127..73da17c 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dto/room/RoomDTO.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dto/room/RoomDTO.java
@@ -34,8 +34,11 @@ import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlRootElement;
 
 import org.apache.openmeetings.db.dao.file.BaseFileItemDao;
+import org.apache.openmeetings.db.dao.room.RoomDao;
+import org.apache.openmeetings.db.dao.user.GroupDao;
 import org.apache.openmeetings.db.entity.room.Room;
 import org.apache.openmeetings.db.entity.room.Room.RoomElement;
+import org.apache.wicket.util.string.Strings;
 
 import com.github.openjson.JSONArray;
 import com.github.openjson.JSONObject;
@@ -48,7 +51,7 @@ public class RoomDTO implements Serializable {
 	private String name;
 	private String comment;
 	private Room.Type type;
-	private Long capacity = new Long(4);
+	private Long capacity = Long.valueOf(4);
 	private boolean appointment;
 	private String confno;
 	private boolean isPublic;
@@ -83,7 +86,7 @@ public class RoomDTO implements Serializable {
 		closed = r.isClosed();
 		demoTime = r.getDemoTime();
 		externalId = r.getExternalId();
-		externalType = r.getExternalType();
+		r.getGroups().stream().findFirst().ifPresent(g -> externalType = g.getGroup().getName());
 		redirectUrl = r.getRedirectURL();
 		moderated = r.isModerated();
 		allowUserQuestions = r.isAllowUserQuestions();
@@ -94,8 +97,8 @@ public class RoomDTO implements Serializable {
 		files = RoomFileDTO.get(r.getFiles());
 	}
 
-	public Room get(BaseFileItemDao fileDao) {
-		Room r = new Room();
+	public Room get(RoomDao roomDao, GroupDao groupDao, BaseFileItemDao fileDao) {
+		Room r = id == null ? new Room() : roomDao.get(id);
 		r.setId(id);
 		r.setName(name);
 		r.setComment(comment);
@@ -107,7 +110,11 @@ public class RoomDTO implements Serializable {
 		r.setDemoRoom(demo);
 		r.setDemoTime(demoTime);
 		r.setExternalId(externalId);
-		r.setExternalType(externalType);
+		if (!Strings.isEmpty(externalType)
+				&& r.getGroups().stream().filter(gu -> gu.getGroup().isExternal() && gu.getGroup().getName().equals(externalType)).count() == 0)
+		{
+			r.addGroup(groupDao.getExternal(externalType));
+		}
 		r.setRedirectURL(redirectUrl);
 		r.setModerated(moderated);
 		r.setAllowUserQuestions(allowUserQuestions);
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dto/user/UserDTO.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dto/user/UserDTO.java
index fe60bd4..da8f0cc 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dto/user/UserDTO.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dto/user/UserDTO.java
@@ -30,11 +30,13 @@ import java.util.Set;
 
 import javax.xml.bind.annotation.XmlRootElement;
 
+import org.apache.openmeetings.db.dao.user.GroupDao;
 import org.apache.openmeetings.db.dao.user.UserDao;
 import org.apache.openmeetings.db.entity.user.Address;
 import org.apache.openmeetings.db.entity.user.User;
 import org.apache.openmeetings.db.entity.user.User.Right;
 import org.apache.openmeetings.db.entity.user.User.Type;
+import org.apache.wicket.util.string.Strings;
 
 import com.github.openjson.JSONObject;
 
@@ -70,11 +72,11 @@ public class UserDTO implements Serializable {
 		timeZoneId = u.getTimeZoneId();
 		type = u.getType();
 		externalId = u.getExternalId();
-		externalType = u.getExternalType();
+		externalType = u.externalType();
 		pictureUri = u.getPictureUri();
 	}
 
-	public User get(UserDao userDao) {
+	public User get(UserDao userDao, GroupDao groupDao) {
 		User u = id == null ? new User() : userDao.get(id);
 		u.setLogin(login);
 		u.setFirstname(firstname);
@@ -83,8 +85,13 @@ public class UserDTO implements Serializable {
 		u.setLanguageId(languageId);
 		u.setAddress(address);
 		u.setTimeZoneId(timeZoneId);
-		u.setExternalId(externalId);
-		u.setExternalType(externalType);
+		if (Type.external == type || (!Strings.isEmpty(externalId) && !Strings.isEmpty(externalType))) {
+			type = Type.external;
+			if (u.getGroupUsers().stream().filter(gu -> gu.getGroup().isExternal() && gu.getGroup().getName().equals(externalType)).count() == 0) {
+				u.addGroup(groupDao.getExternal(externalType));
+			}
+			u.setExternalId(externalId);
+		}
 		u.setType(type);
 		u.setPictureUri(pictureUri);
 		return u;
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/file/BaseFileItem.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/file/BaseFileItem.java
index 590e328..aba7af0 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/file/BaseFileItem.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/file/BaseFileItem.java
@@ -130,6 +130,10 @@ public abstract class BaseFileItem extends HistoricalEntity {
 	@Element(data = true, required = false)
 	private int count = 1;
 
+	@Column(name = "external_type")
+	@Element(data = true, required = false)
+	private String externalType;
+
 	// Not Mapped
 	@Transient
 	private List<FileItemLog> log;
@@ -259,6 +263,14 @@ public abstract class BaseFileItem extends HistoricalEntity {
 		this.readOnly = readOnly;
 	}
 
+	public String getExternalType() {
+		return externalType;
+	}
+
+	public void setExternalType(String externalType) {
+		this.externalType = externalType;
+	}
+
 	public final File getFile(String ext) {
 		File f = null;
 		if (!isDeleted() && getHash() != null) {
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/file/FileItem.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/file/FileItem.java
index d835273..77e44e7 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/file/FileItem.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/file/FileItem.java
@@ -54,9 +54,6 @@ public class FileItem extends BaseFileItem {
 	@Column(name = "external_id")
 	private String externalId;
 
-	@Column(name = "external_type")
-	private String externalType;
-
 	@Override
 	@Element(data = true, name = "fileExplorerItemId")
 	public Long getId() {
@@ -84,12 +81,4 @@ public class FileItem extends BaseFileItem {
 	public void setExternalId(String externalId) {
 		this.externalId = externalId;
 	}
-
-	public String getExternalType() {
-		return externalType;
-	}
-
-	public void setExternalType(String externalType) {
-		this.externalType = externalType;
-	}
 }
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/record/Recording.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/record/Recording.java
index 708bd53..72d9c0c 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/record/Recording.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/record/Recording.java
@@ -59,33 +59,34 @@ import org.simpleframework.xml.Root;
  *
  */
 @Entity
-@NamedQuery(name = "getRecordingsByExternalUser", query = "SELECT c FROM Recording c, User u "
-		+ "WHERE c.insertedBy = u.id AND u.externalId = :externalId  AND u.externalType = :externalType "
-		+ "AND c.deleted = false")
-@NamedQuery(name = "getRecordingsPublic", query = "SELECT f FROM Recording f WHERE f.deleted = false AND f.ownerId IS NULL "
-		+ "AND f.groupId IS NULL AND (f.parentId IS NULL OR f.parentId = 0) "
-		+ "ORDER BY f.type ASC, f.inserted")
-@NamedQuery(name = "getRecordingsByGroup", query = "SELECT f FROM Recording f WHERE f.deleted = false AND f.ownerId IS NULL "
-		+ "AND f.groupId = :groupId AND (f.parentId IS NULL OR f.parentId = 0) "
-		+ "ORDER BY f.type ASC, f.inserted")
-@NamedQuery(name = "getRecordingsByOwner", query = "SELECT f FROM Recording f WHERE f.deleted = false AND f.ownerId = :ownerId "
-		+ "AND (f.parentId IS NULL OR f.parentId = 0) "
-		+ "ORDER BY f.type ASC, f.inserted")
-@NamedQuery(name = "resetRecordingProcessingStatus", query = "UPDATE Recording f SET f.status = :error WHERE f.status IN (:recording, :converting)")
-@NamedQuery(name = "getRecordingsAll", query = "SELECT c FROM Recording c LEFT JOIN FETCH c.chunks ORDER BY c.id")
-@NamedQuery(name = "getRecordingsByRoom", query = "SELECT c FROM Recording c WHERE c.deleted = false AND c.roomId = :roomId "
-		+ "ORDER BY c.type ASC, c.inserted")
-@NamedQuery(name = "getRecordingsByParent", query = "SELECT f FROM Recording f WHERE f.deleted = false AND f.parentId = :parentId "
-		+ "ORDER BY f.type ASC, f.inserted")
-@NamedQuery(name = "getRecordingsByExternalType", query = "SELECT rec FROM Recording rec, Room r, User u "
-		+ "WHERE rec.deleted = false AND rec.roomId = r.id AND rec.insertedBy = u.id "
-		+ "AND (r.externalType = :externalType OR u.externalType = :externalType)")
-@NamedQuery(name = "getExpiringRecordings", query = "SELECT DISTINCT rec FROM Recording rec "
-		+ "WHERE rec.deleted = false AND rec.notified = :notified AND rec.inserted < :date "
-		+ "  AND (rec.groupId = :groupId "
-		+ "    OR rec.ownerId IN (SELECT gu.user.id FROM GroupUser gu WHERE gu.group.id = :groupId)"
-		+ "    OR rec.roomId IN (SELECT rg.room.id FROM RoomGroup rg WHERE rg.group.id = :groupId)"
-		+ "  ) order by rec.inserted ASC")
+@NamedQuery(name = "getRecordingsByExternalUser", query = "SELECT r FROM Recording r "
+		+ "WHERE r.insertedBy = (SELECT gu.user.id FROM GroupUser gu WHERE "
+		+ "gu.group.deleted = false AND gu.group.external = true AND gu.group.name = :externalType "
+		+ "AND gu.user.deleted = false AND gu.user.type = :type AND gu.user.externalId = :externalId) "
+		+ "AND r.deleted = false")
+@NamedQuery(name = "getRecordingsPublic", query = "SELECT r FROM Recording r WHERE r.deleted = false AND r.ownerId IS NULL "
+		+ "AND r.groupId IS NULL AND (r.parentId IS NULL OR r.parentId = 0) "
+		+ "ORDER BY r.type ASC, r.inserted")
+@NamedQuery(name = "getRecordingsByGroup", query = "SELECT r FROM Recording r WHERE r.deleted = false AND r.ownerId IS NULL "
+		+ "AND r.groupId = :groupId AND (r.parentId IS NULL OR r.parentId = 0) "
+		+ "ORDER BY r.type ASC, r.inserted")
+@NamedQuery(name = "getRecordingsByOwner", query = "SELECT r FROM Recording r WHERE r.deleted = false AND r.ownerId = :ownerId "
+		+ "AND (r.parentId IS NULL OR r.parentId = 0) "
+		+ "ORDER BY r.type ASC, r.inserted")
+@NamedQuery(name = "resetRecordingProcessingStatus", query = "UPDATE Recording r SET r.status = :error WHERE r.status IN (:recording, :converting)")
+@NamedQuery(name = "getRecordingsAll", query = "SELECT r FROM Recording r LEFT JOIN FETCH r.chunks ORDER BY r.id")
+@NamedQuery(name = "getRecordingsByRoom", query = "SELECT r FROM Recording r WHERE r.deleted = false AND r.roomId = :roomId "
+		+ "ORDER BY r.type ASC, r.inserted")
+@NamedQuery(name = "getRecordingsByParent", query = "SELECT r FROM Recording r WHERE r.deleted = false AND r.parentId = :parentId "
+		+ "ORDER BY r.type ASC, r.inserted")
+@NamedQuery(name = "getRecordingsByExternalType", query = "SELECT r FROM Recording r "
+		+ "WHERE r.deleted = false AND r.externalType = :externalType")
+@NamedQuery(name = "getExpiringRecordings", query = "SELECT DISTINCT r FROM Recording r "
+		+ "WHERE r.deleted = false AND r.notified = :notified AND r.inserted < :date "
+		+ "  AND (r.groupId = :groupId "
+		+ "    OR r.ownerId IN (SELECT gu.user.id FROM GroupUser gu WHERE gu.group.id = :groupId)"
+		+ "    OR r.roomId IN (SELECT rg.room.id FROM RoomGroup rg WHERE rg.group.id = :groupId)"
+		+ "  ) order by r.inserted ASC")
 @Root(name = "flvrecording")
 @XmlRootElement
 @XmlAccessorType(XmlAccessType.FIELD)
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/room/Room.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/room/Room.java
index c5d2ccf..556206d 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/room/Room.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/room/Room.java
@@ -39,6 +39,7 @@ import javax.persistence.Lob;
 import javax.persistence.NamedQuery;
 import javax.persistence.OneToMany;
 import javax.persistence.Table;
+import javax.persistence.Transient;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlRootElement;
@@ -50,6 +51,7 @@ import org.apache.openjpa.persistence.FetchGroup;
 import org.apache.openjpa.persistence.FetchGroups;
 import org.apache.openjpa.persistence.jdbc.ForeignKey;
 import org.apache.openmeetings.db.entity.HistoricalEntity;
+import org.apache.openmeetings.db.entity.user.Group;
 import org.simpleframework.xml.Element;
 import org.simpleframework.xml.ElementList;
 import org.simpleframework.xml.Root;
@@ -65,9 +67,9 @@ import org.simpleframework.xml.Root;
 @NamedQuery(name = "getRoomByOwnerAndTypeId", query = "SELECT r FROM Room as r WHERE r.ownerId = :ownerId "
 				+ "AND r.type = :type AND r.deleted = false")
 @NamedQuery(name = "selectMaxFromRooms", query = "SELECT COUNT(r.id) from Room r WHERE r.deleted = false AND r.name LIKE :search ")
-@NamedQuery(name = "getRoomByExternalId", query = "SELECT r FROM Room as r "
-		+ "WHERE r.externalId = :externalId AND r.externalType = :externalType "
-		+ "AND r.type = :type AND r.deleted = false")
+@NamedQuery(name = "getExternalRoom", query = "SELECT rg.room FROM RoomGroup rg WHERE "
+		+ "rg.group.deleted = false AND rg.group.external = true AND rg.group.name = :externalType "
+		+ "AND rg.room.deleted = false AND rg.room.type = :type AND rg.room.externalId = :externalId")
 @NamedQuery(name = "getPublicRoomsOrdered", query = "SELECT r from Room r WHERE r.ispublic= true AND r.deleted= false AND r.appointment = false ORDER BY r.name ASC")
 @NamedQuery(name = "getRoomById", query = "SELECT r FROM Room r WHERE r.deleted = false AND r.id = :id")
 @NamedQuery(name = "getRoomsByIds", query = "SELECT r FROM Room r WHERE r.deleted = false AND r.id IN :ids")
@@ -192,8 +194,9 @@ public class Room extends HistoricalEntity {
 	@Element(data = true, required = false)
 	private String externalId;
 
-	@Column(name = "external_type")
 	@Element(data = true, required = false)
+	@Deprecated(since = "5.0")
+	@Transient
 	private String externalType;
 
 	@Column(name = "demo_room", nullable = false)
@@ -381,10 +384,12 @@ public class Room extends HistoricalEntity {
 		this.externalId = externalId;
 	}
 
+	@Deprecated(since = "5.0")
 	public String getExternalType() {
 		return externalType;
 	}
 
+	@Deprecated(since = "5.0")
 	public void setExternalType(String externalType) {
 		this.externalType = externalType;
 	}
@@ -486,6 +491,13 @@ public class Room extends HistoricalEntity {
 		return groups;
 	}
 
+	public void addGroup(Group g) {
+		if (groups == null) {
+			groups = new ArrayList<>();
+		}
+		groups.add(new RoomGroup(g, this));
+	}
+
 	public void setGroups(List<RoomGroup> groups) {
 		this.groups = groups;
 	}
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/user/Group.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/user/Group.java
index 1a939e8..b55d386 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/user/Group.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/user/Group.java
@@ -31,13 +31,14 @@ import org.simpleframework.xml.Element;
 import org.simpleframework.xml.Root;
 
 @Entity
-@NamedQuery(name="getGroupById", query="SELECT g FROM Group AS g WHERE g.id = :id AND g.deleted = false")
-@NamedQuery(name="getGroupByName", query="SELECT g FROM Group AS g WHERE g.name = :name AND g.deleted = false")
-@NamedQuery(name="getAnyGroupById", query="SELECT g FROM Group AS g WHERE g.id = :groupId")
-@NamedQuery(name="getGroupsByIds", query="SELECT g FROM Group AS g WHERE g.id IN :ids")
-@NamedQuery(name="getNondeletedGroups", query="SELECT g FROM Group g WHERE g.deleted = false ORDER BY g.id")
-@NamedQuery(name="countGroups", query="SELECT COUNT(g) FROM Group AS g WHERE g.deleted = false")
-@NamedQuery(name="getLimitedGroups", query="SELECT g FROM Group AS g WHERE g.deleted = false AND g.limited = true")
+@NamedQuery(name = "getGroupById", query = "SELECT g FROM Group AS g WHERE g.id = :id AND g.deleted = false")
+@NamedQuery(name = "getGroupByName", query = "SELECT g FROM Group AS g WHERE g.name = :name AND g.deleted = false")
+@NamedQuery(name = "getExtGroupByName", query = "SELECT g FROM Group AS g WHERE g.name = :name AND g.deleted = false AND g.external = true")
+@NamedQuery(name = "getAnyGroupById", query = "SELECT g FROM Group AS g WHERE g.id = :groupId")
+@NamedQuery(name = "getGroupsByIds", query = "SELECT g FROM Group AS g WHERE g.id IN :ids")
+@NamedQuery(name = "getNondeletedGroups", query = "SELECT g FROM Group g WHERE g.deleted = false ORDER BY g.id")
+@NamedQuery(name = "countGroups", query = "SELECT COUNT(g) FROM Group AS g WHERE g.deleted = false")
+@NamedQuery(name = "getLimitedGroups", query = "SELECT g FROM Group AS g WHERE g.deleted = false AND g.limited = true")
 @Table(name = "om_group")
 @Root(name = "organisation")
 public class Group extends HistoricalEntity {
@@ -91,6 +92,10 @@ public class Group extends HistoricalEntity {
 	@Element(data = true, required = false)
 	private int reminderDays;
 
+	@Column(name = "external", nullable = false)
+	@Element(data = true, required = false)
+	private boolean external;
+
 	public Long getInsertedby() {
 		return insertedby;
 	}
@@ -103,8 +108,9 @@ public class Group extends HistoricalEntity {
 		return name;
 	}
 
-	public void setName(String name) {
+	public Group setName(String name) {
 		this.name = name;
+		return this;
 	}
 
 	@Override
@@ -189,6 +195,15 @@ public class Group extends HistoricalEntity {
 		this.reminderDays = reminderDays;
 	}
 
+	public boolean isExternal() {
+		return external;
+	}
+
+	public Group setExternal(boolean external) {
+		this.external = external;
+		return this;
+	}
+
 	@Override
 	public String toString() {
 		return "Group [id=" + id + ", name=" + name + ", deleted=" + isDeleted() + "]";
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/user/GroupUser.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/user/GroupUser.java
index d4c5d84..7bea5f6 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/user/GroupUser.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/user/GroupUser.java
@@ -35,13 +35,13 @@ import org.simpleframework.xml.Element;
 import org.simpleframework.xml.Root;
 
 @Entity
-@NamedQuery(name="deleteGroupUsersByGroup", query="DELETE FROM GroupUser gu WHERE gu.group.id = :id")
-@NamedQuery(name="countGroupUsers", query="SELECT COUNT(c) FROM GroupUser c WHERE c.group.id = :id")
-@NamedQuery(name="getGroupUsersById", query="SELECT c FROM GroupUser c WHERE c.id = :id")
-@NamedQuery(name="getGroupUsersByGroupId", query="SELECT c FROM GroupUser c WHERE c.group.id = :id")
-@NamedQuery(name="isUserInGroup", query="SELECT c FROM GroupUser c WHERE c.group.id = :groupId AND c.user.id = :userId")
+@NamedQuery(name = "deleteGroupUsersByGroup", query = "DELETE FROM GroupUser gu WHERE gu.group.id = :id")
+@NamedQuery(name = "countGroupUsers", query = "SELECT COUNT(gu) FROM GroupUser gu WHERE gu.group.id = :id")
+@NamedQuery(name = "getGroupUsersById", query = "SELECT gu FROM GroupUser gu WHERE gu.id = :id")
+@NamedQuery(name = "getGroupUsersByGroupId", query = "SELECT gu FROM GroupUser gu WHERE gu.group.id = :id")
+@NamedQuery(name = "isUserInGroup", query = "SELECT gu FROM GroupUser gu WHERE gu.group.id = :groupId AND gu.user.id = :userId")
 @Table(name = "group_user")
-@Root(name="user_organisation")
+@Root(name = "user_organisation")
 public class GroupUser extends HistoricalEntity {
 	private static final long serialVersionUID = 1L;
 	@Id
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/user/User.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/user/User.java
index 8bd83ac..774117f 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/user/User.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/user/User.java
@@ -18,6 +18,8 @@
  */
 package org.apache.openmeetings.db.entity.user;
 
+import static org.apache.openmeetings.db.dao.user.UserDao.FETCH_GROUP_BACKUP;
+import static org.apache.openmeetings.db.dao.user.UserDao.FETCH_GROUP_GROUP;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.getSipContext;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.isSipEnabled;
 import static org.apache.wicket.util.string.Strings.escapeMarkup;
@@ -27,6 +29,7 @@ import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Optional;
 import java.util.Set;
 
 import javax.persistence.Basic;
@@ -76,8 +79,8 @@ import org.simpleframework.xml.Root;
  */
 @Entity
 @FetchGroups({
-	@FetchGroup(name = "backupexport", attributes = { @FetchAttribute(name = "password") })
-	, @FetchGroup(name = "groupUsers", attributes = { @FetchAttribute(name = "groupUsers")})
+	@FetchGroup(name = FETCH_GROUP_BACKUP, attributes = { @FetchAttribute(name = "password") })
+	, @FetchGroup(name = FETCH_GROUP_GROUP, attributes = { @FetchAttribute(name = "groupUsers")})
 })
 @NamedQuery(name = "getUserById", query = "SELECT u FROM User u WHERE u.id = :id")
 @NamedQuery(name = "getUsersByIds", query = "select c from User c where c.id IN :ids")
@@ -86,8 +89,8 @@ import org.simpleframework.xml.Root;
 @NamedQuery(name = "getUserByHash",  query = "SELECT u FROM User u WHERE u.deleted = false AND u.type = :type AND u.resethash = :resethash")
 @NamedQuery(name = "getUserByExpiredHash",  query = "SELECT u FROM User u WHERE u.resetDate < :date")
 @NamedQuery(name = "getContactByEmailAndUser", query = "SELECT u FROM User u WHERE u.deleted = false AND u.address.email = :email AND u.type = :type AND u.ownerId = :ownerId")
-@NamedQuery(name = "selectMaxFromUsersWithSearch", query = "select count(c.id) from User c "
-		+ "where c.deleted = false " + "AND ("
+@NamedQuery(name = "selectMaxFromUsersWithSearch", query = "SELECT count(c.id) FROM User c "
+		+ "WHERE c.deleted = false AND ("
 		+ "lower(c.login) LIKE :search "
 		+ "OR lower(c.firstname) LIKE :search "
 		+ "OR lower(c.lastname) LIKE :search )")
@@ -97,7 +100,9 @@ import org.simpleframework.xml.Root;
 @NamedQuery(name = "getNondeletedUsers", query = "SELECT u FROM User u WHERE u.deleted = false")
 @NamedQuery(name = "countNondeletedUsers", query = "SELECT COUNT(u) FROM User u WHERE u.deleted = false")
 @NamedQuery(name = "getUsersByGroupId", query = "SELECT u FROM User u WHERE u.deleted = false AND u.groupUsers.group.id = :groupId")
-@NamedQuery(name = "getExternalUser", query = "SELECT u FROM User u WHERE u.deleted = false AND u.externalId LIKE :externalId AND u.externalType LIKE :externalType")
+@NamedQuery(name = "getExternalUser", query = "SELECT gu.user FROM GroupUser gu WHERE "
+		+ "gu.group.deleted = false AND gu.group.external = true AND gu.group.name = :externalType "
+		+ "AND gu.user.deleted = false AND gu.user.type = :type AND gu.user.externalId = :externalId")
 @NamedQuery(name = "getUserByLoginOrEmail", query = "SELECT u from User u WHERE u.deleted = false AND u.type = :type AND (u.login = :userOrEmail OR u.address.email = :userOrEmail)")
 @Table(name = "om_user")
 @Root(name = "user")
@@ -260,8 +265,9 @@ public class User extends HistoricalEntity {
 	@Element(name = "externalUserId", data = true, required = false)
 	private String externalId;
 
-	@Column(name = "external_type")
 	@Element(name = "externalUserType", data = true, required = false)
+	@Deprecated(since = "5.0")
+	@Transient
 	private String externalType;
 
 	/**
@@ -453,6 +459,13 @@ public class User extends HistoricalEntity {
 		return groupUsers;
 	}
 
+	public void addGroup(Group g) {
+		if (groupUsers == null) {
+			groupUsers = new ArrayList<>();
+		}
+		groupUsers.add(new GroupUser(g, this));
+	}
+
 	public void setGroupUsers(List<GroupUser> groupUsers) {
 		if (groupUsers != null) {
 			this.groupUsers = groupUsers;
@@ -491,10 +504,20 @@ public class User extends HistoricalEntity {
 		this.externalId = externalId;
 	}
 
+	public String externalType() {
+		Optional<String> extType = groupUsers == null
+				? Optional.empty()
+				: groupUsers.stream().filter(gu -> gu.getGroup().isExternal()).findFirst()
+				.map(gu -> gu.getGroup().getName());
+		return extType.isPresent() ? extType.get() : null;
+	}
+
+	@Deprecated(since = "5.0")
 	public String getExternalType() {
 		return externalType;
 	}
 
+	@Deprecated(since = "5.0")
 	public void setExternalType(String externalType) {
 		this.externalType = externalType;
 	}
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/util/ApplicationHelper.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/util/ApplicationHelper.java
index cb84a4f..5f941ce 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/util/ApplicationHelper.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/util/ApplicationHelper.java
@@ -23,6 +23,7 @@ import static org.apache.openmeetings.util.OpenmeetingsVariables.isInitComplete;
 import static org.springframework.web.context.WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;
 import static org.springframework.web.context.support.WebApplicationContextUtils.getWebApplicationContext;
 
+import java.lang.reflect.InvocationTargetException;
 import java.util.UUID;
 
 import javax.servlet.ServletContext;
@@ -61,7 +62,7 @@ public class ApplicationHelper {
 		if (app == null) {
 			// This is the case for non-web-app applications (command line admin)
 			try {
-				app = (WebApplication)OpenmeetingsVariables.getAppClass().newInstance();
+				app = (WebApplication)OpenmeetingsVariables.getAppClass().getDeclaredConstructor().newInstance();
 				app.setName(String.format("--%s--", UUID.randomUUID())); //temporary name for temporary application
 				ServletContext sc = new MockServletContext(app, null);
 				XmlWebApplicationContext xmlContext = new XmlWebApplicationContext();
@@ -72,7 +73,7 @@ public class ApplicationHelper {
 				app = xmlContext.getBean(WebApplication.class);
 				app.setName(getWicketApplicationName());
 				app.setServletContext(sc);
-			} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
+			} catch (InstantiationException | IllegalAccessException | ClassNotFoundException | InvocationTargetException | NoSuchMethodException e) {
 				log.error("Failed to create Application");
 			}
 		}
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/util/DaoHelper.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/util/DaoHelper.java
index 8b556ff..7bb5649 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/util/DaoHelper.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/util/DaoHelper.java
@@ -18,9 +18,16 @@
  */
 package org.apache.openmeetings.db.util;
 
+import java.util.List;
+import java.util.function.Function;
+
+import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
 
 import org.apache.commons.lang3.StringUtils;
+import org.apache.openjpa.persistence.OpenJPAEntityManager;
+import org.apache.openjpa.persistence.OpenJPAPersistence;
+import org.apache.openjpa.persistence.OpenJPAQuery;
 import org.apache.wicket.util.string.Strings;
 
 public class DaoHelper {
@@ -122,4 +129,23 @@ public class DaoHelper {
 		}
 		return q;
 	}
+
+	public static <T> List<T> fillLazy(EntityManager em, Function<OpenJPAEntityManager, TypedQuery<T>> func, String...groups) {
+		OpenJPAEntityManager oem = OpenJPAPersistence.cast(em);
+		boolean qrce = oem.getFetchPlan().getQueryResultCacheEnabled();
+		try {
+			oem.getFetchPlan().setQueryResultCacheEnabled(false); //update in cache during update
+			TypedQuery<T> q = func.apply(oem);
+			@SuppressWarnings("unchecked")
+			OpenJPAQuery<T> kq = OpenJPAPersistence.cast(q);
+			kq.getFetchPlan().addFetchGroups(groups);
+			return kq.getResultList();
+		} finally {
+			oem.getFetchPlan().setQueryResultCacheEnabled(qrce);
+		}
+	}
+
+	public static <T> T single(List<T> l) {
+		return l.size() == 1 ? l.get(0) : null;
+	}
 }
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/util/LocaleHelper.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/util/LocaleHelper.java
index e641246..ba1c9f4 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/util/LocaleHelper.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/util/LocaleHelper.java
@@ -72,7 +72,7 @@ public class LocaleHelper {
 			}
 			locale = builder.build();
 		} catch (Exception e) {
-			log.error("Unexpected Error while constructing locale for the user", e.getMessage());
+			log.error("Unexpected Error while constructing locale for the user", e);
 		}
 		return locale;
 	}
diff --git a/openmeetings-install/src/main/java/org/apache/openmeetings/backup/BackupExport.java b/openmeetings-install/src/main/java/org/apache/openmeetings/backup/BackupExport.java
index cdeee85..848ffbf 100644
--- a/openmeetings-install/src/main/java/org/apache/openmeetings/backup/BackupExport.java
+++ b/openmeetings-install/src/main/java/org/apache/openmeetings/backup/BackupExport.java
@@ -194,7 +194,7 @@ public class BackupExport {
 		for (File file : getUploadDir().listFiles()) {
 			String fName = file.getName();
 			if (file.isDirectory() && !IMPORT_DIR.equals(fName) && !BACKUP_DIR.equals(fName)) {
-				log.debug("### " + file.getName());
+				log.debug("### {}", file.getName());
 				writeZipDir(BCKP_ROOM_FILES, file.getParentFile().toURI(), file, zos);
 			}
 		}
@@ -531,7 +531,7 @@ public class BackupExport {
 
 	private static void writeZip(String prefix, URI base, File file, ZipOutputStream zos) throws IOException {
 		String path = prefix + "/" + base.relativize(file.toURI()).toString();
-		log.debug("Writing '" + path + "' to zip file");
+		log.debug("Writing '{}' to zip file", path);
 		ZipEntry zipEntry = new ZipEntry(path);
 		zos.putNextEntry(zipEntry);
 
diff --git a/openmeetings-install/src/main/java/org/apache/openmeetings/backup/BackupImport.java b/openmeetings-install/src/main/java/org/apache/openmeetings/backup/BackupImport.java
index 6a79651..98d86ab 100644
--- a/openmeetings-install/src/main/java/org/apache/openmeetings/backup/BackupImport.java
+++ b/openmeetings-install/src/main/java/org/apache/openmeetings/backup/BackupImport.java
@@ -195,7 +195,6 @@ import org.springframework.stereotype.Component;
 @Component
 public class BackupImport {
 	private static final Logger log = LoggerFactory.getLogger(BackupImport.class);
-	private static final String LDAP_EXT_TYPE = "LDAP";
 	private static final Map<String, String> outdatedConfigKeys = new HashMap<>();
 	private static final Map<String, Configuration.Type> configTypes = new HashMap<>();
 	static {
@@ -588,14 +587,14 @@ public class BackupImport {
 			// check that email is unique
 			if (u.getAddress() != null && u.getAddress().getEmail() != null && User.Type.user == u.getType()) {
 				if (userEmailMap.containsKey(u.getAddress().getEmail())) {
-					log.warn("Email is duplicated for user " + u.toString());
+					log.warn("Email is duplicated for user {}", u);
 					String updateEmail = String.format("modified_by_import_<%s>%s", randomUUID(), u.getAddress().getEmail());
 					u.getAddress().setEmail(updateEmail);
 				}
 				userEmailMap.put(u.getAddress().getEmail(), Integer.valueOf(userEmailMap.size()));
 			}
 			if (userLoginMap.containsKey(u.getLogin())) {
-				log.warn("Login is duplicated for user " + u.toString());
+				log.warn("Login is duplicated for user {}", u);
 				String updateLogin = String.format("modified_by_import_<%s>%s", randomUUID(), u.getLogin());
 				u.setLogin(updateLogin);
 			}
@@ -622,14 +621,6 @@ public class BackupImport {
 			if (u.getSipUser() != null && u.getSipUser().getId() != 0) {
 				u.getSipUser().setId(0);
 			}
-			if (LDAP_EXT_TYPE.equals(u.getExternalType()) && User.Type.external != u.getType()) {
-				log.warn("Found LDAP user in 'old' format, external_type == 'LDAP':: " + u);
-				u.setType(User.Type.ldap);
-				u.setExternalType(null);
-				if (u.getDomainId() == null) {
-					u.setDomainId(defaultLdapId); //domainId was not supported in old versions of OM
-				}
-			}
 			if (!Strings.isEmpty(u.getExternalType())) {
 				u.setType(User.Type.external);
 			}
diff --git a/openmeetings-install/src/main/java/org/apache/openmeetings/cli/CleanupHelper.java b/openmeetings-install/src/main/java/org/apache/openmeetings/cli/CleanupHelper.java
index aa679e5..aff6e3f 100644
--- a/openmeetings-install/src/main/java/org/apache/openmeetings/cli/CleanupHelper.java
+++ b/openmeetings-install/src/main/java/org/apache/openmeetings/cli/CleanupHelper.java
@@ -34,8 +34,8 @@ import org.apache.openmeetings.db.entity.file.FileItem;
 import org.apache.openmeetings.db.entity.record.Recording;
 import org.apache.openmeetings.db.entity.user.User;
 import org.apache.openmeetings.util.OmFileHelper;
-import org.slf4j.LoggerFactory;
 import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class CleanupHelper {
 	private static final Logger log = LoggerFactory.getLogger(CleanupHelper.class);
@@ -101,7 +101,7 @@ public class CleanupHelper {
 		int missing = 0;
 		for (File f : list(hibernateDir, (dir, name) -> name.endsWith(EXTENSION_MP4))) {
 			if (!f.isFile()) {
-				log.warn("Recording found is not a file: " + f);
+				log.warn("Recording found is not a file: {}", f);
 				continue;
 			}
 			String hash = f.getName().substring(0, f.getName().length() - EXTENSION_MP4.length() - 1);
diff --git a/openmeetings-install/src/main/java/org/apache/openmeetings/installation/ImportInitvalues.java b/openmeetings-install/src/main/java/org/apache/openmeetings/installation/ImportInitvalues.java
index 3b3be8c..64bba64 100644
--- a/openmeetings-install/src/main/java/org/apache/openmeetings/installation/ImportInitvalues.java
+++ b/openmeetings-install/src/main/java/org/apache/openmeetings/installation/ImportInitvalues.java
@@ -444,11 +444,11 @@ public class ImportInitvalues {
 		u.setFirstname("firstname");
 		u.setLastname("lastname");
 		u.getAddress().setEmail(cfg.getEmail());
-		u.getGroupUsers().add(new GroupUser(g, u));
+		u.addGroup(g);
 
 		u = userDao.update(u, cfg.getPassword(), -1L);
 
-		log.debug("Installation - User Added user-Id " + u.getId());
+		log.debug("Installation - User Added user-Id {}", u.getId());
 
 		if (u.getId() == null) {
 			throw new InstallException("Unable to add user");
diff --git a/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screenshare/Core.java b/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screenshare/Core.java
index bd8c152..bb913c8 100644
--- a/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screenshare/Core.java
+++ b/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screenshare/Core.java
@@ -18,6 +18,20 @@
  */
 package org.apache.openmeetings.screenshare;
 
+import static java.lang.Boolean.TRUE;
+import static java.util.UUID.randomUUID;
+import static org.apache.openmeetings.screenshare.util.Util.getQurtzProps;
+import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.awt.MouseInfo;
+import java.awt.Point;
+import java.net.ConnectException;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.LinkedBlockingQueue;
+
 import org.apache.openmeetings.screenshare.gui.ScreenDimensions;
 import org.apache.openmeetings.screenshare.gui.ScreenSharerFrame;
 import org.apache.openmeetings.screenshare.job.RemoteJob;
@@ -42,20 +56,6 @@ import org.red5.server.net.rtmp.status.StatusCodes;
 import org.slf4j.Logger;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
 
-import java.awt.MouseInfo;
-import java.awt.Point;
-import java.net.ConnectException;
-import java.net.URI;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.LinkedBlockingQueue;
-
-import static java.lang.Boolean.TRUE;
-import static java.util.UUID.randomUUID;
-import static org.apache.openmeetings.screenshare.util.Util.getQurtzProps;
-import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
-import static org.slf4j.LoggerFactory.getLogger;
-
 public class Core implements IPendingServiceCallback, INetStreamEventHandler {
 	private static final Logger log = getLogger(Core.class);
 	private static final String STATUS_EXC = "Exception: ";
@@ -108,7 +108,7 @@ public class Core implements IPendingServiceCallback, INetStreamEventHandler {
 		try {
 			System.setProperty("org.terracotta.quartz.skipUpdateCheck", "true");
 			for (String arg : args) {
-				log.debug("arg: " + arg);
+				log.debug("arg: {}", arg);
 			}
 			String[] textArray = null;
 			if (args.length > 8) {
@@ -127,10 +127,12 @@ public class Core implements IPendingServiceCallback, INetStreamEventHandler {
 				if (labelTexts.length() > 0) {
 					textArray = labelTexts.split(";");
 
-					log.debug("labelTexts :: " + labelTexts);
-					log.debug("textArray Length " + textArray.length);
-					for (int i = 0; i < textArray.length; i++) {
-						log.debug(i + " :: " + textArray[i]);
+					if (log.isDebugEnabled()) {
+						log.debug("labelTexts :: {}", labelTexts);
+						log.debug("textArray Length {}", textArray.length);
+						for (int i = 0; i < textArray.length; i++) {
+							log.debug("{} :: {}", i, textArray[i]);
+						}
 					}
 				}
 			} else {
@@ -439,20 +441,20 @@ public class Core implements IPendingServiceCallback, INetStreamEventHandler {
 			getCapture().release();
 			_capture = null;
 		} catch (Exception e) {
-			log.error("ScreenShare stopStream exception " + e);
+			log.error("ScreenShare stopStream exception ", e);
 		}
 	}
 
 	@Override
 	public void onStreamEvent(Notify notify) {
-		log.debug( "onStreamEvent " + notify );
+		log.debug("onStreamEvent {}", notify);
 
 		@SuppressWarnings("rawtypes")
 		ObjectMap map = (ObjectMap) notify.getCall().getArguments()[0];
 		String code = (String) map.get("code");
 
 		if (StatusCodes.NS_PUBLISH_START.equals(code)) {
-			log.debug( "onStreamEvent Publish start" );
+			log.debug("onStreamEvent Publish start");
 			getCapture().setStartPublish(true);
 			setReadyToRecord(true);
 		}
@@ -467,7 +469,7 @@ public class Core implements IPendingServiceCallback, INetStreamEventHandler {
 			return;
 		}
 		log.trace("#### sendRemoteCursorEvent ");
-		log.trace("Result Map Type "+ obj);
+		log.trace("Result Map Type ", obj);
 
 		if (obj != null) {
 			remoteEvents.offer(obj);
@@ -478,7 +480,7 @@ public class Core implements IPendingServiceCallback, INetStreamEventHandler {
 	@Override
 	public void resultReceived(IPendingServiceCall call) {
 		try {
-			log.trace("service call result: " + call);
+			log.trace("service call result: {}", call);
 			if (call == null) {
 				return;
 			}
@@ -486,12 +488,12 @@ public class Core implements IPendingServiceCallback, INetStreamEventHandler {
 			String method = call.getServiceMethodName();
 			Object o = call.getResult();
 			if (log.isTraceEnabled()) {
-				log.trace("Result Map Type " + (o == null ? null : o.getClass().getName()));
-				log.trace("" + o);
+				log.trace("Result Map Type {}", (o == null ? null : o.getClass().getName()));
+				log.trace("{}", o);
 			}
 			@SuppressWarnings("unchecked")
 			Map<String, Object> returnMap = (o != null && o instanceof Map) ? (Map<String, Object>) o : new HashMap<>();
-			log.trace("call ### get Method Name " + method);
+			log.trace("call ### get Method Name {}", method);
 			if ("connect".equals(method)) {
 				Object code = returnMap.get("code");
 				if (CONNECT_FAILED.equals(code) && !fallbackUsed) {
@@ -569,7 +571,7 @@ public class Core implements IPendingServiceCallback, INetStreamEventHandler {
 			} else if ("setNewCursorPosition".equals(method)) {
 				// Do not do anything
 			} else {
-				log.debug("Unknown method " + method);
+				log.debug("Unknown method {}", method);
 			}
 
 		} catch (Exception err) {
diff --git a/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screenshare/RTMPClientPublish.java b/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screenshare/RTMPClientPublish.java
index ac8dd1e..2a914e3 100644
--- a/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screenshare/RTMPClientPublish.java
+++ b/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screenshare/RTMPClientPublish.java
@@ -73,7 +73,7 @@ class RTMPClientPublish extends RTMPClient implements IPendingServiceCallback, I
 	@Override
 	public void resultReceived(IPendingServiceCall call) {
 		String method = call == null ? null : call.getServiceMethodName();
-		logger.trace("call ### get Method Name " + method);
+		logger.trace("call ### get Method Name {}", method);
 		if ("createStream".equals(method)) {
 			if (call.getResult() != null) {
 				publishScreen.setStreamId((Integer)call.getResult());
diff --git a/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screenshare/gui/ScreenKeyListener.java b/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screenshare/gui/ScreenKeyListener.java
index c3defc7..6f9d019 100644
--- a/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screenshare/gui/ScreenKeyListener.java
+++ b/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screenshare/gui/ScreenKeyListener.java
@@ -29,12 +29,12 @@ public class ScreenKeyListener implements KeyListener {
 
 	@Override
 	public void keyPressed(KeyEvent kEvent) {
-		logger.debug("keyPressed :Code: " + kEvent.getKeyCode());
+		logger.debug("keyPressed :Code: {}", kEvent.getKeyCode());
 	}
 
 	@Override
 	public void keyReleased(KeyEvent kEvent) {
-		logger.debug("keyReleased :Code: " + kEvent.getKeyCode());
+		logger.debug("keyReleased :Code: {}", kEvent.getKeyCode());
 	}
 
 	@Override
diff --git a/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screenshare/gui/ScreenSharerFrame.java b/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screenshare/gui/ScreenSharerFrame.java
index c697c08..a7343b6 100644
--- a/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screenshare/gui/ScreenSharerFrame.java
+++ b/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screenshare/gui/ScreenSharerFrame.java
@@ -607,7 +607,7 @@ public class ScreenSharerFrame extends JFrame {
 		if (status != sharingStarted) {
 			sharingActionRequested = false;
 		}
-		logger.debug("sharingActionRequested=" + sharingActionRequested);
+		logger.debug("sharingActionRequested={}", sharingActionRequested);
 		sharingStarted = status;
 		btnStartStopSharing.setIcon(status ? stopIcon : startIcon);
 		btnStartStopSharing.setText(status ? stopSharingLabel : startSharingLabel);
@@ -619,7 +619,7 @@ public class ScreenSharerFrame extends JFrame {
 		if (status != recordingStarted) {
 			recordingActionRequested = false;
 		}
-		logger.debug("recordingActionRequested=" + recordingActionRequested);
+		logger.debug("recordingActionRequested={}", recordingActionRequested);
 		recordingStarted = status;
 		btnStartStopRecording.setIcon(status ? stopIcon : startIcon);
 		btnStartStopRecording.setText(status ? stopRecordingLabel : startRecordingLabel);
diff --git a/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screenshare/job/RemoteJob.java b/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screenshare/job/RemoteJob.java
index f60c60b..4a6a213 100644
--- a/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screenshare/job/RemoteJob.java
+++ b/openmeetings-screenshare/src/main/java/org/apache/openmeetings/screenshare/job/RemoteJob.java
@@ -80,14 +80,14 @@ public class RemoteJob implements Job {
 					{
 						Point p = getCoordinates(obj);
 						robot.mouseMove(p.x, p.y);
-						robot.mouseRelease(InputEvent.BUTTON1_MASK);
+						robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
 					}
 						break;
 					case "mouseDown":
 					{
 						Point p = getCoordinates(obj);
 						robot.mouseMove(p.x, p.y);
-						robot.mousePress(InputEvent.BUTTON1_MASK);
+						robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
 					}
 						break;
 					case "mousePos":
diff --git a/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/IcalUtils.java b/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/IcalUtils.java
index 3d2c778..f414d4e 100644
--- a/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/IcalUtils.java
+++ b/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/IcalUtils.java
@@ -359,7 +359,7 @@ public class IcalUtils {
 				return date;
 			}
 		}
-		log.error("Unable to parse the date: " + str + " at " + -1);
+		log.error("Unable to parse the date: {} at {}", str, -1);
 		return null;
 	}
 
diff --git a/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/handler/EtagsHandler.java b/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/handler/EtagsHandler.java
index 030db74..262cd50 100644
--- a/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/handler/EtagsHandler.java
+++ b/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/handler/EtagsHandler.java
@@ -86,7 +86,8 @@ public class EtagsHandler extends AbstractCalendarHandler {
 	}
 
 	public EtagsHandler(String path, OmCalendar calendar, HttpClient client,
-	                    HttpClientContext context, AppointmentDao appointmentDao, IcalUtils utils) {
+			HttpClientContext context, AppointmentDao appointmentDao, IcalUtils utils)
+	{
 		super(path, calendar, client, context, appointmentDao, utils);
 	}
 
@@ -206,9 +207,9 @@ public class EtagsHandler extends AbstractCalendarHandler {
 
 					//Check if the ETag header was returned.
 					Header etagh = putMethod.getFirstHeader("ETag");
-					if (etagh == null)
+					if (etagh == null) {
 						hrefs = Collections.singletonList(appointment.getHref());
-					else {
+					} else {
 						appointment.setEtag(etagh.getValue());
 						appointmentDao.update(appointment, appointment.getOwner().getId());
 					}
@@ -260,7 +261,7 @@ public class EtagsHandler extends AbstractCalendarHandler {
 
 				int status = response.getStatusLine().getStatusCode();
 				if (status == SC_NO_CONTENT || status == SC_OK || status == SC_NOT_FOUND) {
-					log.info("Successfully deleted appointment with id: " + appointment.getId());
+					log.info("Successfully deleted appointment with id: {}", appointment.getId());
 					return true;
 				} else {
 					// Appointment Not deleted
diff --git a/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/methods/SyncMethod.java b/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/methods/SyncMethod.java
index 4fcc6e6..2d7c886 100644
--- a/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/methods/SyncMethod.java
+++ b/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/methods/SyncMethod.java
@@ -141,7 +141,7 @@ public class SyncMethod extends BaseDavRequest {
 				Document document = getResponseBodyAsDocument(response.getEntity());
 				if (document != null) {
 					synctoken = DomUtil.getChildText(document.getDocumentElement(), SyncReportInfo.XML_SYNC_TOKEN, DavConstants.NAMESPACE);
-					log.info("Sync-Token for REPORT: " + synctoken);
+					log.info("Sync-Token for REPORT: {}", synctoken);
 					multiStatus = MultiStatus.createFromXml(document.getDocumentElement());
 				}
 			} catch (IOException e) {
diff --git a/openmeetings-service/src/main/java/org/apache/openmeetings/service/room/InvitationManager.java b/openmeetings-service/src/main/java/org/apache/openmeetings/service/room/InvitationManager.java
index c977ef3..0b49fcf 100644
--- a/openmeetings-service/src/main/java/org/apache/openmeetings/service/room/InvitationManager.java
+++ b/openmeetings-service/src/main/java/org/apache/openmeetings/service/room/InvitationManager.java
@@ -167,7 +167,7 @@ public class InvitationManager implements IInvitationManager {
 			return;
 		}
 
-		log.debug(":::: processInvitation ..... " + reminder);
+		log.debug(":::: processInvitation ..... {}", reminder);
 		log.debug("Invitation for Appointment : simple email");
 		try {
 			mm.setInvitation(getInvitation(mm.getInvitation()
diff --git a/openmeetings-util/src/main/java/org/apache/openmeetings/util/crypt/CryptProvider.java b/openmeetings-util/src/main/java/org/apache/openmeetings/util/crypt/CryptProvider.java
index d5c0a0d..bf023d3 100644
--- a/openmeetings-util/src/main/java/org/apache/openmeetings/util/crypt/CryptProvider.java
+++ b/openmeetings-util/src/main/java/org/apache/openmeetings/util/crypt/CryptProvider.java
@@ -37,7 +37,7 @@ public class CryptProvider {
 					try {
 						log.debug("getInstanceOfCrypt:: configKeyCryptClassName: {}", clazz);
 
-						crypt = clazz == null ? null : (ICrypt) Class.forName(clazz).newInstance();
+						crypt = clazz == null ? null : (ICrypt) Class.forName(clazz).getDeclaredConstructor().newInstance();
 					} catch (Exception err) {
 						log.error("[getInstanceOfCrypt]", err);
 					}
diff --git a/openmeetings-util/src/main/java/org/apache/openmeetings/util/mail/IcalHandler.java b/openmeetings-util/src/main/java/org/apache/openmeetings/util/mail/IcalHandler.java
index 9805849..bbae47b 100644
--- a/openmeetings-util/src/main/java/org/apache/openmeetings/util/mail/IcalHandler.java
+++ b/openmeetings-util/src/main/java/org/apache/openmeetings/util/mail/IcalHandler.java
@@ -81,7 +81,7 @@ public class IcalHandler {
 	 *            (@see IcalHandler) constants
 	 */
 	public IcalHandler(Method method) {
-		log.debug("Icalhandler method type : " + method);
+		log.debug("Icalhandler method type : {}", method);
 
 		icsCalendar = new Calendar();
 		icsCalendar.getProperties().add(new ProdId("-//Events Calendar//iCal4j 1.0//EN"));
@@ -138,10 +138,10 @@ public class IcalHandler {
 		Uid ui;
 		if (Strings.isEmpty(uid)) {
 			ui = new Uid(randomUUID().toString());
-			log.debug("Generating Meeting UID : " + ui.getValue());
+			log.debug("Generating Meeting UID : {}", ui.getValue());
 		} else {
 			ui = new Uid(uid);
-			log.debug("Using Meeting UID : " + ui.getValue());
+			log.debug("Using Meeting UID : {}", ui.getValue());
 		}
 
 		meeting.getProperties().add(ui);
diff --git a/openmeetings-util/src/main/java/org/apache/openmeetings/util/process/ProcessResult.java b/openmeetings-util/src/main/java/org/apache/openmeetings/util/process/ProcessResult.java
index 8c45422..443aa86 100644
--- a/openmeetings-util/src/main/java/org/apache/openmeetings/util/process/ProcessResult.java
+++ b/openmeetings-util/src/main/java/org/apache/openmeetings/util/process/ProcessResult.java
@@ -28,7 +28,7 @@ package org.apache.openmeetings.util.process;
  *
  */
 public class ProcessResult {
-	public static final Integer ZERO = new Integer(0);
+	public static final Integer ZERO = Integer.valueOf(0);
 
 	private String process;
 	private String command;
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/groups/GroupsPanel.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/groups/GroupsPanel.java
index d4ae1c7..0d5a218 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/groups/GroupsPanel.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/groups/GroupsPanel.java
@@ -65,7 +65,11 @@ public class GroupsPanel extends AdminBasePanel {
 			protected void populateItem(Item<Group> item) {
 				final Group g = item.getModelObject();
 				item.add(new Label("id"));
-				item.add(new Label("name"));
+				Label name = new Label("name");
+				if (g.isExternal()) {
+					name.add(AttributeModifier.append("class", "external"));
+				}
+				item.add(name);
 				item.add(new AjaxEventBehavior(EVT_CLICK) {
 					private static final long serialVersionUID = 1L;
 
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/oauth/OAuthPanel.html b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/oauth/OAuthPanel.html
index 88c15fc..17831bb 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/oauth/OAuthPanel.html
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/oauth/OAuthPanel.html
@@ -82,7 +82,7 @@
 					<!-- Attribute mapping -->
 					<fieldset class="ui-widget-content">
 						<legend class="ui-widget-header"><wicket:message key="admin.oauth.user.mapping" /></legend>
-						<form wicket:id="mappingForm">
+						<div wicket:id="mappingForm">
 							<div class="formelement">
 								<label wicket:for="omAttr"><wicket:message key="admin.oauth.attr.om" /></label>
 								<input type="text" class="input" wicket:id="omAttr"/>
@@ -92,7 +92,7 @@
 								<input type="text" class="input" wicket:id="oauthAttr"/>
 							</div>
 							<button type="button" wicket:id="addMapping"><wicket:message key="1261"/></button>
-						</form>
+						</div>
 						<table class="list-table small">
 							<thead>
 								<tr class="ui-widget-header">
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/rooms/RoomsPanel.html b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/rooms/RoomsPanel.html
index 107927b..399622b 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/rooms/RoomsPanel.html
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/rooms/RoomsPanel.html
@@ -136,7 +136,7 @@
 				<!-- Room files -->
 				<fieldset class="ui-widget-content">
 					<legend class="ui-widget-header"><wicket:message key="245" /></legend>
-					<form wicket:id="filesForm">
+					<div wicket:id="filesForm">
 						<div class="formelement">
 							<label wicket:for="files2add"><wicket:message key="245" /></label>
 							<div class="om-select2"><select class="input" wicket:id="files2add"></select></div>
@@ -146,7 +146,7 @@
 							<input type="number" class="input" wicket:id="wbidx"/>
 						</div>
 						<button type="button" wicket:id="addFiles"><wicket:message key="1261"/></button>
-					</form>
+					</div>
 					<table class="list-table small">
 						<thead>
 							<tr class="ui-widget-header">
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/UserManager.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/UserManager.java
index 4e0769e..4b9e9b3 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/UserManager.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/UserManager.java
@@ -41,7 +41,6 @@ import org.apache.openmeetings.db.dao.user.IUserManager;
 import org.apache.openmeetings.db.dao.user.UserDao;
 import org.apache.openmeetings.db.dto.user.OAuthUser;
 import org.apache.openmeetings.db.entity.basic.Client;
-import org.apache.openmeetings.db.entity.user.GroupUser;
 import org.apache.openmeetings.db.entity.user.User;
 import org.apache.openmeetings.db.entity.user.User.Right;
 import org.apache.openmeetings.db.entity.user.User.Type;
@@ -113,7 +112,7 @@ public class UserManager implements IUserManager {
 
 				// this is needed cause the language is not a necessary data at registering
 				u.setLanguageId(languageId != 0 ? languageId : 1);
-				u.getGroupUsers().add(new GroupUser(groupDao.get(getDefaultGroup()), u));
+				u.addGroup(groupDao.get(getDefaultGroup()));
 
 				Object user = registerUser(u, password, null);
 
@@ -252,7 +251,7 @@ public class UserManager implements IUserManager {
 			fUser.setType(Type.oauth);
 			fUser.getRights().remove(Right.Login);
 			fUser.setDomainId(serverId);
-			fUser.getGroupUsers().add(new GroupUser(groupDao.get(getDefaultGroup()), fUser));
+			fUser.addGroup(groupDao.get(getDefaultGroup()));
 			for (Map.Entry<String, String> entry : user.getUserData().entrySet()) {
 				final String expression = entry.getKey();
 				PropertyResolver.setValue(expression, fUser, entry.getValue(), new LanguageConverter(expression, fUser, null, null));
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/WebSession.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/WebSession.java
index 6282921..4ab4d3d 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/WebSession.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/WebSession.java
@@ -49,6 +49,7 @@ import org.apache.openmeetings.db.dao.label.LabelDao;
 import org.apache.openmeetings.db.dao.room.InvitationDao;
 import org.apache.openmeetings.db.dao.server.SOAPLoginDao;
 import org.apache.openmeetings.db.dao.server.SessiondataDao;
+import org.apache.openmeetings.db.dao.user.GroupDao;
 import org.apache.openmeetings.db.dao.user.UserDao;
 import org.apache.openmeetings.db.entity.room.Invitation;
 import org.apache.openmeetings.db.entity.server.RemoteSessionObject;
@@ -108,7 +109,6 @@ public class WebSession extends AbstractAuthenticatedWebSession implements IWebS
 	private SOAPLogin soap = null;
 	private Long roomId = null;
 	private Long recordingId = null;
-	private String externalType;
 	private boolean kickedByAdmin = false;
 	private ExtendedClientProperties extProps = new ExtendedClientProperties();
 	@SpringBean
@@ -120,6 +120,8 @@ public class WebSession extends AbstractAuthenticatedWebSession implements IWebS
 	@SpringBean
 	private SessiondataDao sessionDao;
 	@SpringBean
+	private GroupDao groupDao;
+	@SpringBean
 	private UserDao userDao;
 	@SpringBean
 	private LdapLoginManager ldapManager;
@@ -144,7 +146,6 @@ public class WebSession extends AbstractAuthenticatedWebSession implements IWebS
 		soap = null;
 		roomId = null;
 		recordingId = null;
-		externalType = null;
 		tz = null;
 		browserTz = null;
 		extProps = new ExtendedClientProperties();
@@ -241,7 +242,7 @@ public class WebSession extends AbstractAuthenticatedWebSession implements IWebS
 						user.setLogin(remoteUser.getUsername());
 						user.setType(Type.external);
 						user.setExternalId(remoteUser.getExternalUserId());
-						user.setExternalType(remoteUser.getExternalUserType());
+						user.addGroup(groupDao.getExternal(remoteUser.getExternalUserType()));
 						user.getRights().clear();
 						user.getRights().add(Right.Room);
 						user.getAddress().setEmail(remoteUser.getEmail());
@@ -289,7 +290,6 @@ public class WebSession extends AbstractAuthenticatedWebSession implements IWebS
 			this.rights = Collections.unmodifiableSet(rights);
 		}
 		languageId = u.getLanguageId();
-		externalType = u.getExternalType();
 		tz = getTimeZone(u);
 		ISO8601FORMAT = FastDateFormat.getInstance(ISO8601_FULL_FORMAT_STRING, tz);
 		setLocale(LocaleHelper.getLocale(u));
@@ -371,10 +371,6 @@ public class WebSession extends AbstractAuthenticatedWebSession implements IWebS
 		return soap;
 	}
 
-	public static String getExternalType() {
-		return get().externalType;
-	}
-
 	public static TimeZone getUserTimeZone() {
 		return get().tz;
 	}
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/pages/auth/ForgetPasswordDialog.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/pages/auth/ForgetPasswordDialog.java
index aa9370d..03dd837 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/pages/auth/ForgetPasswordDialog.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/pages/auth/ForgetPasswordDialog.java
@@ -18,11 +18,15 @@
  */
 package org.apache.openmeetings.web.pages.auth;
 
-import com.googlecode.wicket.jquery.core.Options;
-import com.googlecode.wicket.jquery.ui.widget.dialog.AbstractFormDialog;
-import com.googlecode.wicket.jquery.ui.widget.dialog.DialogButton;
-import com.googlecode.wicket.jquery.ui.widget.dialog.MessageDialog;
-import com.googlecode.wicket.kendo.ui.panel.KendoFeedbackPanel;
+import static java.util.UUID.randomUUID;
+import static org.apache.openmeetings.util.OpenmeetingsVariables.getBaseUrl;
+import static org.apache.openmeetings.util.OpenmeetingsVariables.getMinLoginLength;
+import static org.apache.openmeetings.web.app.Application.urlForPage;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
 import org.apache.openmeetings.core.mail.MailHandler;
 import org.apache.openmeetings.db.dao.user.UserDao;
 import org.apache.openmeetings.db.entity.user.User;
@@ -51,14 +55,11 @@ import org.apache.wicket.validation.Validatable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.Arrays;
-import java.util.Date;
-import java.util.List;
-
-import static java.util.UUID.randomUUID;
-import static org.apache.openmeetings.util.OpenmeetingsVariables.getBaseUrl;
-import static org.apache.openmeetings.util.OpenmeetingsVariables.getMinLoginLength;
-import static org.apache.openmeetings.web.app.Application.urlForPage;
+import com.googlecode.wicket.jquery.core.Options;
+import com.googlecode.wicket.jquery.ui.widget.dialog.AbstractFormDialog;
+import com.googlecode.wicket.jquery.ui.widget.dialog.DialogButton;
+import com.googlecode.wicket.jquery.ui.widget.dialog.MessageDialog;
+import com.googlecode.wicket.kendo.ui.panel.KendoFeedbackPanel;
 
 public class ForgetPasswordDialog extends AbstractFormDialog<String> {
 	private static final Logger log = LoggerFactory.getLogger(ForgetPasswordDialog.class);
@@ -234,7 +235,7 @@ public class ForgetPasswordDialog extends AbstractFormDialog<String> {
 	 */
 	private boolean resetUser(String email, String username) {
 		try {
-			log.debug("resetUser " + email);
+			log.debug("resetUser {}", email);
 
 			// check if Mail given
 			if (!Strings.isEmpty(email)) {
@@ -257,7 +258,7 @@ public class ForgetPasswordDialog extends AbstractFormDialog<String> {
 	}
 
 	private void sendHashByUser(User us) {
-		log.debug("User: " + us.getLogin());
+		log.debug("User: {}", us.getLogin());
 		us.setResethash(randomUUID().toString());
 		us.setResetDate(new Date());
 		userDao.update(us, null);
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.java
index 3948ca5..abc2ff6 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.java
@@ -338,7 +338,7 @@ public class RoomPanel extends BasePanel {
 				}
 			} else {
 				allowed = r.getIspublic() || (r.getOwnerId() != null && r.getOwnerId().equals(getUserId()));
-				log.debug("public ? " + r.getIspublic() + ", ownedId ? " + r.getOwnerId() + " " + allowed);
+				log.debug("public ? {}, ownedId ? {} {}", r.getIspublic(), r.getOwnerId(), allowed);
 				if (!allowed) {
 					User u = getClient().getUser();
 					for (RoomGroup ro : r.getGroups()) {
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomSidebar.html b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomSidebar.html
index 4093440..1bad8bd 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomSidebar.html
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomSidebar.html
@@ -32,7 +32,7 @@
 					<span class="label"><wicket:message key="245"/></span>
 				</a>
 			</li>
-			<div class="btn-dock" wicket:message="data-ttl-dock:label.dock.panel,data-ttl-undock:label.undock.panel"></div>
+			<li class="btn-dock" wicket:message="data-ttl-dock:label.dock.panel,data-ttl-undock:label.undock.panel"></li>
 		</ul>
 		<div id="room-sidebar-tab-users">
 			<div wicket:id="icons" class="user header"></div>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/UploadDialog.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/UploadDialog.java
index 17c9675..8f370ce 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/UploadDialog.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/UploadDialog.java
@@ -280,7 +280,6 @@ public class UploadDialog extends AbstractFormDialog<String> {
 				FileItem f = new FileItem();
 				f.setSize(size);
 				f.setName(fu.getClientFileName());
-				f.setExternalType(room.getRoom().getExternalType());
 				if (parent == null || !(parent instanceof FileItem)) {
 					f.setOwnerId(getUserId());
 				} else {
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/calendar/AppointmentDialog.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/calendar/AppointmentDialog.java
index e938fa8..ff58d25 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/calendar/AppointmentDialog.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/calendar/AppointmentDialog.java
@@ -180,7 +180,7 @@ public class AppointmentDialog extends AbstractFormDialog<Appointment> {
 		form.start.setModelObject(getDateTime(a.getStart()));
 		form.end.setModelObject(getDateTime(a.getEnd()));
 		form.setEnabled(isOwner(a));
-		log.debug(" -- setModelObjectWithAjaxTarget -- Current model " + a);
+		log.debug(" -- setModelObjectWithAjaxTarget -- Current model {}", a);
 		if (a.getId() != null) {
 			delete.setVisible(isOwner(a), target);
 			enterRoom.setVisible(a.getRoom() != null, target);
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/calendar/CalendarDialog.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/calendar/CalendarDialog.java
index 2b2741f..ced74b3 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/calendar/CalendarDialog.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/calendar/CalendarDialog.java
@@ -268,7 +268,7 @@ public class CalendarDialog extends AbstractFormDialog<OmCalendar> {
 		}
 		apptManager.syncItem(client, context, c);
 		calendarPanel.refresh(handler);
-		log.trace("Calendar " + c.getTitle() + " Successfully synced.");
+		log.trace("Calendar {} Successfully synced.", c.getTitle());
 	}
 
 	/**
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/calendar/CalendarPanel.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/calendar/CalendarPanel.java
index 7fb892a..bb988ef 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/calendar/CalendarPanel.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/calendar/CalendarPanel.java
@@ -403,7 +403,7 @@ public class CalendarPanel extends UserBasePanel {
 		a.setReminder(Reminder.ical);
 		a.setOwner(userDao.get(getUserId()));
 		a.setTitle(getString("1444"));
-		log.debug(" -- getDefault -- Current model " + a);
+		log.debug(" -- getDefault -- Current model {}", a);
 		return a;
 	}
 }
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/record/RecordingResourceReference.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/record/RecordingResourceReference.java
index 1c21ec7..6a8795c 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/record/RecordingResourceReference.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/record/RecordingResourceReference.java
@@ -18,7 +18,6 @@
  */
 package org.apache.openmeetings.web.user.record;
 
-import static org.apache.openmeetings.web.app.WebSession.getExternalType;
 import static org.apache.openmeetings.web.app.WebSession.getRecordingId;
 import static org.apache.openmeetings.web.app.WebSession.getUserId;
 
@@ -32,7 +31,6 @@ import org.apache.openmeetings.db.dto.room.Whiteboards;
 import org.apache.openmeetings.db.entity.basic.Client;
 import org.apache.openmeetings.db.entity.file.BaseFileItem.Type;
 import org.apache.openmeetings.db.entity.record.Recording;
-import org.apache.openmeetings.db.entity.user.User;
 import org.apache.openmeetings.web.app.ClientManager;
 import org.apache.openmeetings.web.app.WebSession;
 import org.apache.openmeetings.web.app.WhiteboardManager;
@@ -123,6 +121,9 @@ public abstract class RecordingResourceReference extends FileItemResourceReferen
 			return r;
 		}
 		//external group check was added for plugin recording download
+		/*
+		FIXME TODO recording/file should have external group assigned
+		WebSession.getUserId()
 		String extType = getExternalType();
 		if (extType != null) {
 			User creator = userDao.get(r.getInsertedBy());
@@ -130,6 +131,7 @@ public abstract class RecordingResourceReference extends FileItemResourceReferen
 				return r;
 			}
 		}
+		*/
 		return null;
 	}
 }
diff --git a/openmeetings-web/src/main/webapp/css/raw-room.css b/openmeetings-web/src/main/webapp/css/raw-room.css
index c47f8d12..85c4364 100644
--- a/openmeetings-web/src/main/webapp/css/raw-room.css
+++ b/openmeetings-web/src/main/webapp/css/raw-room.css
@@ -566,6 +566,14 @@ ul.settings-menu {
 #sharer input {
 	width: 75px;
 }
+#room-sidebar-tabs.tabs .btn-dock {
+	display: block;
+	list-style: none;
+	list-style-type: none;
+	float: right;
+	padding: .4em 1em;
+	border-bottom-width: inherit;
+}
 .video .mute-others {
 	position: absolute;
 	top: calc(50% - 32px);
diff --git a/openmeetings-web/src/test/java/org/apache/openmeetings/calendar/TestDatabaseStructureGetUserStart.java b/openmeetings-web/src/test/java/org/apache/openmeetings/calendar/TestDatabaseStructureGetUserStart.java
index 4dc0b36..7a79ca3 100644
--- a/openmeetings-web/src/test/java/org/apache/openmeetings/calendar/TestDatabaseStructureGetUserStart.java
+++ b/openmeetings-web/src/test/java/org/apache/openmeetings/calendar/TestDatabaseStructureGetUserStart.java
@@ -29,7 +29,7 @@ public class TestDatabaseStructureGetUserStart extends AbstractJUnitDefaults {
 	@Test
 	public void testAddingGroup() {
 		try {
-			userDao.get(new Long(1));
+			userDao.get(1L);
 		} catch (Exception err) {
 			log.error("[testAddingGroup]", err);
 		}
diff --git a/openmeetings-web/src/test/java/org/apache/openmeetings/domain/TestAddGroup.java b/openmeetings-web/src/test/java/org/apache/openmeetings/domain/TestAddGroup.java
index 737d0a4..4b4a780 100644
--- a/openmeetings-web/src/test/java/org/apache/openmeetings/domain/TestAddGroup.java
+++ b/openmeetings-web/src/test/java/org/apache/openmeetings/domain/TestAddGroup.java
@@ -22,7 +22,6 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
 
 import org.apache.openmeetings.AbstractJUnitDefaults;
 import org.apache.openmeetings.db.entity.user.Group;
-import org.apache.openmeetings.db.entity.user.GroupUser;
 import org.apache.openmeetings.db.entity.user.User;
 import org.junit.jupiter.api.Test;
 import org.slf4j.Logger;
@@ -42,7 +41,7 @@ public class TestAddGroup extends AbstractJUnitDefaults {
 		assertNotNull(us, "User should exist");
 
 		assertNotNull(us.getGroupUsers(), "Group User list should exist");
-		us.getGroupUsers().add(new GroupUser(o, us));
+		us.addGroup(o);
 		us = userDao.update(us, null);
 
 		log.error(us.getLastname());
diff --git a/openmeetings-web/src/test/java/org/apache/openmeetings/user/TestUserContact.java b/openmeetings-web/src/test/java/org/apache/openmeetings/user/TestUserContact.java
index 5241871..af882c7 100644
--- a/openmeetings-web/src/test/java/org/apache/openmeetings/user/TestUserContact.java
+++ b/openmeetings-web/src/test/java/org/apache/openmeetings/user/TestUserContact.java
@@ -28,7 +28,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 import java.util.List;
 
 import org.apache.openmeetings.AbstractWicketTester;
-import org.apache.openmeetings.db.entity.user.GroupUser;
 import org.apache.openmeetings.db.entity.user.User;
 import org.junit.jupiter.api.Test;
 
@@ -43,7 +42,7 @@ public class TestUserContact extends AbstractWicketTester {
 	public void createUserWithGroup() throws Exception {
 		String uuid = randomUUID().toString();
 		User u = getUser(uuid);
-		u.getGroupUsers().add(new GroupUser(groupDao.get(1L), u));
+		u.addGroup(groupDao.get(1L));
 		u = userDao.update(u, null);
 		assertTrue(userDao.verifyPassword(u.getId(), createPass()), "Password should be set as expected");
 
diff --git a/openmeetings-web/src/test/java/org/apache/openmeetings/user/TestUserGroup.java b/openmeetings-web/src/test/java/org/apache/openmeetings/user/TestUserGroup.java
index 321ac44..8203a88 100644
--- a/openmeetings-web/src/test/java/org/apache/openmeetings/user/TestUserGroup.java
+++ b/openmeetings-web/src/test/java/org/apache/openmeetings/user/TestUserGroup.java
@@ -119,7 +119,7 @@ public class TestUserGroup extends AbstractJUnitDefaults {
 		}
 		for (int i = 0; i < 10000; ++i) {
 			User u = createUser();
-			u.getGroupUsers().add(new GroupUser(g, u));
+			u.addGroup(g);
 			userDao.update(u, null);
 		}
 	}
diff --git a/openmeetings-web/src/test/java/org/apache/openmeetings/webservice/TestCalendarService.java b/openmeetings-web/src/test/java/org/apache/openmeetings/webservice/TestCalendarService.java
index d9daf78..b70e033 100644
--- a/openmeetings-web/src/test/java/org/apache/openmeetings/webservice/TestCalendarService.java
+++ b/openmeetings-web/src/test/java/org/apache/openmeetings/webservice/TestCalendarService.java
@@ -50,7 +50,6 @@ import org.apache.openmeetings.db.dto.calendar.MeetingMemberDTO;
 import org.apache.openmeetings.db.entity.calendar.Appointment;
 import org.apache.openmeetings.db.entity.calendar.MeetingMember;
 import org.apache.openmeetings.db.entity.room.Room;
-import org.apache.openmeetings.db.entity.user.GroupUser;
 import org.apache.openmeetings.db.entity.user.User;
 import org.apache.openmeetings.webservice.util.AppointmentParamConverter;
 import org.junit.jupiter.api.Test;
@@ -64,7 +63,7 @@ public class TestCalendarService extends AbstractWebServiceTest {
 	private void actualTest(Room r) throws Exception {
 		String uuid = randomUUID().toString();
 		User u = getUser(uuid);
-		u.getGroupUsers().add(new GroupUser(getBean(GroupDao.class).get(1L), u));
+		u.addGroup(getBean(GroupDao.class).get(1L));
 		webCreateUser(u);
 		ServiceResult sr = login(u.getLogin(), createPass());
 		u = getBean(UserDao.class).get(u.getId());
@@ -127,7 +126,7 @@ public class TestCalendarService extends AbstractWebServiceTest {
 	private String loginNewUser() throws Exception {
 		String uuid = randomUUID().toString();
 		User u = getUser(uuid);
-		u.getGroupUsers().add(new GroupUser(getBean(GroupDao.class).get(1L), u));
+		u.addGroup(getBean(GroupDao.class).get(1L));
 		webCreateUser(u);
 		ServiceResult sr = login(u.getLogin(), createPass());
 		return sr.getMessage();
@@ -177,7 +176,7 @@ public class TestCalendarService extends AbstractWebServiceTest {
 
 		String uuid = randomUUID().toString();
 		User u = getUser(uuid);
-		u.getGroupUsers().add(new GroupUser(getBean(GroupDao.class).get(1L), u));
+		u.addGroup(getBean(GroupDao.class).get(1L));
 		u = createUser(getBean(UserDao.class), u);
 		ServiceResult sr = login(u.getLogin(), createPass());
 
diff --git a/openmeetings-web/src/test/java/org/apache/openmeetings/webservice/TestRecordingService.java b/openmeetings-web/src/test/java/org/apache/openmeetings/webservice/TestRecordingService.java
index 9affb5b..74fffc1 100644
--- a/openmeetings-web/src/test/java/org/apache/openmeetings/webservice/TestRecordingService.java
+++ b/openmeetings-web/src/test/java/org/apache/openmeetings/webservice/TestRecordingService.java
@@ -27,6 +27,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 import java.util.Collection;
 
 import org.apache.openmeetings.db.dao.record.RecordingDao;
+import org.apache.openmeetings.db.dao.user.GroupDao;
 import org.apache.openmeetings.db.dto.basic.ServiceResult;
 import org.apache.openmeetings.db.dto.record.RecordingDTO;
 import org.apache.openmeetings.db.entity.record.Recording;
@@ -39,7 +40,7 @@ public class TestRecordingService extends AbstractWebServiceTest {
 	private User getExternalUser() throws Exception {
 		String uuid = randomUUID().toString();
 		User u = getUser(uuid);
-		u.setExternalType(UNIT_TEST_EXT_TYPE);
+		u.addGroup(getBean(GroupDao.class).getExternal(UNIT_TEST_EXT_TYPE));
 		u.setExternalId(uuid);
 		webCreateUser(u);
 		return u;
diff --git a/openmeetings-web/src/test/java/org/apache/openmeetings/webservice/TestUserService.java b/openmeetings-web/src/test/java/org/apache/openmeetings/webservice/TestUserService.java
index 5d46f92..72b662e 100644
--- a/openmeetings-web/src/test/java/org/apache/openmeetings/webservice/TestUserService.java
+++ b/openmeetings-web/src/test/java/org/apache/openmeetings/webservice/TestUserService.java
@@ -143,8 +143,9 @@ public class TestUserService extends AbstractWebServiceTest {
 				.post(new Form().param("user", u.toString()).param("confirm", "" + false), UserDTO.class);
 		assertNotNull(user, "Valid UserDTO should be returned");
 		assertNotNull(user.getId(), "Id should not be NULL");
-		assertEquals(u.getLogin(), user.getLogin(), "OM Call should be successful");
-		assertEquals(tz, user.getTimeZoneId(), "OM Call should be successful");
+		assertEquals(u.getLogin(), user.getLogin(), "Login should match");
+		assertEquals(User.Type.external, user.getType(), "Type should match");
+		assertEquals(tz, user.getTimeZoneId(), "Timezone should match");
 	}
 
 	@Test
diff --git a/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/CalendarWebService.java b/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/CalendarWebService.java
index 68cb40b..b0977f6 100644
--- a/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/CalendarWebService.java
+++ b/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/CalendarWebService.java
@@ -40,6 +40,7 @@ import javax.ws.rs.core.MediaType;
 
 import org.apache.cxf.feature.Features;
 import org.apache.openmeetings.db.dao.calendar.AppointmentDao;
+import org.apache.openmeetings.db.dao.user.GroupDao;
 import org.apache.openmeetings.db.dto.basic.ServiceResult;
 import org.apache.openmeetings.db.dto.basic.ServiceResult.Type;
 import org.apache.openmeetings.db.dto.calendar.AppointmentDTO;
@@ -69,6 +70,9 @@ public class CalendarWebService extends BaseWebService {
 
 	@Autowired
 	private AppointmentDao dao;
+	@Autowired
+	private GroupDao groupDao;
+
 	/**
 	 * Load appointments by a start / end range for the current SID
 	 *
@@ -223,7 +227,7 @@ public class CalendarWebService extends BaseWebService {
 						|| appointment.getOwner().getId().equals(u.getId());
 			}, sd -> {
 				User u = userDao.get(sd.getUserId());
-				Appointment a = appointment.get(userDao, fileDao, dao, u);
+				Appointment a = appointment.get(userDao, groupDao, roomDao, fileDao, dao, u);
 				if (a.getRoom().getId() != null) {
 					if (a.getRoom().isAppointment()) {
 						a.getRoom().setIspublic(false);
diff --git a/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/ErrorWebService.java b/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/ErrorWebService.java
index 313188f..fe2d166 100644
--- a/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/ErrorWebService.java
+++ b/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/ErrorWebService.java
@@ -88,7 +88,7 @@ public class ErrorWebService extends BaseWebService {
 		if (sid != null && message != null) {
 			Sessiondata sd = check(sid);
 			if (sd.getId() != null) {
-				log.error("[CLIENT MESSAGE] " + message);
+				log.error("[CLIENT MESSAGE] {}", message);
 			}
 		}
 	}
diff --git a/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/GroupWebService.java b/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/GroupWebService.java
index 34f56a5..9b2f43c 100644
--- a/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/GroupWebService.java
+++ b/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/GroupWebService.java
@@ -132,7 +132,7 @@ public class GroupWebService extends BaseWebService {
 		return performCall(sid, User.Right.Soap, sd -> {
 			if (!groupUserDao.isUserInGroup(id, userid)) {
 				User u = userDao.get(userid);
-				u.getGroupUsers().add(new GroupUser(groupDao.get(id), u));
+				u.addGroup(groupDao.get(id));
 				userDao.update(u, sd.getUserId());
 			}
 			return new ServiceResult(String.valueOf(userid), Type.SUCCESS);
diff --git a/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/RecordingWebService.java b/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/RecordingWebService.java
index f2eb5a6..ab4fc9c 100644
--- a/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/RecordingWebService.java
+++ b/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/RecordingWebService.java
@@ -82,13 +82,13 @@ public class RecordingWebService extends BaseWebService {
 	}
 
 	/**
-	 * Gets a list of flv recordings
+	 * Gets a list of recordings created by particular external user
 	 *
 	 * @param sid The SID of the User. This SID must be marked as Loggedin
 	 * @param externalId the externalUserId
 	 * @param externalType the externalUserType
 	 *
-	 * @return - list of flv recordings
+	 * @return - list of recordings
 	 */
 	@WebMethod
 	@GET
@@ -97,7 +97,7 @@ public class RecordingWebService extends BaseWebService {
 			, @PathParam("externaltype") @WebParam(name="externaltype") String externalType
 			, @PathParam("externalid") @WebParam(name="externalid") String externalId) {
 		log.debug("getExternal:: type {}, id {}", externalType, externalId);
-		return performCall(sid, User.Right.Soap, sd -> RecordingDTO.list(recordingDao.getByExternalId(externalId, externalType)));
+		return performCall(sid, User.Right.Soap, sd -> RecordingDTO.list(recordingDao.getByExternalUser(externalId, externalType)));
 	}
 
 	/**
diff --git a/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/RoomWebService.java b/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/RoomWebService.java
index 56de7da..a1a1ada 100644
--- a/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/RoomWebService.java
+++ b/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/RoomWebService.java
@@ -39,6 +39,7 @@ import javax.ws.rs.core.MediaType;
 import org.apache.cxf.feature.Features;
 import org.apache.openmeetings.core.util.WebSocketHelper;
 import org.apache.openmeetings.db.dao.room.InvitationDao;
+import org.apache.openmeetings.db.dao.user.GroupDao;
 import org.apache.openmeetings.db.dao.user.IUserManager;
 import org.apache.openmeetings.db.dto.basic.ServiceResult;
 import org.apache.openmeetings.db.dto.basic.ServiceResult.Type;
@@ -86,6 +87,8 @@ public class RoomWebService extends BaseWebService {
 	private InvitationDao inviteDao;
 	@Autowired
 	private InvitationManager inviteManager;
+	@Autowired
+	private GroupDao groupDao;
 
 	/**
 	 * Returns an Object of Type RoomsList which contains a list of
@@ -141,7 +144,7 @@ public class RoomWebService extends BaseWebService {
 		return roomDao.update(r, userId);
 	}
 	/**
-	 * Checks if a room with this exteralRoomId + externalRoomType does exist,
+	 * Checks if a room with this exteralId + externalType does exist,
 	 * if yes it returns the room id if not, it will create the room and then
 	 * return the room id of the newly created room
 	 *
@@ -173,9 +176,9 @@ public class RoomWebService extends BaseWebService {
 				if (room == null) {
 					return null;
 				} else {
-					r = room.get(fileDao);
-					r.setExternalType(externalType);
-					r.setExternalId(externalId);
+					room.setExternalType(externalType);
+					room.setExternalId(externalId);
+					r = room.get(roomDao, groupDao, fileDao);
 					r = updateRtoRoom(r, sd.getUserId());
 					return new RoomDTO(r);
 				}
@@ -200,7 +203,7 @@ public class RoomWebService extends BaseWebService {
 	@Path("/")
 	public RoomDTO add(@WebParam(name="sid") @QueryParam("sid") String sid, @WebParam(name="room") @FormParam("room") RoomDTO room) {
 		return performCall(sid, User.Right.Soap, sd -> {
-			Room r = room.get(fileDao);
+			Room r = room.get(roomDao, groupDao, fileDao);
 			r = updateRtoRoom(r, sd.getUserId());
 			return new RoomDTO(r);
 		});
diff --git a/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/UserWebService.java b/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/UserWebService.java
index 2ba7cea..264cafd 100644
--- a/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/UserWebService.java
+++ b/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/UserWebService.java
@@ -56,7 +56,6 @@ import org.apache.openmeetings.db.dto.user.UserDTO;
 import org.apache.openmeetings.db.entity.server.RemoteSessionObject;
 import org.apache.openmeetings.db.entity.server.Sessiondata;
 import org.apache.openmeetings.db.entity.user.Address;
-import org.apache.openmeetings.db.entity.user.GroupUser;
 import org.apache.openmeetings.db.entity.user.User;
 import org.apache.openmeetings.db.entity.user.User.Right;
 import org.apache.openmeetings.util.OmException;
@@ -180,7 +179,8 @@ public class UserWebService extends BaseWebService {
 			if (user.getLanguageId() == null) {
 				user.setLanguageId(1L);
 			}
-			IValidator<String> passValidator = new StrongPasswordValidator(true, user.get(userDao));
+			User jsonUser = user.get(userDao, groupDao);
+			IValidator<String> passValidator = new StrongPasswordValidator(true, jsonUser);
 			Validatable<String> passVal = new Validatable<>(user.getPassword());
 			passValidator.validate(passVal);
 			if (!passVal.isValid()) {
@@ -191,32 +191,27 @@ public class UserWebService extends BaseWebService {
 				log.debug("addNewUser::weak password '{}', msg: {}", user.getPassword(), sb);
 				throw new ServiceException(sb.toString());
 			}
-			Object _user;
+			Object ouser;
 			try {
-				User u = user.get(userDao);
-				u.getGroupUsers().add(new GroupUser(groupDao.get(getDefaultGroup()), u));
-				_user = userManager.registerUser(u, user.getPassword(), null);
+				jsonUser.addGroup(groupDao.get(getDefaultGroup()));
+				ouser = userManager.registerUser(jsonUser, user.getPassword(), null);
 			} catch (NoSuchAlgorithmException | OmException e) {
 				throw new ServiceException("Unexpected error while creating user");
 			}
 
-			if (_user == null) {
+			if (ouser == null) {
 				throw new ServiceException(UNKNOWN.getMessage());
-			} else if (_user instanceof String) {
-				throw new ServiceException((String)_user);
+			} else if (ouser instanceof String) {
+				throw new ServiceException((String)ouser);
 			}
 
-			User u = (User)_user;
+			User u = (User)ouser;
 
 			u.getRights().add(Right.Room);
 			if (Strings.isEmpty(user.getExternalId()) && Strings.isEmpty(user.getExternalType())) {
 				// activate the User
 				u.getRights().add(Right.Login);
 				u.getRights().add(Right.Dashboard);
-			} else {
-				u.setType(User.Type.external);
-				u.setExternalId(user.getExternalId());
-				u.setExternalType(user.getExternalType());
 			}
 
 			u = userDao.update(u, sd.getUserId());