From c2913255fa332bab34385218c00459b92b0252ca Mon Sep 17 00:00:00 2001
From: srosse <stephane.rosse@frentix.com>
Date: Tue, 4 Sep 2018 09:31:53 +0200
Subject: [PATCH] OO-3633: remove group of area if group removed from the
 course which owned the area, add a warning in the area list of group if one
 of them doesn't link to the course

---
 README.md                                     |   2 +-
 .../course/area/CourseAreasController.java    |   8 +-
 .../org/olat/group/BusinessGroupService.java  |   4 +-
 src/main/java/org/olat/group/area/BGArea.java |   2 +-
 .../org/olat/group/area/BGAreaManager.java    |   2 +
 .../olat/group/area/BGAreaManagerImpl.java    | 126 ++++++++----------
 .../manager/BusinessGroupServiceImpl.java     |   5 +-
 .../org/olat/group/ui/NewAreaController.java  |  30 ++---
 .../group/ui/area/BGAreaEditController.java   |  45 ++++---
 .../group/ui/area/GroupsToAreaDataModel.java  |  18 ++-
 .../ui/area/_i18n/LocalStrings_de.properties  |   1 +
 .../ui/area/_i18n/LocalStrings_en.properties  |   2 +
 .../olat/group/test/BGAreaManagerTest.java    |  46 +++++++
 13 files changed, 164 insertions(+), 127 deletions(-)

diff --git a/README.md b/README.md
index ba6fd516243..d9e31c443ca 100644
--- a/README.md
+++ b/README.md
@@ -396,7 +396,7 @@ The beginning of the installation is the same as Tomcat as described above. To c
      
 #### Configuration WildFly (JBoss AS 10.1)
 
-We need Hibernate 5.2, you need to use the utorial to update the version of hibernate
+We need Hibernate 5.2, you need to use the tutorial to update the version of hibernate
 in Widlfly: http://docs.jboss.org/hibernate/orm/5.2/topical/html_single/wildfly/Wildfly.html
 
 Define a JDBC connection pool in your standalone.xml configuration with a jndi-name like:
