From 986280f115a26c28f6404f4f2ef9233caf29cb4d Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Wed, 22 Jan 2014 08:35:47 +0100
Subject: [PATCH] OO-948: create new roster entries without lock

---
 .../InstantMessagingService.java              |  2 +-
 .../manager/InstantMessagingServiceImpl.java  |  7 +--
 .../instantMessaging/manager/RosterDAO.java   | 42 ++++++++++++---
 .../model/ImPreferencesImpl.java              |  4 +-
 .../model/RosterEntryImpl.java                |  7 +--
 .../model/RosterEntryView.java                |  4 +-
 .../instantMessaging/ui/ChatController.java   |  4 +-
 .../ui/InstantMessagingMainController.java    |  4 +-
 .../InstantMessageServiceTest.java            |  6 +--
 .../olat/instantMessaging/RosterDAOTest.java  | 51 +++++++++++++++++++
 10 files changed, 105 insertions(+), 26 deletions(-)

diff --git a/src/main/java/org/olat/instantMessaging/InstantMessagingService.java b/src/main/java/org/olat/instantMessaging/InstantMessagingService.java
index 9c2063c6825..cad93dfd169 100644
--- a/src/main/java/org/olat/instantMessaging/InstantMessagingService.java
+++ b/src/main/java/org/olat/instantMessaging/InstantMessagingService.java
@@ -73,7 +73,7 @@ public interface InstantMessagingService {
 	 * @param chatResource
 	 * @param listener
 	 */
-	public void listenChat(Identity identity, OLATResourceable chatResource, boolean anonym, boolean asVip, GenericEventListener listener);
+	public void listenChat(Identity identity, OLATResourceable chatResource, String nickName, boolean anonym, boolean asVip, GenericEventListener listener);
 	
 	/**
 	 * Go away
diff --git a/src/main/java/org/olat/instantMessaging/manager/InstantMessagingServiceImpl.java b/src/main/java/org/olat/instantMessaging/manager/InstantMessagingServiceImpl.java
index e03b442cdbf..3be8b576b74 100644
--- a/src/main/java/org/olat/instantMessaging/manager/InstantMessagingServiceImpl.java
+++ b/src/main/java/org/olat/instantMessaging/manager/InstantMessagingServiceImpl.java
@@ -205,8 +205,6 @@ public class InstantMessagingServiceImpl extends BasicManager implements Instant
 		}
 		String fullName = userManager.getUserDisplayName(me);
 		rosterDao.updateRosterEntry(chatResource, me, fullName, nickName, anonym, vip);
-		dbInstance.commit();//commit before sending event
-		
 		coordinator.getCoordinator().getEventBus().fireEventToListenersOf(event, chatResource);
 	}
 	
@@ -376,11 +374,10 @@ public class InstantMessagingServiceImpl extends BasicManager implements Instant
 	}
 
 	@Override
-	public void listenChat(Identity identity, OLATResourceable chatResource,
+	public void listenChat(Identity identity, OLATResourceable chatResource, String nickName,
 			boolean anonym, boolean vip, GenericEventListener listener) {
 		String fullName = userManager.getUserDisplayName(identity);
-		rosterDao.updateRosterEntry(chatResource, identity, fullName, null, anonym, vip);
-		dbInstance.commit();
+		rosterDao.updateRosterEntry(chatResource, identity, fullName, nickName, anonym, vip);
 		coordinator.getCoordinator().getEventBus().registerFor(listener, identity, chatResource);
 	}
 
diff --git a/src/main/java/org/olat/instantMessaging/manager/RosterDAO.java b/src/main/java/org/olat/instantMessaging/manager/RosterDAO.java
index 04c17737eef..e85024fb91f 100644
--- a/src/main/java/org/olat/instantMessaging/manager/RosterDAO.java
+++ b/src/main/java/org/olat/instantMessaging/manager/RosterDAO.java
@@ -59,22 +59,39 @@ public class RosterDAO {
 		return entry;
 	}
 
+	/**
+	 * The method commit the transaction in case of a select for update
+	 * @param chatResource
+	 * @param identity
+	 * @param fullName
+	 * @param nickName
+	 * @param anonym
+	 * @param vip
+	 */
 	public void updateRosterEntry(OLATResourceable chatResource, Identity identity, String fullName, String nickName,
 			boolean anonym, boolean vip) {
-		RosterEntryImpl entry = loadForUpdate(chatResource, identity);
+		RosterEntryImpl entry = load(chatResource, identity);
 		if(entry == null) {
 			createRosterEntry(chatResource, identity, fullName, nickName, anonym, vip);
 		} else {
-			entry.setFullName(fullName);
-			entry.setNickName(nickName);
-			entry.setAnonym(anonym);
-			dbInstance.getCurrentEntityManager().merge(entry);
+			if(entry.isAnonym() == anonym
+				&& ((fullName == null && entry.getFullName() == null) || (fullName != null && fullName.equals(entry.getFullName())))
+				&& ((nickName == null && entry.getNickName() == null) || (nickName != null && nickName.equals(entry.getNickName())))) {
+				return;
+			}
+			
+			RosterEntryImpl reloadedEntry = loadForUpdate(entry);
+			reloadedEntry.setFullName(fullName);
+			reloadedEntry.setNickName(nickName);
+			reloadedEntry.setAnonym(anonym);
+			dbInstance.getCurrentEntityManager().merge(reloadedEntry);
+			dbInstance.commit();
 		}
 	}
 	
-	private RosterEntryImpl loadForUpdate(OLATResourceable ores, Identity identity) {
+	private RosterEntryImpl load(OLATResourceable ores, Identity identity) {
 		TypedQuery<RosterEntryImpl> query = dbInstance.getCurrentEntityManager()
-				.createNamedQuery("loadIMRosterEntryForUpdate", RosterEntryImpl.class)
+				.createNamedQuery("loadIMRosterEntry", RosterEntryImpl.class)
 				.setParameter("resid", ores.getResourceableId())
 				.setParameter("resname", ores.getResourceableTypeName())
 				.setParameter("identityKey", identity.getKey());
@@ -85,6 +102,17 @@ public class RosterDAO {
 		return null;
 	}
 	
+	private RosterEntryImpl loadForUpdate(RosterEntryImpl rosterEntry) {
+		TypedQuery<RosterEntryImpl> query = dbInstance.getCurrentEntityManager()
+				.createNamedQuery("loadIMRosterEntryForUpdate", RosterEntryImpl.class)
+				.setParameter("entryKey", rosterEntry.getKey());
+		List<RosterEntryImpl> entries = query.getResultList();
+		if(entries.size() > 0) {
+			return entries.get(0);
+		}
+		return null;
+	}
+	
 	public List<RosterEntryImpl> getRoster(OLATResourceable ores, int firstResult, int maxResults) {
 		TypedQuery<RosterEntryImpl> query = dbInstance.getCurrentEntityManager()
 				.createNamedQuery("loadIMRosterEntryByResource", RosterEntryImpl.class)
diff --git a/src/main/java/org/olat/instantMessaging/model/ImPreferencesImpl.java b/src/main/java/org/olat/instantMessaging/model/ImPreferencesImpl.java
index 6df47ce15cc..99baafed7b2 100644
--- a/src/main/java/org/olat/instantMessaging/model/ImPreferencesImpl.java
+++ b/src/main/java/org/olat/instantMessaging/model/ImPreferencesImpl.java
@@ -69,8 +69,8 @@ public class ImPreferencesImpl implements ImPreferences, Persistable, CreateInfo
 	private static final long serialVersionUID = -7269061512818714778L;
 
 	@Id
-  @GeneratedValue(generator = "system-uuid")
-  @GenericGenerator(name = "system-uuid", strategy = "hilo")
+	@GeneratedValue(generator = "system-uuid")
+	@GenericGenerator(name = "system-uuid", strategy = "hilo")
 	@Column(name="id", nullable=false, unique=true, insertable=true, updatable=false)
 	private Long key;
 	
diff --git a/src/main/java/org/olat/instantMessaging/model/RosterEntryImpl.java b/src/main/java/org/olat/instantMessaging/model/RosterEntryImpl.java
index 12c1cdafdb0..98fba00d8c8 100644
--- a/src/main/java/org/olat/instantMessaging/model/RosterEntryImpl.java
+++ b/src/main/java/org/olat/instantMessaging/model/RosterEntryImpl.java
@@ -46,8 +46,9 @@ import org.olat.core.id.Persistable;
 @Table(name="o_im_roster_entry")
 @NamedQueries({
 	@NamedQuery(name="loadIMRosterEntryByIdentityandResource", query="select entry from imrosterentry entry where entry.identityKey=:identityKey and entry.resourceId=:resid and entry.resourceTypeName=:resname"),
-	@NamedQuery(name="loadIMRosterEntryForUpdate", query="select entry from imrosterentry entry where entry.identityKey=:identityKey and entry.resourceId=:resid and entry.resourceTypeName=:resname",
+	@NamedQuery(name="loadIMRosterEntryForUpdate", query="select entry from imrosterentry entry where entry.key=:entryKey",
 		lockMode=LockModeType.PESSIMISTIC_WRITE),
+	@NamedQuery(name="loadIMRosterEntry", query="select entry from imrosterentry entry where entry.identityKey=:identityKey and entry.resourceId=:resid and entry.resourceTypeName=:resname"),
 	@NamedQuery(name="loadIMRosterEntryByResource", query="select entry from imrosterentry entry where entry.resourceId=:resid and entry.resourceTypeName=:resname")
 })
 public class RosterEntryImpl implements Persistable, CreateInfo {
@@ -55,8 +56,8 @@ public class RosterEntryImpl implements Persistable, CreateInfo {
 	private static final long serialVersionUID = -4265724240924748369L;
 
 	@Id
-  @GeneratedValue(generator = "system-uuid")
-  @GenericGenerator(name = "system-uuid", strategy = "hilo")
+	@GeneratedValue(generator = "system-uuid")
+	@GenericGenerator(name = "system-uuid", strategy = "hilo")
 	@Column(name="id", nullable=false, unique=true, insertable=true, updatable=false)
 	private Long key;
 	
diff --git a/src/main/java/org/olat/instantMessaging/model/RosterEntryView.java b/src/main/java/org/olat/instantMessaging/model/RosterEntryView.java
index bae0abaa89e..6b66b90dd60 100644
--- a/src/main/java/org/olat/instantMessaging/model/RosterEntryView.java
+++ b/src/main/java/org/olat/instantMessaging/model/RosterEntryView.java
@@ -53,8 +53,8 @@ public class RosterEntryView implements Persistable, CreateInfo {
 	private static final long serialVersionUID = -4265724240924748369L;
 
 	@Id
-  @GeneratedValue(generator = "system-uuid")
-  @GenericGenerator(name = "system-uuid", strategy = "hilo")
+	@GeneratedValue(generator = "system-uuid")
+	@GenericGenerator(name = "system-uuid", strategy = "hilo")
 	@Column(name="re_id", nullable=false, unique=true, insertable=true, updatable=false)
 	private Long key;
 	
diff --git a/src/main/java/org/olat/instantMessaging/ui/ChatController.java b/src/main/java/org/olat/instantMessaging/ui/ChatController.java
index f9cd7f6e135..5c86bba4d65 100644
--- a/src/main/java/org/olat/instantMessaging/ui/ChatController.java
+++ b/src/main/java/org/olat/instantMessaging/ui/ChatController.java
@@ -141,7 +141,6 @@ public class ChatController extends BasicController implements GenericEventListe
 		}
 		
 		// register to chat events for this resource
-		imService.listenChat(getIdentity(), getOlatResourceable(), defaultAnonym, vip, this);
 		
 		if(privateReceiverKey == null) {
 			buddyList = new Roster(getIdentity().getKey());
@@ -150,8 +149,11 @@ public class ChatController extends BasicController implements GenericEventListe
 			//chat started as anonymous depending on configuratino
 			rosterCtrl = new RosterForm(ureq, getWindowControl(), buddyList, defaultAnonym, offerAnonymMode);
 			listenTo(rosterCtrl);
+			String nickName = rosterCtrl.getNickName();
+			imService.listenChat(getIdentity(), getOlatResourceable(), nickName, defaultAnonym, vip, this);
 		} else {
 			buddyList = null;
+			imService.listenChat(getIdentity(), getOlatResourceable(), null, defaultAnonym, vip, this);
 		}
 
 		chatPanelCtr = new FloatingResizableDialogController(ureq, getWindowControl(), mainVC,
diff --git a/src/main/java/org/olat/instantMessaging/ui/InstantMessagingMainController.java b/src/main/java/org/olat/instantMessaging/ui/InstantMessagingMainController.java
index 3d7df0b9253..719fa688522 100644
--- a/src/main/java/org/olat/instantMessaging/ui/InstantMessagingMainController.java
+++ b/src/main/java/org/olat/instantMessaging/ui/InstantMessagingMainController.java
@@ -150,8 +150,8 @@ public class InstantMessagingMainController extends BasicController implements G
 		listenTo(chatMgrCtrl);
 		newMsgIcon.put("chats", chatMgrCtrl.getInitialComponent());
 		
-		//listen to privat chat messages
-		imService.listenChat(getIdentity(), getPrivatListenToResourceable(), false, false, this);
+		//listen to private chat messages
+		imService.listenChat(getIdentity(), getPrivatListenToResourceable(), null, false, false, this);
 		
 		singleUserEventCenter = ureq.getUserSession().getSingleUserEventCenter();
 		singleUserEventCenter.registerFor(this, getIdentity(), InstantMessagingService.ASSESSMENT_EVENT_ORES);
diff --git a/src/test/java/org/olat/instantMessaging/InstantMessageServiceTest.java b/src/test/java/org/olat/instantMessaging/InstantMessageServiceTest.java
index 534b33dc49a..425bd220767 100644
--- a/src/test/java/org/olat/instantMessaging/InstantMessageServiceTest.java
+++ b/src/test/java/org/olat/instantMessaging/InstantMessageServiceTest.java
@@ -82,8 +82,8 @@ public class InstantMessageServiceTest extends OlatTestCase {
 		Identity chatter1 = JunitTestHelper.createAndPersistIdentityAsUser("Chat-1-" + UUID.randomUUID().toString());
 		Identity chatter2 = JunitTestHelper.createAndPersistIdentityAsUser("Chat-2-" + UUID.randomUUID().toString());
 		OLATResourceable chatResource = OresHelper.createOLATResourceableInstance(UUID.randomUUID().toString(), chatter1.getKey());
-		imService.listenChat(chatter1, chatResource, false, false, dummyListener);
-		imService.listenChat(chatter2, chatResource, true, true, dummyListener);
+		imService.listenChat(chatter1, chatResource, null, false, false, dummyListener);
+		imService.listenChat(chatter2, chatResource, "Chatter-2", true, true, dummyListener);
 		dbInstance.commitAndCloseSession();
 
 		//check if the buddies listen to the chat
@@ -109,7 +109,7 @@ public class InstantMessageServiceTest extends OlatTestCase {
 		//create a chat
 		Identity chatter1 = JunitTestHelper.createAndPersistIdentityAsUser("Chat-3-" + UUID.randomUUID().toString());
 		OLATResourceable chatResource = OresHelper.createOLATResourceableInstance(UUID.randomUUID().toString(), chatter1.getKey());
-		imService.listenChat(chatter1, chatResource, false, false, new DummyListener());
+		imService.listenChat(chatter1, chatResource, null, false, false, new DummyListener());
 		dbInstance.commitAndCloseSession();
 		
 		BuddyStats stats = imService.getBuddyStats(chatter1);
diff --git a/src/test/java/org/olat/instantMessaging/RosterDAOTest.java b/src/test/java/org/olat/instantMessaging/RosterDAOTest.java
index 9ae23306357..27512de5b63 100644
--- a/src/test/java/org/olat/instantMessaging/RosterDAOTest.java
+++ b/src/test/java/org/olat/instantMessaging/RosterDAOTest.java
@@ -31,6 +31,7 @@ import org.olat.core.id.OLATResourceable;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.instantMessaging.manager.RosterDAO;
 import org.olat.instantMessaging.model.RosterEntryImpl;
+import org.olat.instantMessaging.model.RosterEntryView;
 import org.olat.test.JunitTestHelper;
 import org.olat.test.OlatTestCase;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -89,6 +90,28 @@ public class RosterDAOTest extends OlatTestCase {
 		Assert.assertEquals(chatResource.getResourceableId(), entry.getResourceId());
 	}
 	
+	@Test
+	public void testGetRosterViews() {
+		OLATResourceable chatResource = OresHelper.createOLATResourceableInstance("unit-test-8-" + UUID.randomUUID().toString(), System.currentTimeMillis());
+		Identity id = JunitTestHelper.createAndPersistIdentityAsAdmin("im-roster-8-" + UUID.randomUUID().toString());
+		rosterDao.createRosterEntry(chatResource, id, "My little name", "Nock", false, false);
+		dbInstance.commitAndCloseSession();
+		
+		List<RosterEntryView> entries = rosterDao.getRosterView(chatResource, 0, -1);
+		Assert.assertNotNull(entries);
+		Assert.assertEquals(1, entries.size());
+		
+		RosterEntryView entry = entries.get(0);
+		Assert.assertNotNull(entry);
+		Assert.assertNotNull(entry.getKey());
+		Assert.assertEquals(id.getKey(), entry.getIdentityKey());
+		Assert.assertEquals("My little name", entry.getFullName());
+		Assert.assertEquals("Nock", entry.getNickName());
+		Assert.assertFalse(entry.isAnonym());
+		Assert.assertEquals(chatResource.getResourceableTypeName(), entry.getResourceTypeName());
+		Assert.assertEquals(chatResource.getResourceableId(), entry.getResourceId());
+	}
+	
 	@Test
 	public void testUpdateRosterEntry() {
 		OLATResourceable chatResource = OresHelper.createOLATResourceableInstance("unit-test-7-" + UUID.randomUUID().toString(), System.currentTimeMillis());
@@ -121,6 +144,34 @@ public class RosterDAOTest extends OlatTestCase {
 		Assert.assertEquals(chatResource.getResourceableId(), reloadEntry.getResourceId());
 	}
 	
+	@Test
+	public void testUpdateRosterEntry_createNew() {
+		OLATResourceable chatResource = OresHelper.createOLATResourceableInstance("unit-test-7-" + UUID.randomUUID().toString(), System.currentTimeMillis());
+		Identity id = JunitTestHelper.createAndPersistIdentityAsAdmin("im-roster-7-" + UUID.randomUUID().toString());
+		rosterDao.updateRosterEntry(chatResource, id, "My old name", "Truck", true, false);
+		dbInstance.commitAndCloseSession();
+		
+		//load the entry
+		List<RosterEntryImpl> entries = rosterDao.getRoster(chatResource, 0, -1);
+		Assert.assertNotNull(entries);
+		Assert.assertEquals(1, entries.size());
+		
+		RosterEntryImpl entry = entries.get(0);
+		
+		Assert.assertNotNull(entries);
+		Assert.assertEquals(1, entries.size());
+		
+		RosterEntryImpl reloadEntry = entries.get(0);
+		Assert.assertNotNull(reloadEntry);
+		Assert.assertNotNull(reloadEntry.getKey());
+		Assert.assertEquals(id.getKey(), reloadEntry.getIdentityKey());
+		Assert.assertEquals("My old name", reloadEntry.getFullName());
+		Assert.assertEquals("Truck", reloadEntry.getNickName());
+		Assert.assertTrue(entry.isAnonym());
+		Assert.assertEquals(chatResource.getResourceableTypeName(), reloadEntry.getResourceTypeName());
+		Assert.assertEquals(chatResource.getResourceableId(), reloadEntry.getResourceId());
+	}
+	
 	@Test
 	public void testDeleteRosterEntries() {
 		//create an entry
-- 
GitLab