diff --git a/src/main/java/org/olat/course/area/CourseAreasController.java b/src/main/java/org/olat/course/area/CourseAreasController.java
index 21c311f5f01..cbaf8987271 100644
--- a/src/main/java/org/olat/course/area/CourseAreasController.java
+++ b/src/main/java/org/olat/course/area/CourseAreasController.java
@@ -61,6 +61,7 @@ public class CourseAreasController extends MainLayoutBasicController {
 	private static final String TABLE_ACTION_DELETE = "tbl_del";
 	
 	private final StackedPanel mainPanel;
+	
 	private final Link createAreaLink;
 	private final VelocityContainer mainVC;
 	private final TableController tableCtrl;
@@ -77,7 +78,6 @@ public class CourseAreasController extends MainLayoutBasicController {
 	
 	public CourseAreasController(UserRequest ureq, WindowControl wControl, OLATResource resource, boolean readOnly) {
 		super(ureq, wControl);
-		
 		this.resource = resource;
 
 		Translator resourceTrans = Util.createPackageTranslator(RepositoryService.class, getLocale(), getTranslator());
@@ -188,10 +188,4 @@ public class CourseAreasController extends MainLayoutBasicController {
 		listenTo(editController);
 		mainPanel.pushContent(editController.getInitialComponent());
 	}
-	
-	
-
-
-
-	
 }
diff --git a/src/main/java/org/olat/group/BusinessGroupService.java b/src/main/java/org/olat/group/BusinessGroupService.java
index b4f99ae764a..4d8cbdd7118 100644
--- a/src/main/java/org/olat/group/BusinessGroupService.java
+++ b/src/main/java/org/olat/group/BusinessGroupService.java
@@ -334,9 +334,9 @@ public interface BusinessGroupService {
 	
 	public void addResourcesTo(List<BusinessGroup> groups, List<RepositoryEntry> resources);
 	
-	public void removeResourceFrom(List<BusinessGroup> group, RepositoryEntryRef re);
+	public void removeResourceFrom(List<BusinessGroup> group, RepositoryEntry re);
 	
-	public void removeResource(RepositoryEntryRef resource);
+	public void removeResource(RepositoryEntry resource);
 	
 	public List<RepositoryEntry> findRepositoryEntries(Collection<BusinessGroup> groups, int firstResult, int maxResults);
 	
diff --git a/src/main/java/org/olat/group/area/BGArea.java b/src/main/java/org/olat/group/area/BGArea.java
index 1353c5515b0..c8409375a4d 100644
--- a/src/main/java/org/olat/group/area/BGArea.java
+++ b/src/main/java/org/olat/group/area/BGArea.java
@@ -42,7 +42,7 @@ import org.olat.resource.OLATResource;
 public interface BGArea extends Persistable, CreateInfo, ShortName {
 	/** regular expression to check for valid area names */
 	// commas are not allowed. name is used in course conditions for weak binding
-	public final static String VALID_AREANAME_REGEXP = "^[^,\"]*$";
+	public static final String VALID_AREANAME_REGEXP = "^[^,\"]*$";
 
 	/**
 	 * @return The group area description
diff --git a/src/main/java/org/olat/group/area/BGAreaManager.java b/src/main/java/org/olat/group/area/BGAreaManager.java
index 0871b5ae28e..42c70c1e7af 100644
--- a/src/main/java/org/olat/group/area/BGAreaManager.java
+++ b/src/main/java/org/olat/group/area/BGAreaManager.java
@@ -105,6 +105,8 @@ public interface BGAreaManager {
 	 * @param area
 	 */
 	public void removeBGFromArea(BusinessGroup group, BGArea area);
+	
+	public void removeBGFromAreas(BusinessGroup group, OLATResource resource);
 
 	/**
 	 * Deletes all business group to area relations from the given business group
diff --git a/src/main/java/org/olat/group/area/BGAreaManagerImpl.java b/src/main/java/org/olat/group/area/BGAreaManagerImpl.java
index 8fff0988f4e..c87cfe8c4f6 100644
--- a/src/main/java/org/olat/group/area/BGAreaManagerImpl.java
+++ b/src/main/java/org/olat/group/area/BGAreaManagerImpl.java
@@ -33,13 +33,12 @@ import javax.persistence.TypedQuery;
 
 import org.olat.basesecurity.GroupRoles;
 import org.olat.core.commons.persistence.DB;
-import org.olat.core.commons.persistence.DBFactory;
 import org.olat.core.id.Identity;
 import org.olat.core.logging.OLATRuntimeException;
-import org.olat.core.manager.BasicManager;
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.coordinate.CoordinatorManager;
-import org.olat.core.util.coordinate.SyncerCallback;
 import org.olat.core.util.coordinate.SyncerExecutor;
 import org.olat.group.BusinessGroup;
 import org.olat.resource.OLATResource;
@@ -53,7 +52,9 @@ import org.springframework.stereotype.Service;
  * @author gnaegi
  */
 @Service("areaManager")
-public class BGAreaManagerImpl extends BasicManager implements BGAreaManager {
+public class BGAreaManagerImpl implements BGAreaManager {
+	
+	private static final OLog log = Tracing.createLoggerFor(BGAreaManagerImpl.class); 
 	
 	@Autowired
 	private DB dbInstance;
@@ -71,16 +72,12 @@ public class BGAreaManagerImpl extends BasicManager implements BGAreaManager {
 		sb.append("select area from ").append(BGAreaImpl.class.getName()).append(" area ")
 		  .append(" where area.key in (:keys)");
 		
-		List<BGArea> areas = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), BGArea.class)
+		return dbInstance.getCurrentEntityManager().createQuery(sb.toString(), BGArea.class)
 				.setParameter("keys", keys)
 				.getResultList();
-		return areas;
 	}
 
-	/**
-	 * @see org.olat.group.area.BGAreaManager#findBGArea(java.lang.String,
-	 *      org.olat.group.context.BGContext)
-	 */
+	@Override
 	public BGArea findBGArea(String areaName, OLATResource resource) {
 		StringBuilder sb = new StringBuilder();
 		sb.append("select area from ").append(BGAreaImpl.class.getName()).append(" area ")
@@ -99,28 +96,20 @@ public class BGAreaManagerImpl extends BasicManager implements BGAreaManager {
 		return areas.get(0);
 	}
 
-	/**
-	 * @see org.olat.group.area.BGAreaManager#updateBGArea(org.olat.group.area.BGArea)
-	 */
+
 	//o_clusterOK by:cg synchronized
+	@Override
 	public BGArea updateBGArea(final BGArea area) {
 		// look if an area with such a name does already exist in this context
 		final OLATResource resource = area.getResource();
-		
-		BGArea updatedBGArea =CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(resource, new SyncerCallback<BGArea>(){
-			public BGArea execute() {
-				BGArea reloadArea = loadArea(area.getKey());
-				reloadArea.setName(area.getName());
-				reloadArea.setDescription(area.getDescription());
-				return dbInstance.getCurrentEntityManager().merge(reloadArea);
-			}
+		return CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(resource, () -> {
+			BGArea reloadArea = loadArea(area.getKey());
+			reloadArea.setName(area.getName());
+			reloadArea.setDescription(area.getDescription());
+			return dbInstance.getCurrentEntityManager().merge(reloadArea);
 		});
-		return updatedBGArea;
 	}
 
-	/**
-	 * @see org.olat.group.area.BGAreaManager#deleteBGArea(org.olat.group.area.BGArea)
-	 */
 	@Override
 	public void deleteBGArea(final BGArea area) {
 		final OLATResource resource = area.getResource();
@@ -136,9 +125,9 @@ public class BGAreaManagerImpl extends BasicManager implements BGAreaManager {
 					deleteAssessmentModeToAreaRelations(reloadArea);
 					// 3) delete area itself
 					dbInstance.deleteObject(reloadArea);
-					logAudit("Deleted Business Group Area", reloadArea.toString());
+					log.audit("Deleted Business Group Area", reloadArea.toString());
 				} else {
-					logAudit("Business Group Area was already deleted", area.toString());
+					log.audit("Business Group Area was already deleted", area.toString());
 				}
 			}
 		});
@@ -158,27 +147,36 @@ public class BGAreaManagerImpl extends BasicManager implements BGAreaManager {
 				.setParameter("groupKey", group.getKey())
 				.executeUpdate();
 	}
-
-	/**
-	 * @see org.olat.group.area.BGAreaManager#addBGToBGArea(org.olat.group.BusinessGroup,
-	 *      org.olat.group.area.BGArea)
-	 */
+	
+	@Override
 	public void addBGToBGArea(BusinessGroup group, BGArea area) {
 		BGtoAreaRelation bgAreaRel = new BGtoAreaRelationImpl(area, group);
 		dbInstance.saveObject(bgAreaRel);
 	}
 
-	/**
-	 * @see org.olat.group.area.BGAreaManager#removeBGFromArea(org.olat.group.BusinessGroup,
-	 *      org.olat.group.area.BGArea)
-	 */
+	@Override
 	public void removeBGFromArea(BusinessGroup group, BGArea area) {
 		removeBGFromArea(group.getKey(), area.getKey());
 	}
+	
+	@Override
+	public void removeBGFromAreas(BusinessGroup group, OLATResource resource) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select bgarel from ").append(BGtoAreaRelationImpl.class.getName()).append(" as bgarel ")
+		  .append(" inner join bgarel.groupArea as area")
+		  .append(" where bgarel.businessGroup.key=:businessGroupKey and area.resource.key=:resourceKey");
+
+		List<BGtoAreaRelationImpl> relations = dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), BGtoAreaRelationImpl.class)
+				.setParameter("businessGroupKey", group.getKey())
+				.setParameter("resourceKey", resource.getKey())
+				.getResultList();
+		for(BGtoAreaRelationImpl relation:relations) {
+			dbInstance.getCurrentEntityManager().remove(relation);
+		}
+	}
 
-	/**
-	 * @see org.olat.group.area.BGAreaManager#findBusinessGroupsOfArea(org.olat.group.area.BGArea)
-	 */
+	@Override
 	public List<BusinessGroup> findBusinessGroupsOfArea(BGArea area) {
 		return findBusinessGroupsOfAreas(Collections.singletonList(area));
 	}
@@ -186,7 +184,7 @@ public class BGAreaManagerImpl extends BasicManager implements BGAreaManager {
 	@Override
 	public List<BusinessGroup> findBusinessGroupsOfAreas(List<BGArea> areas) {
 		if(areas == null || areas.isEmpty()) return Collections.emptyList();
-		List<Long> areaKeys = new ArrayList<Long>();
+		List<Long> areaKeys = new ArrayList<>();
 		for(BGArea area:areas) {
 			areaKeys.add(area.getKey());
 		}
@@ -203,7 +201,7 @@ public class BGAreaManagerImpl extends BasicManager implements BGAreaManager {
 		  .append(" left join fetch businessGroup.resource resource")
 		  .append(" where  bgarel.groupArea.key in (:areaKeys)");
 
-		return DBFactory.getInstance().getCurrentEntityManager()
+		return dbInstance.getCurrentEntityManager()
 				.createQuery(sb.toString(), BusinessGroup.class)
 				.setParameter("areaKeys", areaKeys)
 				.getResultList();
@@ -218,16 +216,12 @@ public class BGAreaManagerImpl extends BasicManager implements BGAreaManager {
 		  .append(" inner join bgarel.businessGroup businessGroup ")
 		  .append(" where  bgarel.groupArea.key in (:areaKeys)");
 
-		return DBFactory.getInstance().getCurrentEntityManager()
+		return dbInstance.getCurrentEntityManager()
 				.createQuery(sb.toString(), Long.class)
 				.setParameter("areaKeys", areaKeys)
 				.getResultList();
 	}
 
-	/**
-	 * @see org.olat.group.area.BGAreaManager#findBusinessGroupsOfAreaAttendedBy(org.olat.core.id.Identity,
-	 *      java.lang.String, org.olat.group.context.BGContext)
-	 */
 	@Override
 	public List<BusinessGroup> findBusinessGroupsOfAreaAttendedBy(Identity identity, List<Long> areaKeys, OLATResource resource) {
 		StringBuilder sb = new StringBuilder();
@@ -253,13 +247,10 @@ public class BGAreaManagerImpl extends BasicManager implements BGAreaManager {
 			query.setParameter("resourceKey", resource.getKey());
 		}
 		
-		List<BusinessGroup> groups = query.getResultList();
-		return groups;
+		return query.getResultList();
 	}
 
-	/**
-	 * @see org.olat.group.area.BGAreaManager#findBGAreasOfBusinessGroup(org.olat.group.BusinessGroup)
-	 */
+	@Override
 	public List<BGArea> findBGAreasOfBusinessGroup(BusinessGroup group) {
 		return findBGAreasOfBusinessGroups(Collections.singletonList(group));
 	}
@@ -273,7 +264,7 @@ public class BGAreaManagerImpl extends BasicManager implements BGAreaManager {
 		  .append("where bgarel.businessGroup.key in (:groupKeys)");
 
 		TypedQuery<BGArea> areaQuery = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), BGArea.class);
-		List<Long> groupKeys = new ArrayList<Long>();
+		List<Long> groupKeys = new ArrayList<>();
 		for(BusinessGroup group:groups) {
 			groupKeys.add(group.getKey());
 		}
@@ -290,7 +281,7 @@ public class BGAreaManagerImpl extends BasicManager implements BGAreaManager {
 		  .append("where bgarel.businessGroup.key in (:groupKeys)");
 
 		TypedQuery<Number> areaQuery = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Number.class);
-		List<Long> groupKeys = new ArrayList<Long>();
+		List<Long> groupKeys = new ArrayList<>();
 		for(BusinessGroup group:groups) {
 			groupKeys.add(group.getKey());
 		}
@@ -298,9 +289,6 @@ public class BGAreaManagerImpl extends BasicManager implements BGAreaManager {
 		return areaQuery.getSingleResult().intValue();
 	}
 
-	/**
-	 * @see org.olat.group.area.BGAreaManager#countBGAreasOfBGContext(org.olat.group.context.BGContext)
-	 */
 	@Override
 	public int countBGAreasInContext(OLATResource resource) {
 		StringBuilder sb = new StringBuilder();
@@ -319,16 +307,13 @@ public class BGAreaManagerImpl extends BasicManager implements BGAreaManager {
 	public List<BGArea> findBGAreasInContext(OLATResource resource) {
 		StringBuilder sb = new StringBuilder();
 		sb.append("select area from ").append(BGAreaImpl.class.getName()).append(" area where area.resource.key=:resourceKey");
-		List<BGArea> areas = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), BGArea.class)
+		return dbInstance.getCurrentEntityManager().createQuery(sb.toString(), BGArea.class)
 				.setParameter("resourceKey", resource.getKey())
 				.getResultList();
-		return areas;
 	}
 
-	/**
-	 * @see org.olat.group.area.BGAreaManager#isIdentityInBGArea(org.olat.core.id.Identity,
-	 *      java.lang.String, org.olat.group.context.BGContext)
-	 */
+
+	@Override
 	public boolean isIdentityInBGArea(Identity identity, String areaName, Long areaKey, OLATResource resource) {
 		StringBuilder sb = new StringBuilder();
 		sb.append("select count(bgarel) from ").append(BGtoAreaRelationImpl.class.getName()).append(" as bgarel")
@@ -360,18 +345,16 @@ public class BGAreaManagerImpl extends BasicManager implements BGAreaManager {
 		return count.intValue() > 0;
 	}
 
-	/**
-	 * @see org.olat.group.area.BGAreaManager#reloadArea(org.olat.group.area.BGArea)
-	 */
+	@Override
 	public BGArea reloadArea(BGArea area) {
-		return (BGArea) DBFactory.getInstance().loadObject(area);
+		return (BGArea) dbInstance.loadObject(area);
 	}
 
 	@Override
 	public boolean existArea(String nameOrKey, OLATResource resource) {
 		Long key = null;
 		if(StringHelper.isLong(nameOrKey)) {
-			key = new Long(nameOrKey);
+			key = Long.valueOf(nameOrKey);
 		}
 		
 		StringBuilder sb = new StringBuilder();
@@ -399,7 +382,7 @@ public class BGAreaManagerImpl extends BasicManager implements BGAreaManager {
 		if(!StringHelper.containsNonWhitespace(areaNames)) return Collections.emptyList();
 		
 		String[] areaNameArr = areaNames.split(",");
-		List<String> areaNameList = new ArrayList<String>();
+		List<String> areaNameList = new ArrayList<>();
 		for(String areaName:areaNameArr) {
 			areaNameList.add(areaName.trim());
 		}
@@ -410,12 +393,11 @@ public class BGAreaManagerImpl extends BasicManager implements BGAreaManager {
 		sb.append("select area.key from ").append(BGAreaImpl.class.getName()).append(" area")
 		  .append(" where area.resource.key=:resourceKey and area.name in (:names)");
 
-		List<Long> keys = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Long.class)
+		return dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Long.class)
 				.setParameter("resourceKey", resource.getKey())
 				.setParameter("names", areaNameList)
 				.setHint("org.hibernate.cacheable", Boolean.TRUE)
 				.getResultList();
-		return keys;
 	}
 
 	/**
@@ -430,9 +412,7 @@ public class BGAreaManagerImpl extends BasicManager implements BGAreaManager {
 	public BGArea createAndPersistBGArea(String areaName, String description, OLATResource resource) {
 		BGArea area = new BGAreaImpl(areaName, description, resource);
 		dbInstance.getCurrentEntityManager().persist(area);
-		if (area != null) {
-			logAudit("Created Business Group Area", area.toString());
-		}
+		log.audit("Created Business Group Area", area.toString());
 		// else no area created, name duplicate
 		return area;
 	}
diff --git a/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java b/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java
index 7d5079bd182..1ad5dc24b8f 100644
--- a/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java
+++ b/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java
@@ -1624,7 +1624,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService {
 	}
 
 	@Override
-	public void removeResourceFrom(List<BusinessGroup> groups, RepositoryEntryRef re) {
+	public void removeResourceFrom(List<BusinessGroup> groups, RepositoryEntry re) {
 		if(groups == null || groups.isEmpty()) {
 			return; // nothing to do
 		}
@@ -1634,6 +1634,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService {
 		int count = 0;
 		for(BusinessGroup group:groups) {
 			businessGroupRelationDAO.deleteRelation(group, re);
+			areaManager.removeBGFromAreas(group, re.getOlatResource());
 			events.add(new BusinessGroupRelationModified(BusinessGroupRelationModified.RESOURCE_REMOVED_EVENT, group.getKey(), re.getKey()));
 			if(count++ % 20 == 0) {
 				dbInstance.commit();
@@ -1648,7 +1649,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService {
 	}
 	
 	@Override
-	public void removeResource(RepositoryEntryRef re) {
+	public void removeResource(RepositoryEntry re) {
 		SearchBusinessGroupParams params = new SearchBusinessGroupParams();
 		List<BusinessGroup> groups = findBusinessGroups(params, re, 0, -1);
 		removeResourceFrom(groups, re);
diff --git a/src/main/java/org/olat/group/ui/NewAreaController.java b/src/main/java/org/olat/group/ui/NewAreaController.java
index a7a15bd2bf4..b304da8491a 100644
--- a/src/main/java/org/olat/group/ui/NewAreaController.java
+++ b/src/main/java/org/olat/group/ui/NewAreaController.java
@@ -29,7 +29,6 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
-import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.velocity.VelocityContainer;
@@ -44,6 +43,7 @@ import org.olat.group.area.BGAreaManager;
 import org.olat.group.ui.area.BGAreaFormController;
 import org.olat.resource.OLATResource;
 import org.olat.util.logging.activity.LoggingResourceable;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * Description:<br>
@@ -65,7 +65,9 @@ public class NewAreaController extends BasicController {
 	private boolean bulkMode = false;
 	private Set<BGArea> newAreas;
 	private HashSet<String> newAreaNames;
-	private final BGAreaManager areaManager;
+	
+	@Autowired
+	private BGAreaManager areaManager;
 
 	/**
 	 * 
@@ -81,8 +83,7 @@ public class NewAreaController extends BasicController {
 		this.resource = resource;
 		this.bulkMode = bulkMode;
 		//
-		areaManager = CoreSpringFactory.getImpl(BGAreaManager.class);
-		contentVC = this.createVelocityContainer("areaform");
+		contentVC = createVelocityContainer("areaform");
 		contentVC.contextPut("bulkMode", bulkMode ? Boolean.TRUE : Boolean.FALSE);
 		//
 		areaCreateController = new BGAreaFormController(ureq, wControl, null, bulkMode);
@@ -94,21 +95,12 @@ public class NewAreaController extends BasicController {
 		}
 		putInitialPanel(contentVC);
 	}
-	
-	/**
-	 * @see org.olat.core.gui.control.DefaultController#doDispose(boolean)
-	 */
+
 	@Override
 	protected void doDispose() {
-		// Don't dispose anything
-		
+		//
 	}
 
-	/**
-	 * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest,
-	 *      org.olat.core.gui.components.Component,
-	 *      org.olat.core.gui.control.Event)
-	 */
 	@Override
 	public void event(UserRequest ureq, Component source, Event event) {
 		// Don't do anything.
@@ -120,7 +112,7 @@ public class NewAreaController extends BasicController {
 			if (event == Event.DONE_EVENT) {
 				String areaDesc = this.areaCreateController.getAreaDescription();
 				
-				Set<String> allNames = new HashSet<String>();
+				Set<String> allNames = new HashSet<>();
 				if (this.bulkMode) {
 					allNames = this.areaCreateController.getGroupNames();
 				} else {
@@ -128,8 +120,8 @@ public class NewAreaController extends BasicController {
 				}
 
 				// create bulkgroups only if there is no name which already exists. 
-				newAreas = new HashSet<BGArea>();
-				newAreaNames = new HashSet<String>();
+				newAreas = new HashSet<>();
+				newAreaNames = new HashSet<>();
 				for (String areaName : allNames) {
 					BGArea newArea = areaManager.createAndPersistBGArea(areaName, areaDesc, resource);
 					newAreas.add(newArea);
@@ -178,7 +170,7 @@ public class NewAreaController extends BasicController {
 	}
 	
 	public List<Long> getCreatedAreaKeys(){
-		List<Long> areaKeys = new ArrayList<Long>();
+		List<Long> areaKeys = new ArrayList<>();
 		for(BGArea newArea:newAreas) {
 			areaKeys.add(newArea.getKey());
 		}
diff --git a/src/main/java/org/olat/group/ui/area/BGAreaEditController.java b/src/main/java/org/olat/group/ui/area/BGAreaEditController.java
index fb7018d1fc3..2b82de3f4e6 100644
--- a/src/main/java/org/olat/group/ui/area/BGAreaEditController.java
+++ b/src/main/java/org/olat/group/ui/area/BGAreaEditController.java
@@ -25,9 +25,9 @@
 
 package org.olat.group.ui.area;
 
+import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.commons.lang.StringEscapeUtils;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
@@ -41,6 +41,7 @@ import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.BasicController;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
+import org.olat.core.util.StringHelper;
 import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupService;
 import org.olat.group.GroupLoggingAction;
@@ -50,6 +51,7 @@ import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryManager;
 import org.olat.resource.OLATResource;
 import org.olat.util.logging.activity.LoggingResourceable;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * Description:<BR>
@@ -74,10 +76,15 @@ public class BGAreaEditController extends BasicController {
 	private BGArea area;
 	private OLATResource resource;
 	private RepositoryEntry repoEntry;
-	private List<BusinessGroup> allGroups, inAreaGroups;
-	// managers
-	private final BGAreaManager areaManager;
-	private final BusinessGroupService businessGroupService;
+	private List<BusinessGroup> allGroups;
+	private List<BusinessGroup> inAreaGroups;
+
+	@Autowired
+	private BGAreaManager areaManager;
+	@Autowired
+	private RepositoryManager repositoryManager;
+	@Autowired
+	private BusinessGroupService businessGroupService;
 
 	/**
 	 * Constructor for the business group area edit controller
@@ -90,10 +97,8 @@ public class BGAreaEditController extends BasicController {
 		super(ureq, wControl);
 
 		this.area = area;
-		areaManager = CoreSpringFactory.getImpl(BGAreaManager.class);
 		resource = area.getResource();
-		repoEntry = RepositoryManager.getInstance().lookupRepositoryEntry(resource, false);
-		businessGroupService = CoreSpringFactory.getImpl(BusinessGroupService.class);
+		repoEntry = repositoryManager.lookupRepositoryEntry(resource, false);
 
 		// tabbed pane
 		tabbedPane = new TabbedPane("tabbedPane", ureq.getLocale());
@@ -109,7 +114,7 @@ public class BGAreaEditController extends BasicController {
 			mainVC.put("backLink", backLink);
 		}
 		mainVC.put("tabbedpane", tabbedPane);
-		mainVC.contextPut("title", translate("area.edit.title", new String[] { StringEscapeUtils.escapeHtml(area.getName()).toString() }));
+		mainVC.contextPut("title", translate("area.edit.title", new String[] { StringHelper.escapeHtml(area.getName()) }));
 		putInitialPanel(mainVC);
 	}
 
@@ -134,22 +139,25 @@ public class BGAreaEditController extends BasicController {
 		tabbedPane.addTab(translate("tab.groups"), groupsTabVC);
 
 		allGroups = businessGroupService.findBusinessGroups(null, repoEntry, 0, -1);
+		List<BusinessGroup> repoGroups = new ArrayList<>(allGroups);
 		inAreaGroups = areaManager.findBusinessGroupsOfArea(area);
-		groupsDataModel = new GroupsToAreaDataModel(allGroups, inAreaGroups);
+		for(BusinessGroup inAreaGroup:inAreaGroups) {
+			if(!allGroups.contains(inAreaGroup)) {
+				allGroups.add(inAreaGroup);
+			}
+		}
+		groupsDataModel = new GroupsToAreaDataModel(allGroups, repoGroups, inAreaGroups, getTranslator());
 
 		groupsChoice = new Choice("groupsChoice", getTranslator());
 		groupsChoice.setSubmitKey("submit");
 		groupsChoice.setCancelKey("cancel");
 		groupsChoice.setModel(groupsDataModel);
+		groupsChoice.setEscapeHtml(false);
 		groupsChoice.addListener(this);
 		groupsTabVC.put("groupsChoice", groupsChoice);
-		groupsTabVC.contextPut("noGroupsFound", (allGroups.size() > 0 ? Boolean.FALSE : Boolean.TRUE));
+		groupsTabVC.contextPut("noGroupsFound", Boolean.valueOf(allGroups.isEmpty()));
 	}
 
-	/**
-	 * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest,
-	 *      org.olat.core.gui.components.Component, org.olat.core.gui.control.Event)
-	 */
 	@Override
 	public void event(UserRequest ureq, Component source, Event event) {
 		if (source == groupsChoice) {
@@ -180,7 +188,7 @@ public class BGAreaEditController extends BasicController {
 					getWindowControl().setWarning(translate("error.area.name.exists"));
 				} else {
 					area = updatedArea;
-					mainVC.contextPut("title", translate("area.edit.title", new String[] { StringEscapeUtils.escapeHtml(area.getName()).toString() }));
+					mainVC.contextPut("title", translate("area.edit.title", new String[] { StringHelper.escapeHtml(area.getName()) }));
 				}
 			} else if (event == Event.CANCELLED_EVENT) {
 				// area might have been changed, reload from db
@@ -227,13 +235,10 @@ public class BGAreaEditController extends BasicController {
 		for (Integer position:removedGroups) {
 			BusinessGroup group = groupsDataModel.getObject(position.intValue());
 			areaManager.removeBGFromArea(group, area);
-			this.inAreaGroups.remove(group);
+			inAreaGroups.remove(group);
 		}
 	}
 
-	/**
-	 * @see org.olat.core.gui.control.DefaultController#doDispose(boolean)
-	 */
 	@Override
 	protected void doDispose() {
 		// don't dispose anything
diff --git a/src/main/java/org/olat/group/ui/area/GroupsToAreaDataModel.java b/src/main/java/org/olat/group/ui/area/GroupsToAreaDataModel.java
index 6f645f61028..918fd2af9a4 100644
--- a/src/main/java/org/olat/group/ui/area/GroupsToAreaDataModel.java
+++ b/src/main/java/org/olat/group/ui/area/GroupsToAreaDataModel.java
@@ -28,6 +28,8 @@ package org.olat.group.ui.area;
 import java.util.List;
 
 import org.olat.core.gui.components.choice.ChoiceModel;
+import org.olat.core.gui.translator.Translator;
+import org.olat.core.util.StringHelper;
 import org.olat.group.BusinessGroup;
 
 /**
@@ -37,8 +39,11 @@ import org.olat.group.BusinessGroup;
  * @author gnaegi
  */
 public class GroupsToAreaDataModel implements ChoiceModel {
+	
+	private final Translator translator;
 	private final List<BusinessGroup> allGroups;
 	private final List<BusinessGroup> inAreaGroups;
+	private final List<BusinessGroup> repoGroups;
 
 	/**
 	 * Constructor for the GroupsToAreaDataModel
@@ -47,9 +52,12 @@ public class GroupsToAreaDataModel implements ChoiceModel {
 	 * @param inAreaGroups All groups that are associated to the group area. The
 	 *          checked rows.
 	 */
-	public GroupsToAreaDataModel(List<BusinessGroup> allGroups, List<BusinessGroup> inAreaGroups) {
+	public GroupsToAreaDataModel(List<BusinessGroup> allGroups, List<BusinessGroup> repoGroups,
+			List<BusinessGroup> inAreaGroups, Translator translator) {
 		this.allGroups = allGroups;
 		this.inAreaGroups = inAreaGroups;
+		this.repoGroups = repoGroups;
+		this.translator = translator;
 	}
 
 	@Override
@@ -64,7 +72,13 @@ public class GroupsToAreaDataModel implements ChoiceModel {
 
 	@Override
 	public String getLabel(int row) {
-		return getObject(row).getName();
+		BusinessGroup group = getObject(row);
+		String label = StringHelper.escapeHtml(group.getName());
+		if(inAreaGroups.contains(group) && !repoGroups.contains(group)) {
+			String explain = translator.translate("");
+			label += " <span title='" + explain + "'><i class='o_icon o_icon_warn'> </i></span>";
+		}
+		return label;
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/group/ui/area/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/group/ui/area/_i18n/LocalStrings_de.properties
index e959ff319a2..309acbeb66a 100644
--- a/src/main/java/org/olat/group/ui/area/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/group/ui/area/_i18n/LocalStrings_de.properties
@@ -20,3 +20,4 @@ groupchoice.no.groups=Es wurde keine Lerngruppe gefunden. Bitte erstellen Sie zu
 
 tab.details=Beschreibung
 tab.groups=Gruppenzuordnung
+warning.group.not.in.repo=Lerngruppe ist nicht in Kurs gebunden.
diff --git a/src/main/java/org/olat/group/ui/area/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/group/ui/area/_i18n/LocalStrings_en.properties
index dcb7c0a88f4..5236ce85550 100644
--- a/src/main/java/org/olat/group/ui/area/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/group/ui/area/_i18n/LocalStrings_en.properties
@@ -20,3 +20,5 @@ groupchoice.no.groups=No learning groups found. Please create a learning group f
 
 tab.details=Description
 tab.groups=Group assignment
+warning.group.not.in.repo=Learning group is not linked to the course.
+
diff --git a/src/test/java/org/olat/group/test/BGAreaManagerTest.java b/src/test/java/org/olat/group/test/BGAreaManagerTest.java
index ae5424f3fc0..9a0bebec233 100644
--- a/src/test/java/org/olat/group/test/BGAreaManagerTest.java
+++ b/src/test/java/org/olat/group/test/BGAreaManagerTest.java
@@ -407,6 +407,52 @@ public class BGAreaManagerTest extends OlatTestCase {
 		Assert.assertTrue(diminushedGroups.contains(group1));
 	}
 	
+	/**
+	 * Check that the remove resource from business group service remove
+	 * the relation to area too
+	 */
+	@Test
+	public void removeResourceFrom_withArea() {
+		//create a resource, an area, a group
+		RepositoryEntry resource1 =  JunitTestHelper.createAndPersistRepositoryEntry();
+		RepositoryEntry resource2 =  JunitTestHelper.createAndPersistRepositoryEntry();
+		String areaName = UUID.randomUUID().toString();
+		BGArea area1 = areaManager.createAndPersistBGArea("area-1-" + areaName, "description:" + areaName, resource1.getOlatResource());
+		BGArea area2 = areaManager.createAndPersistBGArea("area-1-" + areaName, "description:" + areaName, resource2.getOlatResource());
+		//create the group
+		BusinessGroup group = businessGroupService.createBusinessGroup(null, "area-1-group", "area-group-desc", 0, -1, false, false, null);
+		dbInstance.commitAndCloseSession();
+		//add relations group to courses
+		businessGroupService.addResourceTo(group, resource1);
+		businessGroupService.addResourceTo(group, resource2);
+		//add the relations to areas
+		areaManager.addBGToBGArea(group, area1);
+		areaManager.addBGToBGArea(group, area2);
+		dbInstance.commitAndCloseSession();
+		
+		//check find groups
+		List<BusinessGroup> groupArea1s = areaManager.findBusinessGroupsOfArea(area1);
+		Assert.assertNotNull(groupArea1s);
+		Assert.assertEquals(1, groupArea1s.size());
+		Assert.assertTrue(groupArea1s.contains(group));
+		
+		List<BusinessGroup> groupArea2s = areaManager.findBusinessGroupsOfArea(area2);
+		Assert.assertNotNull(groupArea2s);
+		Assert.assertEquals(1, groupArea2s.size());
+		Assert.assertTrue(groupArea2s.contains(group));
+		
+		// remove resource2 from group
+		businessGroupService.removeResourceFrom(Collections.singletonList(group), resource2);
+		
+		List<BusinessGroup> groupArea1s_remove = areaManager.findBusinessGroupsOfArea(area1);
+		Assert.assertNotNull(groupArea1s_remove);
+		Assert.assertEquals(1, groupArea1s.size());
+		Assert.assertTrue(groupArea1s_remove.contains(group));
+		
+		List<BusinessGroup> groupArea2s_remove = areaManager.findBusinessGroupsOfArea(area2);
+		Assert.assertTrue(groupArea2s_remove.isEmpty());
+	}
+	
 	@Test
 	public void findGroupsByAreas() {
 		//create a resource, 3 area and 2 group
-- 
GitLab