diff --git a/src/main/java/de/bps/olat/repository/controllers/RepositorySearchMultiSelectController.java b/src/main/java/de/bps/olat/repository/controllers/RepositorySearchMultiSelectController.java
index acbbcd9f4df85681ce5b75053ff35c7da695ee13..b48c4c8c71652dfda22bd379b839fd0883f885f4 100644
--- a/src/main/java/de/bps/olat/repository/controllers/RepositorySearchMultiSelectController.java
+++ b/src/main/java/de/bps/olat/repository/controllers/RepositorySearchMultiSelectController.java
@@ -135,7 +135,8 @@ public class RepositorySearchMultiSelectController extends RepositorySearchContr
 		RepositoryManager rm = RepositoryManager.getInstance();
 		Set s = searchForm.getRestrictedTypes();
 		List restrictedTypes = (s == null) ? null : new ArrayList(s);
-		List entries = rm.genericANDQueryWithRolesRestriction(null, null, null, null, ureq.getUserSession().getRoles(), ureq.getIdentity().getUser().getProperty("institutionalName", null));
+		//fxdiff VCRP-1,2: access control of resources
+		List entries = rm.genericANDQueryWithRolesRestriction(null, null, null, null, ureq.getIdentity(), ureq.getUserSession().getRoles(), ureq.getIdentity().getUser().getProperty("institutionalName", null));
 		repoTableModel.setObjects(entries);
 		tableCtr.modelChanged();
 		displaySearchResults(ureq);
diff --git a/src/main/java/org/olat/ControllerFactory.java b/src/main/java/org/olat/ControllerFactory.java
index dbdc217409a54b9be1b198413990fcb963c74598..8317b00e93cd6be0dc877fddf74c1cd7a1912d31 100644
--- a/src/main/java/org/olat/ControllerFactory.java
+++ b/src/main/java/org/olat/ControllerFactory.java
@@ -46,15 +46,15 @@ import org.olat.group.BusinessGroupManagerImpl;
 import org.olat.group.ui.BGControllerFactory;
 import org.olat.group.ui.context.BGContextManagementController;
 import org.olat.group.ui.main.BGMainController;
-import org.olat.home.GuestHomeMainController;
-import org.olat.home.HomeMainController;
 import org.olat.home.InviteeHomeMainController;
+import org.olat.home.HomeMainController;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryManager;
 import org.olat.repository.RepositoyUIFactory;
 import org.olat.repository.controllers.RepositoryMainController;
 import org.olat.test.GUIDemoMainController;
 
+
 /**
  *  Initial Date:  May 6, 2004
  *  @author gnaegi
@@ -80,8 +80,7 @@ public class ControllerFactory {
 		if (olatResourceable == null) {
 			// special case after login: guest will get guesthome, other user the
 			// normal home
-			if (ureq.getUserSession().getRoles().isGuestOnly()) return new GuestHomeMainController(ureq, wControl);
-			return new HomeMainController(ureq, wControl);
+			if (ureq.getUserSession().getRoles().isGuestOnly()) return new HomeMainController(ureq, wControl);
 
 		} else if (OresHelper.isOfType(olatResourceable, BGMainController.class)) {
 			if (roles.isGuestOnly()) throw new OLATSecurityException("Tried to launch a BuddyGroupMainController, but is in guest group " + roles);
@@ -159,7 +158,6 @@ public class ControllerFactory {
 		}
 		// --- home ---
 		else if (OresHelper.isOfType(olatResourceable, HomeMainController.class)) {
-			if (roles.isGuestOnly()) throw new OLATSecurityException("Tried to launch a HomeMainController, but is in guest group " + roles);
 			return new HomeMainController(ureq, wControl);
 		} else if (OresHelper.isOfType(olatResourceable, SystemAdminMainController.class)) {
 			if (!roles.isOLATAdmin()) throw new OLATSecurityException("Tried to launch a SystemAdminMainController, but is not in admin group " + roles);
@@ -171,9 +169,6 @@ public class ControllerFactory {
 			if (!roles.isGroupManager()) throw new OLATSecurityException("Tried to launch a BGContextManagementController, but is not in group groupmanager "
 					+ roles);
 			return new BGContextManagementController(ureq, wControl);
-		} else if (OresHelper.isOfType(olatResourceable, GuestHomeMainController.class)) {
-			if (!roles.isGuestOnly() ) throw new OLATSecurityException("Tried to launch a GuestMainController, but is not in guest group " + roles);
-			return new GuestHomeMainController(ureq, wControl);
 		} else if (OresHelper.isOfType(olatResourceable, InviteeHomeMainController.class)) {
 			if (!roles.isInvitee()) throw new OLATSecurityException("Tried to launch a InviteeMainController, but is not an invitee " + roles);
 			return new InviteeHomeMainController(ureq, wControl);
diff --git a/src/main/java/org/olat/admin/AdminModule.java b/src/main/java/org/olat/admin/AdminModule.java
index b69b00a29dbc8ff3bcd968eb9cf309a8f7e70339..5fdd51eb9299572482096818527a3dac13f6a7dc 100644
--- a/src/main/java/org/olat/admin/AdminModule.java
+++ b/src/main/java/org/olat/admin/AdminModule.java
@@ -52,8 +52,8 @@ public class AdminModule extends AbstractOLATModule {
 
 	/** Category for system properties **/
 	public static String SYSTEM_PROPERTY_CATEGORY = "_o3_";
-	private static final String PROPERTY_MAINTENANCE_MESSAGE    = "maintenanceMessageToken";
-	private static final String PROPERTY_SESSION_ADMINISTRATION = "sessionAdministrationToken";
+	public static final String PROPERTY_MAINTENANCE_MESSAGE    = "maintenanceMessageToken";
+	public static final String PROPERTY_SESSION_ADMINISTRATION = "sessionAdministrationToken";
 	private static final String CONFIG_ADMIN_MAX_SESSION = "maxNumberOfSessions";
 	private PropertyManager propertyManager;
 
@@ -106,7 +106,7 @@ public class AdminModule extends AbstractOLATModule {
 			Tracing.logAudit("Trying to set maintenance message without using a token. Remote address::" + request.getRemoteAddr(), AdminModule.class);
 			return false;
 		}
-		// get token and compate
+		// get token and compare
 		PropertyManager pm = PropertyManager.getInstance();
 		Property p = pm.findProperty(null, null, null, AdminModule.SYSTEM_PROPERTY_CATEGORY, tokenPropertyName);
 		String token = (p == null ? "" : p.getStringValue());
diff --git a/src/main/java/org/olat/admin/UserAdminMainController.java b/src/main/java/org/olat/admin/UserAdminMainController.java
index 3501e101e1c1a1f8a4d9292d3da35af216d1f0d5..6f4d04cf8e9312381f8be860969775986cdcf479 100644
--- a/src/main/java/org/olat/admin/UserAdminMainController.java
+++ b/src/main/java/org/olat/admin/UserAdminMainController.java
@@ -693,7 +693,7 @@ public class UserAdminMainController extends MainLayoutBasicController implement
 		for (int i = 0; i < cnt; i++) {
 			Extension anExt = extm.getExtension(i);
 			// 1) general menu extensions
-			ActionExtension ae = (ActionExtension) anExt.getExtensionFor(UserAdminMainController.class.getName() + EXTENSIONPOINT_MENU_MENUQUERIES);
+			ActionExtension ae = (ActionExtension) anExt.getExtensionFor(UserAdminMainController.class.getName() + EXTENSIONPOINT_MENU_MENUQUERIES, ureq);
 			if (ae != null && anExt.isEnabled()) {
 				gtnChild = new GenericTreeNode();
 				String menuText = ae.getActionText(getLocale());
diff --git a/src/main/java/org/olat/basesecurity/AuthHelper.java b/src/main/java/org/olat/basesecurity/AuthHelper.java
index 88ddb6748a3d1f58b28a604ff967cb50e73a9190..86c6e86eebd6462b54963d56f9d0b06efd32696b 100644
--- a/src/main/java/org/olat/basesecurity/AuthHelper.java
+++ b/src/main/java/org/olat/basesecurity/AuthHelper.java
@@ -37,6 +37,7 @@ import org.olat.commons.rss.RSSUtil;
 import org.olat.core.commons.chiefcontrollers.BaseChiefControllerCreator;
 import org.olat.core.commons.fullWebApp.BaseFullWebappController;
 import org.olat.core.commons.fullWebApp.BaseFullWebappControllerParts;
+import org.olat.core.commons.persistence.DBFactory;
 import org.olat.core.dispatcher.DispatcherAction;
 import org.olat.core.gui.GUIInterna;
 import org.olat.core.gui.UserRequest;
@@ -253,7 +254,18 @@ public class AuthHelper {
 				//already a normal olat user, cannot be invited
 				return LOGIN_DENIED;
 			} else {
-				return doLogin(identity, BaseSecurityModule.getDefaultAuthProviderIdentifier(), ureq);
+				//fxdiff FXOLAT-151: add eventually the identity to the security group
+				if(!securityManager.isIdentityInSecurityGroup(identity, invitation.getSecurityGroup())) {
+					securityManager.addIdentityToSecurityGroup(identity, invitation.getSecurityGroup());
+					DBFactory.getInstance().commit();
+				}
+
+				int result = doLogin(identity, BaseSecurityModule.getDefaultAuthProviderIdentifier(), ureq);
+				//fxdiff FXOLAT-151: double check: problem with the DB, invitee is not marked has such
+				if(ureq.getUserSession().getRoles().isInvitee()) {
+					return result;
+				}
+				return LOGIN_DENIED;
 			}
 		}
 		
diff --git a/src/main/java/org/olat/basesecurity/BaseSecurity.java b/src/main/java/org/olat/basesecurity/BaseSecurity.java
index c2d4089db2db8c2ac2efd5520d37e0b4e3667839..69a4fab5ba1c56c0eef339aab038ae92a0f519c4 100644
--- a/src/main/java/org/olat/basesecurity/BaseSecurity.java
+++ b/src/main/java/org/olat/basesecurity/BaseSecurity.java
@@ -91,6 +91,17 @@ public interface BaseSecurity {
 	 * @return list of Identities
 	 */
 	public List<Identity> getIdentitiesOfSecurityGroup(SecurityGroup secGroup);
+	
+	public List<Identity> getIdentitiesOfSecurityGroup(SecurityGroup secGroup, int firstResult, int maxResults);
+	/**
+	 * Return the primary key of
+	 * @param secGroups
+	 * @return
+	 */
+	public List<Identity> getIdentitiesOfSecurityGroups(List<SecurityGroup> secGroups);
+
+	//fxdiff: FXOLAT-219 decrease the load for synching groups
+	public List<IdentityShort> getIdentitiesShortOfSecurityGroups(List<SecurityGroup> secGroups);
 
 	/**
 	 * @param secGroup
@@ -161,10 +172,6 @@ public interface BaseSecurity {
 	 * @return nr of members in the securitygroup
 	 */
 	public int countIdentitiesOfSecurityGroup(SecurityGroup secGroup);
-	
-	public int countAuthors();
-	
-	public int countDisabledUsers();
 
 	/**
 	 * @param username the username
@@ -206,6 +213,9 @@ public interface BaseSecurity {
 	 */
 	public Authentication findAuthentication(Identity identity, String provider);
 
+	//fxdiff: FXOLAT-219 decrease the load for synching groups
+	public boolean hasAuthentication(Long identityKey, String provider);
+
 	/**
 	 * @param identity
 	 * @param provider
diff --git a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java
index 69c1775e147525b5d3f4b38b4768e0abd66a7c46..4913475a668e221ead23ed493556723aff7e0ddd 100644
--- a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java
+++ b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java
@@ -22,6 +22,7 @@
 package org.olat.basesecurity;
 
 import java.util.Calendar;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
@@ -50,6 +51,7 @@ import org.olat.core.id.User;
 import org.olat.core.id.UserConstants;
 import org.olat.core.logging.AssertException;
 import org.olat.core.manager.BasicManager;
+import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
 import org.olat.core.util.coordinate.CoordinatorManager;
 import org.olat.core.util.resource.OresHelper;
@@ -709,6 +711,8 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 	 */
 	@Override
 	public void deleteInvitation(Invitation invitation) {
+		//fxdiff: FXOLAT-251: nothing persisted, nothing to delete
+		if(invitation == null || invitation.getKey() == null) return;
 		DBFactory.getInstance().deleteObject(invitation);
 	}
 
@@ -821,7 +825,7 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 	/**
 	 * @see org.olat.basesecurity.Manager#getIdentitiesOfSecurityGroup(org.olat.basesecurity.SecurityGroup)
 	 */
-	public List getIdentitiesOfSecurityGroup(SecurityGroup secGroup) {
+	public List<Identity> getIdentitiesOfSecurityGroup(SecurityGroup secGroup) {
 		if (secGroup == null) {
 			throw new AssertException("getIdentitiesOfSecurityGroup: ERROR secGroup was null !!");
 		} 
@@ -829,18 +833,70 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 		if (db == null) {
 			throw new AssertException("getIdentitiesOfSecurityGroup: ERROR db was null !!");
 		} 
-		List idents = DBFactory.getInstance().find(
-	            "select ii from"
-	            + " org.olat.basesecurity.IdentityImpl as ii inner join fetch ii.user as iuser, "
-	            + " org.olat.basesecurity.SecurityGroupMembershipImpl as sgmsi "
-	            + " where sgmsi.securityGroup = ? and sgmsi.identity = ii",
-	            new Object[] { secGroup.getKey() },
-	            new Type[] { Hibernate.LONG });
-
-	            return idents;
+
+		List<Identity> idents = getIdentitiesOfSecurityGroup(secGroup, 0, -1);
+		return idents;
+	}
+	
+	@Override
+	public List<Identity> getIdentitiesOfSecurityGroup(SecurityGroup secGroup, int firstResult, int maxResults) {
+		if (secGroup == null) {
+			throw new AssertException("getIdentitiesOfSecurityGroup: ERROR secGroup was null !!");
+		}
+		
+		StringBuilder sb = new StringBuilder();
+		sb.append("select sgmsi.identity from ").append(SecurityGroupMembershipImpl.class.getName()).append(" as sgmsi ")
+			.append(" where sgmsi.securityGroup=:secGroup");
+
+		DBQuery query = DBFactory.getInstance().createQuery(sb.toString());
+		query.setEntity("secGroup", secGroup);
+		if(firstResult >= 0) {
+			query.setFirstResult(firstResult);
+		}
+		if(maxResults > 0) {
+			query.setMaxResults(maxResults);
+		}
+		List<Identity> idents = query.list();
+		return idents;
+	}
+
+	/**
+	 * Return a list of unique identites which are in the list of security groups
+	 * @see org.olat.basesecurity.BaseSecurity#getIdentitiesOfSecurityGroups(java.util.List)
+	 */
+	@Override
+	public List<Identity> getIdentitiesOfSecurityGroups(List<SecurityGroup> secGroups) {
+		if (secGroups == null || secGroups.isEmpty()) {
+			return Collections.emptyList();
+		}
 		
+		StringBuilder sb = new StringBuilder();
+		sb.append("select distinct(sgmsi.identity) from ").append(SecurityGroupMembershipImpl.class.getName()).append(" as sgmsi ")
+			.append(" where sgmsi.securityGroup in (:secGroups)");
+		
+		DBQuery query = DBFactory.getInstance().createQuery(sb.toString());
+		query.setParameterList("secGroups", secGroups);
+		List<Identity> idents = query.list();
+		return idents;
 	}
 	
+	@Override
+	//fxdiff: FXOLAT-219 decrease the load for synching groups
+	public List<IdentityShort> getIdentitiesShortOfSecurityGroups(List<SecurityGroup> secGroups) {
+		if (secGroups == null || secGroups.isEmpty()) {
+			return Collections.emptyList();
+		}
+		
+		StringBuilder sb = new StringBuilder();
+		sb.append("select new org.olat.basesecurity.IdentityShort(sgmsi.identity.key, sgmsi.identity.name) from ").append(SecurityGroupMembershipImpl.class.getName()).append(" as sgmsi ")
+			.append(" where sgmsi.securityGroup in (:secGroups)");
+		
+		DBQuery query = DBFactory.getInstance().createQuery(sb.toString());
+		query.setParameterList("secGroups", secGroups);
+		List<IdentityShort> idents = query.list();
+		return idents;
+	}
+
 	/**
 	 * @see org.olat.basesecurity.Manager#getIdentitiesAndDateOfSecurityGroup(org.olat.basesecurity.SecurityGroup)
 	 */
@@ -981,18 +1037,6 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 		return cntL;
 	}	
 	
-	
-	
-	@Override
-	public int countAuthors() {
-		return 0;
-	}
-
-	@Override
-	public int countDisabledUsers() {
-		return 0;
-	}
-
 	/**
 	 * @see org.olat.basesecurity.Manager#getAuthentications(org.olat.core.id.Identity)
 	 */
@@ -1029,6 +1073,20 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 		if (results.size() > 1) throw new AssertException("Found more than one Authentication for a given subject and a given provider.");
 		return (Authentication) results.get(0);
 	}
+	
+	@Override
+	//fxdiff: FXOLAT-219 decrease the load for synching groups
+	public boolean hasAuthentication(Long identityKey, String provider) {
+		if (identityKey == null || !StringHelper.containsNonWhitespace(provider)) return false;
+		
+		String queryStr = "select count(auth) from org.olat.basesecurity.AuthenticationImpl as auth where auth.identity.key=:key and auth.provider=:provider";
+		DBQuery query = DBFactory.getInstance().createQuery(queryStr);
+		query.setLong("key", identityKey);
+		query.setString("provider", provider);
+		
+		Number count = (Number)query.uniqueResult();
+		return count.intValue() > 0;
+	}
 
 	/**
 	 * @see org.olat.basesecurity.Manager#deleteAuthentication(org.olat.basesecurity.Authentication)
@@ -1136,9 +1194,12 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 					login = makeFuzzyQueryString(login);
 					if (login.contains("_") && (dbVendor.equals("hsqldb") || dbVendor.equals("oracle"))) {
 						//hsqldb needs special ESCAPE sequence to search for escaped strings
-						sb.append(" ident.name like :login ESCAPE '\\'");
-					}else {
+						// fxdiff: 
+						sb.append(" lower(ident.name) like :login ESCAPE '\\'");
+					} else if (dbVendor.equals("mysql")) {
 						sb.append(" ident.name like :login");
+					} else {
+						sb.append(" lower(ident.name) like :login");
 					}
 				// if user fields follow a join element is needed
 				needsUserPropertiesJoin = true;
@@ -1168,7 +1229,15 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 					boolean needsOr = false;
 					for (String key : emailProperties.keySet()) {
 						if (needsOr) sb.append(" or ");
-						sb.append(" user.properties['").append(key).append("'] like :").append(key).append("_value ");
+						//fxdiff
+						if(dbVendor.equals("mysql")) {
+							sb.append(" user.properties['").append(key).append("'] like :").append(key).append("_value ");
+						} else {
+							sb.append(" lower(user.properties['").append(key).append("']) like :").append(key).append("_value ");
+							if(dbVendor.equals("hsqldb") || dbVendor.equals("oracle")) {
+					 	 		sb.append(" escape '\\'");
+					 	 	}
+						}
 						if(dbVendor.equals("hsqldb") || dbVendor.equals("oracle")) {
 							sb.append(" escape '\\'");
 						}
@@ -1182,7 +1251,14 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 				// add other fields
 				for (String key : otherProperties.keySet()) {
 					needsUserPropertiesJoin = checkIntersectionInUserProperties(sb,needsUserPropertiesJoin, userPropertiesAsIntersectionSearch);
-					sb.append(" user.properties['").append(key).append("'] like :").append(key).append("_value ");
+					if(dbVendor.equals("mysql")) {
+						sb.append(" user.properties['").append(key).append("'] like :").append(key).append("_value ");
+					} else {
+						sb.append(" lower(user.properties['").append(key).append("']) like :").append(key).append("_value ");
+						if(dbVendor.equals("hsqldb") || dbVendor.equals("oracle")) {
+				 	 		sb.append(" escape '\\'");
+				 	 	}
+					}
 					if(dbVendor.equals("hsqldb") || dbVendor.equals("oracle")) {
 						sb.append(" escape '\\'");
 					}
@@ -1283,7 +1359,7 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 		
 		// add user attributes
 		if (login != null) 
-			dbq.setString("login", login);
+			dbq.setString("login", login.toLowerCase());
 
 		//	 add user properties attributes
 		if (userproperties != null && !userproperties.isEmpty()) {
@@ -1395,8 +1471,13 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity {
 		// fuzzy search with % at the beginning, but it makes the query very very
 		// slow since it can not use any index and must perform a fulltext search.
 		// User can always use * to make it a really fuzzy search query
-		string = string.replace('*', '%');
-		string = string + "%";
+		// fxdiff FXOLAT-252: use "" to disable this feature and use exact match
+		if (string.length() > 1 && string.startsWith("\"") && string.endsWith("\"")) {			
+			string = string.substring(1, string.length()-1);
+		} else {
+			string = string + "%";
+			string = string.replace('*', '%');
+		}
 		// with 'LIKE' the character '_' is a wildcard which matches exactly one character.
 		// To test for literal instances of '_', we have to escape it.
 		string = string.replace("_", "\\_");
diff --git a/src/main/java/org/olat/basesecurity/BaseSecurityModule.java b/src/main/java/org/olat/basesecurity/BaseSecurityModule.java
index 1a4dafb8400a46e944bf5c365ccc94c35e8b33ab..d37b70efc4cf5245e7e79a7e705f22d80f20ccd0 100644
--- a/src/main/java/org/olat/basesecurity/BaseSecurityModule.java
+++ b/src/main/java/org/olat/basesecurity/BaseSecurityModule.java
@@ -21,8 +21,11 @@
 
 package org.olat.basesecurity;
 
+import org.olat.NewControllerFactory;
+import org.olat.admin.user.UserAdminContextEntryControllerCreator;
 import org.olat.core.configuration.AbstractOLATModule;
 import org.olat.core.configuration.PersistedProperties;
+import org.olat.core.id.User;
 
 /**
  * Initial Date: May 4, 2004
@@ -84,8 +87,9 @@ public class BaseSecurityModule extends AbstractOLATModule {
 
 	@Override
 	public void init() {
-		// TODO Auto-generated method stub
-		
+		// fxdiff: Add controller factory extension point to launch user admin site
+		NewControllerFactory.getInstance().addContextEntryControllerCreator(User.class.getSimpleName(),
+				new UserAdminContextEntryControllerCreator());	
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/basesecurity/Constants.java b/src/main/java/org/olat/basesecurity/Constants.java
index e33a05369fd0b412ff0089e6512afc49fa1fc293..54b931d0075dd8b51ac6246c5a9e46f1ca61e4b1 100644
--- a/src/main/java/org/olat/basesecurity/Constants.java
+++ b/src/main/java/org/olat/basesecurity/Constants.java
@@ -65,6 +65,17 @@ public class Constants {
 	 * chars!
 	 */
 	public static final String GROUP_ANONYMOUS = "anonymous";
+	//fxdiff VCRP-1,2: access control of resources
+	/**
+	 * <code>GROUP_PARTICIPANTS</code> predefined groups length restricted to 16
+	 * chars!
+	 */
+	public static final String GROUP_PARTICIPANTS = "participants";
+	/**
+	 * <code>GROUP_OWNERS</code> predefined groups length restricted to 16
+	 * chars!
+	 */
+	public static final String GROUP_OWNERS = "owners";
 
 	/**
 	 * access a thing; means read, write, update, and delete
@@ -135,7 +146,17 @@ public class Constants {
 	 * resourceable TYPE for authors <code>ORESOURCE_AUTHOR</code>
 	 */
 	public static final OLATResourceable ORESOURCE_AUTHOR = OresHelper.lookupType(BaseSecurityModule.class, "RAuthor");
+	//fxdiff VCRP-1,2: access control of resources
+	/**
+	 * resourceable TYPE for tutors <code>ORESOURCE_TUTOR</code>
+	 */
+	public static final OLATResourceable ORESOURCE_TUTOR = OresHelper.lookupType(BaseSecurityModule.class, "RTutor");
 
+	/**
+	 * resourceable TYPE for participants <code>ORESOURCE_PARTICIPANT</code>
+	 */
+	public static final OLATResourceable ORESOURCE_PARTICIPANT = OresHelper.lookupType(BaseSecurityModule.class, "RParticipant");
+	
 	/**
 	 * resourceable TYPE for groupmanagers <code>ORESOURCE_GROUPMANAGER</code>
 	 */
diff --git a/src/main/java/org/olat/basesecurity/IdentityShort.java b/src/main/java/org/olat/basesecurity/IdentityShort.java
new file mode 100644
index 0000000000000000000000000000000000000000..2fa23a531972c65f535c1f22652bd58ad7fa0ded
--- /dev/null
+++ b/src/main/java/org/olat/basesecurity/IdentityShort.java
@@ -0,0 +1,53 @@
+/**
+ * OLAT - Online Learning and Training<br>
+ * http://www.olat.org
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Copyright (c) frentix GmbH<br>
+ * http://www.frentix.com<br>
+ * <p>
+ */
+package org.olat.basesecurity;
+
+/**
+ * 
+ * Description:<br>
+ * TODO: srosse Class Description for IdentityShort
+ * 
+ * <P>
+ * Initial Date:  14 juil. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+//fxdiff: FXOLAT-219 decrease the load for synching groups
+public class IdentityShort {
+	
+	private final Long key;
+	private final String name;
+	
+	public IdentityShort(Long key, String name) {
+		this.key = key;
+		this.name = name;
+	}
+
+	public Long getKey() {
+		return key;
+	}
+
+	public String getName() {
+		return name;
+	}
+	
+	
+
+}
diff --git a/src/main/java/org/olat/basesecurity/Invitation.java b/src/main/java/org/olat/basesecurity/Invitation.java
index f5b3f12d0339fc95a1a7a7c1929c49a1601b8055..9580a822fd21a3963ef32c8f92e1da818389ea42 100644
--- a/src/main/java/org/olat/basesecurity/Invitation.java
+++ b/src/main/java/org/olat/basesecurity/Invitation.java
@@ -30,6 +30,8 @@ package org.olat.basesecurity;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
 public interface Invitation {
+	
+	public Long getKey();
 
 	public String getToken();
 	
diff --git a/src/main/java/org/olat/catalog/ui/CatalogController.java b/src/main/java/org/olat/catalog/ui/CatalogController.java
index abe5f4b9d5492980d16a817877c3e2cd696e5817..8407cb656bffac60fe8c461acf8bba17e2ebd41a 100644
--- a/src/main/java/org/olat/catalog/ui/CatalogController.java
+++ b/src/main/java/org/olat/catalog/ui/CatalogController.java
@@ -88,6 +88,10 @@ import org.olat.repository.controllers.RepositorySearchController;
 import org.olat.repository.handlers.RepositoryHandler;
 import org.olat.repository.handlers.RepositoryHandlerFactory;
 import org.olat.resource.OLATResource;
+import org.olat.resource.accesscontrol.manager.ACFrontendManager;
+import org.olat.resource.accesscontrol.model.OLATResourceAccess;
+import org.olat.resource.accesscontrol.model.PriceMethodBundle;
+import org.olat.resource.accesscontrol.ui.PriceFormat;
 
 /**
  * <pre>
@@ -197,6 +201,7 @@ public class CatalogController extends BasicController implements Activateable,
 	private VelocityContainer myContent;
 
 	private CatalogManager cm;
+	private ACFrontendManager acFrontendManager;
 	private CatalogEntry currentCatalogEntry;
 	private CatalogEntry newLinkNotPersistedYet;
 	private int currentCatalogEntryLevel = -1;
@@ -248,6 +253,8 @@ public class CatalogController extends BasicController implements Activateable,
 		super(ureq, wControl, Util.createPackageTranslator(RepositoryManager.class, ureq.getLocale()));
 		
 		cm = CatalogManager.getInstance();
+		//fxdiff VCRP-1,2: access control of resources
+		acFrontendManager = (ACFrontendManager)CoreSpringFactory.getBean("acFrontendManager");
 
 		List<CatalogEntry> rootNodes = cm.getRootCatalogEntries();
 		CatalogEntry rootce;
@@ -258,12 +265,9 @@ public class CatalogController extends BasicController implements Activateable,
 		isAuthor = ureq.getUserSession().getRoles().isAuthor();
 		isOLATAdmin = ureq.getUserSession().getRoles().isOLATAdmin();
 		isGuest = ureq.getUserSession().getRoles().isGuestOnly();
+		revokeRightsAndSetDefaults();
 		// and also if user is localTreeAdmin
 		updateToolAccessRights(ureq, rootce, 0);
-		canAddLinks = isOLATAdmin || isAuthor;
-		canAdministrateCategory = isOLATAdmin;
-		canAddSubCategories = isOLATAdmin || isLocalTreeAdmin;
-		canRemoveAllLinks = isOLATAdmin || isLocalTreeAdmin;
 
 		cm = CatalogManager.getInstance();
 
@@ -915,7 +919,7 @@ public class CatalogController extends BasicController implements Activateable,
 			 * add tools
 			 */
 			if(isOLATAdmin || isLocalTreeAdmin || isAuthor){
-					catalogToolC.addHeader(translate(NLS_TOOLS_ADD_HEADER));
+					if (canAddSubCategories || canAddLinks) catalogToolC.addHeader(translate(NLS_TOOLS_ADD_HEADER));
 					if (canAddSubCategories) catalogToolC.addLink(ACTION_ADD_CTLGCATEGORY, translate(NLS_TOOLS_ADD_CATALOG_CATEGORY));
 					if (canAddLinks) catalogToolC.addLink(ACTION_ADD_CTLGLINK, translate(NLS_TOOLS_ADD_CATALOG_LINK));
 					if (currentCatalogEntryLevel == 0 && isOLATAdmin && cm.getChildrenOf(currentCatalogEntry).isEmpty())
@@ -956,10 +960,83 @@ public class CatalogController extends BasicController implements Activateable,
 		myContent.contextPut("canRemoveAllLinks", new Boolean(canRemoveAllLinks));
 		myContent.contextPut("currentCatalogEntry", currentCatalogEntry);
 		childCe = cm.getChildrenOf(ce);
+		// Sort to fix ordering by repo entry display name. For leafs the displayed
+		// name is not the catalog entry name but the repo entry display name. The
+		// SQL query orders by catalog entry name, thus the visual ordering is
+		// wrong.
+		// fxdiff: FXOLAT-100
+		Collections.sort(childCe, new Comparator<CatalogEntry>() {
+			@Override
+			public int compare(final CatalogEntry c1, final CatalogEntry c2) {
+				String c1Title, c2Title;
+				if (c1.getType() == CatalogEntry.TYPE_LEAF) {
+					final RepositoryEntry repoEntry = c1.getRepositoryEntry();
+					if (repoEntry != null) {
+						c1Title = repoEntry.getDisplayname();
+					} else {
+						c1Title = c1.getName();
+					}
+				} else {
+					c1Title = c1.getName();
+				}
+				if (c2.getType() == CatalogEntry.TYPE_LEAF) {
+					final RepositoryEntry repoEntry = c2.getRepositoryEntry();
+					if (repoEntry != null) {
+						c2Title = repoEntry.getDisplayname();
+					} else {
+						c2Title = c2.getName();
+					}
+				} else {
+					c2Title = c2.getName();
+				}
+				// Sort now based on users locale
+				final Collator myCollator = Collator.getInstance(getLocale());
+				return myCollator.compare(c1Title, c2Title);
+			}
+		});
+		
 		myContent.contextPut("children", childCe);
+		//fxdiff VCRP-1,2: access control of resources
+		List<Long> resourceKeys = new ArrayList<Long>();
+		for ( Object leaf : childCe ) {
+			CatalogEntry entry = (CatalogEntry)leaf;
+			if(entry.getRepositoryEntry() != null && entry.getRepositoryEntry().getOlatResource() != null) {
+				resourceKeys.add(entry.getRepositoryEntry().getOlatResource().getKey());
+			}
+		}
+		List<OLATResourceAccess> resourcesWithOffer = acFrontendManager.getAccessMethodForResources(resourceKeys, true, new Date());
 		for ( Object leaf : childCe ) {
 			CatalogEntry entry = (CatalogEntry)leaf;
 			if(entry.getType() == CatalogEntry.TYPE_NODE) continue;
+			//fxdiff VCRP-1,2: access control of resources
+			if(entry.getRepositoryEntry() != null && entry.getRepositoryEntry().getOlatResource() != null) {
+				List<PriceMethod> types = new ArrayList<PriceMethod>();
+				if (entry.getRepositoryEntry().isMembersOnly()) {
+					// members only always show lock icon
+					types.add(new PriceMethod("", "b_access_membersonly_icon"));
+				} else {
+					// collect access control method icons
+					OLATResource resource = entry.getRepositoryEntry().getOlatResource();
+					for(OLATResourceAccess resourceAccess:resourcesWithOffer) {
+						if(resource.getKey().equals(resourceAccess.getResource().getKey())) {
+							for(PriceMethodBundle bundle:resourceAccess.getMethods()) {
+								String type = bundle.getMethod().getMethodCssClass() + "_icon";
+								String price = bundle.getPrice() == null || bundle.getPrice().isEmpty() ? "" : PriceFormat.fullFormat(bundle.getPrice());
+								types.add(new PriceMethod(price, type));
+							}
+						}
+					}
+				}
+				
+				//fxdiff VCRP-1,2: access control of resources
+				String acName = "ac_" + childCe.indexOf(leaf);
+				if(!types.isEmpty()) {
+					myContent.contextPut(acName, types);
+				} else {
+					myContent.contextRemove(acName);
+				}
+			}
+			
 			String name = "image" + childCe.indexOf(leaf);
 			ImageComponent ic = RepositoryEntryImageController.getImageComponentForRepositoryEntry(name, entry.getRepositoryEntry());
 			if(ic == null) {
@@ -1088,10 +1165,7 @@ public class CatalogController extends BasicController implements Activateable,
 			// 3a) below branch that user has admin rights - revoke all rights
 			isLocalTreeAdminLevel = -1;
 			isLocalTreeAdmin = false;
-			canAddLinks = isOLATAdmin || isAuthor;
-			canAdministrateCategory = isOLATAdmin;
-			canAddSubCategories = isOLATAdmin;
-			canRemoveAllLinks = isOLATAdmin;
+			revokeRightsAndSetDefaults();
 			fireEvent(ureq, Event.CHANGED_EVENT);
 			
 		} else if (isLocalTreeAdminLevel == -1) {
@@ -1104,11 +1178,14 @@ public class CatalogController extends BasicController implements Activateable,
 			if (isInGroup) {
 				isLocalTreeAdminLevel = pos;
 				isLocalTreeAdmin = true;
-				canAddLinks = isOLATAdmin || isAuthor;
+				canAddLinks = true;
 				canAdministrateCategory = true;
 				canAddSubCategories = true;
 				canRemoveAllLinks = true;
-				fireEvent(ureq, Event.CHANGED_EVENT);
+				fireEvent(ureq, Event.CHANGED_EVENT);				
+			} else {
+				isLocalTreeAdmin = false;
+				revokeRightsAndSetDefaults();
 			}
 		}
 	}
@@ -1140,6 +1217,14 @@ public class CatalogController extends BasicController implements Activateable,
 			}
 		}
 	}
+	
+	// fxdiff: FXOLAT-71 do the right checks correctly
+	private void revokeRightsAndSetDefaults(){
+		canAddLinks = isOLATAdmin || isAuthor; // author is allowed to add!
+		canAdministrateCategory = isOLATAdmin;
+		canAddSubCategories = isOLATAdmin || isLocalTreeAdmin;
+		canRemoveAllLinks = isOLATAdmin || isLocalTreeAdmin;
+	}
 
 	/**
 	 * @see org.olat.core.gui.control.generic.dtabs.Activateable#activate(org.olat.core.gui.UserRequest, java.lang.String)
@@ -1193,5 +1278,22 @@ public class CatalogController extends BasicController implements Activateable,
 		historyStack.clear();
 		jumpToNode(ureq, jumpToNode);
 	}
-
+	
+	public class PriceMethod {
+		private String price;
+		private String type;
+		
+		public PriceMethod(String price, String type) {
+			this.price = price;
+			this.type = type;
+		}
+		
+		public String getPrice() {
+			return price;
+		}
+		
+		public String getType() {
+			return type;
+		}
+	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/catalog/ui/_content/catalog.html b/src/main/java/org/olat/catalog/ui/_content/catalog.html
index 3957c599e54670f2e79047f1bff890ea270a4ace..e83e915b91fadcf1638b28625ef523b3565a68f1 100644
--- a/src/main/java/org/olat/catalog/ui/_content/catalog.html
+++ b/src/main/java/org/olat/catalog/ui/_content/catalog.html
@@ -42,7 +42,7 @@
 			#foreach($child in $children)
 				#if ($child.getType()==$node)
 					<li><a href="$r.commandURIbg("child$ri")" onclick="return o2cl()"  onkeypress="return o2cl()" $r.bgTarget()>
-						<span class="b_with_small_icon_left o_catalog_sub_icon">$child.getName()</span>
+						<span class="b_with_small_icon_left o_catalog_sub_icon">$child.getName()</span> 
 					</a></li>
 				#end
 				#set ($ri = $ri +1)
@@ -91,6 +91,16 @@
 								});
 									
 								</script>
+								
+								#if($r.get("ac_$ri"))
+									#foreach($ac_type in $r.get("ac_$ri"))
+										#if($ac_type.price && $ac_type.price.length() > 0)
+											<span class='b_float_right b_with_small_icon_left $ac_type.type'>$ac_type.price</span>
+										#else
+											<span class='b_float_right b_small_icon $ac_type.type'></span>
+										#end
+									#end
+								#end
 								<a href="$r.commandURIbg("leaf$ri")" onclick="return o2cl()"  onkeypress="return o2cl()" $r.bgTarget() class="b_with_small_icon_left ${iconRenderer.getIconCssClass($child.getRepositoryEntry())}">
 								<span id="leaf$ri">$child.getRepositoryEntry().getDisplayname()								
 								</span>
diff --git a/src/main/java/org/olat/collaboration/CollaborationTools.java b/src/main/java/org/olat/collaboration/CollaborationTools.java
index 34e089c9aa1cd762318c9e37ace5c1673132e222..7ba157ac548d4f98138a38e8606fec179aff652e 100644
--- a/src/main/java/org/olat/collaboration/CollaborationTools.java
+++ b/src/main/java/org/olat/collaboration/CollaborationTools.java
@@ -228,7 +228,6 @@ public class CollaborationTools implements Serializable {
 			toolArr.add(TOOL_PORTFOLIO);
 		}	
 		TOOLS = ArrayHelper.toArray(toolArr);
-//		TOOLS = (String[]) toolArr.toArray();
 	}
 
 	/**
diff --git a/src/main/java/org/olat/core/gui/components/table/DefaultColumnDescriptor.java b/src/main/java/org/olat/core/gui/components/table/DefaultColumnDescriptor.java
index 1a033be5358ce4c572d8f0d8d34390d6de905a4a..87d22753330eb632a345ae56e73e8df520b6533b 100644
--- a/src/main/java/org/olat/core/gui/components/table/DefaultColumnDescriptor.java
+++ b/src/main/java/org/olat/core/gui/components/table/DefaultColumnDescriptor.java
@@ -147,11 +147,11 @@ public class DefaultColumnDescriptor implements ColumnDescriptor {
 		if (a == null || b == null) {
 			return compareNullObjects(a, b);
 		}
-		if (a instanceof String) {
+		if (a instanceof String && b instanceof String) {
 			return collator.compare(a, b);
-		} else if (a instanceof Comparable) {
+		} else if (a instanceof Comparable && b instanceof Comparable) {
 			return compareComparablesAndTimestamps(a, b);
-		} else if (a instanceof Boolean) {  // faster than string compare
+		} else if (a instanceof Boolean && b instanceof Boolean) { // faster than string compare
 			return compareBooleansHandlingNulls(a, b);
 		} else { // don't know how to compare, use the String value
 			return a.toString().compareTo(b.toString());
diff --git a/src/main/java/org/olat/core/gui/components/table/TableController.java b/src/main/java/org/olat/core/gui/components/table/TableController.java
index d21a623c43f14c9194a5e61f0b021b5416127576..e82461cc07195635e9b84eefd8b2d2b39e0b939f 100644
--- a/src/main/java/org/olat/core/gui/components/table/TableController.java
+++ b/src/main/java/org/olat/core/gui/components/table/TableController.java
@@ -170,9 +170,31 @@ public class TableController extends BasicController {
 	 *          <code>null</code> if not used
 	 * @param tableTrans The translator that is used to translate the table
 	 */
-	public TableController(final TableGuiConfiguration tableConfig, final UserRequest ureq, final WindowControl wControl, final List filters, final ShortName activeFilter,
+	public TableController(final TableGuiConfiguration tableConfig, final UserRequest ureq, final WindowControl wControl, final List<ShortName> filters, final ShortName activeFilter,
 			final String filterTitle, final String noFilterOption, final Translator tableTrans) {
 		// init using regular constructor
+		this(tableConfig, ureq, wControl, filters, activeFilter, filterTitle, noFilterOption, false, tableTrans);
+
+	}
+	
+	/**
+	 * Constructor for the table controller using the table filter.
+	 * 
+	 * @param tableConfig The table GUI configuration determines the tables
+	 *          behavior, may be <code>null</code> to use default table configuration.
+	 * @param ureq The user request
+	 * @param wControl The window control
+	 * @param filters A list of filter objects ({@link ShortName})
+	 * @param activeFilter The initially activated filter object
+	 * @param filterTitle The translated title of the filter
+	 * @param noFilterOption The translated key for the no-filter filter or
+	 *          <code>null</code> if not used
+	 * @param enableTableSearch Enable the auto completter for search within the table
+	 * @param tableTrans The translator that is used to translate the table
+	 */
+	public TableController(final TableGuiConfiguration tableConfig, final UserRequest ureq, final WindowControl wControl, final List<ShortName> filters, final ShortName activeFilter,
+			final String filterTitle, final String noFilterOption, final boolean enableTableSearch, final Translator tableTrans) {
+		// init using regular constructor
 		this(tableConfig, ureq, wControl, tableTrans);
 
 		// push filter to velocity page
@@ -184,6 +206,14 @@ public class TableController extends BasicController {
 		} else {
 			this.contentVc.contextPut(VC_VAR_USE_NO_FILTER_OPTION, Boolean.FALSE);
 		}
+		
+		if (enableTableSearch) {
+			tableSearchController = createTableSearchController(ureq, wControl);
+			contentVc.put("tableSearch", tableSearchController.getInitialComponent());
+			contentVc.contextPut(VC_VAR_HAS_TABLE_SEARCH, Boolean.TRUE);
+		} else {
+			contentVc.contextPut(VC_VAR_HAS_TABLE_SEARCH, Boolean.FALSE);
+		}
 	}
 
 	/**
diff --git a/src/main/java/org/olat/core/gui/components/table/TableDataModelWithMarkableRows.java b/src/main/java/org/olat/core/gui/components/table/TableDataModelWithMarkableRows.java
new file mode 100644
index 0000000000000000000000000000000000000000..7130f5696ad5745672274d55f6162a83794f2564
--- /dev/null
+++ b/src/main/java/org/olat/core/gui/components/table/TableDataModelWithMarkableRows.java
@@ -0,0 +1,44 @@
+/**
+ * OLAT - Online Learning and Training<br>
+ * http://www.olat.org
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Copyright (c) 2008 frentix GmbH, Switzerland<br>
+ * <p>
+ */
+
+package org.olat.core.gui.components.table;
+
+/**
+ * Description:<br>
+ * Interface to extend TableDataModel with the feature to mark a certain row
+ * with a CSS class.
+ * VCRP-16
+ * 
+ * <P>
+ * Initial Date: 20.04.2011 <br>
+ * 
+ * @author gnaegi
+ */
+public interface TableDataModelWithMarkableRows extends TableDataModel {
+
+	/**
+	 * Get an optional CSS class name to mark this row
+	 * 
+	 * @param rowId
+	 * @return null or the CSS class name
+	 */
+	public String getRowCssClass(int rowId);
+
+}
diff --git a/src/main/java/org/olat/core/gui/components/table/TableRenderer.java b/src/main/java/org/olat/core/gui/components/table/TableRenderer.java
index 49082b7095e0e026067096b20c426d1017e6f757..0c7098678529c0f7f481fa4b8ba805ecf2d5e83f 100644
--- a/src/main/java/org/olat/core/gui/components/table/TableRenderer.java
+++ b/src/main/java/org/olat/core/gui/components/table/TableRenderer.java
@@ -240,6 +240,15 @@ public class TableRenderer implements ComponentRenderer {
 			boolean isMark = selRowUnSelectable && (selRowId == currentPosInModel);
 
 			cssClass = defineCssClassDependingOnRow(startRowId, lastVisibleRowId, i);
+			// VCRP-16
+			TableDataModel model = table.getTableDataModel();
+			if (model instanceof TableDataModelWithMarkableRows) {
+				TableDataModelWithMarkableRows markableModel = (TableDataModelWithMarkableRows) model;
+				String rowCss = markableModel.getRowCssClass(i);
+				if (rowCss != null) {
+					cssClass += " " + rowCss;
+				}
+			}
 
 			target.append("<tr class=\"").append(cssClass).append(CLOSE_HTML_BRACE);
 			appendSingleDataRow(renderer, target, ubu, table, iframePostEnabled, cols, i, currentPosInModel, isMark);
diff --git a/src/main/java/org/olat/course/CourseFactory.java b/src/main/java/org/olat/course/CourseFactory.java
index 2f8d4240750a42877fc89eff96ed3d2a2d44d546..fe2059ec194be322650270bca851d38b5d7ad853 100644
--- a/src/main/java/org/olat/course/CourseFactory.java
+++ b/src/main/java/org/olat/course/CourseFactory.java
@@ -604,6 +604,25 @@ public class CourseFactory extends BasicManager {
 		// -> All owners of repository entries are course admins
 		securityManager.createAndPersistPolicy(re.getOwnerGroup(), Constants.PERMISSION_ADMIN, re.getOlatResource());
 		
+		//fxdiff VCRP-1,2: access control of resources
+		// create security group for tutors / coaches
+		SecurityGroup tutorGroup = securityManager.createAndPersistSecurityGroup();
+		// member of this group may modify member's membership
+		securityManager.createAndPersistPolicy(tutorGroup, Constants.PERMISSION_ACCESS, re.getOlatResource());
+		securityManager.createAndPersistPolicy(tutorGroup, Constants.PERMISSION_COACH, re.getOlatResource());
+		// members of this group are always tutors also
+		securityManager.createAndPersistPolicy(tutorGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_TUTOR);
+		re.setTutorGroup(tutorGroup);
+	
+		// create security group for participants
+		SecurityGroup participantGroup = securityManager.createAndPersistSecurityGroup();
+		// member of this group may modify member's membership
+		securityManager.createAndPersistPolicy(participantGroup, Constants.PERMISSION_ACCESS, re.getOlatResource());
+		securityManager.createAndPersistPolicy(participantGroup, Constants.PERMISSION_PARTI, re.getOlatResource());
+		// members of this group are always participants also
+		securityManager.createAndPersistPolicy(participantGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_PARTICIPANT);
+		re.setParticipantGroup(participantGroup);
+		
 		// deploy any referenced repository entries of the editor structure. This will also
 		// include any references in the run structure, since any node in the runstructure is also
 		// present in the editor structure.
diff --git a/src/main/java/org/olat/course/archiver/CourseLogsArchiveController.java b/src/main/java/org/olat/course/archiver/CourseLogsArchiveController.java
index b58ddf7dfc58df54075deaf400cb2816a13b3b96..af8624565a73ed2cbad6a99a0432edbefa4d23c7 100644
--- a/src/main/java/org/olat/course/archiver/CourseLogsArchiveController.java
+++ b/src/main/java/org/olat/course/archiver/CourseLogsArchiveController.java
@@ -46,7 +46,7 @@ import org.olat.core.util.vfs.VFSContainer;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.statistic.AsyncExportManager;
-import org.olat.home.HomeMainController;
+import org.olat.home.InviteeHomeMainController;
 import org.olat.repository.RepositoryManager;
 import org.olat.user.UserManager;
 
@@ -145,7 +145,7 @@ public class CourseLogsArchiveController extends BasicController {
 				bcrun.activate(ureq, relPath);
 			}
 			
-			String personalFolder = Util.createPackageTranslator(HomeMainController.class, ureq.getLocale(), null).translate("menu.bc");
+			String personalFolder = Util.createPackageTranslator(InviteeHomeMainController.class, ureq.getLocale(), null).translate("menu.bc");
 			
 			removeAsListenerAndDispose(cmc);
 			cmc = new CloseableModalController(
diff --git a/src/main/java/org/olat/course/condition/interpreter/ConditionInterpreter.java b/src/main/java/org/olat/course/condition/interpreter/ConditionInterpreter.java
index 6eeffbb1d3e09ecf1a0a59b9d97babdbb06fd27f..5d3c1523f3dec5c0b83ba7ab3818f17cbc138fa7 100644
--- a/src/main/java/org/olat/course/condition/interpreter/ConditionInterpreter.java
+++ b/src/main/java/org/olat/course/condition/interpreter/ConditionInterpreter.java
@@ -120,6 +120,7 @@ public class ConditionInterpreter {
 		env.addFunction(HasLanguageFunction.name, new HasLanguageFunction(userCourseEnv));
 		env.addFunction(InInstitutionFunction.name, new InInstitutionFunction(userCourseEnv));
 		env.addFunction(IsCourseCoachFunction.name, new IsCourseCoachFunction(userCourseEnv));
+		env.addFunction(IsCourseParticipantFunction.name, new IsCourseParticipantFunction(userCourseEnv));
 		env.addFunction(IsCourseAdministratorFunction.name, new IsCourseAdministratorFunction(userCourseEnv));
 
 		env.addFunction(GetInitialCourseLaunchDateFunction.name, new GetInitialCourseLaunchDateFunction(userCourseEnv));
diff --git a/src/main/java/org/olat/course/condition/interpreter/IsCourseParticipantFunction.java b/src/main/java/org/olat/course/condition/interpreter/IsCourseParticipantFunction.java
new file mode 100644
index 0000000000000000000000000000000000000000..062923b53f4742243d9e04380e176a6e27d350ca
--- /dev/null
+++ b/src/main/java/org/olat/course/condition/interpreter/IsCourseParticipantFunction.java
@@ -0,0 +1,80 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+
+package org.olat.course.condition.interpreter;
+
+import org.olat.core.id.Identity;
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
+import org.olat.course.editor.CourseEditorEnv;
+import org.olat.course.groupsandrights.CourseGroupManager;
+import org.olat.course.run.userview.UserCourseEnvironment;
+
+/**
+ * 
+ * Description:<br>
+ * A user is a participant coach if he/she is in at least particpant of a learning group of the learning group context of the course
+ * or in the participant group of the repository entry
+ * 
+ * <P>
+ * Initial Date:  28 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class IsCourseParticipantFunction extends AbstractFunction {
+	private static final OLog log = Tracing.createLoggerFor(IsCourseParticipantFunction.class);
+	
+	public static final String name = "isCourseParticipant";
+	
+	/**
+	 * @param userCourseEnv
+	 */
+	public IsCourseParticipantFunction(UserCourseEnvironment userCourseEnv) {
+		super(userCourseEnv);
+	}
+
+	/**
+	 * @see com.neemsoft.jmep.FunctionCB#call(java.lang.Object[])
+	 */
+	public Object call(Object[] inStack) {
+		/*
+		 * expression check only if cev != null
+		 */
+		CourseEditorEnv cev = getUserCourseEnv().getCourseEditorEnv();
+		if (cev != null) {
+			// return a valid value to continue with condition evaluation test
+			return defaultValue();
+		}
+
+		Identity ident = getUserCourseEnv().getIdentityEnvironment().getIdentity();
+		CourseGroupManager cgm = getUserCourseEnv().getCourseEnvironment().getCourseGroupManager();
+		boolean isParticipant = cgm.isIdentityCourseParticipant(ident);
+		if (log.isDebug()) {
+			log.debug("identity "+ident.getName()+", coursecoach:"+isParticipant+", in course "+getUserCourseEnv().getCourseEnvironment().getCourseResourceableId());
+		}
+		
+		return isParticipant ? ConditionInterpreter.INT_TRUE: ConditionInterpreter.INT_FALSE;
+	}
+
+	protected Object defaultValue() {
+		return ConditionInterpreter.INT_TRUE;
+	}
+
+}
diff --git a/src/main/java/org/olat/course/condition/interpreter/OnlyGroupConditionInterpreter.java b/src/main/java/org/olat/course/condition/interpreter/OnlyGroupConditionInterpreter.java
index a5b6f3c9f248a9e4ba0c024c1f6e3f1fac41a31f..3175cd61fa69104f1c228ffb1ab37b48fa65ba33 100644
--- a/src/main/java/org/olat/course/condition/interpreter/OnlyGroupConditionInterpreter.java
+++ b/src/main/java/org/olat/course/condition/interpreter/OnlyGroupConditionInterpreter.java
@@ -79,6 +79,7 @@ public class OnlyGroupConditionInterpreter extends ConditionInterpreter{
 		env.addFunction(HasLanguageFunction.name, new DummyBooleanFunction(userCourseEnv));
 		env.addFunction(InInstitutionFunction.name, new DummyBooleanFunction(userCourseEnv));
 		env.addFunction(IsCourseCoachFunction.name, new DummyBooleanFunction(userCourseEnv));
+		env.addFunction(IsCourseParticipantFunction.name, new DummyBooleanFunction(userCourseEnv));
 		env.addFunction(IsCourseAdministratorFunction.name, new DummyBooleanFunction(userCourseEnv));
 
 		env.addFunction(GetAttemptsFunction.name, new DummyIntegerFunction(userCourseEnv));
diff --git a/src/main/java/org/olat/course/editor/EditorMainController.java b/src/main/java/org/olat/course/editor/EditorMainController.java
index 2cb31bcb0cbadbcbba9dab4c16ebe28279fa6519..212270fa082a386f24d76dbf3fb82d1856e9fdf3 100644
--- a/src/main/java/org/olat/course/editor/EditorMainController.java
+++ b/src/main/java/org/olat/course/editor/EditorMainController.java
@@ -102,6 +102,7 @@ import org.olat.course.tree.CourseEditorTreeModel;
 import org.olat.course.tree.CourseEditorTreeNode;
 import org.olat.course.tree.CourseInternalLinkTreeModel;
 import org.olat.group.ui.context.BGContextEvent;
+import org.olat.repository.RepositoryEntry;
 import org.olat.testutils.codepoints.server.Codepoint;
 import org.olat.util.logging.activity.LoggingResourceable;
 
@@ -572,11 +573,18 @@ public class EditorMainController extends MainLayoutBasicController implements G
 						if (runContext.containsKey("changedaccess")) {
 							// there were changes made to the general course access
 							String newAccessStr = (String) runContext.get("changedaccess");
-							int newAccess = Integer.valueOf(newAccessStr);
+							int newAccess;
+							//fxdiff VCRP-1,2: access control of resources
+							boolean membersOnly = RepositoryEntry.MEMBERS_ONLY.equals(newAccessStr);
+							if(membersOnly) {
+								newAccess = RepositoryEntry.ACC_OWNERS;
+							} else {
+								newAccess = Integer.valueOf(newAccessStr);
+							}
 							PublishProcess publishManager = (PublishProcess) runContext.get("publishProcess");
 							// fires an EntryChangedEvent for repository entry notifying
 							// about modification.
-							publishManager.changeGeneralAccess(ureq1, newAccess);
+							publishManager.changeGeneralAccess(ureq1, newAccess, membersOnly);
 							hasChanges = true;
 						}
 
diff --git a/src/main/java/org/olat/course/editor/PublishProcess.java b/src/main/java/org/olat/course/editor/PublishProcess.java
index 8d0f47e165d1d1d1f5d5d6e9a6fe702fe3452d46..71b5f8787cd6ebca0e5cd38577b9796597fa5c6c 100644
--- a/src/main/java/org/olat/course/editor/PublishProcess.java
+++ b/src/main/java/org/olat/course/editor/PublishProcess.java
@@ -513,8 +513,6 @@ public class PublishProcess {
 	}
 
 
-
-
 	void clearPublishSet() {
 		resultingCourseRun = null;
 		// clear publis datastructures
@@ -578,8 +576,9 @@ public class PublishProcess {
 		return publishTreeModel;
 	}
 
-	public void changeGeneralAccess(UserRequest ureq, int access){
-		RepositoryManager.getInstance().setAccess(repositoryEntry, access);
+	//fxdiff VCRP-1,2: access control of resources
+	public void changeGeneralAccess(UserRequest ureq, int access, boolean membersOnly){
+		RepositoryManager.getInstance().setAccess(repositoryEntry, access, membersOnly);
 		MultiUserEvent modifiedEvent = new EntryChangedEvent(repositoryEntry, EntryChangedEvent.MODIFIED_AT_PUBLISH);
 		CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(modifiedEvent, repositoryEntry);
 	}
diff --git a/src/main/java/org/olat/course/groupsandrights/CourseGroupManager.java b/src/main/java/org/olat/course/groupsandrights/CourseGroupManager.java
index a148d4231bd203b23a9261dfb3d8ffb9c5f8a746..d508294964df71121e042e9683adf12596c9e469 100644
--- a/src/main/java/org/olat/course/groupsandrights/CourseGroupManager.java
+++ b/src/main/java/org/olat/course/groupsandrights/CourseGroupManager.java
@@ -165,6 +165,14 @@ public interface CourseGroupManager {
 	 * @return boolean
 	 */
 	public boolean isIdentityCourseAdministrator(Identity identity);
+	
+	/**
+	 * Checks if user is course participant
+	 * 
+	 * @param identity
+	 * @return boolean
+	 */
+	public boolean isIdentityCourseParticipant(Identity identity);
 
 	/**
 	 * Checks if user is participant in any right group of this course
@@ -356,6 +364,9 @@ public interface CourseGroupManager {
 	 * @return a list with all coaches of this course
 	 */
 	public List getCoachesFromLearningGroup(String groupName);
+	
+	//fxdiff VCRP-1,2: access control of resources
+	public List<Identity> getCoaches();
 
 	/**
 	 * List with identities being coaches in the areas of this course. If
@@ -374,6 +385,9 @@ public interface CourseGroupManager {
 	 * @return a list with all participants of this course
 	 */
 	public List getParticipantsFromLearningGroup(String groupName);
+	
+	//fxdiff VCRP-1,2: access control of resources
+	public List<Identity> getParticipants();
 
 	/**
 	 * List with identities being participants in the areas of this course. If
diff --git a/src/main/java/org/olat/course/groupsandrights/PersistingCourseGroupManager.java b/src/main/java/org/olat/course/groupsandrights/PersistingCourseGroupManager.java
index 06200fd23d5d523279c1f06508f882168383320e..476b4436cea92275849ab793ae28c4fcbacfffc9 100644
--- a/src/main/java/org/olat/course/groupsandrights/PersistingCourseGroupManager.java
+++ b/src/main/java/org/olat/course/groupsandrights/PersistingCourseGroupManager.java
@@ -47,6 +47,8 @@ import org.olat.group.context.BGContextManager;
 import org.olat.group.context.BGContextManagerImpl;
 import org.olat.group.right.BGRightManager;
 import org.olat.group.right.BGRightManagerImpl;
+import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryManager;
 import org.olat.resource.OLATResource;
 import org.olat.resource.OLATResourceManager;
 
@@ -483,6 +485,15 @@ public class PersistingCourseGroupManager extends BasicManager implements Course
 	 */
 	public boolean isIdentityCourseCoach(Identity identity) {
 		BaseSecurity secManager = BaseSecurityManager.getInstance();
+		
+	//fxdiff VCRP-1: access control of learn resource
+		RepositoryEntry re = RepositoryManager.getInstance().lookupRepositoryEntry(courseResource, false);
+		if(re != null && re.getTutorGroup() != null) {
+			boolean isCoach = secManager.isIdentityInSecurityGroup(identity, re.getTutorGroup());
+			if (isCoach) // don't check any further
+				return true;
+		}
+		
 		Iterator iterator = learningGroupContexts.iterator();
 		while (iterator.hasNext()) {
 			BGContext bgContext = (BGContext) iterator.next();
@@ -492,6 +503,32 @@ public class PersistingCourseGroupManager extends BasicManager implements Course
 		}
 		return false;
 	}
+	
+	/**
+	 * @see org.olat.course.groupsandrights.CourseGroupManager#isIdentityCourseCoach(org.olat.core.id.Identity)
+	 */
+	public boolean isIdentityCourseParticipant(Identity identity) {
+		BaseSecurity secManager = BaseSecurityManager.getInstance();
+		
+		//fxdiff VCRP-1: access control of learn resource
+		RepositoryEntry re = RepositoryManager.getInstance().lookupRepositoryEntry(courseResource, false);
+		if(re != null && re.getParticipantGroup() != null) {
+			boolean isParticipant = secManager.isIdentityInSecurityGroup(identity, re.getParticipantGroup());
+			if (isParticipant) // don't check any further
+				return true;
+		}
+		
+		Iterator<BGContext> iterator = learningGroupContexts.iterator();
+		for( ; iterator.hasNext(); ) {
+			BGContext bgContext = iterator.next();
+			boolean isParticipant = secManager.isIdentityPermittedOnResourceable(identity, Constants.PERMISSION_PARTI, bgContext);
+			if (isParticipant) // don't check any further
+				return true;
+		}
+		
+		
+		return false;
+	}
 
 	/**
 	 * @see org.olat.course.groupsandrights.CourseGroupManager#isIdentityCourseAdministrator(org.olat.core.id.Identity)
@@ -777,6 +814,28 @@ public class PersistingCourseGroupManager extends BasicManager implements Course
 		}
 		return retVal;
 	}
+	
+	@Override
+	//fxdiff VCRP-1,2: access control of resources
+	public List<Identity> getCoaches() {
+		BaseSecurity secManager = BaseSecurityManager.getInstance();
+		RepositoryEntry re = RepositoryManager.getInstance().lookupRepositoryEntry(courseResource, false);
+		if(re != null && re.getTutorGroup() != null) {
+			return secManager.getIdentitiesOfSecurityGroup(re.getTutorGroup());
+		}
+		return Collections.emptyList();
+	}
+
+	@Override
+	//fxdiff VCRP-1,2: access control of resources
+	public List<Identity> getParticipants() {
+		BaseSecurity secManager = BaseSecurityManager.getInstance();
+		RepositoryEntry re = RepositoryManager.getInstance().lookupRepositoryEntry(courseResource, false);
+		if(re != null && re.getParticipantGroup() != null) {
+			return secManager.getIdentitiesOfSecurityGroup(re.getParticipantGroup());
+		}
+		return Collections.emptyList();
+	}
 
 	/**
 	 * @see org.olat.course.groupsandrights.CourseGroupManager#getCoachesFromArea(java.lang.String)
diff --git a/src/main/java/org/olat/course/nodes/info/SendMembersMailOption.java b/src/main/java/org/olat/course/nodes/info/SendMembersMailOption.java
index 092c10ad866d5bc7d44b06890ac538d70ebe48ad..2d75f3250adf4c4fcfba4f5633d0fe14784b8e80 100644
--- a/src/main/java/org/olat/course/nodes/info/SendMembersMailOption.java
+++ b/src/main/java/org/olat/course/nodes/info/SendMembersMailOption.java
@@ -21,12 +21,13 @@
 package org.olat.course.nodes.info;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
+import java.util.Set;
 
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.BaseSecurityManager;
-import org.olat.basesecurity.SecurityGroup;
 import org.olat.commons.info.ui.SendMailOption;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
@@ -69,7 +70,7 @@ public class SendMembersMailOption implements SendMailOption {
 
 	@Override
 	public List<Identity> getSelectedIdentities() {
-		List<Identity> identities = new ArrayList<Identity>();
+		Set<Identity> identities = new HashSet<Identity>();
 		CourseGroupManager cgm = course.getCourseEnvironment().getCourseGroupManager();
 		List<BusinessGroup> learningGroups = cgm.getAllLearningGroupsFromAllContexts();
 		for(BusinessGroup bg:learningGroups) {
@@ -78,14 +79,18 @@ public class SendMembersMailOption implements SendMailOption {
 			List<Identity> coaches = cgm.getCoachesFromLearningGroup(bg.getName());
 			identities.addAll(coaches);
 		}
-
+		//fxdiff VCRP-1,2: access control of resources
 		RepositoryEntry repositoryEntry = rm.lookupRepositoryEntry(course, true);
-		SecurityGroup sg = repositoryEntry.getOwnerGroup();
 		BaseSecurity securityManager = BaseSecurityManager.getInstance();
-		List<Object[]> owners = securityManager.getIdentitiesAndDateOfSecurityGroup(sg);
-		for(Object[] owner:owners) {
-			identities.add((Identity)owner[0]);
+		if(repositoryEntry.getParticipantGroup() != null) {
+			identities.addAll(securityManager.getIdentitiesOfSecurityGroup(repositoryEntry.getParticipantGroup()));
+		}
+		if(repositoryEntry.getTutorGroup() != null) {
+			identities.addAll(securityManager.getIdentitiesOfSecurityGroup(repositoryEntry.getTutorGroup()));
+		}
+		if(repositoryEntry.getOwnerGroup() != null) {
+			identities.addAll(securityManager.getIdentitiesOfSecurityGroup(repositoryEntry.getOwnerGroup()));
 		}
-		return identities;
+		return new ArrayList<Identity>(identities);
 	}
 }
diff --git a/src/main/java/org/olat/course/repository/CreateNewCourseController.java b/src/main/java/org/olat/course/repository/CreateNewCourseController.java
index 7d7754fc9365d9b4ce062ed331804f7fa0999b93..55b70919fe52f79849e6437e3f9e6c43bfe5f5ee 100644
--- a/src/main/java/org/olat/course/repository/CreateNewCourseController.java
+++ b/src/main/java/org/olat/course/repository/CreateNewCourseController.java
@@ -129,6 +129,9 @@ public class CreateNewCourseController extends BasicController implements IAddCo
 		// -> All owners of repository entries are course admins
 		BaseSecurity secMgr = BaseSecurityManager.getInstance();
 		secMgr.createAndPersistPolicy(re.getOwnerGroup(), Constants.PERMISSION_ADMIN, re.getOlatResource());
+		//fxdiff VCRP-1,2: access control of resources
+		secMgr.createAndPersistPolicy(re.getParticipantGroup(), Constants.PERMISSION_PARTI, re.getOlatResource());
+		secMgr.createAndPersistPolicy(re.getTutorGroup(), Constants.PERMISSION_COACH, re.getOlatResource());
 		// set root node title
 				
 		course = CourseFactory.openCourseEditSession(re.getOlatResource().getResourceableId());
diff --git a/src/main/java/org/olat/course/repository/ImportGlossaryReferencesController.java b/src/main/java/org/olat/course/repository/ImportGlossaryReferencesController.java
index 8ff183fb03330a61875c2e041eed0c92e28fe8b2..24c9fc9dca43cd49d97550629e5d0f84955ca0bd 100644
--- a/src/main/java/org/olat/course/repository/ImportGlossaryReferencesController.java
+++ b/src/main/java/org/olat/course/repository/ImportGlossaryReferencesController.java
@@ -195,6 +195,24 @@ public class ImportGlossaryReferencesController extends BasicController {
 		securityManager.createAndPersistPolicy(newGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_AUTHOR);
 		securityManager.addIdentityToSecurityGroup(owner, newGroup);
 		importedRepositoryEntry.setOwnerGroup(newGroup);
+		
+		//fxdiff VCRP-1,2: access control of resources
+		// security group for tutors / coaches
+		SecurityGroup tutorGroup = securityManager.createAndPersistSecurityGroup();
+		// member of this group may modify member's membership
+		securityManager.createAndPersistPolicy(tutorGroup, Constants.PERMISSION_ACCESS, importedRepositoryEntry.getOlatResource());
+		// members of this group are always tutors also
+		securityManager.createAndPersistPolicy(tutorGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_TUTOR);
+		importedRepositoryEntry.setTutorGroup(tutorGroup);
+		
+		// security group for participants
+		SecurityGroup participantGroup = securityManager.createAndPersistSecurityGroup();
+		// member of this group may modify member's membership
+		securityManager.createAndPersistPolicy(participantGroup, Constants.PERMISSION_ACCESS, importedRepositoryEntry.getOlatResource());
+		// members of this group are always participants also
+		securityManager.createAndPersistPolicy(participantGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_PARTICIPANT);
+		importedRepositoryEntry.setParticipantGroup(participantGroup);
+		
 		rm.saveRepositoryEntry(importedRepositoryEntry);
 
 		if (!keepSoftkey) {
diff --git a/src/main/java/org/olat/course/repository/ImportPortfolioReferencesController.java b/src/main/java/org/olat/course/repository/ImportPortfolioReferencesController.java
index 23019ab9dd4862ec321f0b1292e0817c2b8dff2c..73e39eb7ffd350f16b55bb6fae2101a0e56ce7e8 100644
--- a/src/main/java/org/olat/course/repository/ImportPortfolioReferencesController.java
+++ b/src/main/java/org/olat/course/repository/ImportPortfolioReferencesController.java
@@ -215,6 +215,24 @@ public class ImportPortfolioReferencesController extends BasicController {
 		securityManager.createAndPersistPolicy(newGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_AUTHOR);
 		securityManager.addIdentityToSecurityGroup(owner, newGroup);
 		importedRepositoryEntry.setOwnerGroup(newGroup);
+		
+		//fxdiff VCRP-1,2: access control of resources
+		// security group for tutors / coaches
+		SecurityGroup tutorGroup = securityManager.createAndPersistSecurityGroup();
+		// member of this group may modify member's membership
+		securityManager.createAndPersistPolicy(tutorGroup, Constants.PERMISSION_ACCESS, importedRepositoryEntry.getOlatResource());
+		// members of this group are always tutors also
+		securityManager.createAndPersistPolicy(tutorGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_TUTOR);
+		importedRepositoryEntry.setTutorGroup(tutorGroup);
+		
+		// security group for participants
+		SecurityGroup participantGroup = securityManager.createAndPersistSecurityGroup();
+		// member of this group may modify member's membership
+		securityManager.createAndPersistPolicy(participantGroup, Constants.PERMISSION_ACCESS, importedRepositoryEntry.getOlatResource());
+		// members of this group are always participants also
+		securityManager.createAndPersistPolicy(participantGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_PARTICIPANT);
+		importedRepositoryEntry.setParticipantGroup(participantGroup);
+		
 		rm.saveRepositoryEntry(importedRepositoryEntry);
 
 		if (!keepSoftkey) {
diff --git a/src/main/java/org/olat/course/repository/ImportReferencesController.java b/src/main/java/org/olat/course/repository/ImportReferencesController.java
index 9289ab5fac84e5366a24740799c28a77158631a3..181c6515dcb9e9c77acefff0763c11156ba1f88f 100644
--- a/src/main/java/org/olat/course/repository/ImportReferencesController.java
+++ b/src/main/java/org/olat/course/repository/ImportReferencesController.java
@@ -323,6 +323,24 @@ public class ImportReferencesController extends BasicController {
 		securityManager.createAndPersistPolicy(newGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_AUTHOR);
 		securityManager.addIdentityToSecurityGroup(owner, newGroup);
 		importedRepositoryEntry.setOwnerGroup(newGroup);
+		
+		//fxdiff VCRP-1,2: access control of resources
+		// security group for tutors / coaches
+		SecurityGroup tutorGroup = securityManager.createAndPersistSecurityGroup();
+		// member of this group may modify member's membership
+		securityManager.createAndPersistPolicy(tutorGroup, Constants.PERMISSION_ACCESS, importedRepositoryEntry.getOlatResource());
+		// members of this group are always tutors also
+		securityManager.createAndPersistPolicy(tutorGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_TUTOR);
+		importedRepositoryEntry.setTutorGroup(tutorGroup);
+		
+		// security group for participants
+		SecurityGroup participantGroup = securityManager.createAndPersistSecurityGroup();
+		// member of this group may modify member's membership
+		securityManager.createAndPersistPolicy(participantGroup, Constants.PERMISSION_ACCESS, importedRepositoryEntry.getOlatResource());
+		// members of this group are always participants also
+		securityManager.createAndPersistPolicy(participantGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_PARTICIPANT);
+		importedRepositoryEntry.setParticipantGroup(participantGroup);
+		
 		rm.saveRepositoryEntry(importedRepositoryEntry);
 
 		if (!keepSoftkey) setReference(importedRepositoryEntry, node, importMode);
diff --git a/src/main/java/org/olat/course/repository/ImportSharedfolderReferencesController.java b/src/main/java/org/olat/course/repository/ImportSharedfolderReferencesController.java
index d11c46fddcfe4dc6fb2d64bbf682e53fb54557f1..661824b78a3dbd0bb3eac6e61dea0a639740c7e1 100644
--- a/src/main/java/org/olat/course/repository/ImportSharedfolderReferencesController.java
+++ b/src/main/java/org/olat/course/repository/ImportSharedfolderReferencesController.java
@@ -189,6 +189,24 @@ public class ImportSharedfolderReferencesController extends BasicController {
 		securityManager.createAndPersistPolicy(newGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_AUTHOR);
 		securityManager.addIdentityToSecurityGroup(owner, newGroup);
 		importedRepositoryEntry.setOwnerGroup(newGroup);
+		
+		//fxdiff VCRP-1,2: access control of resources
+		// security group for tutors / coaches
+		SecurityGroup tutorGroup = securityManager.createAndPersistSecurityGroup();
+		// member of this group may modify member's membership
+		securityManager.createAndPersistPolicy(tutorGroup, Constants.PERMISSION_ACCESS, importedRepositoryEntry.getOlatResource());
+		// members of this group are always tutors also
+		securityManager.createAndPersistPolicy(tutorGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_TUTOR);
+		importedRepositoryEntry.setTutorGroup(tutorGroup);
+		
+		// security group for participants
+		SecurityGroup participantGroup = securityManager.createAndPersistSecurityGroup();
+		// member of this group may modify member's membership
+		securityManager.createAndPersistPolicy(participantGroup, Constants.PERMISSION_ACCESS, importedRepositoryEntry.getOlatResource());
+		// members of this group are always participants also
+		securityManager.createAndPersistPolicy(participantGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_PARTICIPANT);
+		importedRepositoryEntry.setParticipantGroup(participantGroup);
+		
 		rm.saveRepositoryEntry(importedRepositoryEntry);
 		
 		if (!keepSoftkey) {
diff --git a/src/main/java/org/olat/course/run/preview/PreviewCourseGroupManager.java b/src/main/java/org/olat/course/run/preview/PreviewCourseGroupManager.java
index dbe3016ea50b01a6de57ba3c967da85f3395bb2a..12c04892e172f9c5249055486ab046515f4d940a 100644
--- a/src/main/java/org/olat/course/run/preview/PreviewCourseGroupManager.java
+++ b/src/main/java/org/olat/course/run/preview/PreviewCourseGroupManager.java
@@ -141,6 +141,11 @@ final class PreviewCourseGroupManager extends BasicManager implements CourseGrou
 		return isCoach;
 	}
 
+	@Override
+	public boolean isIdentityCourseParticipant(Identity identity) {
+		return false;
+	}
+
 	/**
 	 * @see org.olat.course.groupsandrights.CourseGroupManager#isIdentityCourseAdministrator(org.olat.core.id.Identity)
 	 */
@@ -310,6 +315,17 @@ final class PreviewCourseGroupManager extends BasicManager implements CourseGrou
 	public List getParticipantsFromArea(String areaName) {
 		throw new AssertException("unsupported");
 	}
+	
+	//fxdiff VCRP-1,2: access control of resources
+	@Override
+	public List<Identity> getCoaches() {
+		throw new AssertException("unsupported");
+	}
+
+	@Override
+	public List<Identity> getParticipants() {
+		throw new AssertException("unsupported");
+	}
 
 	public List getRightGroupsFromAllContexts(String groupName) {
 		throw new AssertException("unsupported");
diff --git a/src/main/java/org/olat/group/BusinessGroupContextEntryControllerCreator.java b/src/main/java/org/olat/group/BusinessGroupContextEntryControllerCreator.java
index 06afb67e5bf6917ae97ff4460c8c10852bed16d7..a922b79fb58fd30fec1a786bbf3944dbe7d771ca 100644
--- a/src/main/java/org/olat/group/BusinessGroupContextEntryControllerCreator.java
+++ b/src/main/java/org/olat/group/BusinessGroupContextEntryControllerCreator.java
@@ -20,6 +20,9 @@
  */
 package org.olat.group;
 
+import java.util.Date;
+
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
@@ -27,6 +30,10 @@ import org.olat.core.id.OLATResourceable;
 import org.olat.core.id.context.ContextEntry;
 import org.olat.core.id.context.ContextEntryControllerCreator;
 import org.olat.group.ui.BGControllerFactory;
+import org.olat.resource.OLATResource;
+import org.olat.resource.OLATResourceManager;
+import org.olat.resource.accesscontrol.AccessControlModule;
+import org.olat.resource.accesscontrol.manager.ACFrontendManager;
 
 /**
  * <h3>Description:</h3>
@@ -54,7 +61,8 @@ public class BusinessGroupContextEntryControllerCreator implements ContextEntryC
 		Controller ctrl = null;
 		boolean isOlatAdmin = ureq.getUserSession().getRoles().isOLATAdmin();
 		// check if allowed to start (must be member or admin)
-		if (isOlatAdmin || bman.isIdentityInBusinessGroup(ureq.getIdentity(), bgroup)) {
+		//fxdiff VCRP-1,2: access control of resources
+		if (isOlatAdmin || bman.isIdentityInBusinessGroup(ureq.getIdentity(), bgroup) || isAccessControlled(bgroup)) {
 			// only olatadmins or admins of this group can administer this group
 			ctrl = BGControllerFactory.getInstance().createRunControllerFor(ureq, wControl, bgroup, isOlatAdmin, null);
 		}
@@ -85,7 +93,22 @@ public class BusinessGroupContextEntryControllerCreator implements ContextEntryC
 		Long gKey = ores.getResourceableId();
 		BusinessGroupManager bman = BusinessGroupManagerImpl.getInstance();
 		BusinessGroup bgroup = bman.loadBusinessGroup(gKey, false);
-		return bgroup != null;
+		if (bgroup != null){
+			return bman.isIdentityInBusinessGroup(ureq.getIdentity(), bgroup) || isAccessControlled(bgroup);
+		}
+		return false;
+	}
+	
+	private boolean isAccessControlled(BusinessGroup bgroup) {
+		AccessControlModule acModule = (AccessControlModule)CoreSpringFactory.getBean("acModule");
+		if(acModule.isEnabled()) {
+			ACFrontendManager acFrontendManager = (ACFrontendManager)CoreSpringFactory.getBean("acFrontendManager");
+			OLATResource resource = OLATResourceManager.getInstance().findResourceable(bgroup);
+			if(acFrontendManager.isResourceAccessControled(resource, new Date())) {
+				return true;
+			}
+		}
+		return false;
 	}
 
 }
diff --git a/src/main/java/org/olat/group/BusinessGroupManager.java b/src/main/java/org/olat/group/BusinessGroupManager.java
index eb9483810e98e2ba8c477877f132b99cc7444d68..6e87d32dd766020c06273ec70ff449806347941b 100644
--- a/src/main/java/org/olat/group/BusinessGroupManager.java
+++ b/src/main/java/org/olat/group/BusinessGroupManager.java
@@ -22,6 +22,7 @@
 package org.olat.group;
 
 import java.io.File;
+import java.util.Collection;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -34,6 +35,7 @@ import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.group.context.BGContext;
 import org.olat.group.ui.BGConfigFlags;
+import org.olat.resource.OLATResource;
 
 /**
  * Description: <br>
@@ -118,6 +120,15 @@ public interface BusinessGroupManager {
 	 * @return The group or null if not found
 	 */
 	public BusinessGroup findBusinessGroup(SecurityGroup secGroup);
+
+	/**
+	 * 
+	 * @param nameOrDesc name or description of this group (put in a like search)
+	 * @param type Restrict find to this group type or null if not restricted to a
+	 *          specific type
+	 * @return
+	 */
+	public List<BusinessGroup> findBusinessGroup(String nameOrDesc, String type);
 	
 	/**
 	 * commit the changes on a BusinessGroup instance to the persistence store
@@ -191,6 +202,15 @@ public interface BusinessGroupManager {
 	 * @return THe loaded group
 	 */
 	public BusinessGroup loadBusinessGroup(Long groupKey, boolean strict);
+	
+	/**
+	 * @param resource The OLAT resource
+	 * @param strict true: will throw exception if load failed false: will return
+	 *          null if not found
+	 * @return The loaded group
+	 */
+	 //fxdiff VCRP-1,2: access control of resources
+	public BusinessGroup loadBusinessGroup(OLATResource resource, boolean strict);
 
 	/**
 	 * Create and persist a new business group based on a source group.
@@ -367,6 +387,11 @@ public interface BusinessGroupManager {
 	 */
 	public List findBusinessGroupsWithWaitingListAttendedBy(String groupType, Identity identity, BGContext bgContext);
 
+	//fxdiff VCRP-1,2: access control of resources
+	public List<BusinessGroup> findBusinessGroups(Collection<String> types, Identity identityP, Long id, String name, String description, String owner);
+	
+	public List<BusinessGroup> findBusinessGroups(Collection<Long> keys);
+	
 	/**
 	 * Get postion of an idenity on a certain waiting-list 
 	 * @param identity
@@ -413,6 +438,10 @@ public interface BusinessGroupManager {
    */
 	public void removeOwnersAndFireEvent(Identity ureqIdentity, List<Identity> addIdentities, BusinessGroup currBusinessGroup, BGConfigFlags flags);
 
+	//fxdiff VCRP-1,2: access control of resources
+	public void removeAndFireEvent(Identity ureqIdentity, List<Identity> addIdentities, SecurityGroup secGroup);
+
+	
   /**
    * Remove a list of identity as participant from a business-group.
    * @param ureqIdentity       This identity triggered the method (typically identity of user-request).
@@ -444,6 +473,9 @@ public interface BusinessGroupManager {
    */
 	public void removeFromWaitingListAndFireEvent(Identity ureqIdentity, List<Identity> identities, BusinessGroup currBusinessGroup, BGConfigFlags flags);
 
+	//fxdiff VCRP-1,2: access control of resources
+	public BusinessGroupAddResponse addToSecurityGroupAndFireEvent(Identity ureqIdentity, List<Identity> addIdentities, SecurityGroup secGroup);
+	
 	public void exportGroup(BusinessGroup businessGroup, File file);
 
 	public void archiveGroups(BGContext context, File exportFile);
diff --git a/src/main/java/org/olat/group/BusinessGroupManagerImpl.java b/src/main/java/org/olat/group/BusinessGroupManagerImpl.java
index 19fb030b3049dfd60575ec40135d614d4228e1ae..fc1263092060f81b020f286a0badd0c649662ea3 100644
--- a/src/main/java/org/olat/group/BusinessGroupManagerImpl.java
+++ b/src/main/java/org/olat/group/BusinessGroupManagerImpl.java
@@ -26,6 +26,7 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.lang.reflect.Field;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashSet;
@@ -40,6 +41,7 @@ import org.olat.admin.user.delete.service.UserDeletionManager;
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.BaseSecurityManager;
 import org.olat.basesecurity.Constants;
+import org.olat.basesecurity.IdentityImpl;
 import org.olat.basesecurity.SecurityGroup;
 import org.olat.basesecurity.SecurityGroupMembershipImpl;
 import org.olat.collaboration.CollaborationTools;
@@ -62,6 +64,7 @@ import org.olat.core.logging.activity.ActionType;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
 import org.olat.core.manager.BasicManager;
 import org.olat.core.util.FileUtils;
+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;
@@ -92,8 +95,11 @@ import org.olat.notifications.NotificationsManagerImpl;
 import org.olat.properties.Property;
 import org.olat.repository.RepoJumpInHandlerFactory;
 import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryManager;
+import org.olat.resource.OLATResource;
 import org.olat.testutils.codepoints.server.Codepoint;
 import org.olat.user.UserDataDeletable;
+import org.olat.user.UserImpl;
 import org.olat.util.logging.activity.LoggingResourceable;
 
 /**
@@ -113,6 +119,8 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 	private BaseSecurity securityManager;
 	private List<DeletableGroupData> deleteListeners;
 	
+	private String dbVendor;
+	
 	/**
 	 * @return singleton instance
 	 */
@@ -129,6 +137,15 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 		deleteListeners = new ArrayList<DeletableGroupData>();
 		INSTANCE = this;
 	}
+	
+	/**
+	 * [used by Spring]
+	 * @param dbVendor
+	 */
+	 //fxdiff VCRP-1,2: access control of resources
+  public void setDbVendor(String dbVendor) {
+		this.dbVendor = dbVendor;
+	}
 
   /** 
    * @see org.olat.group.BusinessGroupManager#createAndPersistBusinessGroup(java.lang.String, org.olat.core.id.Identity, java.lang.String, java.lang.String, java.lang.Integer, java.lang.Integer, java.lang.Boolean, java.lang.Boolean, org.olat.group.context.BGContext)
@@ -150,7 +167,7 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 	 * @param groupContext
 	 * @return
 	 */
-	protected boolean checkIfOneOrMoreNameExistsInContext(Set names, BGContext groupContext){
+	protected boolean checkIfOneOrMoreNameExistsInContext(Set<String> names, BGContext groupContext){
 		return BusinessGroupFactory.checkIfOneOrMoreNameExistsInContext(names, groupContext);
 	}
 	
@@ -158,7 +175,7 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 	 * @see org.olat.group.BusinessGroupManager#findBusinessGroupsOwnedBy(java.lang.String,
 	 *      org.olat.core.id.Identity, org.olat.group.context.BGContext)
 	 */
-	public List findBusinessGroupsOwnedBy(String type, Identity identityP, BGContext bgContext) {
+	public List<BusinessGroup> findBusinessGroupsOwnedBy(String type, Identity identityP, BGContext bgContext) {
 		// attach group context to session - maybe a proxy...
 		String query = "select bgi from " + " org.olat.basesecurity.SecurityGroupMembershipImpl as sgmi,"
 				+ " org.olat.group.BusinessGroupImpl as bgi" + " where bgi.ownerGroup = sgmi.securityGroup and sgmi.identity = :identId";
@@ -179,7 +196,7 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 		if (bgContext != null) dbq.setEntity("context", bgContext);
 		if (type != null) dbq.setString("type", type);
 
-		List res = dbq.list();
+		List<BusinessGroup> res = dbq.list();
 		return res;
 	}
 
@@ -187,7 +204,7 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 	 * @see org.olat.group.BusinessGroupManager#findBusinessGroupsAttendedBy(java.lang.String,
 	 *      org.olat.core.id.Identity, org.olat.group.context.BGContext)
 	 */
-	public List findBusinessGroupsAttendedBy(String type, Identity identityP, BGContext bgContext) {
+	public List<BusinessGroup> findBusinessGroupsAttendedBy(String type, Identity identityP, BGContext bgContext) {
 		String query = "select bgi from " + "  org.olat.group.BusinessGroupImpl as bgi "
 				+ ", org.olat.basesecurity.SecurityGroupMembershipImpl as sgmi"
 				+ " where bgi.partipiciantGroup = sgmi.securityGroup";
@@ -201,7 +218,22 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 		if (bgContext != null) dbq.setEntity("context", bgContext);
 		if (type != null) dbq.setString("type", type);
 
-		List res = dbq.list();
+		List<BusinessGroup> res = dbq.list();
+		return res;
+	}
+	
+	public List<BusinessGroup> findBusinessGroups(Collection<Long> keys) {
+		if(keys == null || keys.isEmpty()) return Collections.emptyList();
+		
+		StringBuilder sb = new StringBuilder();
+		sb.append("select bgi from ").append(BusinessGroupImpl.class.getName()).append(" as bgi ")
+			.append(" where bgi.key in (:keys)");
+
+		DB db = DBFactory.getInstance();
+		DBQuery dbq = db.createQuery(sb.toString());
+		dbq.setParameterList("keys", keys);
+
+		List<BusinessGroup> res = dbq.list();
 		return res;
 	}
 	
@@ -296,7 +328,7 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 	 * 
 	 * @see org.olat.group.BusinessGroupManager#getAllBusinessGroups()
 	 */
-	public List getAllBusinessGroups() {
+	public List<BusinessGroup> getAllBusinessGroups() {
 		DBQuery dbq = DBFactory.getInstance().createQuery("select bgi from " + "  org.olat.group.BusinessGroupImpl as bgi ");
 		return dbq.list();
 	}
@@ -305,7 +337,7 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 	 * @see org.olat.group.BusinessGroupManager#findBusinessGroupsAttendedBy(java.lang.String,
 	 *      org.olat.core.id.Identity, org.olat.group.context.BGContext)
 	 */
-	public List findBusinessGroupsWithWaitingListAttendedBy(String type, Identity identityP, BGContext bgContext) {
+	public List<BusinessGroup> findBusinessGroupsWithWaitingListAttendedBy(String type, Identity identityP, BGContext bgContext) {
 		String query = "select bgi from " + "  org.olat.group.BusinessGroupImpl as bgi "
 				+ ", org.olat.basesecurity.SecurityGroupMembershipImpl as sgmi"
 				+ " where bgi.waitingGroup = sgmi.securityGroup and sgmi.identity = :identId";
@@ -318,10 +350,102 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 		if (bgContext != null) dbq.setEntity("context", bgContext);
 		if (type != null) dbq.setString("type", type);
 
-		List res = dbq.list();
+		List<BusinessGroup> res = dbq.list();
 		return res;
 	}
 	
+	/**
+	 * @see org.olat.group.BusinessGroupManager#findBusinessGroupsAttendedBy(java.lang.String,
+	 *      org.olat.core.id.Identity, org.olat.group.context.BGContext)
+	 */
+	 //fxdiff VCRP-1,2: access control of resources
+	public List<BusinessGroup> findBusinessGroups(Collection<String> types, Identity identityP, Long id, String name, String description, String owner) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select distinct(bgi) from ").append(BusinessGroupImpl.class.getName()).append(" as bgi");
+
+		boolean where = false;
+		//fuzzy search owner (like author in repository search)
+		if(StringHelper.containsNonWhitespace(owner)) {
+			//implicit joins
+			sb.append(", ").append(SecurityGroupMembershipImpl.class.getName()).append(" as sgmi ")
+				.append(", ").append(IdentityImpl.class.getName()).append(" identity")
+				.append(", ").append(UserImpl.class.getName()).append(" user ");
+
+			where = true;
+			sb.append(" where bgi.ownerGroup = sgmi.securityGroup")
+				.append(" and sgmi.identity = identity ")
+				.append(" and identity.user = user and ");
+			
+			//query the name in login, firstName and lastName
+			sb.append("(");
+			searchLikeUserProperty(sb, "firstName", "owner").append(" or ");
+			searchLikeUserProperty(sb, "lastName", "owner").append(" or ");
+			searchLikeAttribute(sb, "identity", "name", "owner").append(")");
+		}
+
+		if(id != null) {
+			where = where(sb, where);
+			sb.append(" bgi.key=:id");
+		}
+		if(StringHelper.containsNonWhitespace(name)) {
+			where = where(sb, where);
+			searchLikeAttribute(sb, "bgi", "name", "name");
+		}
+		if(StringHelper.containsNonWhitespace(description)) {
+			where = where(sb, where);
+			searchLikeAttribute(sb, "bgi", "description", "description");
+		}
+		if (types != null && !types.isEmpty()) {
+			where = where(sb, where);
+			sb.append("bgi.type in (:types)");
+		}
+
+		DB db = DBFactory.getInstance();
+		DBQuery query = db.createQuery(sb.toString());
+		if(id != null) {
+			query.setLong("id", id);
+		}
+		if(StringHelper.containsNonWhitespace(name)) {
+			query.setParameter("name", makeFuzzyQueryString(name));
+		}
+		if(StringHelper.containsNonWhitespace(description)) {
+			query.setParameter("description", makeFuzzyQueryString(description));
+		}
+		if(StringHelper.containsNonWhitespace(owner)) {
+			query.setParameter("owner", makeFuzzyQueryString(owner));
+		}
+		if (types != null && !types.isEmpty()) {
+			query.setParameterList("types", types);
+		}
+
+		List<BusinessGroup> res = query.list();
+		return res;
+	}
+	
+	private StringBuilder searchLikeUserProperty(StringBuilder sb, String key, String var) {
+		if(dbVendor.equals("mysql")) {
+			sb.append(" user.properties['").append(key).append("'] like :").append(var);
+		} else {
+			sb.append(" lower(user.properties['").append(key).append("']) like :").append(var);
+			if(dbVendor.equals("hsqldb") || dbVendor.equals("oracle")) {
+	 	 		sb.append(" escape '\\'");
+	 	 	}
+		}
+		return sb;
+	}
+	
+	private StringBuilder searchLikeAttribute(StringBuilder sb, String objName, String attribute, String var) {
+		if(dbVendor.equals("mysql")) {
+			sb.append(" ").append(objName).append(".").append(attribute).append(" like :").append(var);
+		} else {
+			sb.append(" lower(").append(objName).append(".").append(attribute).append(") like :").append(var);
+			if(dbVendor.equals("hsqldb") || dbVendor.equals("oracle")) {
+	 	 		sb.append(" escape '\\'");
+	 	 	}
+		}
+		return sb;
+	}
+	
 	private boolean where(StringBuilder sb, boolean where) {
 		if(where) {
 			sb.append(" and ");
@@ -331,6 +455,19 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 		return true;
 	}
 	
+	private String makeFuzzyQueryString(String string) {
+		// By default only fuzzyfy at the end. Usually it makes no sense to do a
+		// fuzzy search with % at the beginning, but it makes the query very very
+		// slow since it can not use any index and must perform a fulltext search.
+		// User can always use * to make it a really fuzzy search query
+		string = string.replace('*', '%');
+		string = string + "%";
+		// with 'LIKE' the character '_' is a wildcard which matches exactly one character.
+		// To test for literal instances of '_', we have to escape it.
+		string = string.replace("_", "\\_");
+		return string.toLowerCase();
+	}
+	
 	/**
 	 * @see org.olat.group.BusinessGroupManager#findBusinessGroup(org.olat.basesecurity.SecurityGroup)
 	 */
@@ -370,7 +507,9 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 			businessGroupTodelete = loadBusinessGroup(businessGroupTodelete);
 			// 0) Loop over all deletableGroupData
 			for (DeletableGroupData deleteListener : deleteListeners) {
-				logDebug("deleteBusinessGroup: call deleteListener=" + deleteListener);
+				if(isLogDebugEnabled()) {
+					logDebug("deleteBusinessGroup: call deleteListener=" + deleteListener);
+				}
 				deleteListener.deleteGroupDataFor(businessGroupTodelete);
 			} 
 			ProjectBrokerManagerFactory.getProjectBrokerManager().deleteGroupDataFor(businessGroupTodelete);
@@ -380,6 +519,8 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 			// 1.b)delete display member property
 			BusinessGroupPropertyManager bgpm = new BusinessGroupPropertyManager(businessGroupTodelete);
 			bgpm.deleteDisplayMembers();
+			// 1.c)delete user in security groups
+			removeFromRepositoryEntrySecurityGroup(businessGroupTodelete);
 			// 2) Delete the group areas
 			if (BusinessGroup.TYPE_LEARNINGROUP.equals(type)) {
 				BGAreaManagerImpl.getInstance().deleteBGtoAreaRelations(businessGroupTodelete);
@@ -421,7 +562,40 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 			}
 		}
 	}
-
+	
+	private void removeFromRepositoryEntrySecurityGroup(BusinessGroup group) {
+		BGContext context = group.getGroupContext();
+		if(context == null) return;//nothing to do
+		
+		BGContextManager contextManager = BGContextManagerImpl.getInstance();
+		List<Identity> coaches = group.getOwnerGroup() == null ? Collections.<Identity>emptyList() :
+			securityManager.getIdentitiesOfSecurityGroup(group.getOwnerGroup());
+		List<Identity> participants = group.getPartipiciantGroup() == null ? Collections.<Identity>emptyList() :
+			securityManager.getIdentitiesOfSecurityGroup(group.getPartipiciantGroup());
+		List<RepositoryEntry> entries = contextManager.findRepositoryEntriesForBGContext(context);
+		
+		for(Identity coach:coaches) {
+			List<BusinessGroup> businessGroups = contextManager.getBusinessGroupAsOwnerOfBGContext(coach, context) ;
+			if(context.isDefaultContext() && businessGroups.size() == 1) {
+				for(RepositoryEntry entry:entries) {
+					if(entry.getTutorGroup() != null && securityManager.isIdentityInSecurityGroup(coach, entry.getTutorGroup())) {
+						securityManager.removeIdentityFromSecurityGroup(coach, entry.getTutorGroup());
+					}
+				}
+			}
+		}
+		
+		for(Identity participant:participants) {
+			List<BusinessGroup> businessGroups = contextManager.getBusinessGroupAsParticipantOfBGContext(participant, context) ;
+			if(context.isDefaultContext() && businessGroups.size() == 1) {
+				for(RepositoryEntry entry:entries) {
+					if(entry.getParticipantGroup() != null && securityManager.isIdentityInSecurityGroup(participant, entry.getParticipantGroup())) {
+						securityManager.removeIdentityFromSecurityGroup(participant, entry.getParticipantGroup());
+					}
+				}
+			}
+		}
+	}
 	/**
 	 * @see org.olat.group.BusinessGroupManager#deleteBusinessGroupWithMail(org.olat.group.BusinessGroup,
 	 *      org.olat.core.gui.control.WindowControl, org.olat.core.gui.UserRequest,
@@ -433,20 +607,20 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 		
 		// collect data for mail
 		BaseSecurity secMgr = BaseSecurityManager.getInstance();
-		List users = new ArrayList();
+		List<Identity> users = new ArrayList<Identity>();
 		SecurityGroup ownerGroup = businessGroupTodelete.getOwnerGroup();
 		if (ownerGroup != null) {
-			List owner = secMgr.getIdentitiesOfSecurityGroup(ownerGroup);
+			List<Identity> owner = secMgr.getIdentitiesOfSecurityGroup(ownerGroup);
 			users.addAll(owner);
 		}
 		SecurityGroup partGroup = businessGroupTodelete.getPartipiciantGroup();
 		if (partGroup != null) {
-			List participants = secMgr.getIdentitiesOfSecurityGroup(partGroup);
+			List<Identity> participants = secMgr.getIdentitiesOfSecurityGroup(partGroup);
 			users.addAll(participants);
 		}
 		SecurityGroup watiGroup = businessGroupTodelete.getWaitingGroup();
 		if (watiGroup != null) {
-			List waiting = secMgr.getIdentitiesOfSecurityGroup(watiGroup);
+			List<Identity> waiting = secMgr.getIdentitiesOfSecurityGroup(watiGroup);
 			users.addAll(waiting);
 		}
 		// now delete the group first
@@ -455,8 +629,10 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 		MailerWithTemplate mailer = MailerWithTemplate.getInstance();
 		MailTemplate mailTemplate = BGMailHelper.createDeleteGroupMailTemplate(businessGroupTodelete, ureq.getIdentity());
 		if (mailTemplate != null) {
-			MailerResult mailerResult = mailer.sendMailAsSeparateMails(users, null, null, mailTemplate, null);
-			MailHelper.printErrorsAndWarnings(mailerResult, wControl, ureq.getLocale());
+			//fxdiff VCRP-16: intern mail system
+		//TODO SR MailContext context = new MailContextImpl(wControl.getBusinessControl().getAsString());
+		//TODO SR MailerResult mailerResult = mailer.sendMailAsSeparateMails(context, users, null, null, mailTemplate, null);
+		//TODO SR MailHelper.printErrorsAndWarnings(mailerResult, wControl, ureq.getLocale());
 		}
 		
 	}
@@ -587,6 +763,21 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 		if (strict) return (BusinessGroup) DBFactory.getInstance().loadObject(BusinessGroupImpl.class, groupKey);
 		return (BusinessGroup) DBFactory.getInstance().findObject(BusinessGroupImpl.class, groupKey);
 	}
+	
+	public BusinessGroup loadBusinessGroup(String groupKey, boolean strict) {
+		Long key = Long.parseLong(groupKey); 
+		return loadBusinessGroup(key, strict);
+	}
+	
+	/**
+	 * @see org.olat.group.BusinessGroupManager#loadBusinessGroup(java.lang.Long,
+	 *      boolean)
+	 */
+	@Override
+	//fxdiff VCRP-1,2: access control of resources
+	public BusinessGroup loadBusinessGroup(OLATResource resource, boolean strict) {
+		return loadBusinessGroup(resource.getResourceableId(), strict);
+	}
 
 	/**
 	 * @see org.olat.group.BusinessGroupManager#copyBusinessGroup(org.olat.group.BusinessGroup,
@@ -693,6 +884,20 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 			boolean doOnlyPostAddingStuff) {
 		CoordinatorManager.getInstance().getCoordinator().getSyncer().assertAlreadyDoInSyncFor(group);
 		if (!doOnlyPostAddingStuff) {
+			//fxdiff VCRP-1,2: access control of resources
+			BGContext context = group.getGroupContext();
+			if(context != null) {
+				List<RepositoryEntry> res = BGContextManagerImpl.getInstance().findRepositoryEntriesForBGContext(context);
+				for(RepositoryEntry re:res) {
+					if(re.getParticipantGroup() == null) {
+						RepositoryManager.getInstance().createParticipantSecurityGroup(re);
+						RepositoryManager.getInstance().updateRepositoryEntry(re);
+					}
+					if(re.getParticipantGroup() != null && !securityManager.isIdentityInSecurityGroup(identity, re.getParticipantGroup())) {
+						securityManager.addIdentityToSecurityGroup(identity, re.getParticipantGroup());
+					}
+				}
+			}
 			securityManager.addIdentityToSecurityGroup(identity, group.getPartipiciantGroup());
 		}
 		// add user to buddies rosters
@@ -700,7 +905,7 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 		// notify currently active users of this business group
 		BusinessGroupModifiedEvent.fireModifiedGroupEvents(BusinessGroupModifiedEvent.IDENTITY_ADDED_EVENT, group, identity);
 		// do logging
-		ThreadLocalUserActivityLogger.log(GroupLoggingAction.GROUP_PARTICIPANT_ADDED, getClass(), LoggingResourceable.wrap(identity));
+		ThreadLocalUserActivityLogger.log(GroupLoggingAction.GROUP_PARTICIPANT_ADDED, getClass(), LoggingResourceable.wrap(group), LoggingResourceable.wrap(identity));
 		// send notification mail in your controller!
 	}
 
@@ -714,6 +919,20 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 	public void addOwnerAndFireEvent(Identity ureqIdentity, Identity identity, BusinessGroup group, BGConfigFlags flags, 
 			boolean doOnlyPostAddingStuff) {
 		if (!doOnlyPostAddingStuff) {
+			//fxdiff VCRP-1,2: access control of resources
+			BGContext context = group.getGroupContext();
+			if(context != null) {
+				List<RepositoryEntry> res = BGContextManagerImpl.getInstance().findRepositoryEntriesForBGContext(context);
+				for(RepositoryEntry re:res) {
+					if(re.getTutorGroup() == null) {
+						RepositoryManager.getInstance().createTutorSecurityGroup(re);
+						RepositoryManager.getInstance().updateRepositoryEntry(re);
+					}
+					if(re.getTutorGroup() != null && !securityManager.isIdentityInSecurityGroup(identity, re.getTutorGroup())) {
+						securityManager.addIdentityToSecurityGroup(identity, re.getTutorGroup());
+					}
+				}
+			}
 			securityManager.addIdentityToSecurityGroup(identity, group.getOwnerGroup());
 		}
 		// add user to buddies rosters
@@ -721,9 +940,34 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 		// notify currently active users of this business group
 		BusinessGroupModifiedEvent.fireModifiedGroupEvents(BusinessGroupModifiedEvent.IDENTITY_ADDED_EVENT, group, identity);
 		// do logging
+		ThreadLocalUserActivityLogger.log(GroupLoggingAction.GROUP_OWNER_ADDED, getClass(), LoggingResourceable.wrap(group), LoggingResourceable.wrap(identity));
+		// send notification mail in your controller!
+	}
+	
+	//fxdiff VCRP-1,2: access control of resources
+	public void addAndFireEvent(Identity ureqIdentity, Identity identity, SecurityGroup secGroup, boolean doOnlyPostAddingStuff) {
+		if (!doOnlyPostAddingStuff) {
+			securityManager.addIdentityToSecurityGroup(identity, secGroup);
+		}
+		// add user to buddies rosters
+		// notify currently active users of this business group
+		//TODO BusinessGroupModifiedEvent.fireModifiedGroupEvents(BusinessGroupModifiedEvent.IDENTITY_ADDED_EVENT, group, identity);
+		// do logging
 		ThreadLocalUserActivityLogger.log(GroupLoggingAction.GROUP_OWNER_ADDED, getClass(), LoggingResourceable.wrap(identity));
 		// send notification mail in your controller!
 	}
+	
+	//fxdiff VCRP-1,2: access control of resources
+	public void removeAndFireEvent(Identity ureqIdentity, Identity identity, SecurityGroup secGroup, boolean doOnlyPostRemovingStuff) {
+		if(!doOnlyPostRemovingStuff) {
+			securityManager.removeIdentityFromSecurityGroup(identity, secGroup);
+		}
+		// remove user from buddies rosters
+		//TODO removeFromRoster(identity, group, flags);
+		
+		//remove subsciptions if user gets removed
+		//TODO removeSubscriptions(identity, group);
+	}
 
 	/**
 	 * @see org.olat.group.BusinessGroupManager#removeOwner(org.olat.core.gui.control.WindowControl,
@@ -735,6 +979,20 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 	public void removeOwnerAndFireEvent(Identity ureqIdentity, Identity identity, BusinessGroup group, BGConfigFlags flags,
 			boolean doOnlyPostRemovingStuff) {
 		if (!doOnlyPostRemovingStuff) {
+			//fxdiff VCRP-2: access control
+			BGContext context = group.getGroupContext();
+			if(context != null) {
+				BGContextManager contextManager = BGContextManagerImpl.getInstance();
+				List<BusinessGroup> businessGroups = contextManager.getBusinessGroupAsOwnerOfBGContext(identity, context) ;
+				if(context.isDefaultContext() && businessGroups.size() == 1) {
+					List<RepositoryEntry> entries = contextManager.findRepositoryEntriesForBGContext(context);
+					for(RepositoryEntry entry:entries) {
+						if(entry.getTutorGroup() != null && securityManager.isIdentityInSecurityGroup(identity, entry.getTutorGroup())) {
+							securityManager.removeIdentityFromSecurityGroup(identity, entry.getTutorGroup());
+						}
+					}
+				}
+			}
 			securityManager.removeIdentityFromSecurityGroup(identity, group.getOwnerGroup());
 		}
 		// remove user from buddies rosters
@@ -766,6 +1024,20 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 			final boolean doOnlyPostRemovingStuff) {
 		CoordinatorManager.getInstance().getCoordinator().getSyncer().assertAlreadyDoInSyncFor(group);
 		if (!doOnlyPostRemovingStuff) {
+			//fxdiff VCRP-2: access control
+			BGContext context = group.getGroupContext();
+			if(context != null) {
+				BGContextManager contextManager = BGContextManagerImpl.getInstance();
+				List<BusinessGroup> businessGroups = contextManager.getBusinessGroupAsParticipantOfBGContext(identity, context) ;
+				if(context.isDefaultContext() && businessGroups.size() == 1) {
+					List<RepositoryEntry> entries = contextManager.findRepositoryEntriesForBGContext(context);
+					for(RepositoryEntry entry:entries) {
+						if(entry.getParticipantGroup() != null && securityManager.isIdentityInSecurityGroup(identity, entry.getParticipantGroup())) {
+							securityManager.removeIdentityFromSecurityGroup(identity, entry.getParticipantGroup());
+						}
+					}
+				}
+			}
 			securityManager.removeIdentityFromSecurityGroup(identity, group.getPartipiciantGroup());
 		}
 		// remove user from buddies rosters
@@ -905,6 +1177,7 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 		if (calendarAccess != null) {
 			newGroup.calendarAccess = calendarAccess;
 		}
+
 		String info = ct.lookupNews();
 		if (info != null && !info.trim().equals("")) {
 			newGroup.info = info.trim();
@@ -1019,6 +1292,10 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 					Long calendarAccess = group.calendarAccess;
 					ct.saveCalendarAccess(calendarAccess);
 				}
+				//fxdiff VCRP-8: collaboration tools folder access control
+			//TODO SR if(group.folderAccess != null) {
+			//TODO SR 	  ct.saveFolderAccess(group.folderAccess);				  
+			//TODO SR 	}
 				if (group.info != null) {
 					ct.saveNews(group.info);
 				}
@@ -1095,6 +1372,29 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 		}
 		return pos;
 	}
+	
+	@Override
+	//fxdiff VCRP-1,2: access control of resources
+	public BusinessGroupAddResponse addToSecurityGroupAndFireEvent(Identity ureqIdentity, List<Identity> addIdentities, SecurityGroup secGroup) {
+		BusinessGroupAddResponse response = new BusinessGroupAddResponse();
+		for (Identity identity : addIdentities) {
+			if (securityManager.isIdentityPermittedOnResourceable(identity, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_GUESTONLY)) {
+				response.getIdentitiesWithoutPermission().add(identity);
+			}
+			// Check if identity is already in group. make a db query in case
+			// someone in another workflow already added this user to this group. if
+			// found, add user to model
+			else if (securityManager.isIdentityInSecurityGroup(identity, secGroup)) {
+				response.getIdentitiesAlreadyInGroup().add(identity);
+			} else {
+	      // identity has permission and is not already in group => add it
+				addAndFireEvent(ureqIdentity, identity, secGroup, false);
+				response.getAddedIdentities().add(identity);
+				logAudit("added identity '" + identity.getName() + "' to securitygroup with key " + secGroup.getKey());
+			}
+		}
+		return response;
+	}
 
 	/**
 	 * 
@@ -1179,6 +1479,15 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 				}});
 		return response;
 	}
+	
+	@Override
+	//fxdiff VCRP-1,2: access control of resources
+	public void removeAndFireEvent(Identity ureqIdentity, List<Identity> identities, SecurityGroup secGroup) {
+		for (Identity identity : identities) {
+		  removeAndFireEvent(ureqIdentity, identity, secGroup, false);
+		  logAudit("removed identiy '" + identity.getName() + "' from securitygroup with key " + secGroup.getKey());
+		}
+	}
 
 	/**
 	 * 
@@ -1333,7 +1642,9 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 						MailTemplate mailTemplate = BGMailHelper.createWaitinglistTransferMailTemplate(group, ureqIdentity);
 						if (mailTemplate != null) {
 							MailerWithTemplate mailer = MailerWithTemplate.getInstance();
-							MailerResult mailerResult = mailer.sendMail(firstWaitingListIdentity, null, null, mailTemplate, null);
+							//fxdiff VCRP-16: intern mail system
+						//TODO SR MailContext context = new MailContextImpl("[BusinessGroup:" + group.getKey() + "]");
+							//TODO SR MailerResult mailerResult = mailer.sendMail(context, firstWaitingListIdentity, null, null, mailTemplate, null);
 							// Does not report errors to current screen because this is the identity who triggered the transfer
 							Tracing.logWarn("Could not send WaitinglistTransferMail for identity=" + firstWaitingListIdentity.getName() , BusinessGroupManagerImpl.class);
 						}						
@@ -1354,22 +1665,22 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 	 */
 	public void deleteUserData(Identity identity, String newDeletedUserName) {
 		// remove as Participant 
-		List attendedGroups = findAllBusinessGroupsAttendedBy(identity);
-		for (Iterator iter = attendedGroups.iterator(); iter.hasNext();) {
-			securityManager.removeIdentityFromSecurityGroup(identity, ((BusinessGroup)iter.next()).getPartipiciantGroup());
+		List<BusinessGroup> attendedGroups = findAllBusinessGroupsAttendedBy(identity);
+		for (Iterator<BusinessGroup> iter = attendedGroups.iterator(); iter.hasNext();) {
+			securityManager.removeIdentityFromSecurityGroup(identity, iter.next().getPartipiciantGroup());
 		}
 		Tracing.logDebug("Remove partipiciant identity=" + identity + " from " + attendedGroups.size() + " groups", this.getClass());
 		// remove from waitinglist 
-		List waitingGroups = findBusinessGroupsWithWaitingListAttendedBy(identity);
-		for (Iterator iter = waitingGroups.iterator(); iter.hasNext();) {
-			securityManager.removeIdentityFromSecurityGroup(identity, ((BusinessGroup)iter.next()).getWaitingGroup());
+		List<BusinessGroup> waitingGroups = findBusinessGroupsWithWaitingListAttendedBy(identity);
+		for (Iterator<BusinessGroup> iter = waitingGroups.iterator(); iter.hasNext();) {
+			securityManager.removeIdentityFromSecurityGroup(identity, iter.next().getWaitingGroup());
 		}
 		Tracing.logDebug("Remove from waiting-list identity=" + identity + " in " + waitingGroups.size() + " groups", this.getClass());
 
 		// remove as owner
-		List ownerGroups = findAllBusinessGroupsOwnedBy(identity);
-		for (Iterator iter = ownerGroups.iterator(); iter.hasNext();) {
-			BusinessGroup businessGroup = (BusinessGroup) iter.next();
+		List<BusinessGroup> ownerGroups = findAllBusinessGroupsOwnedBy(identity);
+		for (Iterator<BusinessGroup> iter = ownerGroups.iterator(); iter.hasNext();) {
+			BusinessGroup businessGroup = iter.next();
 			securityManager.removeIdentityFromSecurityGroup(identity, businessGroup.getOwnerGroup());
 			if (businessGroup.getType().equals(BusinessGroup.TYPE_BUDDYGROUP) && securityManager.countIdentitiesOfSecurityGroup(businessGroup.getOwnerGroup()) == 0 ) {
 				// Buddygroup has no owner anymore => add OLAT-Admin as owner
@@ -1381,15 +1692,15 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 		Tracing.logDebug("All entries in groups deleted for identity=" + identity, this.getClass());
 	}
 
-	private List findAllBusinessGroupsOwnedBy(Identity identity) {
+	private List<BusinessGroup> findAllBusinessGroupsOwnedBy(Identity identity) {
 		return findBusinessGroupsOwnedBy(null, identity, null);
 	}
 
-	private List findAllBusinessGroupsAttendedBy(Identity identity) {
+	private List<BusinessGroup> findAllBusinessGroupsAttendedBy(Identity identity) {
 		return findBusinessGroupsAttendedBy(null, identity, null);
 	}
 	
-	private List findBusinessGroupsWithWaitingListAttendedBy(Identity identity) {
+	private List<BusinessGroup> findBusinessGroupsWithWaitingListAttendedBy(Identity identity) {
 		return findBusinessGroupsWithWaitingListAttendedBy(null, identity, null);
 	}
 
@@ -1400,8 +1711,8 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 	private void removeSubscriptions(Identity identity, BusinessGroup group) {
 		NotificationsManager notiMgr = NotificationsManager.getInstance();
 		List<Subscriber> l = notiMgr.getSubscribers(identity);
-		for (Iterator iterator = l.iterator(); iterator.hasNext();) {
-			Subscriber subscriber = (Subscriber) iterator.next();
+		for (Iterator<Subscriber> iterator = l.iterator(); iterator.hasNext();) {
+			Subscriber subscriber = iterator.next();
 			Long resId = subscriber.getPublisher().getResId();
 			Long groupKey = group.getKey();
 			if (resId != null && groupKey != null && resId.equals(groupKey)) {
@@ -1472,4 +1783,20 @@ public class BusinessGroupManagerImpl extends BasicManager implements BusinessGr
 		return deletableList;
 	}
 
+	@Override
+	public List<BusinessGroup> findBusinessGroup(String nameOrDesc, String type) {
+		String query = "select bgi from " + "  org.olat.group.BusinessGroupImpl as bgi "
+		+ " where bgi.name like :search or bgi.description like :search";
+		if (type != null) query = query + " and bgi.type = :type";
+		
+		DB db = DBFactory.getInstance();
+		DBQuery dbq = db.createQuery(query);
+		if (type != null) dbq.setString("type", type);
+		
+		dbq.setString("search", nameOrDesc);
+		
+		List<BusinessGroup> res = dbq.list();
+		return res;
+	}
+
 }
diff --git a/src/main/java/org/olat/group/GroupLoggingAction.java b/src/main/java/org/olat/group/GroupLoggingAction.java
index f177fc65800332e05274bb14e7b3cb977806c46c..5b86ca60c71b0fe487721692a4cb1278d6c30b7c 100644
--- a/src/main/java/org/olat/group/GroupLoggingAction.java
+++ b/src/main/java/org/olat/group/GroupLoggingAction.java
@@ -59,7 +59,9 @@ public class GroupLoggingAction extends BaseLoggingAction {
 		// this is the standalone group admin case
 		or().addMandatory(OlatResourceableType.businessGroup, StringResourceableType.targetIdentity).
 		// this is the repository detail -> benutzer verwalten case
-		or().addMandatory(OlatResourceableType.course, StringResourceableType.targetIdentity);
+		or().addMandatory(OlatResourceableType.course, StringResourceableType.targetIdentity).
+		// the user import case with adding to group in same step
+		or().addMandatory(OlatResourceableType.businessGroup).addOptional(OlatResourceableType.businessGroup).addOptional(StringResourceableType.targetIdentity);
 	
 	public static final ILoggingAction GROUP_OPEN = 
 		new GroupLoggingAction(ActionType.tracking, CrudAction.retrieve, ActionVerb.open, ActionObject.group).setTypeList(
@@ -67,7 +69,8 @@ public class GroupLoggingAction extends BaseLoggingAction {
 	
 	public static final ILoggingAction GROUP_CLOSED = 
 		new GroupLoggingAction(ActionType.tracking, CrudAction.exit, ActionVerb.close, ActionObject.group).setTypeList(
-				new ResourceableTypeList().addMandatory(OlatResourceableType.businessGroup).addOptional(OlatResourceableType.course));
+				new ResourceableTypeList().addMandatory(OlatResourceableType.businessGroup).addOptional(OlatResourceableType.course).
+				or().addMandatory(OlatResourceableType.businessGroup).addOptional(StringResourceableType.targetIdentity, OlatResourceableType.sharedFolder, OlatResourceableType.genRepoEntry));
 	
 	/** logging action: group owner has been added to group * */
 	public static final ILoggingAction GROUP_OWNER_ADDED = 
diff --git a/src/main/java/org/olat/group/_spring/businessGroupContext.xml b/src/main/java/org/olat/group/_spring/businessGroupContext.xml
index 87f8f1d3672ffb570906e2f197727b483798bbad..b426ee717d0c155bc555a5355b989e024f1b76cc 100644
--- a/src/main/java/org/olat/group/_spring/businessGroupContext.xml
+++ b/src/main/java/org/olat/group/_spring/businessGroupContext.xml
@@ -16,6 +16,7 @@
 <bean id="businessGroupManager" class="org.olat.group.BusinessGroupManagerImpl" depends-on="collaborationToolsFactory">
 <constructor-arg index="0" ref="baseSecurityManager" />
 <constructor-arg index="1" ref="userDeletionManager" />
+<property name="dbVendor" value="${db.vendor}" />
 </bean>
 
 </beans>
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/context/BGContextManager.java b/src/main/java/org/olat/group/context/BGContextManager.java
index 8b8724138cefe0eab4ef74b2cc3d651096f3da59..64342d0e373af71c2ecfda8ec9790edb4d7d4e03 100644
--- a/src/main/java/org/olat/group/context/BGContextManager.java
+++ b/src/main/java/org/olat/group/context/BGContextManager.java
@@ -21,10 +21,12 @@
 
 package org.olat.group.context;
 
+import java.util.Collection;
 import java.util.List;
 
 import org.olat.core.id.Identity;
 import org.olat.group.BusinessGroup;
+import org.olat.repository.RepositoryEntry;
 import org.olat.resource.OLATResource;
 
 /**
@@ -120,6 +122,10 @@ public interface BGContextManager {
 	 * @return A list of identities
 	 */
 	public abstract List getBGOwnersOfBGContext(BGContext bgContext);
+	
+	//fxdiff VCRP-2: access control
+	public List<BusinessGroup> getBusinessGroupAsOwnerOfBGContext(Identity owner, BGContext bgContext);
+
 
 	/**
 	 * Count the number of identities that are owner of any group in the given
@@ -138,6 +144,9 @@ public interface BGContextManager {
 	 * @return A list of identities
 	 */
 	public abstract List getBGParticipantsOfBGContext(BGContext bgContext);
+	
+	//fxdiff VCRP-2: access control
+	public List<BusinessGroup> getBusinessGroupAsParticipantOfBGContext(Identity participant, BGContext bgContext);
 
 	/**
 	 * Count the number of identities that are participants of any group in the
@@ -263,7 +272,12 @@ public interface BGContextManager {
 	 * @param bgContext
 	 * @return List of repository entries
 	 */
-	public List findRepositoryEntriesForBGContext(BGContext bgContext);
+	public List<RepositoryEntry> findRepositoryEntriesForBGContext(BGContext bgContext);
+	//fxdiff VCRP-1,2: access control of resources
+	public List<RepositoryEntry> findRepositoryEntriesForBGContext(Collection<BGContext> bgContext);
+	//fxdiff VCRP-1,2: access control of resources
+	public List<RepositoryEntry> findRepositoryEntriesForBGContext(Collection<BGContext> bgContexts, int access, boolean asOwner, boolean asCoach,
+			boolean asParticipant,  Identity identity);
 
 	/**
 	 * Remove the given business group context from this OLATResource
diff --git a/src/main/java/org/olat/group/context/BGContextManagerImpl.java b/src/main/java/org/olat/group/context/BGContextManagerImpl.java
index 9ceeff97f87b24326c0e797d88a5921399e6a086..3fceb879502f759bd802f6602bdfdfdb1b225a0c 100644
--- a/src/main/java/org/olat/group/context/BGContextManagerImpl.java
+++ b/src/main/java/org/olat/group/context/BGContextManagerImpl.java
@@ -22,6 +22,8 @@
 package org.olat.group.context;
 
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -32,10 +34,12 @@ import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.BaseSecurityManager;
 import org.olat.basesecurity.Constants;
 import org.olat.basesecurity.SecurityGroup;
+import org.olat.basesecurity.SecurityGroupMembershipImpl;
 import org.olat.core.commons.persistence.DB;
 import org.olat.core.commons.persistence.DBFactory;
 import org.olat.core.commons.persistence.DBQuery;
 import org.olat.core.id.Identity;
+import org.olat.core.id.Roles;
 import org.olat.core.logging.AssertException;
 import org.olat.core.logging.Tracing;
 import org.olat.core.manager.BasicManager;
@@ -272,6 +276,21 @@ public class BGContextManagerImpl extends BasicManager implements BGContextManag
 		return query.list();
 	}
 
+	@Override
+	//fxdiff VCRP-2: access control
+	public List<BusinessGroup> getBusinessGroupAsOwnerOfBGContext(Identity owner, BGContext bgContext) {
+		DB db = DBFactory.getInstance();
+		StringBuilder sb = new StringBuilder();
+		sb.append("select bg from org.olat.group.BusinessGroupImpl bg")
+			.append(" ,org.olat.basesecurity.SecurityGroupMembershipImpl sgm")
+			.append(" where bg.groupContext=:context and bg.ownerGroup=sgm.securityGroup and sgm.identity=:id");
+
+		DBQuery query = db.createQuery(sb.toString());
+		query.setEntity("context", bgContext);
+		query.setEntity("id", owner);
+		return query.list();
+	}
+
 	/**
 	 * @see org.olat.group.context.BGContextManager#countBGOwnersOfBGContext(org.olat.group.context.BGContext)
 	 */
@@ -307,6 +326,21 @@ public class BGContextManagerImpl extends BasicManager implements BGContextManag
 		query.setEntity("context", bgContext);
 		return query.list();
 	}
+	
+	@Override
+	//fxdiff VCRP-2: access control
+	public List<BusinessGroup> getBusinessGroupAsParticipantOfBGContext(Identity participant, BGContext bgContext) {
+		DB db = DBFactory.getInstance();
+		StringBuilder sb = new StringBuilder();
+		sb.append("select bg from org.olat.group.BusinessGroupImpl bg")
+			.append(" ,org.olat.basesecurity.SecurityGroupMembershipImpl sgm")
+			.append(" where bg.groupContext=:context and bg.partipiciantGroup=sgm.securityGroup and sgm.identity=:id");
+
+		DBQuery query = db.createQuery(sb.toString());
+		query.setEntity("context", bgContext);
+		query.setEntity("id", participant);
+		return query.list();
+	}
 
 	/**
 	 * @see org.olat.group.context.BGContextManager#countBGParticipantsOfBGContext(org.olat.group.context.BGContext)
@@ -470,8 +504,8 @@ public class BGContextManagerImpl extends BasicManager implements BGContextManag
 	/**
 	 * @see org.olat.group.context.BGContextManager#findRepositoryEntriesForBGContext(org.olat.group.context.BGContext)
 	 */
-	public List findRepositoryEntriesForBGContext(BGContext bgContext) {
-		List resources = findOLATResourcesForBGContext(bgContext);
+	public List<RepositoryEntry> findRepositoryEntriesForBGContext(BGContext bgContext) {
+		/*List resources = findOLATResourcesForBGContext(bgContext);
 		List entries = new ArrayList();
 		for (Iterator iter = resources.iterator(); iter.hasNext();) {
 			OLATResource resource = (OLATResource) iter.next();
@@ -482,8 +516,83 @@ public class BGContextManagerImpl extends BasicManager implements BGContextManag
 			} else {
 				entries.add(entry);
 			}
+		}*/
+		//fxdiff VCRP-1,2: access control of resources
+		return findRepositoryEntriesForBGContext(Collections.singletonList(bgContext));
+	}
+	
+	@Override
+	//fxdiff VCRP-1,2: access control of resources
+	public List<RepositoryEntry> findRepositoryEntriesForBGContext(Collection<BGContext> bgContexts) {
+		if(bgContexts == null || bgContexts.isEmpty()) return Collections.emptyList();
+		DB db = DBFactory.getInstance();
+		StringBuilder sb = new StringBuilder();
+		sb.append("select v from ").append(RepositoryEntry.class.getName()).append(" as v ")
+			.append(" inner join fetch v.olatResource as ores ")
+			.append(" where ores in (")
+			.append("  select bgcr.resource from ").append(BGContext2Resource.class.getName()).append(" as bgcr where bgcr.groupContext in (:contexts)")
+			.append(" )");
+
+		DBQuery query = db.createQuery(sb.toString());
+		query.setParameterList("contexts", bgContexts);
+		return query.list();
+	}
+	
+	@Override
+	//fxdiff VCRP-1,2: access control of resources
+	public List<RepositoryEntry> findRepositoryEntriesForBGContext(Collection<BGContext> bgContexts, int access, boolean asOwner, boolean asCoach,
+			boolean asParticipant, Identity identity) {
+		if(bgContexts == null || bgContexts.isEmpty()) return Collections.emptyList();
+		
+		DB db = DBFactory.getInstance();
+		StringBuilder sb = new StringBuilder();
+		sb.append("select distinct v from ").append(RepositoryEntry.class.getName()).append(" as v ")
+			.append(" inner join fetch v.olatResource as ores ")
+			.append(" where ores in (")
+			.append("  select bgcr.resource from ").append(BGContext2Resource.class.getName()).append(" as bgcr where bgcr.groupContext in (:contexts)")
+			.append(" ) and ");
+		
+		boolean setIdentity = appendAccessSubSelects(sb, access, asOwner, asCoach, asParticipant, identity);
+
+		DBQuery query = db.createQuery(sb.toString());
+		query.setParameterList("contexts", bgContexts);
+		if(setIdentity) {
+			query.setEntity("identity", identity);
+		}
+		
+		List<RepositoryEntry> results = query.list();
+		return results;
+	}
+	
+	private boolean appendAccessSubSelects(StringBuilder sb, int access, boolean asOwner, boolean asCoach, boolean asParticipant, Identity identity) {
+		sb.append("(v.access >= ");
+		if (access == RepositoryEntry.ACC_OWNERS) {
+			sb.append(access).append(")");
+			return false;
+		}
+		sb.append(access);
+		boolean setIdentity = false;
+		if(identity != null && (asOwner || asCoach || asParticipant)) {
+			setIdentity = true;
+			//sub select are very quick
+			sb.append(" or (")
+				.append("  v.access=1 and v.membersOnly=true and (");
+			
+			if(asOwner) {
+				sb.append(" v.ownerGroup in (select ownerSgmsi.securityGroup from ").append(SecurityGroupMembershipImpl.class.getName()).append(" ownerSgmsi where ownerSgmsi.identity=:identity)");
+			}
+			if(asCoach) {
+				if(asOwner) sb.append(" or ");
+				sb.append(" v.tutorGroup in (select tutorSgmsi.securityGroup from ").append(SecurityGroupMembershipImpl.class.getName()).append(" tutorSgmsi where tutorSgmsi.identity=:identity)");
+			}
+			if(asParticipant) {
+				if(asOwner || asCoach) sb.append(" or ");
+				sb.append(" v.participantGroup in (select partiSgmsi.securityGroup from ").append(SecurityGroupMembershipImpl.class.getName()).append(" partiSgmsi where partiSgmsi.identity=:identity)");
+			}
+			sb.append(" ))");
 		}
-		return entries;
+		sb.append(")");
+		return setIdentity;
 	}
 
 	/**
diff --git a/src/main/java/org/olat/group/ui/BusinessGroupFormController.java b/src/main/java/org/olat/group/ui/BusinessGroupFormController.java
index 21fa15d7816b4e952787eb9077529004e84a4eb5..c18e3f6ece8161ddaf8fe0d23821b53c80d13d0b 100644
--- a/src/main/java/org/olat/group/ui/BusinessGroupFormController.java
+++ b/src/main/java/org/olat/group/ui/BusinessGroupFormController.java
@@ -22,6 +22,7 @@
 package org.olat.group.ui;
 
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 import org.olat.basesecurity.BaseSecurityManager;
@@ -35,6 +36,8 @@ import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
+import org.olat.core.id.context.BusinessControlFactory;
+import org.olat.core.id.context.ContextEntry;
 import org.olat.core.util.StringHelper;
 import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupFactory;
@@ -161,6 +164,13 @@ public class BusinessGroupFormController extends FormBasicController {
 		businessGroupDescription = uifactory.addRichTextElementForStringDataMinimalistic("create.form.title.description",
 				"create.form.title.description", "", 10, -1, false, formLayout, ureq.getUserSession(), getWindowControl());
 
+		if(businessGroup != null && !bulkMode) {
+			BusinessControlFactory bcf = BusinessControlFactory.getInstance();
+			List<ContextEntry> entries = bcf.createCEListFromString("[BusinessGroup:" + businessGroup.getKey() + "]");
+			String url = BusinessControlFactory.getInstance().getAsURIString(entries, true);
+			uifactory.addStaticTextElement("create.form.businesspath", url, formLayout);
+		}
+		
 		uifactory.addSpacerElement("myspacer", formLayout, true);
 
 		// Minimum members input
diff --git a/src/main/java/org/olat/group/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/group/ui/_i18n/LocalStrings_de.properties
index 7af2139acb0f0c73678a9b645e69065a0e9a97ee..727bb1dc920dc52dba7ff9fff4787e72fd61eec3 100644
--- a/src/main/java/org/olat/group/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/group/ui/_i18n/LocalStrings_de.properties
@@ -20,6 +20,7 @@ create.form.title.description=Beschreibung
 create.form.title.min=Mindestanzahl <br>Teilnehmer
 create.form.title.max=Vorgesehene Anzahl <br>Teilnehmer
 create.form.title.minmax.example=Falls unbeschr\u00E4nkt\: leer lassen
+create.form.businesspath=Link zu dieser Gruppe
 error.group.name.exists=Dieser Gruppenname wird in diesem Kontext bereits verwendet, w\u00E4hlen Sie einen anderen Namen.
 form.error.disableNonEmptyWaitingList=Die Warteliste ist nicht leer. Zum Ausschalten der Warteliste m\u00FCssen alle Teilnehmer ausgetragen werden.  
 group.type=Arbeitsgruppe
diff --git a/src/main/java/org/olat/group/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/group/ui/_i18n/LocalStrings_en.properties
index 094ec0c07a42430ea2376fd4db1b09434bec4380..15f9bb8eeaf021eefa151672308476bd4bd61877 100644
--- a/src/main/java/org/olat/group/ui/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/group/ui/_i18n/LocalStrings_en.properties
@@ -20,6 +20,7 @@ create.form.title.description=Description
 create.form.title.max=Maximum number of <br>participants
 create.form.title.min=Minimum number of <br>participants
 create.form.title.minmax.example=If unrestricted\: leave blank
+create.form.businesspath=Link to this group
 error.group.name.exists=This group name is already being used in this context, please select another one.
 form.error.disableNonEmptyWaitingList=Waiting list does contain data. In order to deactivate this list you have to delete all participants first. 
 group.type=Project group
diff --git a/src/main/java/org/olat/group/ui/edit/BusinessGroupEditAccessController.java b/src/main/java/org/olat/group/ui/edit/BusinessGroupEditAccessController.java
new file mode 100644
index 0000000000000000000000000000000000000000..fd5663def0420dec53c169bb7fd3f81c37fd3e67
--- /dev/null
+++ b/src/main/java/org/olat/group/ui/edit/BusinessGroupEditAccessController.java
@@ -0,0 +1,96 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.group.ui.edit;
+
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.util.Util;
+import org.olat.group.BusinessGroup;
+import org.olat.resource.OLATResource;
+import org.olat.resource.OLATResourceManager;
+import org.olat.resource.accesscontrol.AccessControlModule;
+import org.olat.resource.accesscontrol.ui.AccessConfigurationController;
+
+/**
+ * 
+ * Description:<br>
+ * Add a check box to the standard access control controller
+ * 
+ * <P>
+ * Initial Date:  26 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+//fxdiff VCRP-1,2: access control of resources
+public class BusinessGroupEditAccessController extends FormBasicController {
+	
+	private AccessConfigurationController configController;
+	
+	public BusinessGroupEditAccessController(UserRequest ureq, WindowControl wControl, BusinessGroup businessGroup) {
+		super(ureq, wControl, LAYOUT_VERTICAL);
+		setTranslator(Util.createPackageTranslator(AccessConfigurationController.class, getLocale(), getTranslator()));
+		
+		AccessControlModule acModule = (AccessControlModule)CoreSpringFactory.getBean("acModule");
+		if(acModule.isEnabled()) {
+			OLATResource resource = OLATResourceManager.getInstance().findResourceable(businessGroup);
+			configController = new AccessConfigurationController(ureq, wControl, resource, businessGroup.getName(), mainForm);
+			listenTo(configController);
+		}
+		
+		initForm(ureq);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		if(configController != null) {
+			formLayout.add(configController.getInitialFormItem());
+			uifactory.addSpacerElement("spacer1", formLayout, false);
+		}
+
+		setFormTitle("accesscontrol.title");
+		setFormDescription("accesscontrol.desc");
+		setFormContextHelp(AccessConfigurationController.class.getPackage().getName(), "accesscontrol_group.html", "chelp.accesscontrol_group.hover");
+
+		final FormLayoutContainer buttonGroupLayout = FormLayoutContainer.createButtonLayout("buttonLayout", getTranslator());
+		buttonGroupLayout.setRootForm(mainForm);
+		formLayout.add(buttonGroupLayout);
+		
+		uifactory.addFormSubmitButton("save", formLayout);
+	}
+	
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		if(configController != null) {
+			configController.formOK(ureq);
+		}
+		fireEvent(ureq, Event.DONE_EVENT);
+	}
+}
diff --git a/src/main/java/org/olat/group/ui/edit/BusinessGroupEditController.java b/src/main/java/org/olat/group/ui/edit/BusinessGroupEditController.java
index 0c7091359092e2ebc567b23e78e85528d37d1d2c..6568683f765028ef6e5f0e8b3ebd0e43bce84009 100644
--- a/src/main/java/org/olat/group/ui/edit/BusinessGroupEditController.java
+++ b/src/main/java/org/olat/group/ui/edit/BusinessGroupEditController.java
@@ -131,6 +131,9 @@ public class BusinessGroupEditController extends BasicController implements Cont
 	private VelocityContainer vc_tab_bgCTools;
 	private VelocityContainer vc_tab_bgAreas;
 	private VelocityContainer vc_tab_bgRights;
+	//fxdiff VCRP-1,2: access control of resources
+	private int tabAccessIndex;
+	private BusinessGroupEditAccessController tabAccessCtrl;
 	private BGConfigFlags flags;
 	private DisplayMemberSwitchForm dmsForm;
 
@@ -196,6 +199,8 @@ public class BusinessGroupEditController extends BasicController implements Cont
 			/*
 			 * add Tabbed Panes for configuration
 			 */
+			//fxdiff VCRP-1,2: access control of resources
+			int tabIndex = 0;
 			tabbedPane = new TabbedPane("bgTabbs", ureq.getLocale());
 			tabbedPane.addListener(this);
 			vc_tab_bgDetails = createTabDetails(ureq, currBusinessGroup);// modifies vc_tab_bgDetails
@@ -203,17 +208,30 @@ public class BusinessGroupEditController extends BasicController implements Cont
 			if (flags.isEnabled(BGConfigFlags.GROUP_COLLABTOOLS)) {
 				vc_tab_bgCTools = createTabCollabTools(ureq, flags);
 				tabbedPane.addTab(translate("group.edit.tab.collabtools"), vc_tab_bgCTools);
+				tabIndex++;
 			}
 			if (flags.isEnabled(BGConfigFlags.AREAS)) {
 				vc_tab_bgAreas = createTabAreas();
 				tabbedPane.addTab(translate("group.edit.tab.areas"), vc_tab_bgAreas);
+				tabIndex++;
 			}
 			if (flags.isEnabled(BGConfigFlags.RIGHTS)) {
 				vc_tab_bgRights = createTabRights();
 				tabbedPane.addTab(translate("group.edit.tab.rights"), vc_tab_bgRights);
+				tabIndex++;
 			}
 			vc_tab_grpmanagement = createTabGroupManagement(ureq);
 			tabbedPane.addTab(translate("group.edit.tab.members"), vc_tab_grpmanagement);
+			//fxdiff VCRP-1,2: access control of resources
+			tabIndex++;
+			
+			if(BusinessGroup.TYPE_BUDDYGROUP.equals(currBusinessGroup.getType())) {
+				tabAccessCtrl = new BusinessGroupEditAccessController(ureq, getWindowControl(), currBusinessGroup);
+		  	listenTo(tabAccessCtrl);
+		  	tabbedPane.addTab(translate("group.edit.tab.accesscontrol"), tabAccessCtrl.getInitialComponent());
+		  	tabIndex++;
+		  	tabAccessIndex = tabIndex;
+			}
 
 			vc_edit = createVelocityContainer("edit");
 			vc_edit.put("tabbedpane", tabbedPane);
@@ -344,12 +362,15 @@ public class BusinessGroupEditController extends BasicController implements Cont
 				MailerWithTemplate mailer = MailerWithTemplate.getInstance();
 				MailTemplate mailTemplate = identitiesMoveEvent.getMailTemplate();
 				if (mailTemplate != null) {
-					MailerResult mailerResult = mailer.sendMailAsSeparateMails(identitiesMoveEvent.getMovedIdentities(), null, null, mailTemplate, null);
-					MailHelper.printErrorsAndWarnings(mailerResult, getWindowControl(), ureq.getLocale());
+					//fxdiff VCRP-16: intern mail system
+					//TODO SR MailContext context = new MailContextImpl(currBusinessGroup, null, getWindowControl().getBusinessControl().getAsString());
+				//TODO SR MailerResult mailerResult = mailer.sendMailAsSeparateMails(context, identitiesMoveEvent.getMovedIdentities(), null, null, mailTemplate, null);
+				//TODO SR MailHelper.printErrorsAndWarnings(mailerResult, getWindowControl(), ureq.getLocale());
 				}
 				fireEvent(ureq, Event.CHANGED_EVENT );		
 			} 
-		} else if (source == this.modifyBusinessGroupController) {
+		//fxdiff VCRP-1,2: access control of resources
+		} else if (source == this.modifyBusinessGroupController || source == tabAccessCtrl) {
 			if (event == Event.DONE_EVENT) {
 				// update business group with the specified values
 				// values are taken from the modifyBusinessGroupForm
@@ -368,6 +389,11 @@ public class BusinessGroupEditController extends BasicController implements Cont
 				}
 				// do logging
 				ThreadLocalUserActivityLogger.log(GroupLoggingAction.GROUP_CONFIGURATION_CHANGED, getClass());
+				//fxdiff VCRP-1,2: access control of resources
+				if(source == tabAccessCtrl) {
+					tabbedPane.setSelectedPane(tabAccessIndex);
+				}
+				
 			} else if (event == Event.CANCELLED_EVENT) {
 				// reinit details form
 				// TODO:fj:b introduce reset() for a form
@@ -694,5 +720,8 @@ public class BusinessGroupEditController extends BasicController implements Cont
 			tabbedPane.addTab(translate("group.edit.tab.rights"), vc_tab_bgRights);
 		}
 		tabbedPane.addTab(translate("group.edit.tab.members"), createTabGroupManagement(ureq));
+		if(tabAccessCtrl != null) {
+			tabbedPane.addTab(translate("group.edit.tab.accesscontrol"), tabAccessCtrl.getInitialComponent());
+		}
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_de.properties
index 620a00f90d88b07ff84fb36b5d843dbfae1c6829..72ec5b416070f15e035632ac3b7ad0adfc4fe343 100644
--- a/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_de.properties
@@ -111,6 +111,7 @@ chelp.tools.title=Konfiguration kollaborativer Werkzeuge
 chkBox.show.owners=Mitglieder sehen Besitzer
 chkBox.show.partips=Mitglieder sehen Teilnehmer
 chkBox.show.waitingList=Mitglieder sehen Warteliste
+chkBox.open=Gruppe für Buchung in Gruppenbereich ver\u00F6ffentlichen
 error.message.locked=Diese Gruppe wird im Moment vom Benutzer {0} ({1}) ver\u00E4ndert und ist daher gesperrt. Bitte versuchen Sie es sp\u00E4ter noch einmal.
 fieldset.legend.areas=Zugewiesene Lernbereiche
 fieldset.legend.collabtools=Kollaborative Werkzeuge
@@ -120,9 +121,11 @@ fieldset.legend.groupowners=Besitzer
 fieldset.legend.grouppartips=Teilnehmer
 fieldset.legend.rights=Zugewiesene Rechte
 fieldset.legend.waitinggroup=Warteliste
+fieldset.legend.open=Sichtbarkeit
 group.edit.tab.areas=Lernbereiche
 group.edit.tab.collabtools=Werkzeuge
 group.edit.tab.details=Beschreibung
 group.edit.tab.members=Mitglieder
 group.edit.tab.rights=Berechtigungen
+group.edit.tab.accesscontrol=Veröffentlichung und Buchungskonfiguration
 group.edit.title=Gruppe <i>{0}</i> editieren
diff --git a/src/main/java/org/olat/group/ui/main/BGAccessControlledCellRenderer.java b/src/main/java/org/olat/group/ui/main/BGAccessControlledCellRenderer.java
new file mode 100644
index 0000000000000000000000000000000000000000..be431301b235bb362bf48bbbe578369a6230f33d
--- /dev/null
+++ b/src/main/java/org/olat/group/ui/main/BGAccessControlledCellRenderer.java
@@ -0,0 +1,74 @@
+/**
+ * OLAT - Online Learning and Training<br>
+ * http://www.olat.org
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Copyright (c) frentix GmbH<br>
+ * http://www.frentix.com<br>
+ * <p>
+ */
+
+package org.olat.group.ui.main;
+
+import java.util.Collection;
+import java.util.Locale;
+
+import org.olat.core.gui.components.table.CustomCellRenderer;
+import org.olat.core.gui.render.Renderer;
+import org.olat.core.gui.render.StringOutput;
+import org.olat.resource.accesscontrol.model.OLATResourceAccess;
+import org.olat.resource.accesscontrol.model.Price;
+import org.olat.resource.accesscontrol.model.PriceMethodBundle;
+import org.olat.resource.accesscontrol.ui.PriceFormat;
+
+/**
+ * 
+ * Description:<br>
+ * TODO: srosse Class Description for BGAccessControlledCellRenderer
+ * 
+ * <P>
+ * Initial Date:  18 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+//fxdiff VCRP-1,2: access control of resources
+public class BGAccessControlledCellRenderer implements CustomCellRenderer {
+
+	@Override
+	public void render(StringOutput sb, Renderer renderer, Object val, Locale locale, int alignment, String action) {
+		if(val instanceof Collection) {
+			Collection<?> accessTypes = (Collection<String>)val;
+			for(Object accessType:accessTypes) {
+				if(accessType instanceof String) {
+					String type = (String)accessType;
+					sb.append("<span class='b_small_icon ").append(type).append("_icon b_access_method'>").append("</span>");
+				} else if (accessType instanceof PriceMethodBundle) {
+					PriceMethodBundle bundle = (PriceMethodBundle)accessType;
+					Price price = bundle.getPrice();
+					String type = bundle.getMethod().getMethodCssClass();
+					if(price == null || price.isEmpty()) {
+						sb.append("<span class='b_small_icon ").append(type).append("_icon b_access_method'>").append("</span>");
+					} else {
+						String p = PriceFormat.fullFormat(price);
+						sb.append("<span class='b_with_small_icon_left ").append(type).append("_icon b_access_method'>").append(p).append("</span>");
+					}
+				}
+			}
+		} else if(val instanceof Boolean) {
+			boolean acessControlled = ((Boolean)val).booleanValue();
+			if(acessControlled) {
+				sb.append("<span class='b_small_icon b_group_accesscontrolled b_access_method'>").append("</span>");
+			}
+		}
+	}
+}
diff --git a/src/main/java/org/olat/group/ui/main/BGMainController.java b/src/main/java/org/olat/group/ui/main/BGMainController.java
index af4cd8630b875e7680ab16c74f73b53190654b32..1d6e18076b41720d675f50a5d728c9a8324fda24 100644
--- a/src/main/java/org/olat/group/ui/main/BGMainController.java
+++ b/src/main/java/org/olat/group/ui/main/BGMainController.java
@@ -22,20 +22,35 @@
 package org.olat.group.ui.main;
 
 import java.util.ArrayList;
-import java.util.Iterator;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
+import org.olat.NewControllerFactory;
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.BaseSecurityManager;
 import org.olat.basesecurity.SecurityGroup;
 import org.olat.commons.calendar.CalendarManager;
 import org.olat.commons.calendar.CalendarManagerFactory;
 import org.olat.commons.calendar.ui.components.KalendarRenderWrapper;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.fullWebApp.LayoutMain3ColsController;
 import org.olat.core.commons.persistence.PersistenceHelper;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.link.Link;
+import org.olat.core.gui.components.link.LinkFactory;
+import org.olat.core.gui.components.segmentedview.SegmentViewComponent;
+import org.olat.core.gui.components.segmentedview.SegmentViewEvent;
+import org.olat.core.gui.components.segmentedview.SegmentViewFactory;
 import org.olat.core.gui.components.table.BooleanColumnDescriptor;
+import org.olat.core.gui.components.table.ColumnDescriptor;
+import org.olat.core.gui.components.table.CustomCellRenderer;
+import org.olat.core.gui.components.table.CustomRenderColumnDescriptor;
 import org.olat.core.gui.components.table.DefaultColumnDescriptor;
 import org.olat.core.gui.components.table.Table;
 import org.olat.core.gui.components.table.TableController;
@@ -67,6 +82,7 @@ import org.olat.core.id.context.ContextEntry;
 import org.olat.core.id.context.StateEntry;
 import org.olat.core.logging.Tracing;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
+import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
 import org.olat.core.util.mail.ContactList;
 import org.olat.core.util.notifications.NotificationsManager;
@@ -78,12 +94,24 @@ import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupManager;
 import org.olat.group.BusinessGroupManagerImpl;
 import org.olat.group.GroupLoggingAction;
+import org.olat.group.context.BGContextManager;
+import org.olat.group.context.BGContextManagerImpl;
 import org.olat.group.delete.TabbedPaneController;
 import org.olat.group.ui.BGConfigFlags;
 import org.olat.group.ui.BGControllerFactory;
 import org.olat.group.ui.BGTranslatorFactory;
 import org.olat.group.ui.BusinessGroupFormController;
 import org.olat.group.ui.run.BusinessGroupMainRunController;
+import org.olat.repository.RepositoryEntry;
+import org.olat.resource.OLATResource;
+import org.olat.resource.OLATResourceManager;
+import org.olat.resource.accesscontrol.ACUIFactory;
+import org.olat.resource.accesscontrol.AccessResult;
+import org.olat.resource.accesscontrol.manager.ACFrontendManager;
+import org.olat.resource.accesscontrol.model.BusinessGroupAccess;
+import org.olat.resource.accesscontrol.model.OLATResourceAccess;
+import org.olat.resource.accesscontrol.model.PriceMethodBundle;
+import org.olat.resource.accesscontrol.ui.AccessEvent;
 import org.olat.util.logging.activity.LoggingResourceable;
 
 import de.bps.olat.util.notifications.SubscriptionProvider;
@@ -127,17 +155,29 @@ public class BGMainController extends MainLayoutBasicController implements Activ
 	private BusinessGroupTableModelWithType groupListModel;
 	private BusinessGroupFormController createBuddyGroupController;
 	private BusinessGroup currBusinessGroup;
-	private Identity identity;
-	private BusinessGroupManager bgm;
+	private final Identity identity;
+	private final BusinessGroupManager bgm;
+	//fxdiff VCRP-1,2: access control of resources
+	private final ACFrontendManager acFrontendManager;
+	private final BGContextManager contextManager;
 	private TabbedPaneController deleteTabPaneCtr;
 	private CloseableModalController cmc;
 	private DialogBoxController deleteDialogBox;
+	private DialogBoxController sendEMailOnDeleteDialogBox;
 	private DialogBoxController leaveDialogBox;
+	//fxdiff VCRP-1,2: access control of resources
+	private Controller accessController;
+	private Link allOpenLink;
+	private Link searchOpenLink;
+	private SegmentViewComponent segmentView;
+	private BGSearchController searchController;
 
 	// group list table rows
 	private static final String TABLE_ACTION_LEAVE = "bgTblLeave";
 	private static final String TABLE_ACTION_DELETE = "bgTblDelete";
 	private static final String TABLE_ACTION_LAUNCH = "bgTblLaunch";
+	//fxdiff VCRP-1,2: access control of resources
+	private static final String TABLE_ACTION_ACCESS = "bgTblAccess";
 	private static final String CMD_MENU_INDEX = "cmd.menu.index";
 	private static final String CMD_MENU_BUDDY = "cmd.menu.buddy";
 	private static final String CMD_MENU_LEARN = "cmd.menu.learn";
@@ -158,6 +198,9 @@ public class BGMainController extends MainLayoutBasicController implements Activ
 		identity = ureq.getIdentity();
 		setTranslator(BGTranslatorFactory.createBGPackageTranslator(PACKAGE, BusinessGroup.TYPE_BUDDYGROUP, ureq.getLocale()));
 		bgm = BusinessGroupManagerImpl.getInstance();
+		contextManager = BGContextManagerImpl.getInstance();
+		//fxdiff VCRP-1,2: access control of resources
+		acFrontendManager = (ACFrontendManager)CoreSpringFactory.getBean("acFrontendManager");
 
 		// main component layed out in panel
 		main = createVelocityContainer("index");
@@ -181,7 +224,10 @@ public class BGMainController extends MainLayoutBasicController implements Activ
 		
 		listenTo(columnLayoutCtr);
 		putInitialPanel(columnLayoutCtr.getInitialComponent());
-
+		//fxdiff VCRP-1,2: access control of resources
+		searchController = new BGSearchController(ureq, getWindowControl(), ureq.getUserSession().getRoles().isOLATAdmin());
+		listenTo(searchController);
+		
 		// start with list of all groups
 		doAllGroupList(ureq, getWindowControl());
 	}
@@ -199,6 +245,23 @@ public class BGMainController extends MainLayoutBasicController implements Activ
 				Object userObject = clickedNode.getUserObject();
 				activateContent(ureq, userObject);
 			}
+		} else if (source instanceof Link && source.getComponentName().startsWith("repo_entry_")) {
+			Long repoEntryKey = (Long)((Link)source).getUserObject();
+			BusinessControl bc = BusinessControlFactory.getInstance().createFromString("[RepositoryEntry:" + repoEntryKey + "]");
+			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(bc, getWindowControl());
+			NewControllerFactory.getInstance().launch(ureq, bwControl);
+		//fxdiff VCRP-1,2: access control of resources
+		} else if(source == segmentView) {
+			if(event instanceof SegmentViewEvent) {
+				SegmentViewEvent sve = (SegmentViewEvent)event;
+				String segmentCName = sve.getComponentName();
+				Component clickedLink = main.getComponent(segmentCName);
+				if (clickedLink == allOpenLink) {
+					doOpenGroupList(ureq, getWindowControl());
+				} else if (clickedLink == searchOpenLink){
+					doSearchOpenGroupList(ureq, getWindowControl());
+				}
+			}
 		}
 	}
 
@@ -210,6 +273,13 @@ public class BGMainController extends MainLayoutBasicController implements Activ
 	 * @param userObject
 	 */
 	private void activateContent(UserRequest ureq, Object userObject) {
+		//fxdiff VCRP-1,2: access control of resources
+		if(this.accessController != null) {
+			main.remove(accessController.getInitialComponent());
+			removeAsListenerAndDispose(accessController);
+			accessController = null;
+		}
+		
 		if (userObject.equals(CMD_MENU_INDEX)) {
 			doAllGroupList(ureq, getWindowControl());
 		} else if (userObject.equals(CMD_MENU_BUDDY)) {
@@ -218,6 +288,11 @@ public class BGMainController extends MainLayoutBasicController implements Activ
 			doLearningGroupList(ureq, getWindowControl());
 		} else if (userObject.equals(CMD_MENU_RIGHT)) {
 			doRightGroupList(ureq, getWindowControl());
+		//fxdiff VCRP-1,2: access control of resources
+		} else if (userObject.equals(CMD_MENU_OPEN)) {
+			doOpenGroupList(ureq, getWindowControl());
+		} else if (userObject.equals(CMD_MENU_OPEN_SEARCH)) {
+			doSearchOpenGroupList(ureq, getWindowControl());
 		}
 	}
 
@@ -245,9 +320,31 @@ public class BGMainController extends MainLayoutBasicController implements Activ
 			} else if (actionid.equals(TABLE_ACTION_LEAVE) && currBusinessGroup.getType().equals(BusinessGroup.TYPE_BUDDYGROUP)) {
 				// only for buddygroups allowed
 				leaveDialogBox = activateYesNoDialog(ureq, null, translate("dialog.modal.bg.leave.text", trnslP), leaveDialogBox);
+			//fxdiff VCRP-1,2: access control of resources
+			} else if (actionid.equals(TABLE_ACTION_ACCESS)) {
+				handleAccess(ureq);
 			}
 		}
 	}
+	//fxdiff VCRP-1,2: access control of resources
+	private void handleAccess(UserRequest ureq) {
+		if(bgm.isIdentityInBusinessGroup(getIdentity(), currBusinessGroup)) {
+			BGControllerFactory.getInstance().createRunControllerAsTopNavTab(currBusinessGroup, ureq, getWindowControl(), false, null);
+			return;
+		}
+
+		AccessResult acResult = acFrontendManager.isAccessible(currBusinessGroup, getIdentity(), true);
+		if(acResult.isAccessible()) {
+			BGControllerFactory.getInstance().createRunControllerAsTopNavTab(currBusinessGroup, ureq, getWindowControl(), false, null);
+		} else if (currBusinessGroup != null && acResult.getAvailableMethods().size() > 0) {
+			accessController = ACUIFactory.createAccessController(ureq, getWindowControl(), acResult.getAvailableMethods());
+			listenTo(accessController);
+			main.put("access", accessController.getInitialComponent());
+			main.setDirty(true);
+		} else {
+			showError("No access");
+		}
+	}
 
 	/**
 	 * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest,
@@ -267,8 +364,13 @@ public class BGMainController extends MainLayoutBasicController implements Activ
 			}
 		} else if (source == deleteDialogBox) {
 			if (DialogBoxUIFactory.isOkEvent(event)) {
-				doBuddyGroupDelete(ureq);
+				sendEMailOnDeleteDialogBox = activateYesNoDialog(ureq, null, translate("dialog.modal.bg.mail.text"), sendEMailOnDeleteDialogBox);
 			}//else cancel was clicked or box closed
+		} else if(source == sendEMailOnDeleteDialogBox){
+			if(DialogBoxUIFactory.isOkEvent(event))
+				doBuddyGroupDelete(ureq,true);
+			else
+				doBuddyGroupDelete(ureq,false);
 		} else if (source == leaveDialogBox) {
 			if (event != Event.CANCELLED_EVENT) {
 				if (DialogBoxUIFactory.isYesEvent(event)) {
@@ -295,6 +397,23 @@ public class BGMainController extends MainLayoutBasicController implements Activ
 			} else if (event == Event.CANCELLED_EVENT) {
 				// notthing to do
 			}
+		//fxdiff VCRP-1,2: access control of resources
+		} else if (source == accessController) {
+			if(event.equals(AccessEvent.ACCESS_OK_EVENT)) {
+				activateContent(ureq, CMD_MENU_OPEN);
+				BGControllerFactory.getInstance().createRunControllerAsTopNavTab(currBusinessGroup, ureq, getWindowControl(), false, null);
+			} else if(event.equals(AccessEvent.ACCESS_FAILED_EVENT)) {
+				String msg = ((AccessEvent)event).getMessage();
+				if(StringHelper.containsNonWhitespace(msg)) {
+					getWindowControl().setError(msg);
+				} else {
+					showError("error.accesscontrol");
+				}
+			}
+		} else if (source == searchController) {
+			if(event.equals(Event.DONE_EVENT)) {
+				updateSearchGroupList();
+			}
 		}
 	}
 
@@ -327,12 +446,13 @@ public class BGMainController extends MainLayoutBasicController implements Activ
 	 * otherwhise does nothing
 	 * 
 	 * @param ureq
+	 * @param doSendMail specifies if notification mails should be sent to users of delted group
 	 */
-	private void doBuddyGroupDelete(UserRequest ureq) {
+	private void doBuddyGroupDelete(UserRequest ureq, boolean doSendMail) {
 		// 1) send notification mails to users
 		BaseSecurity securityManager = BaseSecurityManager.getInstance();
 		ContactList owners = new ContactList(translate("userlist.owners.title"));
-		List ow = securityManager.getIdentitiesOfSecurityGroup(currBusinessGroup.getOwnerGroup());
+		List<Identity> ow = securityManager.getIdentitiesOfSecurityGroup(currBusinessGroup.getOwnerGroup());
 		owners.addAllIdentites(ow);
 		ContactList participants = new ContactList(translate("userlist.participants.title"));
 		participants.addAllIdentites(securityManager.getIdentitiesOfSecurityGroup(currBusinessGroup.getPartipiciantGroup()));
@@ -342,7 +462,7 @@ public class BGMainController extends MainLayoutBasicController implements Activ
 			return;
 		}
 
-		List everybody = new ArrayList();
+		List<ContactList> everybody = new ArrayList<ContactList>();
 		everybody.add(owners);
 		everybody.add(participants);
 		// inform Indexer about change
@@ -360,7 +480,12 @@ public class BGMainController extends MainLayoutBasicController implements Activ
 			pub.setState(1); //int 0 is OK -> all other is not OK
 		}
 		
-		bgm.deleteBusinessGroupWithMail(currBusinessGroup, getWindowControl(), ureq, getTranslator(), everybody);
+		// fxdiff: FXOLAT-138
+		if (doSendMail) {
+			bgm.deleteBusinessGroupWithMail(currBusinessGroup, getWindowControl(), ureq, getTranslator(), everybody);
+		} else {
+			bgm.deleteBusinessGroup(currBusinessGroup);
+		}
 		// do Logging
 		ThreadLocalUserActivityLogger.log(GroupLoggingAction.GROUP_DELETED, getClass(), LoggingResourceable.wrap(currBusinessGroup));
 		// 4) update Tables
@@ -440,7 +565,7 @@ public class BGMainController extends MainLayoutBasicController implements Activ
 	 */
 	private void doAllGroupList(UserRequest ureq, WindowControl wControl) {
 		// 1) initialize list controller and datamodel
-		initGroupListCtrAndModel(true, ureq);
+		initGroupListCtrAndModel(true, true, false, CMD_MENU_INDEX, ureq);
 		// 2) load data into model
 		updateGroupListModelAll();
 		// 3) set correct page
@@ -460,7 +585,7 @@ public class BGMainController extends MainLayoutBasicController implements Activ
 	 */
 	private void doBuddyGroupList(UserRequest ureq, WindowControl wControl) {
 		// 1) initialize list controller and datamodel
-		initGroupListCtrAndModel(true, ureq);
+		initGroupListCtrAndModel(true, false, false, CMD_MENU_BUDDY, ureq);
 		// 2) load data into model
 		updateGroupListModelBuddygroups();
 		// 3) set correct page
@@ -480,7 +605,7 @@ public class BGMainController extends MainLayoutBasicController implements Activ
 	 */
 	private void doLearningGroupList(UserRequest ureq, WindowControl wControl) {
 		// 1) initialize list controller and datamodel
-		initGroupListCtrAndModel(false, ureq);
+		initGroupListCtrAndModel(false, true, false, CMD_MENU_LEARN, ureq);
 		// 2) load data into model
 		updateGroupListModelLearninggroups();
 		// 3) set correct page
@@ -500,7 +625,7 @@ public class BGMainController extends MainLayoutBasicController implements Activ
 	 */
 	private void doRightGroupList(UserRequest ureq, WindowControl wControl) {
 		// 1) initialize list controller and datamodel
-		initGroupListCtrAndModel(false, ureq);
+		initGroupListCtrAndModel(false, true, false, CMD_MENU_RIGHT, ureq);
 		// 2) load data into model
 		updateGroupListModelRightgroups();
 		// 3) set correct page
@@ -511,14 +636,63 @@ public class BGMainController extends MainLayoutBasicController implements Activ
 		OLATResourceable ores = OresHelper.createOLATResourceableInstance(CMD_MENU_RIGHT, 0l);
 		addToHistory(ureq, ores, null, wControl, true);
 	}
+	//fxdiff VCRP-1,2: access control of resources
+	private void doOpenGroupList(UserRequest ureq, WindowControl wControl) {
+		// 1) initialize list controller and datamodel
+		initGroupListCtrAndModel(false, false, true, CMD_MENU_OPEN, ureq);
+		// 2) load data into model
+		updateOpenGroupList();
+		// 3) set correct page and segmented view
+		main.setPage(Util.getPackageVelocityRoot(this.getClass()) + "/open.html");
+		
+		main.put("segmentContent", groupListCtr.getInitialComponent());
+		main.remove(searchController.getInitialComponent());
+
+		if(segmentView == null) {
+			segmentView = SegmentViewFactory.createSegmentView("segments", main, this);
+			allOpenLink = LinkFactory.createLink("opengroups.all", main, this);
+			segmentView.addSegment(allOpenLink, true);
+		
+			searchOpenLink = LinkFactory.createLink("opengroups.search", main, this);
+			segmentView.addSegment(searchOpenLink, false);
+		} else {
+			segmentView.select(allOpenLink);
+		}
+		
+		
+		// 4) update toolboxe
+		columnLayoutCtr.hideCol2(true);
+		//fxdiff BAKS-7 Resume function
+		OLATResourceable ores = OresHelper.createOLATResourceableInstance(CMD_MENU_OPEN, 0l);
+		addToHistory(ureq, ores, null, wControl, true);
+	}
+	//fxdiff VCRP-1,2: access control of resources
+	private void doSearchOpenGroupList(UserRequest ureq, WindowControl wControl) {
+		// 1) initialize list controller and datamodel
+		initGroupListCtrAndModel(false, false, true, CMD_MENU_OPEN_SEARCH, ureq);
+		// 2) load data into model
+		updateSearchGroupList();
+		// 3) set correct page and segmented view
+		main.setPage(Util.getPackageVelocityRoot(this.getClass()) + "/open.html");
+		main.put("search", searchController.getInitialComponent());
+		
+		if(segmentView == null) {
+			segmentView = SegmentViewFactory.createSegmentView("segments", main, this);
+			allOpenLink = LinkFactory.createLink("opengroups.all", main, this);
+			segmentView.addSegment(allOpenLink, false);
+		
+			searchOpenLink = LinkFactory.createLink("opengroups.search", main, this);
+			segmentView.addSegment(searchOpenLink, true);
+		} else {
+			segmentView.select(searchOpenLink);
+		}
 
-	/**
-	 * Prepare everything and show delete groups workflow
-	 * 
-	 * @param ureq
-	 * @param wControl
-	 */
-	private void doDeleteGroups(UserRequest ureq, WindowControl wControl) {
+		// 4) update toolboxe
+		columnLayoutCtr.hideCol2(true);
+		
+		//fxdiff BAKS-7 Resume function
+		OLATResourceable ores = OresHelper.createOLATResourceableInstance(CMD_MENU_OPEN_SEARCH, 0l);
+		addToHistory(ureq, ores, null, wControl, true);
 	}
 
 	/**
@@ -528,25 +702,51 @@ public class BGMainController extends MainLayoutBasicController implements Activ
 	 *          showed, false: not showed
 	 * @param ureq
 	 */
-	private void initGroupListCtrAndModel(boolean withLeaveAndDelete, UserRequest ureq) {
+	 //fxdiff VCRP-1,2: access control of resources
+	private void initGroupListCtrAndModel(boolean withLeaveAndDelete, boolean withCourse, boolean withAC, String tableId, UserRequest ureq) {
 		// 1) init listing controller
 		TableGuiConfiguration tableConfig = new TableGuiConfiguration();
-		tableConfig.setTableEmptyMessage(translate("index.table.nogroup"));
+		tableConfig.setPreferencesOffered(true, tableId);
+		if (CMD_MENU_OPEN.equals(tableId) || CMD_MENU_OPEN_SEARCH.equals(tableId)) {
+			tableConfig.setTableEmptyMessage(translate("open.nogroup"));			
+		} else {
+			tableConfig.setTableEmptyMessage(translate("index.table.nogroup"));			
+		}
 		removeAsListenerAndDispose(groupListCtr);
-		groupListCtr = new TableController(tableConfig, ureq, getWindowControl(), getTranslator());
+		groupListCtr = new TableController(tableConfig, ureq, getWindowControl(), getTranslator(), false);
 		listenTo(groupListCtr);
-		
+
+		int columnCount = 0;
+		if(withAC) {
+			CustomCellRenderer acRenderer = new BGAccessControlledCellRenderer();
+			groupListCtr.addColumnDescriptor(new CustomRenderColumnDescriptor("table.header.ac", 8, null, getLocale(),
+				ColumnDescriptor.ALIGNMENT_LEFT, acRenderer));
+			columnCount++;
+		}
 		groupListCtr.addColumnDescriptor(new DefaultColumnDescriptor("table.header.bgname", 0, TABLE_ACTION_LAUNCH, getLocale()));
-		groupListCtr.addColumnDescriptor(new DefaultColumnDescriptor("table.header.description", 1, null, getLocale()));
+		groupListCtr.addColumnDescriptor(!withCourse, new DefaultColumnDescriptor("table.header.description", 1, null, getLocale()));
+		columnCount += 2;
+		if(withCourse) {
+			CustomCellRenderer resourcesRenderer = new BGResourcesCellRenderer(this, main, getTranslator());
+			groupListCtr.addColumnDescriptor(new CustomRenderColumnDescriptor("table.header.resources", 5, null, getLocale(), 
+				ColumnDescriptor.ALIGNMENT_LEFT, resourcesRenderer));
+			columnCount++;
+		}
 		groupListCtr.addColumnDescriptor(new DefaultColumnDescriptor("table.header.type", 2, null, getLocale()));
+		columnCount++;
 		if (withLeaveAndDelete) {
 			groupListCtr.addColumnDescriptor(new BooleanColumnDescriptor("table.header.leave", 3, TABLE_ACTION_LEAVE, 
 					translate("table.header.leave"), null));
 			groupListCtr.addColumnDescriptor(new BooleanColumnDescriptor("table.header.delete", 4, TABLE_ACTION_DELETE, 
 					translate("table.header.delete"), null));
+			columnCount += 2;
+		}
+		if(withAC) {
+			groupListCtr.addColumnDescriptor(new DefaultColumnDescriptor("table.header.ac", 7, TABLE_ACTION_ACCESS, getLocale()));
+			columnCount++;
 		}
 		// 2) init list model
-		groupListModel = new BusinessGroupTableModelWithType(new ArrayList(), getTranslator());
+		groupListModel = new BusinessGroupTableModelWithType(new ArrayList<BGTableItem>(), getTranslator(), columnCount);
 		groupListCtr.setTableDataModel(groupListModel);
 		main.put("groupList", groupListCtr.getInitialComponent());
 	}
@@ -555,40 +755,24 @@ public class BGMainController extends MainLayoutBasicController implements Activ
 	 * Get most recent data from the database and init the group list model with
 	 * data for all groups
 	 */
+	 //fxdiff VCRP-1,2: access control of resources
 	private void updateGroupListModelAll() {
-		List wrapped = new ArrayList();
+		List<BGTableItem> wrapped = new ArrayList<BGTableItem>();
 		// buddy groups
-		List groups = bgm.findBusinessGroupsOwnedBy(BusinessGroup.TYPE_BUDDYGROUP, identity, null);
-		Iterator iter = groups.iterator();
-		while (iter.hasNext()) {
-			BusinessGroup group = (BusinessGroup) iter.next();
-			wrapped.add(wrapGroup(group, Boolean.TRUE, Boolean.TRUE));
-		}
-		groups = bgm.findBusinessGroupsAttendedBy(BusinessGroup.TYPE_BUDDYGROUP, identity, null);
-		iter = groups.iterator();
-		while (iter.hasNext()) {
-			BusinessGroup group = (BusinessGroup) iter.next();
-			wrapped.add(wrapGroup(group, Boolean.TRUE, null));
-		}
+		collectGroupListModelBuddygroups(wrapped);
 		// learning groups
-		groups = bgm.findBusinessGroupsOwnedBy(BusinessGroup.TYPE_LEARNINGROUP, identity, null);
-		iter = groups.iterator();
-		while (iter.hasNext()) {
-			BusinessGroup group = (BusinessGroup) iter.next();
-			wrapped.add(wrapGroup(group, null, null));
+		List<BusinessGroup> groups = bgm.findBusinessGroupsOwnedBy(BusinessGroup.TYPE_LEARNINGROUP, identity, null);
+		for (BusinessGroup group:groups) {
+			wrapped.add(wrapGroup(group, true, null, null, false, null));
 		}
 		groups = bgm.findBusinessGroupsAttendedBy(BusinessGroup.TYPE_LEARNINGROUP, identity, null);
-		iter = groups.iterator();
-		while (iter.hasNext()) {
-			BusinessGroup group = (BusinessGroup) iter.next();
-			wrapped.add(wrapGroup(group, null, null));
+		for (BusinessGroup group:groups) {
+			wrapped.add(wrapGroup(group, true, null, null, false, null));
 		}
 		// right groups
 		groups = bgm.findBusinessGroupsAttendedBy(BusinessGroup.TYPE_RIGHTGROUP, identity, null);
-		iter = groups.iterator();
-		while (iter.hasNext()) {
-			BusinessGroup group = (BusinessGroup) iter.next();
-			wrapped.add(wrapGroup(group, null, null));
+		for (BusinessGroup group:groups) {
+			wrapped.add(wrapGroup(group, true, null, null, false, null));
 		}
 		groupListModel.setEntries(wrapped);
 		groupListCtr.modelChanged();
@@ -598,23 +782,26 @@ public class BGMainController extends MainLayoutBasicController implements Activ
 	 * Get most recent data from the database and init the group list model with
 	 * data for buddy groups
 	 */
+	 //fxdiff VCRP-1,2: access control of resources
 	private void updateGroupListModelBuddygroups() {
-		List wrapped = new ArrayList();
+		List<BGTableItem> wrapped = new ArrayList<BGTableItem>();
+		collectGroupListModelBuddygroups(wrapped);
+		groupListModel.setEntries(wrapped);
+		groupListCtr.modelChanged();
+	}
+	//fxdiff VCRP-1,2: access control of resources
+	private void collectGroupListModelBuddygroups(List<BGTableItem> wrapped) {
 		// buddy groups
-		List groups = bgm.findBusinessGroupsOwnedBy(BusinessGroup.TYPE_BUDDYGROUP, identity, null);
-		Iterator iter = groups.iterator();
-		while (iter.hasNext()) {
-			BusinessGroup group = (BusinessGroup) iter.next();
-			wrapped.add(wrapGroup(group, Boolean.TRUE, Boolean.TRUE));
+		List<BusinessGroup> groups = bgm.findBusinessGroupsOwnedBy(BusinessGroup.TYPE_BUDDYGROUP, identity, null);
+		for (BusinessGroup group:groups) {
+			BGTableItem item = wrapGroup(group, true, Boolean.TRUE, Boolean.TRUE, false, null);
+			wrapped.add(item);
 		}
 		groups = bgm.findBusinessGroupsAttendedBy(BusinessGroup.TYPE_BUDDYGROUP, identity, null);
-		iter = groups.iterator();
-		while (iter.hasNext()) {
-			BusinessGroup group = (BusinessGroup) iter.next();
-			wrapped.add(wrapGroup(group, Boolean.TRUE, null));
+		for (BusinessGroup group:groups) {
+			BGTableItem item = wrapGroup(group, true, Boolean.TRUE, null, false, null);
+			wrapped.add(item);
 		}
-		groupListModel.setEntries(wrapped);
-		groupListCtr.modelChanged();
 	}
 
 	/**
@@ -622,19 +809,15 @@ public class BGMainController extends MainLayoutBasicController implements Activ
 	 * data for learning groups
 	 */
 	private void updateGroupListModelLearninggroups() {
-		List wrapped = new ArrayList();
+		List<BGTableItem> wrapped = new ArrayList<BGTableItem>();
 		// learning groups
-		List groups = bgm.findBusinessGroupsOwnedBy(BusinessGroup.TYPE_LEARNINGROUP, identity, null);
-		Iterator iter = groups.iterator();
-		while (iter.hasNext()) {
-			BusinessGroup group = (BusinessGroup) iter.next();
-			wrapped.add(wrapGroup(group, null, null));
+		List<BusinessGroup> groups = bgm.findBusinessGroupsOwnedBy(BusinessGroup.TYPE_LEARNINGROUP, identity, null);
+		for (BusinessGroup group:groups) {
+			wrapped.add(wrapGroup(group, true, null, null, false, null));
 		}
 		groups = bgm.findBusinessGroupsAttendedBy(BusinessGroup.TYPE_LEARNINGROUP, identity, null);
-		iter = groups.iterator();
-		while (iter.hasNext()) {
-			BusinessGroup group = (BusinessGroup) iter.next();
-			wrapped.add(wrapGroup(group, null, null));
+		for (BusinessGroup group:groups) {
+			wrapped.add(wrapGroup(group, true, null, null, false, null));
 		}
 		groupListModel.setEntries(wrapped);
 		groupListCtr.modelChanged();
@@ -645,14 +828,69 @@ public class BGMainController extends MainLayoutBasicController implements Activ
 	 * data for right groups
 	 */
 	private void updateGroupListModelRightgroups() {
-		List wrapped = new ArrayList();
+		List<BGTableItem> wrapped = new ArrayList<BGTableItem>();
 		// buddy groups
 		// right groups
-		List groups = bgm.findBusinessGroupsAttendedBy(BusinessGroup.TYPE_RIGHTGROUP, identity, null);
-		Iterator iter = groups.iterator();
-		while (iter.hasNext()) {
-			BusinessGroup group = (BusinessGroup) iter.next();
-			wrapped.add(wrapGroup(group, null, null));
+		List<BusinessGroup> groups = bgm.findBusinessGroupsAttendedBy(BusinessGroup.TYPE_RIGHTGROUP, identity, null);
+		for(BusinessGroup group:groups) {
+			wrapped.add(wrapGroup(group, true, null, null, false, null));
+		}
+		groupListModel.setEntries(wrapped);
+		groupListCtr.modelChanged();
+	}
+	//fxdiff VCRP-1,2: access control of resources
+	private void updateOpenGroupList() {
+		List<BGTableItem> wrapped = new ArrayList<BGTableItem>();
+
+		List<BusinessGroupAccess> bgAccess = acFrontendManager.getOfferAccessForBusinessGroup(true, new Date());
+		for(BusinessGroupAccess bga:bgAccess) {
+			BusinessGroup group = bga.getGroup();
+			boolean member = bgm.isIdentityInBusinessGroup(getIdentity(), group);
+			if(bga.getMethods() != null && !bga.getMethods().isEmpty()) {
+				wrapped.add(wrapGroup(group, member, Boolean.TRUE, null, true, bga.getMethods()));
+			}
+		}
+		groupListModel.setEntries(wrapped);
+		groupListCtr.modelChanged();
+	}
+	//fxdiff VCRP-1,2: access control of resources
+	private void updateSearchGroupList() {
+		List<BusinessGroup> groups; 
+		if(searchController.isEmpty()) {
+			groups = Collections.emptyList();
+		} else {
+			Long id = searchController.getId();
+			String name = searchController.getName();
+			String description = searchController.getDescription();
+			String owner = searchController.getOwner();
+			groups = bgm.findBusinessGroups(null, getIdentity(), id, name, description, owner);
+		}
+
+		List<BGTableItem> wrapped = new ArrayList<BGTableItem>();
+		Set<Long> membership = new HashSet<Long>();
+		Map<Long,Long> resourceKeys = new HashMap<Long,Long>();
+		for(BusinessGroup group:groups) {
+			OLATResource ores = OLATResourceManager.getInstance().findResourceable(group);
+			resourceKeys.put(group.getKey(), ores.getKey());
+			if(bgm.isIdentityInBusinessGroup(this.getIdentity(), group)) {
+				membership.add(group.getKey());
+			}
+		}
+		
+		List<OLATResourceAccess> resourcesWithAC = acFrontendManager.getAccessMethodForResources(resourceKeys.values(), true, new Date());
+		for(BusinessGroup group:groups) {
+			Long oresKey = resourceKeys.get(group.getKey());
+			OLATResourceAccess bgAccess = null;
+			
+			for(OLATResourceAccess access:resourcesWithAC) {
+				if(oresKey.equals(access.getResource().getKey())){
+					bgAccess = access;
+					break;
+				}
+			}
+			if(bgAccess != null) {
+				wrapped.add(wrapGroup(group, true, Boolean.TRUE, null, true, bgAccess.getMethods()));
+			}
 		}
 		groupListModel.setEntries(wrapped);
 		groupListCtr.modelChanged();
@@ -667,8 +905,17 @@ public class BGMainController extends MainLayoutBasicController implements Activ
 	 * @param allowDelete true: user can delete
 	 * @return Object[]
 	 */
-	private Object[] wrapGroup(BusinessGroup group, Boolean allowLeave, Boolean allowDelete) {
-		return new Object[] { group, allowLeave, allowDelete };
+	//fxdiff VCRP-1,2: access control of resources
+	private BGTableItem wrapGroup(BusinessGroup group, boolean member, Boolean allowLeave, Boolean allowDelete, boolean accessControl,
+			List<PriceMethodBundle> access) {
+		BGTableItem tableItem = new BGTableItem(group, member, allowLeave, allowDelete, accessControl, access);
+		
+		if(group.getGroupContext() != null) {
+			List<RepositoryEntry> resources = contextManager.findRepositoryEntriesForBGContext(group.getGroupContext());
+			tableItem.setResources(resources);
+		}
+		
+		return tableItem;
 	}
 
 	/**
@@ -700,6 +947,12 @@ public class BGMainController extends MainLayoutBasicController implements Activ
 		myEntriesTn.setUserObject(CMD_MENU_RIGHT);
 		myEntriesTn.setAltText(translate("menu.rightgroups.alt"));
 		rootNode.addChild(myEntriesTn);
+		//fxdiff VCRP-1,2: access control of resources
+		myEntriesTn = new GenericTreeNode();
+		myEntriesTn.setTitle(translate("menu.opengroups"));
+		myEntriesTn.setUserObject(CMD_MENU_OPEN);
+		myEntriesTn.setAltText(translate("menu.opengroups.alt"));
+		rootNode.addChild(myEntriesTn);
 
 		return gtm;
 	}
diff --git a/src/main/java/org/olat/group/ui/main/BGResourcesCellRenderer.java b/src/main/java/org/olat/group/ui/main/BGResourcesCellRenderer.java
new file mode 100644
index 0000000000000000000000000000000000000000..e401665799ec8b60bef5c0066a2520bd10e9a8f6
--- /dev/null
+++ b/src/main/java/org/olat/group/ui/main/BGResourcesCellRenderer.java
@@ -0,0 +1,81 @@
+/**
+ * OLAT - Online Learning and Training<br>
+ * http://www.olat.org
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Copyright (c) frentix GmbH<br>
+ * http://www.frentix.com<br>
+ * <p>
+ */
+package org.olat.group.ui.main;
+
+import java.util.List;
+import java.util.Locale;
+import java.util.UUID;
+
+import org.olat.core.gui.components.link.Link;
+import org.olat.core.gui.components.link.LinkFactory;
+import org.olat.core.gui.components.table.CustomCellRenderer;
+import org.olat.core.gui.components.velocity.VelocityContainer;
+import org.olat.core.gui.render.RenderResult;
+import org.olat.core.gui.render.Renderer;
+import org.olat.core.gui.render.StringOutput;
+import org.olat.core.gui.render.URLBuilder;
+import org.olat.core.gui.translator.Translator;
+import org.olat.repository.RepositoryEntry;
+
+/**
+ * 
+ * Description:<br>
+ * Render a list of resources / with link
+ * 
+ * <P>
+ * Initial Date:  7 mars 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class BGResourcesCellRenderer implements CustomCellRenderer {
+	
+	private final Translator translator;
+	private VelocityContainer container;
+	private final BGMainController listeningController;
+	
+	public BGResourcesCellRenderer(BGMainController listeningController, VelocityContainer container, Translator translator) {
+		this.listeningController = listeningController;
+		this.container = container;
+		this.translator = translator;
+	}
+
+	@Override
+	public void render(StringOutput sb, Renderer renderer, Object val, Locale locale, int alignment, String action) {
+		if(val instanceof List) {
+			List<RepositoryEntry> resources = (List<RepositoryEntry>)val;
+			for(RepositoryEntry resource:resources) {
+				if(renderer == null) {//fxdiff: FXOLAT-267 for XSL export
+					if(sb.length() > 0) {
+						sb.append(", ");
+					}
+					sb.append(resource.getDisplayname());
+				} else {
+					Link link = LinkFactory.createLink("repo_entry_" + UUID.randomUUID().toString(), container, listeningController);
+					link.setCustomDisplayText(resource.getDisplayname());
+					link.setUserObject(resource.getKey());
+					
+					URLBuilder ubu = renderer.getUrlBuilder().createCopyFor(link);
+					RenderResult renderResult = new RenderResult();
+					link.getHTMLRendererSingleton().render(renderer, sb, link, ubu, translator, renderResult, null);
+				}
+			}
+		}
+	}
+}
diff --git a/src/main/java/org/olat/group/ui/main/BGSearchController.java b/src/main/java/org/olat/group/ui/main/BGSearchController.java
new file mode 100644
index 0000000000000000000000000000000000000000..e5f198eb5dc0c4e6fcbd26bff6707c33e31a5527
--- /dev/null
+++ b/src/main/java/org/olat/group/ui/main/BGSearchController.java
@@ -0,0 +1,168 @@
+/**
+ * OLAT - Online Learning and Training<br>
+ * http://www.olat.org
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Copyright (c) frentix GmbH<br>
+ * http://www.frentix.com<br>
+ * <p>
+ */
+
+package org.olat.group.ui.main;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
+import org.olat.core.gui.components.form.flexible.elements.TextElement;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.components.link.Link;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+
+/**
+ * 
+ * Description:<br>
+ * Search form for Business groups
+ * 
+ * <P>
+ * Initial Date:  21 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+//fxdiff VCRP-1,2: access control of resources
+public class BGSearchController extends FormBasicController{
+
+	private TextElement id; // only for admins
+	private TextElement displayName;
+	private TextElement owner;
+	private TextElement description;
+	private FormLink searchButton;
+	
+	private String limitUsername;
+	private boolean isAdmin;
+
+	/**
+	 * Generic search form.
+	 * @param name Internal form name.
+	 * @param translator Translator
+	 * @param withCancel Display a cancel button?
+	 * @param isAdmin Is calling identity an administrator? If yes, allow search by ID
+	 * @param limitTypes Limit searches to specific types.
+	 */
+	public BGSearchController(UserRequest ureq, WindowControl wControl, boolean isAdmin) {
+		super(ureq, wControl);
+		this.isAdmin = isAdmin;
+		initForm(ureq);
+	}
+	
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		displayName = uifactory.addTextElement("cif_displayname", "cif.displayname", 255, "", formLayout);
+		displayName.setFocus(true);
+		
+		owner = uifactory.addTextElement("cif_owner", "cif.owner", 255, "", formLayout);
+		if (limitUsername != null) {
+			owner.setValue(limitUsername);
+			owner.setEnabled(false);
+		}
+		description = uifactory.addTextElement("cif_description", "cif.description", 255, "", formLayout);
+		
+		if(isAdmin) {
+			id = uifactory.addTextElement("cif_id", "cif.id", 12, "", formLayout);
+			id.setVisible(isAdmin);
+			id.setRegexMatchCheck("\\d*", "search.id.format");
+		}
+		
+		FormLayoutContainer buttonLayout = FormLayoutContainer.createButtonLayout("button_layout", getTranslator());
+		formLayout.add(buttonLayout);
+		searchButton = uifactory.addFormLink("search", buttonLayout, Link.BUTTON);
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+	
+	/**
+	 * @return Return value of ID field.
+	 */
+	public Long getId() {
+		if (id != null && !id.isEmpty()) {
+			return new Long(id.getValue());
+		}
+		return null;
+	}
+
+	/**
+	 * @return Display name filed value.
+	 */
+	public String getName() {
+		return displayName.getValue();
+	}
+
+	/**
+	 * @return Author field value.
+	 */
+	public String getOwner() {
+		return owner.getValue();
+	}
+
+	/**
+	 * @return Descritpion field value.
+	 */
+	public String getDescription() {
+		return description.getValue();
+	}
+	
+	public boolean isEmpty() {
+		return displayName.isEmpty() && owner.isEmpty() && description.isEmpty() && (id != null && id.isEmpty());
+	}
+	
+	@Override
+	protected boolean validateFormLogic(UserRequest ureq) {
+		boolean allOk = true;
+		if (isEmpty())	{
+			showWarning("cif.error.allempty", null);
+			allOk &= false;
+		}
+		
+		if(id != null) {
+			id.clearError();
+			if (id != null && !id.isEmpty()) {
+				try {
+					new Long(id.getValue());
+				} catch (NumberFormatException e) {
+					id.setErrorKey("", null);
+					allOk &= false;
+				}
+			}
+		}
+		return allOk && super.validateFormLogic(ureq);
+	}
+
+	@Override
+	protected void formOK (UserRequest ureq) {
+		fireEvent (ureq, Event.DONE_EVENT); 
+	}
+	
+	@Override
+	protected void formInnerEvent (UserRequest ureq, FormItem source, FormEvent event) {
+		if (source == searchButton) {
+			fireEvent (ureq, Event.DONE_EVENT); 
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/ui/main/BGTableItem.java b/src/main/java/org/olat/group/ui/main/BGTableItem.java
new file mode 100644
index 0000000000000000000000000000000000000000..aafb9778e8ca34b3e3f73f85a0f92e4221a866ce
--- /dev/null
+++ b/src/main/java/org/olat/group/ui/main/BGTableItem.java
@@ -0,0 +1,112 @@
+/**
+ * OLAT - Online Learning and Training<br>
+ * http://www.olat.org
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Copyright (c) frentix GmbH<br>
+ * http://www.frentix.com<br>
+ * <p>
+ */
+package org.olat.group.ui.main;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.olat.group.BusinessGroup;
+import org.olat.repository.RepositoryEntry;
+import org.olat.resource.accesscontrol.model.OLATResourceAccess;
+import org.olat.resource.accesscontrol.model.PriceMethodBundle;
+
+/**
+ * 
+ * Description:<br>
+ * A wrapper class for the list of business group
+ * 
+ * <P>
+ * Initial Date:  7 mars 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class BGTableItem {
+	private boolean accessControl;
+	private final boolean member;
+	private final Boolean allowLeave;
+	private final Boolean allowDelete;
+	private final BusinessGroup businessGroup;
+	private List<RepositoryEntry> resources;
+	private List<PriceMethodBundle> access;
+	
+	public BGTableItem(BusinessGroup businessGroup, boolean member, Boolean allowLeave, Boolean allowDelete,
+			boolean accessControl, List<PriceMethodBundle> access) {
+		this.accessControl = accessControl;
+		this.businessGroup = businessGroup;
+		this.member = member;
+		this.allowLeave = allowLeave;
+		this.allowDelete = allowDelete;
+		this.access = access;
+	}
+
+	//fxdiff VCRP-1,2: access control of resources
+	public boolean isMember() {
+		return member;
+	}
+	//fxdiff VCRP-1,2: access control of resources
+	public boolean isAccessControl() {
+		return accessControl;
+	}
+
+	public List<PriceMethodBundle> getAccessTypes() {
+		return access;
+	}
+
+	public void setAccessControl(boolean accessControl) {
+		this.accessControl = accessControl;
+	}
+
+	public Boolean getAllowLeave() {
+		return allowLeave;
+	}
+
+	public Boolean getAllowDelete() {
+		return allowDelete;
+	}
+
+	public BusinessGroup getBusinessGroup() {
+		return businessGroup;
+	}
+	
+	public List<RepositoryEntry> getResources() {
+		return resources;
+	}
+
+	public void setResources(List<RepositoryEntry> resources) {
+		this.resources = resources;
+	}
+
+	@Override
+	public int hashCode() {
+		return businessGroup.getKey().hashCode();
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+		if(this == obj) {
+			return true;
+		}
+		if(obj instanceof BGTableItem) {
+			BGTableItem item = (BGTableItem)obj;
+			return businessGroup != null && businessGroup.equalsByPersistableKey(item.businessGroup);
+		}
+		return false;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/ui/main/BusinessGroupTableModelWithType.java b/src/main/java/org/olat/group/ui/main/BusinessGroupTableModelWithType.java
index 8a8b8e74e0cbf72f2014357077d68c8af9f11450..5ee0e5231658d7c0e92d36acc740af9457b12107 100644
--- a/src/main/java/org/olat/group/ui/main/BusinessGroupTableModelWithType.java
+++ b/src/main/java/org/olat/group/ui/main/BusinessGroupTableModelWithType.java
@@ -21,6 +21,7 @@
 
 package org.olat.group.ui.main;
 
+import java.util.Collections;
 import java.util.List;
 
 import org.apache.commons.lang.StringEscapeUtils;
@@ -35,31 +36,32 @@ import org.olat.group.BusinessGroup;
  * @author gnaegi
  */
 public class BusinessGroupTableModelWithType extends DefaultTableDataModel implements TableDataModel {
-	private static final int COLUMN_COUNT = 5;
+	private final int columnCount;
 	private Translator trans;
 
 	/**
 	 * @param owned list of business groups
 	 */
-	public BusinessGroupTableModelWithType(List owned, Translator trans) {
+	public BusinessGroupTableModelWithType(List<BGTableItem> owned, Translator trans, int columnCount) {
 		super(owned);
 		this.trans = trans;
+		//fxdiff VCRP-1,2: access control of resources
+		this.columnCount = columnCount;
 	}
 
 	/**
 	 * @see org.olat.core.gui.components.table.TableDataModel#getColumnCount()
 	 */
 	public int getColumnCount() {
-		return COLUMN_COUNT;
+		return columnCount;
 	}
 
 	/**
 	 * @see org.olat.core.gui.components.table.TableDataModel#getValueAt(int, int)
 	 */
 	public Object getValueAt(int row, int col) {
-		Object[] wrapped = (Object[]) objects.get(row);
-		;
-		BusinessGroup businessGroup = (BusinessGroup) wrapped[0];
+		BGTableItem wrapped = (BGTableItem)objects.get(row);
+		BusinessGroup businessGroup = wrapped.getBusinessGroup();
 		switch (col) {
 			case 0:
 				String name = businessGroup.getName();
@@ -73,18 +75,35 @@ public class BusinessGroupTableModelWithType extends DefaultTableDataModel imple
 			case 2:
 				return trans.translate(businessGroup.getType());
 			case 3:
-				return wrapped[1];
+				return wrapped.getAllowLeave();
 			case 4:
-				return wrapped[2];
+				return wrapped.getAllowDelete();
+			case 5:
+				return wrapped.getResources();
+			//fxdiff VCRP-1,2: access control of resources
+			case 6:
+				return new Boolean(wrapped.isAccessControl());
+			case 7:
+				if(wrapped.isMember()) return trans.translate("select");
+				return trans.translate("table.access");
+			case 8:
+				return wrapped.getAccessTypes();
+				
 			default:
 				return "ERROR";
 		}
 	}
+	
+	@Override
+	//fxdiff VCRP-1,2: access control of resources
+	public Object createCopyWithEmptyList() {
+		return new BusinessGroupTableModelWithType(Collections.<BGTableItem>emptyList(), trans, columnCount);
+	}
 
 	/**
 	 * @param owned
 	 */
-	public void setEntries(List owned) {
+	public void setEntries(List<BGTableItem> owned) {
 		this.objects = owned;
 	}
 
@@ -93,9 +112,7 @@ public class BusinessGroupTableModelWithType extends DefaultTableDataModel imple
 	 * @return the business group at the given row
 	 */
 	public BusinessGroup getBusinessGroupAt(int row) {
-		Object[] wrapped = (Object[]) objects.get(row);
-		;
-		return (BusinessGroup) wrapped[0];
+		BGTableItem wrapped = (BGTableItem)objects.get(row);
+		return wrapped.getBusinessGroup();
 	}
-
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/ui/main/_content/open.html b/src/main/java/org/olat/group/ui/main/_content/open.html
new file mode 100644
index 0000000000000000000000000000000000000000..6d4c863b7a7b1bd5d8fae20f568611a9551446a3
--- /dev/null
+++ b/src/main/java/org/olat/group/ui/main/_content/open.html
@@ -0,0 +1,19 @@
+#if($r.available("access"))
+	$r.render("access")
+#else
+	<h4 class="b_with_small_icon_left b_group_icon">
+		$r.translate("open.header")
+	</h4>
+	$r.translate("open.intro")
+	<p />
+	
+	<div class="b_clearfix">
+		$r.render("segments") <br/>	
+		
+		#if($r.available("search"))
+			$r.render("search")
+		#end
+		
+		$r.render("groupList")
+	</div>
+#end
diff --git a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties
index 50ba91093c05b94b5d4f3980ba2806cf0d14199e..cf8ffe603a37aa58fe847b0f2707c6c9f6b641e0 100644
--- a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties
@@ -3,6 +3,7 @@ buddy.header=Arbeitsgruppen
 buddy.intro=In der untenstehenden Liste finden Sie alle Arbeitsgruppen, an denen Sie teilnehmen.
 create.form.title=Neue Arbeitsgruppe erstellen
 dialog.modal.bg.delete.text=Wollen Sie die Arbeitsgruppe "{0}" wirklich l\u00F6schen?<p>
+dialog.modal.bg.mail.text=Wollen Sie die Mitglieder per Mail benachrichtigen?
 dialog.modal.bg.leave.text=Wenn Sie die Arbeitsgruppe "{0}" verlassen, haben Sie keinen Zugang mehr. <br> Wollen Sie die Arbeitsgruppe wirklich verlassen?<p>
 index.header=Gruppen
 index.intro=In der untenstehenden Liste finden Sie alle Arbeits-, Lern- und Rechtegruppen, an denen Sie teilnehmen. 
@@ -18,15 +19,35 @@ menu.learninggroups=Meine Lerngruppen
 menu.learninggroups.alt=Arbeiten Sie mit Ihren Lerngruppen
 menu.rightgroups=Meine Rechtegruppen
 menu.rightgroups.alt=Arbeiten Sie mit Ihren Rechtegruppen
+menu.opengroups=Ver\u00F6ffentlichte Gruppen
+menu.opengroups.alt=Arbeitsgruppen in die \u00F6ffentlich sind und an denen ich teilnehmen kann.
 msg.atleastone=Es muss mindestens ein Besitzer in der Arbeitsgruppe eingetragen sein.
 right.header=Rechtegruppen
 right.intro=In dieser Liste finden Sie alle Rechtegruppen, an denen Sie teilnehmen. 
+open.header=Öffentliche Arbeitsgruppen
+open.intro=In dieser Liste finden Sie alle ver\u00F6ffentlichten Arbeitsgruppen, an denen Sie teilnehmen k\u00F6nnen.
+open.nogroup=Es wurde keine Arbeitsgruppe gefunden die angezeigt werden könnte. 
+opengroups.all=Alle Gruppen
+opengroups.search=Suchmaske
+search.header=Gruppe
+search.intro=In Gruppe suchen
+search.generic=Suchmaske
+cif.displayname=Name
+cif.description=Beschreibung
+cif.owner=Besitzer
+cif.id=ID
+cif.error.allempty=Bitte f\u00FCllen Sie mindestens ein Formularfeld aus.
+search.limit.type=Typ
+group.access.success=Zugriff auf Gruppe ist erfolgreich. 
+table.header.ac=AC
 table.header.bgname=Name
 table.header.delete=L\u00F6schen
 table.header.description=Beschreibung
 table.header.edit=\u00C4ndern
 table.header.leave=Verlassen
 table.header.type=Typ
+table.header.resources=Kurs
+table.access=Belegen
 tools.add.buddygroup=Arbeitsgruppe
 tools.add.header=Erstellen
 tools.delete.header=L\u00F6schen
diff --git a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_en.properties
index 036be4cfaf6c6d86b466cb56cb30b79cdc811d6e..8466dfa3df5afd9f0ba5156394b8afa875b98ef1 100644
--- a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_en.properties
@@ -1,9 +1,16 @@
-#Mon Feb 01 14:32:42 CET 2010
+#Thu May 26 09:55:47 CEST 2011
 buddy.header=Project groups
 buddy.intro=The following list shows all project groups you participate in. 
+cif.description=Description
+cif.displayname=Name
+cif.error.allempty=Please fill at least one form field.
+cif.id=ID
+cif.owner=Owner
 create.form.title=Create a new project group
 dialog.modal.bg.delete.text=Do you really want to delete the project group "{0}" ?<p>
+dialog.modal.bg.mail.text=Do you want to inform the members of this group by email?
 dialog.modal.bg.leave.text=If you leave the project group "{0}" you will no longer have access. <br>Do you really want to leave this project group?<p>
+group.access.success=Access to group is successful
 index.header=Groups
 index.intro=The following list shows all project groups, learning groups, and right groups you participate in.
 index.table.nogroup=You are not registered in any group.
@@ -16,16 +23,30 @@ menu.index=Groups
 menu.index.alt=Work with your groups
 menu.learninggroups=My learning groups
 menu.learninggroups.alt=Work with your personal learning groups
+menu.opengroups=Published groups
+menu.opengroups.alt=Project groups that are published and bookable.
 menu.rightgroups=My right groups
 menu.rightgroups.alt=Work with your personal right groups
 msg.atleastone=There must be at least one owner in this project group.
+open.header=Public project groups
+open.intro=In this list you will find all published project groups that you can participate in.
+open.nogroup=No project groups have been found that can be displayed.
+opengroups.all=All groups
+opengroups.search=Search
 right.header=Right groups
 right.intro=The following list shows all right groups you participate in. 
+search.generic=Search mask
+search.header=Group
+search.intro=Search in group
+search.limit.type=Type
+table.access=Book
+table.header.ac=AC
 table.header.bgname=Name
 table.header.delete=Delete
 table.header.description=Description
 table.header.edit=Edit
 table.header.leave=Leave
+table.header.resources=Course
 table.header.type=Type
 tools.add.buddygroup=Project group
 tools.add.header=Create
diff --git a/src/main/java/org/olat/group/ui/run/BusinessGroupMainRunController.java b/src/main/java/org/olat/group/ui/run/BusinessGroupMainRunController.java
index a65b908d29f5988f5dbac4ba33cbd53836309a8c..58d34c01831ae721ff681c9b8d79964cbe347a45 100644
--- a/src/main/java/org/olat/group/ui/run/BusinessGroupMainRunController.java
+++ b/src/main/java/org/olat/group/ui/run/BusinessGroupMainRunController.java
@@ -64,6 +64,7 @@ import org.olat.core.id.context.StateEntry;
 import org.olat.core.logging.AssertException;
 import org.olat.core.logging.activity.OlatResourceableType;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
+import org.olat.core.util.StringHelper;
 import org.olat.core.util.UserSession;
 import org.olat.core.util.Util;
 import org.olat.core.util.coordinate.CoordinatorManager;
@@ -93,6 +94,12 @@ import org.olat.portfolio.PortfolioModule;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryTableModel;
 import org.olat.resource.OLATResource;
+import org.olat.resource.OLATResourceManager;
+import org.olat.resource.accesscontrol.ACUIFactory;
+import org.olat.resource.accesscontrol.AccessControlModule;
+import org.olat.resource.accesscontrol.AccessResult;
+import org.olat.resource.accesscontrol.manager.ACFrontendManager;
+import org.olat.resource.accesscontrol.ui.AccessEvent;
 import org.olat.util.logging.activity.LoggingResourceable;
 
 /**
@@ -156,6 +163,9 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 	public static final String ACTIVITY_MENUSELECT_WIKI = "MENU_SHOW_WIKI";
 	/* activity identitfyer: user selected show portoflio in menu */
 	public static final String ACTIVITY_MENUSELECT_PORTFOLIO = "MENU_SHOW_PORTFOLIO";
+	/* activity identitfyer: user selected show access control in menu */
+	//fxdiff VCRP-1,2: access control of resources
+	public static final String ACTIVITY_MENUSELECT_AC = "MENU_SHOW_AC";
 
 	private Panel mainPanel;
 	private VelocityContainer main, vc_sendToChooserForm, resourcesVC;
@@ -172,6 +182,8 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 	private Controller chatCtr;
 	
 	private BusinessGroupEditController bgEditCntrllr;
+	//fxdiff VCRP-1,2: access control of resources
+	private Controller bgACHistoryCtrl;
 	private TableController resourcesCtr;
 
 	private BusinessGroupSendToChooserForm sendToChooserForm;
@@ -187,6 +199,7 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 	private BusinessGroupPropertyManager bgpm;
 	private UserSession userSession;
 	private String adminNodeId; // reference to admin menu item
+	private String acNodeId;//fxdiff VCRP-1,2: access control of resources
 
 	// not null indicates tool is enabled
 	private GenericTreeNode nodeFolder;
@@ -202,6 +215,8 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 	private GenericTreeNode nodeAdmin;
 	private boolean groupRunDisabled;
 	private OLATResourceable assessmentEventOres;
+	//fxdiff VCRP-1,2: access control of resources
+	private Controller accessController;
 
 	/**
 	 * Do not use this constructor! Use the BGControllerFactory instead!
@@ -276,6 +291,24 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 			groupRunDisabled = true;
 			this.showError("grouprun.disabled");				
 		}
+		
+		//check managed
+		//fxdiff VCRP-1,2: access control of resources
+		ACFrontendManager acFrontendManager = (ACFrontendManager)CoreSpringFactory.getBean("acFrontendManager");
+		AccessResult acResult = acFrontendManager.isAccessible(currBusinessGroup, getIdentity(), false);
+		if(acResult.isAccessible()) {
+			//ok
+		}  else if (currBusinessGroup != null && acResult.getAvailableMethods().size() > 0) {
+			accessController = ACUIFactory.createAccessController(ureq, getWindowControl(), acResult.getAvailableMethods());
+			listenTo(accessController);
+			mainPanel.setContent(accessController.getInitialComponent());
+			bgTree.setTreeModel(new GenericTreeModel());
+			return;
+		} else {
+			mainPanel.setContent(new Panel("empty"));
+			bgTree.setTreeModel(new GenericTreeModel());
+			return;
+		}
 
 		//REVIEW:PB:2009-05-31: consolidate ContextEntry <-> initialViewIdentifier Concept -> go for ContextEntry at the end.
 		// first step -> if initialViewIdentifier != null -> map initialViewIdentifier to ore with OresHelper
@@ -484,6 +517,20 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 				mainPanel.setContent(main);
 			}
 		//fxdiff VCRP-1,2: access control of resources
+		} else if (source == accessController) {
+			if(event.equals(AccessEvent.ACCESS_OK_EVENT)) {
+				mainPanel.setContent(main);
+				bgTree.setTreeModel(buildTreeModel());
+				removeAsListenerAndDispose(accessController);
+				accessController = null;
+			} else if(event.equals(AccessEvent.ACCESS_FAILED_EVENT)) {
+				String msg = ((AccessEvent)event).getMessage();
+				if(StringHelper.containsNonWhitespace(msg)) {
+					getWindowControl().setError(msg);
+				} else {
+					showError("error.accesscontrol");
+				}
+			}
 		}
 	}
 
@@ -595,8 +642,13 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 		}
 		
 		cmsg.setSubject( translate("businessgroup.contact.subject", businessGroup.getName() ) );
-		String restUrl = BusinessControlFactory.getInstance().getAsURIString(getWindowControl().getBusinessControl(), true);
-		cmsg.setBodyText( getTranslator().translate("businessgroup.contact.bodytext", new String[]{ businessGroup.getName(), restUrl} ) );
+		
+		if (sendToChooserForm.waitingListChecked().equals(BusinessGroupSendToChooserForm.NLS_RADIO_NOTHING)) {
+			String restUrl = BusinessControlFactory.getInstance().getAsURIString(getWindowControl().getBusinessControl(), true);
+			cmsg.setBodyText( getTranslator().translate("businessgroup.contact.bodytext", new String[]{ businessGroup.getName(), restUrl} ) );
+		} else {
+			cmsg.setBodyText ("");
+		}
 		
 		CollaborationTools collabTools = CollaborationToolsFactory.getInstance().getOrCreateCollaborationTools(businessGroup);
 		ContactFormController cofocntrllr = collabTools.createContactFormController(ureq, getWindowControl(), cmsg);
@@ -708,6 +760,9 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 			collabToolCtr = collabTools.createPortfolioController(ureq, bwControl, businessGroup);
 			listenTo(collabToolCtr);
 			mainPanel.setContent(collabToolCtr.getInitialComponent());
+		//fxdiff VCRP-1,2: access control of resources
+		}  else if (ACTIVITY_MENUSELECT_AC.equals(cmd)) {
+			doAccessControlHistory(ureq);
 		} 
 	}
 
@@ -719,6 +774,15 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 		listenTo(bgEditCntrllr);
 		mainPanel.setContent(bgEditCntrllr.getInitialComponent());
 	}
+	
+	//fxdiff VCRP-1,2: access control of resources
+	private void doAccessControlHistory(UserRequest ureq) {
+		removeAsListenerAndDispose(bgACHistoryCtrl);
+		OLATResource resource = OLATResourceManager.getInstance().findResourceable(businessGroup);
+		bgACHistoryCtrl = ACUIFactory.createOrdersAdminController(ureq, getWindowControl(), resource);
+		listenTo(bgACHistoryCtrl);
+		mainPanel.setContent(bgACHistoryCtrl.getInitialComponent());
+	}
 
 	private void doContactForm(UserRequest ureq) {
 		if (vc_sendToChooserForm == null) vc_sendToChooserForm = createVelocityContainer("cosendtochooser");
@@ -1108,6 +1172,21 @@ public class BusinessGroupMainRunController extends MainLayoutBasicController im
 			adminNodeId = gtnChild.getIdent();
 			//fxdiff BAKS-7 Resume function
 			nodeAdmin = gtnChild;
+
+			//fxdiff VCRP-1,2: access control of resources
+			if(BusinessGroup.TYPE_BUDDYGROUP.equals(businessGroup.getType())) {
+				AccessControlModule acModule = (AccessControlModule)CoreSpringFactory.getBean("acModule");
+				if(acModule.isEnabled()) {
+					gtnChild = new GenericTreeNode();
+					gtnChild.setTitle(translate("menutree.ac"));
+					gtnChild.setUserObject(ACTIVITY_MENUSELECT_AC);
+					gtnChild.setIdent(ACTIVITY_MENUSELECT_AC);
+					gtnChild.setAltText(translate("menutree.ac.alt"));
+					gtnChild.setIconCssClass("b_order_icon");
+					root.addChild(gtnChild);
+					acNodeId = gtnChild.getIdent();
+				}
+			}
 		}
 
 		return gtm;
diff --git a/src/main/java/org/olat/group/ui/run/BusinessGroupSendToChooserForm.java b/src/main/java/org/olat/group/ui/run/BusinessGroupSendToChooserForm.java
index ac559b14fee7fdea0289024ed7f05270b26a2c1c..87947ae4afc9a29c62ee89b9bd1a00c74f102766 100644
--- a/src/main/java/org/olat/group/ui/run/BusinessGroupSendToChooserForm.java
+++ b/src/main/java/org/olat/group/ui/run/BusinessGroupSendToChooserForm.java
@@ -88,7 +88,7 @@ public class BusinessGroupSendToChooserForm extends FormBasicController {
 	private boolean isAdmin;
 	
 	public final static String NLS_RADIO_ALL = "all";
-	private final static String NLS_RADIO_NOTHING = "nothing";
+	public final static String NLS_RADIO_NOTHING = "nothing";
 	public final static String NLS_RADIO_CHOOSE = "choose";
 
 	/**
diff --git a/src/main/java/org/olat/ims/qti/repository/handlers/QTIHandler.java b/src/main/java/org/olat/ims/qti/repository/handlers/QTIHandler.java
index ee4350a5090f3cd78b0e63a5b9eb27887de48eab..52a23c78aea5404e87aa8d0abbbb84e026426b9c 100644
--- a/src/main/java/org/olat/ims/qti/repository/handlers/QTIHandler.java
+++ b/src/main/java/org/olat/ims/qti/repository/handlers/QTIHandler.java
@@ -50,6 +50,7 @@ import org.olat.repository.controllers.RepositoryAddController;
 import org.olat.repository.handlers.FileHandler;
 import org.olat.repository.handlers.RepositoryHandler;
 import org.olat.repository.handlers.RepositoryHandlerFactory;
+import org.olat.resource.accesscontrol.ui.RepositoryMainAccessControllerWrapper;
 import org.olat.resource.references.ReferenceManager;
 
 /**
@@ -84,7 +85,10 @@ public abstract class QTIHandler extends FileHandler implements RepositoryHandle
 			// use on column layout
 			LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(ureq, wControl, null, null, runController.getInitialComponent(), null);
 			layoutCtr.addDisposableChildController(runController); // dispose content on layout dispose
-			return layoutCtr;
+			
+			//fxdiff VCRP-1: access control of learn resources
+			RepositoryMainAccessControllerWrapper wrapper = new RepositoryMainAccessControllerWrapper(ureq, wControl, res, layoutCtr);
+			return wrapper;
 	}
 
 	/**
diff --git a/src/main/java/org/olat/instantMessaging/SmackInstantMessagingImpl.java b/src/main/java/org/olat/instantMessaging/SmackInstantMessagingImpl.java
index 17ff7dd3f04685c2dec1e43abf90174b06ff078d..5f413769810a45dd9459f134033dbaff38110d95 100644
--- a/src/main/java/org/olat/instantMessaging/SmackInstantMessagingImpl.java
+++ b/src/main/java/org/olat/instantMessaging/SmackInstantMessagingImpl.java
@@ -330,7 +330,7 @@ public class SmackInstantMessagingImpl extends LogDelegator implements InstantMe
 		BGContextManager contextManager = BGContextManagerImpl.getInstance();
 		//pull as admin
 		Roles roles = new Roles(true, true, true, true, false, true, false);
-		List<RepositoryEntry> allCourses = rm.queryByTypeLimitAccess(CourseModule.getCourseTypeName(), roles);
+		List<RepositoryEntry> allCourses = rm.queryByTypeLimitAccess(null, CourseModule.getCourseTypeName(), roles);
 		int counter = 0;
 		for (Iterator<RepositoryEntry> iterator = allCourses.iterator(); iterator.hasNext();) {
 			RepositoryEntry entry = iterator.next();
diff --git a/src/main/java/org/olat/login/LoginAuthprovidersController.java b/src/main/java/org/olat/login/LoginAuthprovidersController.java
index 65350248b9901327849e863422a0e5bc6eabcf71..ce146125b1ef83e0fcc1d5f8883f269be3f380ae 100644
--- a/src/main/java/org/olat/login/LoginAuthprovidersController.java
+++ b/src/main/java/org/olat/login/LoginAuthprovidersController.java
@@ -47,8 +47,11 @@ import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.MainLayoutBasicController;
+import org.olat.core.gui.control.generic.dtabs.Activateable2;
 import org.olat.core.helpers.Settings;
 import org.olat.core.id.Identity;
+import org.olat.core.id.context.ContextEntry;
+import org.olat.core.id.context.StateEntry;
 import org.olat.core.logging.AssertException;
 import org.olat.core.util.ArrayHelper;
 import org.olat.core.util.Util;
diff --git a/src/main/java/org/olat/modules/dialog/DialogElementsController.java b/src/main/java/org/olat/modules/dialog/DialogElementsController.java
index 17ef25a8d42aafee3ceb3ea744f232c12046fea9..11105b39d96e35384e27d77e4696ac3c0c7178de 100644
--- a/src/main/java/org/olat/modules/dialog/DialogElementsController.java
+++ b/src/main/java/org/olat/modules/dialog/DialogElementsController.java
@@ -48,6 +48,7 @@ import org.olat.core.gui.control.generic.modal.DialogBoxController;
 import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
 import org.olat.core.gui.control.generic.popup.PopupBrowserWindow;
 import org.olat.core.gui.control.generic.title.TitleInfo;
+import org.olat.core.id.Identity;
 import org.olat.core.logging.OLATRuntimeException;
 import org.olat.core.logging.activity.CourseLoggingAction;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
@@ -63,6 +64,8 @@ import org.olat.core.util.vfs.VFSMediaResource;
 import org.olat.core.util.vfs.filters.VFSLeafFilter;
 import org.olat.course.CourseFactory;
 import org.olat.course.CourseModule;
+import org.olat.course.ICourse;
+import org.olat.course.groupsandrights.CourseRights;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.DialogCourseNode;
 import org.olat.course.nodes.dialog.DialogConfigForm;
@@ -73,6 +76,8 @@ import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.modules.fo.Forum;
 import org.olat.modules.fo.ForumManager;
 import org.olat.modules.fo.ForumUIFactory;
+import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryManager;
 import org.olat.util.logging.activity.LoggingResourceable;
 
 /**
@@ -110,6 +115,7 @@ public class DialogElementsController extends BasicController {
 	private UserCourseEnvironment userCourseEnv;
 	private TableGuiConfiguration tableConf;
 	private Link uploadButton;
+	private Link copyButton;
 	private Controller forumCtr;
 
 	public DialogElementsController(UserRequest ureq, WindowControl wControl, CourseNode courseNode, UserCourseEnvironment userCourseEnv,
@@ -124,9 +130,20 @@ public class DialogElementsController extends BasicController {
 
 		content = createVelocityContainer("dialog");		
 		uploadButton = LinkFactory.createButton("dialog.upload.file", content, this);
-
+		
 		isOlatAdmin = ureq.getUserSession().getRoles().isOLATAdmin();
 		isGuestOnly = ureq.getUserSession().getRoles().isGuestOnly();
+
+		// fxdiff VCRP-12: copy files from course folder
+		// add copy from course folder if user has course editor rights (course owner and users in a right group with the author right)
+		Identity identity = ureq.getIdentity();
+		ICourse course = CourseFactory.loadCourse(userCourseEnv.getCourseEnvironment().getCourseResourceableId());
+		RepositoryManager rm = RepositoryManager.getInstance();
+		RepositoryEntry entry = rm.lookupRepositoryEntry(course, true);
+		if (isOlatAdmin || rm.isOwnerOfRepositoryEntry(identity, entry)
+				|| userCourseEnv.getCourseEnvironment().getCourseGroupManager().hasRight(identity, CourseRights.RIGHT_COURSEEDITOR)) {
+			copyButton = LinkFactory.createButton("dialog.copy.file", content, this);
+		}
 		
 		forumCallback = new DialogNodeForumCallback(nodeEvaluation, isOlatAdmin, isGuestOnly, subsContext);
 		content.contextPut("security", forumCallback);
diff --git a/src/main/java/org/olat/modules/sharedfolder/SharedFolderWebDAVProvider.java b/src/main/java/org/olat/modules/sharedfolder/SharedFolderWebDAVProvider.java
index 6196db078a5d8b8019bd38298465df431455e4e1..5c5f56e7fe4d8656fab791d65e7c9e503711bf9a 100644
--- a/src/main/java/org/olat/modules/sharedfolder/SharedFolderWebDAVProvider.java
+++ b/src/main/java/org/olat/modules/sharedfolder/SharedFolderWebDAVProvider.java
@@ -108,7 +108,8 @@ public class SharedFolderWebDAVProvider extends LogDelegator implements WebDAVPr
 			if (firstItem != null && firstItem.equals("*")) {
 				// fake role that represents normally logged in user
 				Roles registeredUserRole = new Roles(false, false, false, false, false, false, false);
-				List<RepositoryEntry> allEntries = (List<RepositoryEntry>) repoManager.queryByTypeLimitAccess(SharedFolderFileResource.TYPE_NAME,
+				//fxdiff VCRP-1,2: access control of resources
+				List<RepositoryEntry> allEntries = repoManager.queryByTypeLimitAccess(identity, SharedFolderFileResource.TYPE_NAME,
 						registeredUserRole);
 				for (RepositoryEntry entry : allEntries) {
 					addReadonlyFolder(rootContainer, entry, sfm, addedEntries);
@@ -120,7 +121,7 @@ public class SharedFolderWebDAVProvider extends LogDelegator implements WebDAVPr
 						Long repoKey = Long.parseLong(folder);
 						RepositoryEntry entry = repoManager.lookupRepositoryEntry(repoKey);
 						if (entry != null) {
-							if (entry.getAccess() >= RepositoryEntry.ACC_USERS) {
+							if (entry.getAccess() >= RepositoryEntry.ACC_USERS || (entry.getAccess() == RepositoryEntry.ACC_OWNERS && entry.isMembersOnly())) {
 								// add folder (which is a repo entry) to root container if not
 								// present
 								addReadonlyFolder(rootContainer, entry, sfm, addedEntries);
diff --git a/src/main/java/org/olat/notifications/NotificationSubscriptionAndNewsController.java b/src/main/java/org/olat/notifications/NotificationSubscriptionAndNewsController.java
index f13ea4acaf2d56e60341923d90a4b77561ca1d53..dfab7bc587744b268ab66f42f1460711b65b1c3e 100644
--- a/src/main/java/org/olat/notifications/NotificationSubscriptionAndNewsController.java
+++ b/src/main/java/org/olat/notifications/NotificationSubscriptionAndNewsController.java
@@ -42,7 +42,7 @@ import org.olat.core.id.UserConstants;
 import org.olat.core.id.context.ContextEntry;
 import org.olat.core.id.context.StateEntry;
 import org.olat.core.util.Util;
-import org.olat.home.GuestHomeSite;
+import org.olat.home.InviteeHomeMainController;
 
 /**
  * Description:<br>
@@ -63,7 +63,7 @@ public class NotificationSubscriptionAndNewsController extends BasicController i
 
 	protected NotificationSubscriptionAndNewsController(Identity subscriberIdentity, UserRequest ureq, WindowControl wControl,
 			Date newsSinceDate) {
-		super(ureq, wControl, Util.createPackageTranslator(GuestHomeSite.class, ureq.getLocale()));
+		super(ureq, wControl, Util.createPackageTranslator(InviteeHomeMainController.class, ureq.getLocale()));
 		this.subscriberIdentity = subscriberIdentity;
 		tabbedPane = new TabbedPane("tabbedPane", getLocale());
 		tabbedPane.addListener(this);
diff --git a/src/main/java/org/olat/notifications/NotificationSubscriptionController.java b/src/main/java/org/olat/notifications/NotificationSubscriptionController.java
index 5cfb7bd3818268c7da7136934a35926bbf9e1a51..bc66a596e2abb548a32d1a19f6a10436490a1c5e 100644
--- a/src/main/java/org/olat/notifications/NotificationSubscriptionController.java
+++ b/src/main/java/org/olat/notifications/NotificationSubscriptionController.java
@@ -40,7 +40,7 @@ import org.olat.core.id.Identity;
 import org.olat.core.util.Util;
 import org.olat.core.util.notifications.NotificationsManager;
 import org.olat.core.util.notifications.Subscriber;
-import org.olat.home.HomeMainController;
+import org.olat.home.InviteeHomeMainController;
 
 /**
  * Description:<br>
@@ -66,7 +66,7 @@ public class NotificationSubscriptionController extends BasicController {
 
 	protected NotificationSubscriptionController(Identity subscriberIdentity, UserRequest ureq, WindowControl wControl) {
 		// use home fallback for rss translations
-		super(ureq, wControl, Util.createPackageTranslator(HomeMainController.class, ureq.getLocale()));
+		super(ureq, wControl, Util.createPackageTranslator(InviteeHomeMainController.class, ureq.getLocale()));
 		this.subscriberIdentity = subscriberIdentity;
 		// Build the table that contains all the subscriptions
 		TableGuiConfiguration tableGuiPrefs = new TableGuiConfiguration();
diff --git a/src/main/java/org/olat/notifications/NotificationUIFactory.java b/src/main/java/org/olat/notifications/NotificationUIFactory.java
index 34c3085599a58edd30757508bdceaa11ffd33ac7..563b34046072e382bd7d2d346da049a4e5207ae7 100644
--- a/src/main/java/org/olat/notifications/NotificationUIFactory.java
+++ b/src/main/java/org/olat/notifications/NotificationUIFactory.java
@@ -140,6 +140,7 @@ public class NotificationUIFactory {
 		if (subidentifier.equals(CalendarController.ACTION_CALENDAR_GROUP)) {
 			resName = BusinessGroupManagerImpl.getInstance().loadBusinessGroup(pub.getResId(), true).getResourceableTypeName();
 		}
+
 		OLATResourceable ores = OresHelper.createOLATResourceableInstance(resName, resId);
 		String title = NotificationsManager.getInstance().getNotificationsHandler(sub.getPublisher()).createTitleInfo(sub, ureq.getLocale());
 		// Launch in dtab
@@ -157,7 +158,12 @@ public class NotificationUIFactory {
 			boolean newFactory = false;
 			if (launchController == null) {
 				try {
-					String resourceUrl = "[" + resName + ":0][notifications]";
+					String resourceUrl;
+					if("Inbox".equals(resName)) {
+						resourceUrl = "[HomeSite:" + ureq.getIdentity().getKey() + "][" + resName + ":0]";
+					} else {
+						resourceUrl = "[" + resName + ":0][notifications]";
+					}
 					BusinessControl bc = BusinessControlFactory.getInstance().createFromString(resourceUrl);
 					WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(bc, windowControl);
 					NewControllerFactory.getInstance().launch(ureq, bwControl);
diff --git a/src/main/java/org/olat/notifications/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/notifications/_i18n/LocalStrings_de.properties
index 756963b4c1697e62ea0e7d2ab275d19635e12000..39da14f0ca02d4a64824994f3c76b0daf79dd8f4 100644
--- a/src/main/java/org/olat/notifications/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/notifications/_i18n/LocalStrings_de.properties
@@ -22,6 +22,8 @@ subscriptions.desc = W
 subscriptions.no.subscriptions = Sie haben zur Zeit keine Abonnements. Sie können Neuigkeiten von Foren, Wikis, Ordner und vielen anderen Ressourcen abonnieren. Um ein Abonnement anzulegen, öffnen Sie eine solche Ressource und klicken dann den Link "abonnieren".
 overview.tab.news = Neuigkeiten
 news.title = Neuigkeiten aus Abonnements
+news.type = Typ
+news.type.all = Alle
 news.desc = Die folgende Liste zeigt die jeweils letzte Änderung in Ihren abonnierten Ressourcen. Sie können den Änderungszeitraum frei wählen.
 news.no.news = Keine Informationen vorhanden
 news.in = gefunden in
diff --git a/src/main/java/org/olat/repository/DetailsReadOnlyForm.java b/src/main/java/org/olat/repository/DetailsReadOnlyForm.java
index 0769b476fd1484c176e452d4c956421bf61d2379..b46f8a5afcf59bb50016fc834e0fc44abe8ade08 100644
--- a/src/main/java/org/olat/repository/DetailsReadOnlyForm.java
+++ b/src/main/java/org/olat/repository/DetailsReadOnlyForm.java
@@ -142,17 +142,25 @@ public class DetailsReadOnlyForm extends FormBasicController {
 				"" + RepositoryEntry.ACC_OWNERS,
 				"" + RepositoryEntry.ACC_OWNERS_AUTHORS,
 				"" + RepositoryEntry.ACC_USERS,
-				"" + RepositoryEntry.ACC_USERS_GUESTS
+				"" + RepositoryEntry.ACC_USERS_GUESTS,
+				RepositoryEntry.MEMBERS_ONLY//fxdiff VCRP-1,2: access control of resources
 		};
 		String[] values = new String[] {
 				translate("cif.access.owners"),
 				translate("cif.access.owners_authors"),
 				translate("cif.access.users"),
 				translate("cif.access.users_guests"),
+				translate("cif.access.membersonly")//fxdiff VCRP-1,2: access control of resources
 		};
 			
 		access = uifactory.addRadiosVertical("cif_access", "cif.access", formLayout, keys, values);
 		access.setVisible(enableAuthorView);
+		//fxdiff VCRP-1,2: access control of resources
+		if(entry.isMembersOnly()) {
+			access.select(RepositoryEntry.MEMBERS_ONLY, true);
+		} else {
+			access.select(Integer.toString(entry.getAccess()), true);
+		}
 	}
 
 	
diff --git a/src/main/java/org/olat/repository/DisplayInfoForm.java b/src/main/java/org/olat/repository/DisplayInfoForm.java
index 1f7f54b9868c4cfbf2a1eadfa9337264c18f88f0..2712271a2521f80f9808dbf3985221be6bc75284 100644
--- a/src/main/java/org/olat/repository/DisplayInfoForm.java
+++ b/src/main/java/org/olat/repository/DisplayInfoForm.java
@@ -84,16 +84,23 @@ public class DisplayInfoForm extends FormBasicController {
 					"" + RepositoryEntry.ACC_OWNERS,
 					"" + RepositoryEntry.ACC_OWNERS_AUTHORS,
 					"" + RepositoryEntry.ACC_USERS,
-					"" + RepositoryEntry.ACC_USERS_GUESTS
+					"" + RepositoryEntry.ACC_USERS_GUESTS,
+					RepositoryEntry.MEMBERS_ONLY//fxdiff VCRP-1,2: access control of resources
 		};
 		String[] values = new String[] {
 					translate("cif.access.owners"),
 					translate("cif.access.owners_authors"),
 					translate("cif.access.users"),
 					translate("cif.access.users_guests"),
+					translate("cif.access.membersonly")//fxdiff VCRP-1,2: access control of resources
 		};
 		access = uifactory.addRadiosVertical("cif_access", "cif.access", formLayout, keys, values);
-		access.select(""+entry.getAccess(), true);
+		//fxdiff VCRP-1,2: access control of resources
+		if(entry.isMembersOnly()) {
+			access.select(RepositoryEntry.MEMBERS_ONLY, true);
+		} else {
+			access.select(""+entry.getAccess(), true);
+		}
 
 		flc.setEnabled(false);
 	}
diff --git a/src/main/java/org/olat/repository/PropPupForm.java b/src/main/java/org/olat/repository/PropPupForm.java
index c6deb0d9b2d9ddd7d0729e0e8375dc4904abfc0e..46f4eee2bfbc9e72a1347c7f43610601938b09d1 100644
--- a/src/main/java/org/olat/repository/PropPupForm.java
+++ b/src/main/java/org/olat/repository/PropPupForm.java
@@ -75,7 +75,8 @@ public class PropPupForm extends FormBasicController {
 				"" + RepositoryEntry.ACC_OWNERS,
 				"" + RepositoryEntry.ACC_OWNERS_AUTHORS,
 				"" + RepositoryEntry.ACC_USERS,
-				"" + RepositoryEntry.ACC_USERS_GUESTS
+				"" + RepositoryEntry.ACC_USERS_GUESTS,
+				RepositoryEntry.MEMBERS_ONLY//fxdiff VCRP-1,2: access control of resources
 		};
 		
 		values = new String[] {
@@ -83,6 +84,7 @@ public class PropPupForm extends FormBasicController {
 				translate("cif.access.owners_authors"),
 				translate("cif.access.users"),
 				translate("cif.access.users_guests"),
+				translate("cif.access.membersonly"),//fxdiff VCRP-1,2: access control of resources
 		};
 	
 		initForm(ureq);
@@ -142,7 +144,16 @@ public class PropPupForm extends FormBasicController {
 	 * ACC_USERS, ACC_USERS_GUESTS)
 	 */
 	public int getAccess() {
-		return Integer.parseInt(access.getSelectedKey());
+		//fxdiff VCRP-1,2: access control of resources
+		String key = access.getSelectedKey();
+		if(RepositoryEntry.MEMBERS_ONLY.equals(key)) {
+			return RepositoryEntry.ACC_OWNERS;
+		}
+		return Integer.parseInt(key);
+	}
+	//fxdiff VCRP-1,2: access control of resources
+	public boolean isMembersOnly() {
+		return RepositoryEntry.MEMBERS_ONLY.equals(access.getSelectedKey());
 	}
 
 	@Override
@@ -173,7 +184,12 @@ public class PropPupForm extends FormBasicController {
 		canDownload.setVisible(handler != null && handler.supportsDownload(this.entry));
 			
 		access = uifactory.addRadiosVertical("cif_access", "cif.access", formLayout, keys, values);
-		access.select("" + entry.getAccess(), true);
+		//fxdiff VCRP-1,2: access control of resources
+		if(entry.isMembersOnly()) {
+			access.select(RepositoryEntry.MEMBERS_ONLY, true);
+		} else {
+			access.select("" + entry.getAccess(), true);
+		}
 	
 		uifactory.addFormSubmitButton("submit", formLayout);
 	}
diff --git a/src/main/java/org/olat/repository/RepoBookmarkHandler.java b/src/main/java/org/olat/repository/RepoBookmarkHandler.java
index 2e22d09d1e1856e773d92496f8f85bcb1886c9cf..bd317daf1333c49ed23818ed7dba9fe2121b418c 100644
--- a/src/main/java/org/olat/repository/RepoBookmarkHandler.java
+++ b/src/main/java/org/olat/repository/RepoBookmarkHandler.java
@@ -74,7 +74,7 @@ public class RepoBookmarkHandler implements BookmarkHandler {
 			DTab dt = dts.getDTab(ores);
 			if (dt == null) {
 				// does not yet exist -> create and add
-				dt = dts.createDTab(ores, bookmark.getTitle());
+				dt = dts.createDTab(ores, re, bookmark.getTitle());
 				if (dt == null) {
 					//ups? what happend here?
 					log.warn("Could not create dTab for bookmark with title::" + bookmark.getTitle() + " and ores::" + ores);
diff --git a/src/main/java/org/olat/repository/RepositoryEntry.hbm.xml b/src/main/java/org/olat/repository/RepositoryEntry.hbm.xml
index eee33f9cf2776ecc8f6fe5a7fffe8d5b102f9af3..010bdb22e9276205b18fc541ceda623771833073 100644
--- a/src/main/java/org/olat/repository/RepositoryEntry.hbm.xml
+++ b/src/main/java/org/olat/repository/RepositoryEntry.hbm.xml
@@ -40,6 +40,20 @@
                      outer-join="true"   
                      unique="true" 
                      cascade="none"/>
+                     
+		<many-to-one name="participantGroup"
+                     column="fk_participantgroup"
+                     class="org.olat.basesecurity.SecurityGroupImpl" 
+                     outer-join="true"   
+                     unique="true" 
+                     cascade="none"/>
+                     
+		<many-to-one name="tutorGroup"
+                     column="fk_tutorgroup"
+                     class="org.olat.basesecurity.SecurityGroupImpl" 
+                     outer-join="true"   
+                     unique="true" 
+                     cascade="none"/>
 
 		<property name="description" type="string">
 			<column name="description" length="16777210" unique="false" not-null="false" />
@@ -53,6 +67,10 @@
 			<column name="accesscode" unique="false" not-null="true" index="access_idx"/>
 		</property>
 		
+		<property name="membersOnly" type="boolean">
+			<column name="membersonly" unique="false" not-null="true" />
+		</property>
+		
 		<property name="canLaunch">
 			<column name="canlaunch" unique="false" not-null="true"/>
 		</property>
diff --git a/src/main/java/org/olat/repository/RepositoryEntry.java b/src/main/java/org/olat/repository/RepositoryEntry.java
index 81232eb1eb1582c073098cf2cf17b9ffb3312be8..78d07db1ac51b9423137e972d7fee7b540f95905 100644
--- a/src/main/java/org/olat/repository/RepositoryEntry.java
+++ b/src/main/java/org/olat/repository/RepositoryEntry.java
@@ -59,9 +59,15 @@ public class RepositoryEntry extends PersistentObject implements ModifiedInfo, O
 	 */
 	public static final int ACC_USERS_GUESTS = 4; // no limits
 	
+	//fxdiff VCRP-1,2: access control of resources
+	public static final String MEMBERS_ONLY =  "membersonly";
+	
 	private String softkey; // mandatory
 	private OLATResource olatResource; // mandatory
 	private SecurityGroup ownerGroup; // mandatory
+	//fxdiff VCRP-1,2: access control of resources
+	private SecurityGroup tutorGroup;
+	private SecurityGroup participantGroup;
 	private String resourcename; // mandatory
 	private String displayname; // mandatory
 	private String description; // mandatory
@@ -71,6 +77,7 @@ public class RepositoryEntry extends PersistentObject implements ModifiedInfo, O
 	private boolean canReference;
 	private boolean canLaunch;
 	private boolean canDownload;
+	private boolean membersOnly;//fxdiff VCRP-1,2: access control of resources
 	private int statusCode;
 	private List<MetaDataElement> metaDataElements;
 	private long launchCounter;
@@ -215,6 +222,38 @@ public class RepositoryEntry extends PersistentObject implements ModifiedInfo, O
 		this.ownerGroup = ownerGroup;
 	}
 	
+	/**
+	 * @return The group for tutors
+	 */
+	//fxdiff VCRP-1,2: access control of resources
+	public SecurityGroup getTutorGroup() {
+		return tutorGroup;
+	}
+
+	/**
+	 * Set the group for tutors
+	 * @param tutorGroup
+	 */
+	public void setTutorGroup(SecurityGroup tutorGroup) {
+		this.tutorGroup = tutorGroup;
+	}
+
+	/**
+	 * @return The group of participants
+	 */
+	//fxdiff VCRP-1,2: access control of resources
+	public SecurityGroup getParticipantGroup() {
+		return participantGroup;
+	}
+
+	/**
+	 * Set the group of participants
+	 * @param participantGroup
+	 */
+	public void setParticipantGroup(SecurityGroup participantGroup) {
+		this.participantGroup = participantGroup;
+	}
+
 	/**
 	 * @return Wether this repo entry can be copied.
 	 */
@@ -249,6 +288,14 @@ public class RepositoryEntry extends PersistentObject implements ModifiedInfo, O
 	public int getAccess() {
 		return access;
 	}
+	
+	/**
+	 * Is the repository entry exclusive
+	 * @return
+	 */
+	public boolean isMembersOnly() {
+		return membersOnly;
+	}
 
 	/**
 	 * @param b
@@ -285,6 +332,14 @@ public class RepositoryEntry extends PersistentObject implements ModifiedInfo, O
 	public void setAccess(int i) {
 		access = i;
 	}
+	
+	/**
+	 * Set if the repository entry is exclusive 
+	 * @param membersOnly
+	 */
+	public void setMembersOnly(boolean membersOnly) {
+		this.membersOnly = membersOnly;
+	}
 
 	/**
 	 * @return Download count for this repo entry.
diff --git a/src/main/java/org/olat/repository/RepositoryEntryACColumnDescriptor.java b/src/main/java/org/olat/repository/RepositoryEntryACColumnDescriptor.java
new file mode 100644
index 0000000000000000000000000000000000000000..1c1b39227c622e34c50faf3b700191254c24c3fc
--- /dev/null
+++ b/src/main/java/org/olat/repository/RepositoryEntryACColumnDescriptor.java
@@ -0,0 +1,75 @@
+/**
+ * OLAT - Online Learning and Training<br>
+ * http://www.olat.org
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Copyright (c) frentix GmbH<br>
+ * http://www.frentix.com<br>
+ * <p>
+ */
+package org.olat.repository;
+
+import java.util.Collection;
+import java.util.Locale;
+
+import org.olat.core.gui.components.table.CustomCellRenderer;
+import org.olat.core.gui.render.Renderer;
+import org.olat.core.gui.render.StringOutput;
+import org.olat.resource.accesscontrol.model.OLATResourceAccess;
+import org.olat.resource.accesscontrol.model.Price;
+import org.olat.resource.accesscontrol.model.PriceMethodBundle;
+import org.olat.resource.accesscontrol.ui.PriceFormat;
+
+/**
+ * 
+ * Description:<br>
+ * TODO: srosse Class Description for RepositoryEntryACColumnDescriptor
+ * 
+ * <P>
+ * Initial Date:  18 avr. 2011 <br>
+ * @author srosse
+ */
+//fxdiff VCRP-1,2: access control of resources
+public class RepositoryEntryACColumnDescriptor implements CustomCellRenderer {
+
+	@Override
+	public void render(StringOutput sb, Renderer renderer, Object val, Locale locale, int alignment, String action) {
+		if(val instanceof Collection) {
+			Collection<?> accessTypes = (Collection<?>)val;
+			for(Object accessType:accessTypes) {
+				if(accessType instanceof String) {
+					String type = (String)accessType;
+					sb.append("<span class='b_small_icon ").append(type).append("_icon b_access_method'>").append("</span>");
+				}
+			}
+		} else if(val instanceof Boolean) {
+			boolean acessControlled = ((Boolean)val).booleanValue();
+			if(acessControlled) {
+				sb.append("<span class='b_small_icon b_group_accesscontrolled b_access_method'>").append("</span>");
+			}
+		} else if (val instanceof OLATResourceAccess) {
+			OLATResourceAccess access = (OLATResourceAccess)val;
+			for(PriceMethodBundle bundle:access.getMethods()) {
+				Price price = bundle.getPrice();
+				String type = bundle.getMethod().getMethodCssClass();
+				if(price == null || price.isEmpty()) {
+					sb.append("<span class='b_small_icon ").append(type).append("_icon b_access_method'>").append("</span>");
+				} else {
+					String p = PriceFormat.fullFormat(price);
+					sb.append("<span class='b_with_small_icon_left ").append(type).append("_icon b_access_method'>").append(p).append("</span>");
+				}
+			}
+		}
+	}
+}
diff --git a/src/main/java/org/olat/repository/RepositoryManager.java b/src/main/java/org/olat/repository/RepositoryManager.java
index 454310f87a3489107ca3986aa5bb05c4799c8499..b5dfc89564b3da513310a217c40e514da8220681 100644
--- a/src/main/java/org/olat/repository/RepositoryManager.java
+++ b/src/main/java/org/olat/repository/RepositoryManager.java
@@ -23,6 +23,7 @@ package org.olat.repository;
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 
@@ -51,6 +52,9 @@ import org.olat.core.logging.activity.OlatResourceableType;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
 import org.olat.core.manager.BasicManager;
 import org.olat.core.util.StringHelper;
+import org.olat.course.CourseFactory;
+import org.olat.course.ICourse;
+import org.olat.course.groupsandrights.CourseGroupManager;
 import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupManagerImpl;
 import org.olat.group.GroupLoggingAction;
@@ -161,6 +165,30 @@ public class RepositoryManager extends BasicManager {
 		RepositoryEntryImageController.deleteImage(re);
 	}
 	
+	public void createTutorSecurityGroup(RepositoryEntry re) {
+		if(re.getTutorGroup() != null) return;
+		
+		SecurityGroup tutorGroup = securityManager.createAndPersistSecurityGroup();
+		// member of this group may modify member's membership
+		securityManager.createAndPersistPolicy(tutorGroup, Constants.PERMISSION_ACCESS, re.getOlatResource());
+		securityManager.createAndPersistPolicy(tutorGroup, Constants.PERMISSION_COACH, re.getOlatResource());
+		// members of this group are always tutors also
+		securityManager.createAndPersistPolicy(tutorGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_TUTOR);
+		re.setTutorGroup(tutorGroup);
+	}
+	
+	public void createParticipantSecurityGroup(RepositoryEntry re) {
+		if(re.getParticipantGroup() != null) return;
+		
+		SecurityGroup participantGroup = securityManager.createAndPersistSecurityGroup();
+		// member of this group may modify member's membership
+		securityManager.createAndPersistPolicy(participantGroup, Constants.PERMISSION_ACCESS, re.getOlatResource());
+		securityManager.createAndPersistPolicy(participantGroup, Constants.PERMISSION_PARTI, re.getOlatResource());
+		// members of this group are always participants also
+		securityManager.createAndPersistPolicy(participantGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_PARTICIPANT);
+		re.setParticipantGroup(participantGroup);
+	}
+	
 	/**
 	 * 
 	 * @param addedEntry
@@ -176,6 +204,21 @@ public class RepositoryManager extends BasicManager {
 			BaseSecurityManager.getInstance().deleteSecurityGroup(ownerGroup);
 			OLATResourceManager.getInstance().deleteOLATResourceable(ownerGroup);
 		}
+		SecurityGroup participantGroup = entry.getParticipantGroup();
+		if (participantGroup != null) {
+			// delete secGroup
+			logDebug("deleteRepositoryEntry deleteSecurityGroup participantGroup=" + participantGroup);
+			BaseSecurityManager.getInstance().deleteSecurityGroup(participantGroup);
+			OLATResourceManager.getInstance().deleteOLATResourceable(participantGroup);
+		}
+		SecurityGroup tutorGroup = entry.getTutorGroup();
+		if (tutorGroup != null) {
+			// delete secGroup
+			logDebug("deleteRepositoryEntry deleteSecurityGroup tutorGroup=" + tutorGroup);
+			BaseSecurityManager.getInstance().deleteSecurityGroup(tutorGroup);
+			OLATResourceManager.getInstance().deleteOLATResourceable(tutorGroup);
+		}
+		
 		//TODO:pb:b this should be called in a  RepoEntryImageManager.delete
 		//instead of a controller.
 		RepositoryEntryImageController.deleteImage(entry);
@@ -215,6 +258,7 @@ public class RepositoryManager extends BasicManager {
 		entry = (RepositoryEntry) DBFactory.getInstance().loadObject(entry,true);
 		Tracing.logDebug("deleteRepositoryEntry after reload entry=" + entry, this.getClass());
 		deleteRepositoryEntryAndBasesecurity(entry);
+		
 		// inform handler to do any cleanup work... handler must delete the
 		// referenced resourceable aswell.
 		handler.cleanupOnDelete(entry.getOlatResource());
@@ -358,8 +402,13 @@ public class RepositoryManager extends BasicManager {
 			else return false;
 		}
 		// else allow if access granted for users
-		return re.getAccess() >= RepositoryEntry.ACC_USERS;
+		if(re.getAccess() >= RepositoryEntry.ACC_USERS) {
+			return true;
+		} else if (re.getAccess() == RepositoryEntry.ACC_OWNERS && re.isMembersOnly()) {
+			return isMember(identity, re);
+		}
 		
+		return false;
 	}
 
 	/**
@@ -388,8 +437,8 @@ public class RepositoryManager extends BasicManager {
 		}
 	}
 
-	public void setAccess(final RepositoryEntry re, int access ) {
-		SetAccessBackgroundTask task = new SetAccessBackgroundTask(re, access);
+	public void setAccess(final RepositoryEntry re, int access, boolean membersOnly ) {
+		SetAccessBackgroundTask task = new SetAccessBackgroundTask(re, access, membersOnly);
 		taskQueueManager.addTask(task);
 		task.waitForDone();
 	}
@@ -445,25 +494,34 @@ public class RepositoryManager extends BasicManager {
 
 	/**
 	 * Query by type, limit by ownership or role accessability.
+	 * @param identity Identity (optional)
 	 * @param restrictedType
 	 * @param roles
 	 * @return Results
 	 */
-	public List queryByTypeLimitAccess(String restrictedType, Roles roles) {
-		StringBuilder query = new StringBuilder(400);
-		query.append("select distinct v from" +
-			" org.olat.repository.RepositoryEntry v" +
-			" inner join fetch v.olatResource as res"+
-		  " where res.resName= :restrictedType and v.access >= ");
-
-		if (roles.isOLATAdmin()) query.append(RepositoryEntry.ACC_OWNERS); // treat admin special b/c admin is author as well
-		else {
-			if (roles.isAuthor()) query.append(RepositoryEntry.ACC_OWNERS_AUTHORS);
-			else if (roles.isGuestOnly()) query.append(RepositoryEntry.ACC_USERS_GUESTS);
-			else query.append(RepositoryEntry.ACC_USERS);
+	//fxdiff VCRP-1,2: access control of resources
+	public List<RepositoryEntry> queryByTypeLimitAccess(Identity identity, String restrictedType, Roles roles) {
+		if(roles.isOLATAdmin()) {
+			identity = null;//not need for the query as administrator
 		}
-		DBQuery dbquery = DBFactory.getInstance().createQuery(query.toString());
+		
+		StringBuilder sb = new StringBuilder(400);
+		sb.append("select distinct v from ").append(RepositoryEntry.class.getName()).append(" v ");
+		sb.append(" inner join fetch v.olatResource as res")
+			.append(" where res.resName=:restrictedType and ");
+		
+		boolean setIdentity = false;
+		if (roles.isOLATAdmin()) {
+			sb.append("v.access>=").append(RepositoryEntry.ACC_OWNERS); // treat admin special b/c admin is author as well
+		} else {
+			setIdentity = appendAccessSubSelects(sb, identity, roles);
+		}
+
+		DBQuery dbquery = DBFactory.getInstance().createQuery(sb.toString());
 		dbquery.setString("restrictedType", restrictedType);
+		if(setIdentity) {
+			dbquery.setEntity("identity", identity);
+		}
 		dbquery.setCacheable(true);
 		return dbquery.list();
 	}
@@ -474,10 +532,12 @@ public class RepositoryManager extends BasicManager {
 	 * @param roles
 	 * @return Results
 	 */
-	public List queryByTypeLimitAccess(String restrictedType, UserRequest ureq) {
+	//fxdiff VCRP-1: access control
+	public List<RepositoryEntry> queryByTypeLimitAccess(String restrictedType, UserRequest ureq) {
 		Roles roles = ureq.getUserSession().getRoles();
-		String institution = "";
-		institution = ureq.getIdentity().getUser().getProperty("institutionalName", null);
+		String institution = ureq.getIdentity().getUser().getProperty("institutionalName", null);
+		
+		List<RepositoryEntry> results = new ArrayList<RepositoryEntry>();
 		if(!roles.isOLATAdmin() && institution != null && institution.length() > 0 && roles.isInstitutionalResourceManager()) {
 			StringBuilder query = new StringBuilder(400);
 			query.append("select distinct v from org.olat.repository.RepositoryEntry v inner join fetch v.olatResource as res"
@@ -496,22 +556,27 @@ public class RepositoryManager extends BasicManager {
 			dbquery.setCacheable(true);
 			
 			long start = System.currentTimeMillis();
-			List result = dbquery.list();
+			List<RepositoryEntry> institutionalResults = dbquery.list();
 			long timeQuery1 = System.currentTimeMillis() - start;
-			Tracing.logInfo("Repo-Perf: queryByTypeLimitAccess#3 takes " + timeQuery1, this.getClass());
-			start = System.currentTimeMillis();
-			result.addAll(queryByTypeLimitAccess(restrictedType, roles));
-			long timeQuery2 = System.currentTimeMillis() - start;
-			Tracing.logInfo("Repo-Perf: queryByTypeLimitAccess#3 takes " + timeQuery2, this.getClass());
-			return result;
-			
+			logInfo("Repo-Perf: queryByTypeLimitAccess#3 takes " + timeQuery1);
+			results.addAll(institutionalResults);
+		}
+		
+		long start = System.currentTimeMillis();
+		List<RepositoryEntry> genericResults = queryByTypeLimitAccess(ureq.getIdentity(), restrictedType, roles);
+		long timeQuery3 = System.currentTimeMillis() - start;
+		logInfo("Repo-Perf: queryByTypeLimitAccess#3 takes " + timeQuery3);
+		
+		if(results.isEmpty()) {
+			results.addAll(genericResults);
 		} else {
-			long start = System.currentTimeMillis();
-			List result = queryByTypeLimitAccess(restrictedType, roles);
-			long timeQuery3 = System.currentTimeMillis() - start;
-			Tracing.logInfo("Repo-Perf: queryByTypeLimitAccess#3 takes " + timeQuery3, this.getClass());
-			return result;
+			for(RepositoryEntry genericResult:genericResults) {
+				if(!PersistenceHelper.listContainsObjectByKey(results, genericResult)) {
+					results.add(genericResult);
+				}
+			}
 		}
+		return results;
 	}
 
 	/**
@@ -667,13 +732,18 @@ public class RepositoryManager extends BasicManager {
 	 * @param limitAccess
 	 * @return Results
 	 */
-	public List queryByOwnerLimitAccess(Identity identity, int limitAccess) {
+	public List<RepositoryEntry> queryByOwnerLimitAccess(Identity identity, int limitAccess, Boolean membersOnly) {
 		String query = "select v from" +
 			" org.olat.repository.RepositoryEntry v inner join fetch v.olatResource as res," + 
 			" org.olat.basesecurity.SecurityGroupMembershipImpl as sgmsi" +
 			" where" +
 			" v.ownerGroup = sgmsi.securityGroup "+
-		  " and sgmsi.identity = :identity and v.access >= :limitAccess";
+		  " and sgmsi.identity = :identity and (v.access>=:limitAccess";
+		
+		if(limitAccess != RepositoryEntry.ACC_OWNERS && membersOnly != null && membersOnly.booleanValue()) {
+			query += " or (v.access=1 and v.membersOnly=true)";
+		}
+		query += ")";
 		
 		DBQuery dbquery = DBFactory.getInstance().createQuery(query);
 		dbquery.setEntity("identity", identity);
@@ -703,7 +773,8 @@ public class RepositoryManager extends BasicManager {
 	 * @param roles The calling user's roles
 	 * @return Results as List containing RepositoryEntries
 	 */
-	private List runGenericANDQueryWithRolesRestriction(String displayName, String author, String desc, List resourceTypes, Roles roles) {
+	private List<RepositoryEntry> runGenericANDQueryWithRolesRestriction(String displayName, String author, String desc, List resourceTypes, Identity identity, Roles roles) {
+		long start = System.currentTimeMillis();
 		StringBuilder query = new StringBuilder(400);
 		
 		boolean var_author = (author != null && author.length() != 0);
@@ -758,14 +829,12 @@ public class RepositoryManager extends BasicManager {
 			query.append("res.resName in (:resourcetypes)");
 			isFirstOfWhereClause = false;
 		}
-
+		//fxdiff VCRP-1,2: access control of resources
+		boolean setIdentity = false;
 		// finally limit on roles, if not olat admin
 		if (!roles.isOLATAdmin()) {
 			if (!isFirstOfWhereClause) query.append(" and ");
-			query.append("v.access >= ");
-			if (roles.isAuthor()) query.append(RepositoryEntry.ACC_OWNERS_AUTHORS);
-			else if (roles.isGuestOnly()) query.append(RepositoryEntry.ACC_USERS_GUESTS);
-			else query.append(RepositoryEntry.ACC_USERS);
+			setIdentity = appendAccessSubSelects(query, identity, roles);
 			isFirstOfWhereClause = false;
 		}
 		
@@ -782,7 +851,59 @@ public class RepositoryManager extends BasicManager {
 		if (var_resourcetypes) {
 			dbQuery.setParameterList("resourcetypes", resourceTypes, Hibernate.STRING);
 		}
-		return dbQuery.list();
+		if(setIdentity) {
+			dbQuery.setEntity("identity", identity);
+		}
+		
+		
+		List<RepositoryEntry> result = dbQuery.list();
+		long timeQuery1 = System.currentTimeMillis() - start;
+		logInfo("Repo-Perf: runGenericANDQueryWithRolesRestriction#1 takes " + timeQuery1);
+		return result;
+	}
+	//fxdiff VCRP-1,2: access control of resources
+	private boolean appendAccessSubSelects(StringBuilder sb, Identity identity, Roles roles) {
+		sb.append("(v.access >= ");
+		if (roles.isAuthor()) sb.append(RepositoryEntry.ACC_OWNERS_AUTHORS);
+		else if (roles.isGuestOnly()) sb.append(RepositoryEntry.ACC_USERS_GUESTS);
+		else sb.append(RepositoryEntry.ACC_USERS);
+		
+		boolean setIdentity = false;
+		if(identity != null) {
+			setIdentity = true;
+			//sub select are very quick
+			sb.append(" or (")
+				.append("  v.access=1 and v.membersOnly=true and (")
+				.append("    v.ownerGroup in (select ownerSgmsi.securityGroup from ").append(SecurityGroupMembershipImpl.class.getName()).append(" ownerSgmsi where ownerSgmsi.identity=:identity)")
+				.append("    or")
+				.append("    v.tutorGroup in (select tutorSgmsi.securityGroup from ").append(SecurityGroupMembershipImpl.class.getName()).append(" tutorSgmsi where tutorSgmsi.identity=:identity)")
+				.append("    or")
+				.append("    v.participantGroup in (select partiSgmsi.securityGroup from ").append(SecurityGroupMembershipImpl.class.getName()).append(" partiSgmsi where partiSgmsi.identity=:identity)")
+				.append(" ))");
+		}
+		sb.append(")");
+		return setIdentity;
+	}
+	
+	//fxdiff VCRP-1,2: access control
+	public boolean isMember(Identity identity, RepositoryEntry entry) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select count(v) from ").append(RepositoryEntry.class.getName()).append(" as v ")
+			.append(" where v=:repositoryEntry and ")
+			.append(" (")
+			.append("   v.ownerGroup in (select ownerSgmsi.securityGroup from ").append(SecurityGroupMembershipImpl.class.getName()).append(" ownerSgmsi where ownerSgmsi.identity=:identity)")
+			.append("   or")
+			.append("   v.tutorGroup in (select tutorSgmsi.securityGroup from ").append(SecurityGroupMembershipImpl.class.getName()).append(" tutorSgmsi where tutorSgmsi.identity=:identity)")
+			.append("   or")
+			.append("   v.participantGroup in (select partiSgmsi.securityGroup from ").append(SecurityGroupMembershipImpl.class.getName()).append(" partiSgmsi where partiSgmsi.identity=:identity)")
+			.append(" )");
+
+		DBQuery query = DBFactory.getInstance().createQuery(sb.toString());
+		query.setEntity("identity", identity);
+		query.setEntity("repositoryEntry", entry);
+		
+		Number counter = (Number)query.uniqueResult();
+		return counter.intValue() > 0;
 	}
 	
 	/**
@@ -800,7 +921,9 @@ public class RepositoryManager extends BasicManager {
 	 * @param institution null -> no restriction
 	 * @return Results as List containing RepositoryEntries
 	 */
-	public List genericANDQueryWithRolesRestriction(String displayName, String author, String desc, List resourceTypes, Roles roles, String institution) {
+	//fxdiff VCRP-1: access control
+	public List<RepositoryEntry> genericANDQueryWithRolesRestriction(String displayName, String author, String desc, List resourceTypes, Identity identity, Roles roles, String institution) {
+		List<RepositoryEntry> results = new ArrayList<RepositoryEntry>();
 		if (!roles.isOLATAdmin() && institution != null && institution.length() > 0 && roles.isInstitutionalResourceManager()) {
 			StringBuilder query = new StringBuilder(400);
 			if(author == null || author.length() == 0) author = "*";
@@ -868,25 +991,33 @@ public class RepositoryManager extends BasicManager {
 			if (var_resourcetypes) {
 				dbQuery.setParameterList("resourcetypes", resourceTypes, Hibernate.STRING);
 			}
-			List result = dbQuery.list();
-			result.addAll(runGenericANDQueryWithRolesRestriction(displayName, author, desc, resourceTypes, roles));
-			return result;
+			results.addAll(dbQuery.list());
+		}
+		
+		List<RepositoryEntry> genericResults = runGenericANDQueryWithRolesRestriction(displayName, author, desc, resourceTypes, identity, roles);
+		if(results.isEmpty()) {
+			results.addAll(genericResults);
 		} else {
-			return runGenericANDQueryWithRolesRestriction(displayName, author, desc, resourceTypes, roles);
+			for(RepositoryEntry genericResult:genericResults) {
+				if(!PersistenceHelper.listContainsObjectByKey(results, genericResult)) {
+					results.add(genericResult);
+				}
+			}
 		}
+		return results;
 	}
 	
-	public int countGenericANDQueryWithRolesRestriction(String displayName, String author, String desc, List<String> resourceTypes, Roles roles,
+	public int countGenericANDQueryWithRolesRestriction(String displayName, String author, String desc, List<String> resourceTypes, Identity identity, Roles roles,
 			String institution, boolean orderBy) {
-		DBQuery dbQuery = createGenericANDQueryWithRolesRestriction(displayName, author, desc, resourceTypes, roles, institution, orderBy, true);
+		DBQuery dbQuery = createGenericANDQueryWithRolesRestriction(displayName, author, desc, resourceTypes, identity, roles, institution, orderBy, true);
 		Number count = (Number)dbQuery.uniqueResult();
 		return count.intValue();
 	}
 	
-	public List<RepositoryEntry> genericANDQueryWithRolesRestriction(String displayName, String author, String desc, List<String> resourceTypes, Roles roles,
+	public List<RepositoryEntry> genericANDQueryWithRolesRestriction(String displayName, String author, String desc, List<String> resourceTypes, Identity identity, Roles roles,
 			String institution, int firstResult, int maxResults, boolean orderBy) {
 		
-		DBQuery dbQuery = createGenericANDQueryWithRolesRestriction(displayName, author, desc, resourceTypes, roles, institution, orderBy, false);
+		DBQuery dbQuery = createGenericANDQueryWithRolesRestriction(displayName, author, desc, resourceTypes, identity, roles, institution, orderBy, false);
 		dbQuery.setFirstResult(firstResult);
 		if(maxResults > 0) {
 			dbQuery.setMaxResults(maxResults);
@@ -895,7 +1026,7 @@ public class RepositoryManager extends BasicManager {
 		return res;
 	}
 	
-	private DBQuery createGenericANDQueryWithRolesRestriction(String displayName, String author, String desc, List<String> resourceTypes, Roles roles,
+	private DBQuery createGenericANDQueryWithRolesRestriction(String displayName, String author, String desc, List<String> resourceTypes, Identity identity, Roles roles,
 			String institution, boolean orderBy, boolean count) {
 		
 		boolean institut = (!roles.isOLATAdmin() && institution != null && institution.length() > 0 && roles.isInstitutionalResourceManager());
@@ -930,10 +1061,8 @@ public class RepositoryManager extends BasicManager {
 			     .append(" msuser.properties['institutionalName']=:institution)")
 			     .append("))");
 		} else {
-			query.append(" where v.access>=");
-			if (roles.isAuthor()) query.append(RepositoryEntry.ACC_OWNERS_AUTHORS);
-			else if (roles.isGuestOnly()) query.append(RepositoryEntry.ACC_USERS_GUESTS);
-			else query.append(RepositoryEntry.ACC_USERS);
+			query.append(" where ");
+			appendAccessSubSelects(query, identity, roles);
 		}
 		
 		if (var_author) { // fuzzy author search
@@ -990,7 +1119,6 @@ public class RepositoryManager extends BasicManager {
 	public void addOwners(Identity ureqIdentity, IdentitiesAddEvent iae, RepositoryEntry re) {
 		List<Identity> addIdentities = iae.getAddIdentities();
 		List<Identity> reallyAddedId = new ArrayList<Identity>();
-		SecurityGroup group = re.getOwnerGroup();
 		for (Identity identity : addIdentities) {
 			if (!securityManager.isIdentityInSecurityGroup(identity, re.getOwnerGroup())) {
 				securityManager.addIdentityToSecurityGroup(identity, re.getOwnerGroup());
@@ -1003,8 +1131,8 @@ public class RepositoryManager extends BasicManager {
 				} finally {
 					ThreadLocalUserActivityLogger.setStickyActionType(actionType);
 				}
-				Tracing.logAudit("Idenitity(.key):" + ureqIdentity.getKey() + " added identity '" + identity.getName()
-						+ "' to securitygroup with key " + re.getOwnerGroup().getKey(), this.getClass());
+				logAudit("Idenitity(.key):" + ureqIdentity.getKey() + " added identity '" + identity.getName()
+						+ "' to securitygroup with key " + re.getOwnerGroup().getKey());
 			}//else silently ignore already owner identities
 		}
 		iae.setIdentitiesAddedEvent(reallyAddedId);
@@ -1020,7 +1148,6 @@ public class RepositoryManager extends BasicManager {
 	public void removeOwners(Identity ureqIdentity, List<Identity> removeIdentities, RepositoryEntry re){
     for (Identity identity : removeIdentities) {
     	securityManager.removeIdentityFromSecurityGroup(identity, re.getOwnerGroup());
-			String details = "Remove Owner from RepoEntry:"+re.getKey()+" USER:" + identity.getName();
 
 			ActionType actionType = ThreadLocalUserActivityLogger.getStickyActionType();
 			ThreadLocalUserActivityLogger.setStickyActionType(ActionType.admin);
@@ -1030,10 +1157,145 @@ public class RepositoryManager extends BasicManager {
 			} finally {
 				ThreadLocalUserActivityLogger.setStickyActionType(actionType);
 			}
-			Tracing.logAudit("Idenitity(.key):" + ureqIdentity.getKey() + " removed identity '" + identity.getName()
-					+ "' from securitygroup with key " + re.getOwnerGroup().getKey(), this.getClass());
+			logAudit("Idenitity(.key):" + ureqIdentity.getKey() + " removed identity '" + identity.getName()
+					+ "' from securitygroup with key " + re.getOwnerGroup().getKey());
     }
 	}
+	
+	/**
+	 * add provided list of identities as tutor to the repo entry. silently ignore
+	 * if some identities were already tutor before.
+	 * @param ureqIdentity
+	 * @param addIdentities
+	 * @param re
+	 * @param userActivityLogger
+	 */
+	public void addTutors(Identity ureqIdentity, IdentitiesAddEvent iae, RepositoryEntry re) {
+		List<Identity> addIdentities = iae.getAddIdentities();
+		List<Identity> reallyAddedId = new ArrayList<Identity>();
+		for (Identity identity : addIdentities) {
+			if (!securityManager.isIdentityInSecurityGroup(identity, re.getTutorGroup())) {
+				securityManager.addIdentityToSecurityGroup(identity, re.getTutorGroup());
+				reallyAddedId.add(identity);
+				ActionType actionType = ThreadLocalUserActivityLogger.getStickyActionType();
+				ThreadLocalUserActivityLogger.setStickyActionType(ActionType.admin);
+				try{
+					ThreadLocalUserActivityLogger.log(GroupLoggingAction.GROUP_OWNER_ADDED, getClass(),
+							LoggingResourceable.wrap(re, OlatResourceableType.genRepoEntry), LoggingResourceable.wrap(identity));
+				} finally {
+					ThreadLocalUserActivityLogger.setStickyActionType(actionType);
+				}
+				logAudit("Idenitity(.key):" + ureqIdentity.getKey() + " added identity '" + identity.getName()
+						+ "' to securitygroup with key " + re.getTutorGroup().getKey());
+			}//else silently ignore already owner identities
+		}
+		iae.setIdentitiesAddedEvent(reallyAddedId);
+	}
+	
+	/**
+	 * remove list of identities as tutor of given repository entry.
+	 * @param ureqIdentity
+	 * @param removeIdentities
+	 * @param re
+	 * @param logger
+	 */
+	public void removeTutors(Identity ureqIdentity, List<Identity> removeIdentities, RepositoryEntry re){
+		List<BusinessGroup> groups = getCourseGroups(re);
+		for (Identity identity : removeIdentities) {
+    	securityManager.removeIdentityFromSecurityGroup(identity, re.getTutorGroup());
+    	for(BusinessGroup group:groups) {
+    		if(securityManager.isIdentityInSecurityGroup(identity, group.getOwnerGroup())) {
+					securityManager.removeIdentityFromSecurityGroup(identity, group.getOwnerGroup());
+				}
+    	}
+    	
+			ActionType actionType = ThreadLocalUserActivityLogger.getStickyActionType();
+			ThreadLocalUserActivityLogger.setStickyActionType(ActionType.admin);
+			try{
+				ThreadLocalUserActivityLogger.log(GroupLoggingAction.GROUP_OWNER_REMOVED, getClass(),
+						LoggingResourceable.wrap(re, OlatResourceableType.genRepoEntry), LoggingResourceable.wrap(identity));
+			} finally {
+				ThreadLocalUserActivityLogger.setStickyActionType(actionType);
+			}
+			logAudit("Idenitity(.key):" + ureqIdentity.getKey() + " removed identity '" + identity.getName()
+					+ "' from securitygroup with key " + re.getTutorGroup().getKey());
+    }
+	}
+	
+	/**
+	 * add provided list of identities as participant to the repo entry. silently ignore
+	 * if some identities were already participant before.
+	 * @param ureqIdentity
+	 * @param addIdentities
+	 * @param re
+	 * @param userActivityLogger
+	 */
+	public void addParticipants(Identity ureqIdentity, IdentitiesAddEvent iae, RepositoryEntry re) {
+		List<Identity> addIdentities = iae.getAddIdentities();
+		List<Identity> reallyAddedId = new ArrayList<Identity>();
+		for (Identity identity : addIdentities) {
+			if (!securityManager.isIdentityInSecurityGroup(identity, re.getParticipantGroup())) {
+				securityManager.addIdentityToSecurityGroup(identity, re.getParticipantGroup());
+				reallyAddedId.add(identity);
+				ActionType actionType = ThreadLocalUserActivityLogger.getStickyActionType();
+				ThreadLocalUserActivityLogger.setStickyActionType(ActionType.admin);
+				try{
+					ThreadLocalUserActivityLogger.log(GroupLoggingAction.GROUP_OWNER_ADDED, getClass(),
+							LoggingResourceable.wrap(re, OlatResourceableType.genRepoEntry), LoggingResourceable.wrap(identity));
+				} finally {
+					ThreadLocalUserActivityLogger.setStickyActionType(actionType);
+				}
+				logAudit("Idenitity(.key):" + ureqIdentity.getKey() + " added identity '" + identity.getName()
+						+ "' to securitygroup with key " + re.getParticipantGroup().getKey());
+			}//else silently ignore already owner identities
+		}
+		iae.setIdentitiesAddedEvent(reallyAddedId);
+	}
+	
+	/**
+	 * remove list of identities as participant of given repository entry.
+	 * @param ureqIdentity
+	 * @param removeIdentities
+	 * @param re
+	 * @param logger
+	 */
+	public void removeParticipants(Identity ureqIdentity, List<Identity> removeIdentities, RepositoryEntry re){
+    List<BusinessGroup> groups = getCourseGroups(re);
+		for (Identity identity : removeIdentities) {
+    	securityManager.removeIdentityFromSecurityGroup(identity, re.getParticipantGroup());
+    	for(BusinessGroup group:groups) {
+    		if(securityManager.isIdentityInSecurityGroup(identity, group.getPartipiciantGroup())) {
+					securityManager.removeIdentityFromSecurityGroup(identity, group.getPartipiciantGroup());
+				}
+    	}
+
+			ActionType actionType = ThreadLocalUserActivityLogger.getStickyActionType();
+			ThreadLocalUserActivityLogger.setStickyActionType(ActionType.admin);
+			try{
+				ThreadLocalUserActivityLogger.log(GroupLoggingAction.GROUP_OWNER_REMOVED, getClass(),
+						LoggingResourceable.wrap(re, OlatResourceableType.genRepoEntry), LoggingResourceable.wrap(identity));
+			} finally {
+				ThreadLocalUserActivityLogger.setStickyActionType(actionType);
+			}
+			logAudit("Idenitity(.key):" + ureqIdentity.getKey() + " removed identity '" + identity.getName()
+					+ "' from securitygroup with key " + re.getParticipantGroup().getKey());
+    }
+	}
+	
+	/**
+	 * Load the business group associated to the repository entry
+	 * @param repoEntry
+	 * @return
+	 */
+	private List<BusinessGroup> getCourseGroups(RepositoryEntry repoEntry) {
+		if("CourseModule".equals(repoEntry.getOlatResource().getResourceableTypeName())) {
+			ICourse course = CourseFactory.loadCourse(repoEntry.getOlatResource());
+			CourseGroupManager gm = course.getCourseEnvironment().getCourseGroupManager();
+			List<BusinessGroup> groups = gm.getAllLearningGroupsFromAllContexts();
+			return groups;
+		}
+		return Collections.emptyList();
+	}
 
 	/**
 	 * has one owner of repository entry the same institution like the resource manager
@@ -1065,22 +1327,20 @@ public class RepositoryManager extends BasicManager {
 	 * @param identity
 	 * @return list of RepositoryEntries
 	 */
+	 //fxdiff VCRP-1,2: access control of resources
 	public List<RepositoryEntry> getLearningResourcesAsStudent(Identity identity) {
-		List<RepositoryEntry> allRepoEntries = new ArrayList<RepositoryEntry>();
-		List<BusinessGroup>groupList = BusinessGroupManagerImpl.getInstance().findBusinessGroupsAttendedBy(BusinessGroup.TYPE_LEARNINGROUP, identity, null);
-		for (BusinessGroup group : groupList) {
-			BGContext bgContext = group.getGroupContext();
-			if (bgContext == null) continue;
-			List<RepositoryEntry> repoEntries = BGContextManagerImpl.getInstance().findRepositoryEntriesForBGContext(bgContext);
-			if (repoEntries == null || repoEntries.size() == 0) continue;
-			for (RepositoryEntry repositoryEntry : repoEntries) {
-				// only find resources that are published
-				if ( ! PersistenceHelper.listContainsObjectByKey(allRepoEntries, repositoryEntry) && repositoryEntry.getAccess() >= RepositoryEntry.ACC_USERS ) {
-					allRepoEntries.add(repositoryEntry);
-				}				
-			}
-		}
-		return allRepoEntries;
+		StringBuilder sb = new StringBuilder(400);
+		sb.append("select distinct v from ").append(RepositoryEntry.class.getName()).append(" v ")
+			.append(" inner join fetch v.olatResource as res where ")
+			.append(" (v.access>=").append(RepositoryEntry.ACC_USERS).append(" or (v.access=").append(RepositoryEntry.ACC_OWNERS).append(" and v.membersOnly=true))")
+			.append(" and ")
+			.append(" v.participantGroup in (select participantSgmsi.securityGroup from ").append(SecurityGroupMembershipImpl.class.getName()).append(" participantSgmsi where participantSgmsi.identity=:identity)");
+
+		DBQuery dbquery = DBFactory.getInstance().createQuery(sb.toString());
+		dbquery.setEntity("identity", identity);
+		dbquery.setCacheable(true);
+		List<RepositoryEntry> repoEntries = dbquery.list();	
+		return repoEntries;
 	}
 	
 	/**
@@ -1091,44 +1351,38 @@ public class RepositoryManager extends BasicManager {
 	 * @param identity
 	 * @return list of RepositoryEntries
 	 */
+	 //fxdiff VCRP-1,2: access control of resources
 	public List<RepositoryEntry> getLearningResourcesAsTeacher(Identity identity) {
-		List<RepositoryEntry> allRepoEntries = new ArrayList<RepositoryEntry>();
-		// 1: search for all learning groups where user is coach
-		List<BusinessGroup>groupList = BusinessGroupManagerImpl.getInstance().findBusinessGroupsOwnedBy(BusinessGroup.TYPE_LEARNINGROUP, identity, null);
-		for (BusinessGroup group : groupList) {
-			BGContext bgContext = group.getGroupContext();
-			if (bgContext == null) continue;
-			List<RepositoryEntry> repoEntries = BGContextManagerImpl.getInstance().findRepositoryEntriesForBGContext(bgContext);
-			if (repoEntries.size() == 0) continue;
-			for (RepositoryEntry repositoryEntry : repoEntries) {
-				// only find resources that are published
-				if ( ! PersistenceHelper.listContainsObjectByKey(allRepoEntries, repositoryEntry) && repositoryEntry.getAccess() >= RepositoryEntry.ACC_USERS) {
-					allRepoEntries.add(repositoryEntry);
-				}				
-			}
-		}
+		StringBuilder sb = new StringBuilder(400);
+		sb.append("select distinct v from ").append(RepositoryEntry.class.getName()).append(" v ")
+			.append(" inner join fetch v.olatResource as res where ")
+			.append(" (v.access>=").append(RepositoryEntry.ACC_USERS).append(" or (v.access=").append(RepositoryEntry.ACC_OWNERS).append(" and v.membersOnly=true))")
+			.append(" and ")
+			.append(" (")
+			.append("  v.tutorGroup in (select tutorSgmsi.securityGroup from ").append(SecurityGroupMembershipImpl.class.getName()).append(" tutorSgmsi where tutorSgmsi.identity=:identity)")
+			.append("  or")
+			.append("  v.ownerGroup in (select ownerSgmsi.securityGroup from ").append(SecurityGroupMembershipImpl.class.getName()).append(" ownerSgmsi where ownerSgmsi.identity=:identity)")
+			.append(" )");
+
+		DBQuery dbquery = DBFactory.getInstance().createQuery(sb.toString());
+		dbquery.setEntity("identity", identity);
+		dbquery.setCacheable(true);
+		List<RepositoryEntry> repoEntries = dbquery.list();
+		List<RepositoryEntry> allRepoEntries = new ArrayList<RepositoryEntry>(repoEntries);
+		
+		
 		// 2: search for all learning groups where user is coach
-		List<BusinessGroup>rightGrougList = BusinessGroupManagerImpl.getInstance().findBusinessGroupsAttendedBy(BusinessGroup.TYPE_RIGHTGROUP, identity, null);
+		List<BGContext> bgContexts = new ArrayList<BGContext>();
+		List<BusinessGroup> rightGrougList = BusinessGroupManagerImpl.getInstance().findBusinessGroupsAttendedBy(BusinessGroup.TYPE_RIGHTGROUP, identity, null);
 		for (BusinessGroup group : rightGrougList) {
 			BGContext bgContext = group.getGroupContext();
-			if (bgContext == null) continue;
-			List<RepositoryEntry> repoEntries = BGContextManagerImpl.getInstance().findRepositoryEntriesForBGContext(bgContext);
-			if (repoEntries.size() == 0) continue;
-			for (RepositoryEntry repositoryEntry : repoEntries) {
-				// only find resources that are published
-				if ( ! PersistenceHelper.listContainsObjectByKey(allRepoEntries, repositoryEntry) && repositoryEntry.getAccess() >= RepositoryEntry.ACC_USERS) {
-					allRepoEntries.add(repositoryEntry);
-				}				
+			if (bgContext != null && !PersistenceHelper.listContainsObjectByKey(bgContexts, bgContext)) {
+				bgContexts.add(bgContext);
 			}
 		}
-		// 3) search for all published learning resources that user owns
-		List<RepositoryEntry> repoEntries = RepositoryManager.getInstance().queryByOwnerLimitAccess(identity, RepositoryEntry.ACC_USERS);
-		for (RepositoryEntry repositoryEntry : repoEntries) {
-			if ( ! PersistenceHelper.listContainsObjectByKey(allRepoEntries, repositoryEntry)) {
-				allRepoEntries.add(repositoryEntry);
-			}				
-		}
+		
+		List<RepositoryEntry> repoEntriesRightGroup = BGContextManagerImpl.getInstance().findRepositoryEntriesForBGContext(bgContexts, RepositoryEntry.ACC_USERS, false, false, false, identity);
+		allRepoEntries.addAll(repoEntriesRightGroup);
 		return allRepoEntries;
 	}
-	
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/repository/RepositoryTableModel.java b/src/main/java/org/olat/repository/RepositoryTableModel.java
index bc77e8027c186e2abf2193ae17ef3d3894739e42..e8bcd2078c9e9d3123cf523e2c94e56a3f8a1635 100644
--- a/src/main/java/org/olat/repository/RepositoryTableModel.java
+++ b/src/main/java/org/olat/repository/RepositoryTableModel.java
@@ -22,9 +22,16 @@
 package org.olat.repository;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.components.table.ColumnDescriptor;
+import org.olat.core.gui.components.table.CustomCellRenderer;
+import org.olat.core.gui.components.table.CustomRenderColumnDescriptor;
 import org.olat.core.gui.components.table.DefaultColumnDescriptor;
 import org.olat.core.gui.components.table.DefaultTableDataModel;
 import org.olat.core.gui.components.table.StaticColumnDescriptor;
@@ -32,6 +39,9 @@ import org.olat.core.gui.components.table.TableController;
 import org.olat.core.gui.components.table.TableDataModel;
 import org.olat.core.gui.translator.PackageTranslator;
 import org.olat.core.gui.translator.Translator;
+import org.olat.resource.accesscontrol.manager.ACFrontendManager;
+import org.olat.resource.accesscontrol.model.AccessMethod;
+import org.olat.resource.accesscontrol.model.OLATResourceAccess;
 
 /**
  * Initial Date:  Mar 31, 2004
@@ -52,9 +62,12 @@ public class RepositoryTableModel extends DefaultTableDataModel implements Table
 	 * Identifies a table launch event (if clicked on an item in the name column).
 	 */
 	public static final String TABLE_ACTION_SELECT_ENTRY = "rtbSelectEntry";
-	
-	private static final int COLUMN_COUNT = 6;
+	//fxdiff VCRP-1,2: access control of resources
+	private static final int COLUMN_COUNT = 7;
 	Translator translator; // package-local to avoid synthetic accessor method.
+	private final ACFrontendManager acFrontendManager;
+	
+	private Map<Long,OLATResourceAccess> repoEntriesWithOffer;
 		
 	/**
 	 * Default constructor.
@@ -63,6 +76,7 @@ public class RepositoryTableModel extends DefaultTableDataModel implements Table
 	public RepositoryTableModel(Translator translator) {
 		super(new ArrayList<RepositoryEntry>());
 		this.translator = translator;
+		acFrontendManager = (ACFrontendManager)CoreSpringFactory.getBean("acFrontendManager");
 	}
 
 	/**
@@ -71,15 +85,17 @@ public class RepositoryTableModel extends DefaultTableDataModel implements Table
 	 * @param enableDirectLaunch
 	 */
 	public void addColumnDescriptors(TableController tableCtr, String selectButtonLabel, boolean enableDirectLaunch) {
-		
-		
-		tableCtr.addColumnDescriptor(new RepositoryEntryTypeColumnDescriptor("table.header.typeimg", 0, null, 
+		//fxdiff VCRP-1,2: access control of resources
+		CustomCellRenderer acRenderer = new RepositoryEntryACColumnDescriptor();
+		tableCtr.addColumnDescriptor(new CustomRenderColumnDescriptor("table.header.ac", 0, null, 
+				translator.getLocale(), ColumnDescriptor.ALIGNMENT_LEFT, acRenderer));
+		tableCtr.addColumnDescriptor(new RepositoryEntryTypeColumnDescriptor("table.header.typeimg", 1, null, 
 				translator.getLocale(), ColumnDescriptor.ALIGNMENT_LEFT));
-		tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("table.header.displayname", 1, enableDirectLaunch ? TABLE_ACTION_SELECT_ENTRY : null, translator.getLocale()));
-		tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("table.header.author", 2, null, translator.getLocale()));
-		tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("table.header.access", 3, null, translator.getLocale()));
-		tableCtr.addColumnDescriptor(false, new DefaultColumnDescriptor("table.header.date", 4, null, translator.getLocale()));
-		tableCtr.addColumnDescriptor(false, new DefaultColumnDescriptor("table.header.lastusage", 5, null, translator.getLocale()));
+		tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("table.header.displayname", 2, enableDirectLaunch ? TABLE_ACTION_SELECT_ENTRY : null, translator.getLocale()));
+		tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("table.header.author", 3, null, translator.getLocale()));
+		tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("table.header.access", 4, null, translator.getLocale()));
+		tableCtr.addColumnDescriptor(false, new DefaultColumnDescriptor("table.header.date", 5, null, translator.getLocale()));
+		tableCtr.addColumnDescriptor(false, new DefaultColumnDescriptor("table.header.lastusage", 6, null, translator.getLocale()));
 		if (selectButtonLabel != null) {
 			StaticColumnDescriptor desc = new StaticColumnDescriptor(TABLE_ACTION_SELECT_LINK, selectButtonLabel, selectButtonLabel);
 			desc.setTranslateHeaderKey(false);			
@@ -95,18 +111,34 @@ public class RepositoryTableModel extends DefaultTableDataModel implements Table
 		return COLUMN_COUNT;
 	}
 
-
-
 	/**
 	 * @see org.olat.core.gui.components.table.TableDataModel#getValueAt(int, int)
 	 */
 	public Object getValueAt(int row, int col) {
 		RepositoryEntry re = (RepositoryEntry)getObject(row);
 		switch (col) {
-			case 0: return re; 
-			case 1: return getDisplayName(re, translator.getLocale());
-			case 2: return re.getInitialAuthor();
-			case 3: {
+			//fxdiff VCRP-1,2: access control of resources
+			case 0: {
+				if (re.isMembersOnly()) {
+					// members only always show lock icon
+					List<String> types = new ArrayList<String>(1);
+					types.add("b_access_membersonly");
+					return types;
+				}
+				OLATResourceAccess access = repoEntriesWithOffer.get(re.getOlatResource().getKey());
+				if(access == null) {
+					return null;						
+				}
+				return access;
+			}
+			case 1: return re; 
+			case 2: return getDisplayName(re, translator.getLocale());
+			case 3: return re.getInitialAuthor();
+			case 4: {
+				//fxdiff VCRP-1,2: access control of resources
+				if(re.isMembersOnly()) {
+					return translator.translate("table.header.access.membersonly"); 
+				}
 				switch (re.getAccess()) {
 					case RepositoryEntry.ACC_OWNERS: return translator.translate("table.header.access.owner");
 					case RepositoryEntry.ACC_OWNERS_AUTHORS: return translator.translate("table.header.access.author");
@@ -118,12 +150,25 @@ public class RepositoryTableModel extends DefaultTableDataModel implements Table
 						return "ERROR";
 				}
 			}
-			case 4: return re.getCreationDate();
-			case 5: return re.getLastUsage();
+			case 5: return re.getCreationDate();
+			case 6: return re.getLastUsage();
 			default: return "ERROR";
 		}
 	}
 	
+	
+	@Override
+	//fxdiff VCRP-1,2: access control of resources
+	public void setObjects(List objects) {
+		super.setObjects(objects);
+		
+		repoEntriesWithOffer = new HashMap<Long,OLATResourceAccess>();
+		List<OLATResourceAccess> withOffers = acFrontendManager.filterRepositoryEntriesWithAC(objects);
+		for(OLATResourceAccess withOffer:withOffers) {
+			repoEntriesWithOffer.put(withOffer.getResource().getKey(), withOffer);
+		}
+	}
+
 	/**
 	 * Get displayname of a repository entry. If repository entry a course 
 	 * and is this course closed then add a prefix to the title.
diff --git a/src/main/java/org/olat/repository/_chelp/rep-meta-olatauthor.html b/src/main/java/org/olat/repository/_chelp/rep-meta-olatauthor.html
index 48cd2be95d7b8e4ebbb9b1f367c31fa9c02e934e..9f5ccdea4df61913aaaa02eb856e1a4d97db30be 100644
--- a/src/main/java/org/olat/repository/_chelp/rep-meta-olatauthor.html
+++ b/src/main/java/org/olat/repository/_chelp/rep-meta-olatauthor.html
@@ -9,5 +9,8 @@
 	<li>$r.translate("chelp.rep15") <br/></li>
 	<li>$r.translate("chelp.rep16") <br/></li>
 	<li>$r.translate("chelp.rep17") <br/></li>
-	<li>$r.translate("chelp.rep18") </li>
+	<li>$r.translate("chelp.rep18") <br/></li>
+	<!-- fxdiff VCRP-1,2: access control of resources -->
+	<li>$r.translate("chelp.membersonly")</li> 
+	
 	</ul>
diff --git a/src/main/java/org/olat/repository/_chelp/rep-meta-olatauthorEd.html b/src/main/java/org/olat/repository/_chelp/rep-meta-olatauthorEd.html
index b42be4e2a82c5ea3a70e281ec3d1c67d6940d930..c6dc031ec1b0d330674417e772db5d3ed531c9c3 100644
--- a/src/main/java/org/olat/repository/_chelp/rep-meta-olatauthorEd.html
+++ b/src/main/java/org/olat/repository/_chelp/rep-meta-olatauthorEd.html
@@ -8,5 +8,7 @@
 	$r.translate("chelp.rep15") <br/>
 	$r.translate("chelp.rep16") <br/>
 	$r.translate("chelp.rep17") <br/>
-	$r.translate("chelp.rep18") 
+	$r.translate("chelp.rep18") <br />
+	<!-- fxdiff VCRP-1,2: access control of resources -->
+	$r.translate("chelp.membersonly") 
 </fieldset>
\ No newline at end of file
diff --git a/src/main/java/org/olat/repository/_content/editproptabpub.html b/src/main/java/org/olat/repository/_content/editproptabpub.html
index 4f508e76baa8a89a79fb0aefa421c23155c1e948..67422e46645faa89536314525d386e5ca499e1c2 100644
--- a/src/main/java/org/olat/repository/_content/editproptabpub.html
+++ b/src/main/java/org/olat/repository/_content/editproptabpub.html
@@ -2,4 +2,17 @@
 	<legend>$r.translate("rentry.prop")</legend>
 	$r.contextHelpWithWrapper("org.olat.repository","rep-meta-olatauthorEd.html", "help.hover.rep.detail")
 	$r.render("proppupform")
+	
+	#if($r.available("accesscontrol") && $isGuestAccess)
+	<div class="b_warning">
+		<b>$r.translate("warn.header")</b>: 
+		$r.translate("cif.access.users_guests.warning")
+	</div>
+	#end
+	
 </fieldset>
+
+#if($r.available("accesscontrol"))
+	$r.render("accesscontrol")
+#end
+
diff --git a/src/main/java/org/olat/repository/_content/groups.html b/src/main/java/org/olat/repository/_content/groups.html
index 6190f34520ccd6136371dd526dd5d7b1f84d11de..8e26699a2e6183701467e06c1699e9844a1a1ed7 100644
--- a/src/main/java/org/olat/repository/_content/groups.html
+++ b/src/main/java/org/olat/repository/_content/groups.html
@@ -1,6 +1,6 @@
-<h4>$r.translate("groups.header")</h4>
 $r.contextHelpWithWrapper("org.olat.repository", "rep-meta-info-owner.html", "help.hover.meta.info.owner")
-<p>
+<h4>$r.translate("groups.header")</h4>
+<p  class="b_info">
 	$r.translate("groups.intro")
 </p>
 $r.render("groupcomp")
\ No newline at end of file
diff --git a/src/main/java/org/olat/repository/_content/groups_participant.html b/src/main/java/org/olat/repository/_content/groups_participant.html
new file mode 100644
index 0000000000000000000000000000000000000000..5f483ebe9ad303a704242461a6a77efa442d62ef
--- /dev/null
+++ b/src/main/java/org/olat/repository/_content/groups_participant.html
@@ -0,0 +1,5 @@
+<h4>$r.translate("groups.participant.header")</h4>
+<p class="b_info">
+	$r.translate("groups.participant.intro")
+</p>
+$r.render("groupcomp")
\ No newline at end of file
diff --git a/src/main/java/org/olat/repository/_content/groups_tutor.html b/src/main/java/org/olat/repository/_content/groups_tutor.html
new file mode 100644
index 0000000000000000000000000000000000000000..97dcfd6e975a100c6dac4e89aaa7cec2f2acd207
--- /dev/null
+++ b/src/main/java/org/olat/repository/_content/groups_tutor.html
@@ -0,0 +1,5 @@
+<h4>$r.translate("groups.tutor.header")</h4>
+<p class="b_info">
+	$r.translate("groups.tutor.intro")
+</p>
+$r.render("groupcomp")
\ No newline at end of file
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties
index 267e753c973e11ecaecfcfbd929698b1c05f0111..3d02a52c9c67c3a80e176981375b29d6fdc359b2 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties
@@ -102,6 +102,7 @@ chelp.o=<i>&laquo;$org.olat.repository\:cif.access.owners&raquo;</i>\:
 chelp.oa=<i>&laquo;$org.olat.repository\:cif.access.owners_authors&raquo;</i>\:
 chelp.oau=<i>&laquo;$org.olat.repository\:cif.access.users&raquo;</i>\:
 chelp.oaug=<i>&laquo;$org.olat.repository\:cif.access.users_guests&raquo;</i>\:
+chelp.m=<i>&laquo;$:cif.access.membersonly&raquo;</i>\:
 
 
 chelp.ref=<b>$org.olat.repository\:cif.resourcename\:</b>
@@ -186,6 +187,11 @@ cif.access.owners=Nur Besitzer dieser Lernressource
 cif.access.owners_authors=Besitzer und \u00FCbrige OLAT-Autoren
 cif.access.users=Alle registrierten OLAT-Benutzer
 cif.access.users_guests=Registrierte OLAT-Benutzer und G\u00E4ste
+cif.access.users_guests.warning=Gäste können in dieser Konfiguration ohne weitere Einschränkung auf diese Lernressource zugreifen. Allfällige weiter unten konfigurierte Buchungsmethoden haben keine Anwendung für anonyme Gäste. Die Buchung ist in dem Fall nur für die registrierten Benutzer relevant. Innerhalb eines Kurses können Sie einzelne Bausteine für Gäste sperren und andere nur für registrierte Benutzer freischalten. 
+cif.access.membersonly=Nur Mitglieder dieser Lernressource (Besitzer, Betreuer, Teilnehmer)
+chelp.membersonly=$\:chelp.m Lediglich die Mitglieder dieser Lernressource k\u00F6nnen die Lernressource sehen und auf sie zugreifen. Als Mitglieder gelten alle Besitzer, Betreuer und Teilnehmer. Wählen Sie diese Konfiguration wenn Sie den Zugriff nur einzelnene Personen gewähren lassen wollen. Die zugelassenen Personen können Sie in der Teilnehmerverwaltung der Ressoruce administrieren. 
+
+
 cif.author=Autor
 cif.canCopy=Kopieren m\u00F6glich
 cif.canDownload=Export m\u00F6glich
@@ -250,7 +256,11 @@ details.edit=\u00C4ndern
 details.edit.error.references=Lernressource kann nicht editiert werden. Es bestehen aktive Referenzen auf die gew\u00E4hlte Lernressource innerhalb von OLAT.<br /><br /><font color\="red">{0}</font>
 details.entryinfoheader=Information zum Eintrag
 details.extlinkheader=Externer Link auf diese Lernressource
+details.members=Mitgliederverwaltung
 details.groups=Besitzer verwalten
+details.groups.tutor=Betreuer verwalten
+details.groups.participant=Teilnehmer verwalten
+details.orders=Buchungen
 details.header=Detailansicht
 details.launch=Inhalt anzeigen
 details.noreferenceinfo=Wird in keinem Kurs verwendet.
@@ -279,7 +289,11 @@ form.log.level.user=Benutzer-Logfile (personalisiert)
 glossary.isconfigured=Gew\u00E4hltes Glossar
 glossary.no.glossary=Kein Glossar gew\u00E4hlt
 groups.header=Besitzer der Lernressource verwalten
-groups.intro=Sie können beliebige OLAT-Benutzer zu Besitzern der gew\u00E4hlten Lernressource ernennen und bisherige Besitzer entfernen.<br />Besitzer k\u00F6nnen die Lernressource anzeigen lassen, bearbeiten, l\u00F6schen und Besitzer verwalten.
+groups.intro=$org.olat.resource.accesscontrol.ui:members.owners.info
+groups.tutor.header=Betreuer der Lernressource verwalten
+groups.tutor.intro=$org.olat.resource.accesscontrol.ui:members.tutors.info
+groups.participant.header=Teilnehmer der Lernressource verwalten
+groups.participant.intro=$org.olat.resource.accesscontrol.ui:members.participants.info
 heading.disabled=Funktion nicht verf\u00FCgbar
 help.hover.rep.detail=Hilfe zu den Informationen in der Lernressourcen-Detailansicht
 help.hover.rep.picture=Hilfe zum Hochladen eines Bildes zur Lernressource
@@ -349,8 +363,11 @@ search.mycourses.teacher=Meine betreuten Kurse
 search.podcast=Podcasts
 search.blog=Blogs
 search.limit.type=Suche einschränken
+search.filter.type=Typ
+search.filter.showAll=alle anzeigen
 sf.notconfigured=Kein Ressourcenordner ausgew\u00E4hlt
 sf.resourcetitle=Gew\u00E4hlter Ressourcenordner
+tab.accesscontrol=Access control
 tab.calendar=Kalender
 tab.chat=Kurs-Chat
 tab.efficencystatement=Leistungsnachweis
@@ -361,12 +378,14 @@ tab.public=Allgemein
 tab.glossary.flexions=Morphologischer Dienst
 tab.glossary.register=Alphabetisches Register
 tab.sharedfolder=Ressourcenordner
+table.header.ac=AC
 table.header.access=Zugriff*
 table.header.access.author=<span class\="o_ochre">BA--</span>
 table.header.access.desc=*)<br />B\=<b>B</b>esitzer dieser Lernressource <span class\="o_ochre"> (nicht \u00F6ffentlich)</span><br />A\=Alle OLAT-<b>A</b>utoren <span class\="o_ochre"> (nicht \u00F6ffentlich)</span><br />R\=<b>R</b>egistrierte OLAT-Benutzer <span class\="o_blue"> (\u00F6ffentlich)</span><br />G\=<b>G</b>\u00E4ste <span class\="o_blue"> (\u00F6ffentlich)</span>
 table.header.access.guest=<span class\="o_blue">BARG</span>
 table.header.access.owner=<span class\="o_ochre">B---</span>
 table.header.access.user=<span class\="o_blue">BAR-</span>
+table.header.access.membersonly=<span class\="o_blue">Nur Mitglieder</span>
 table.header.author=Urheber
 table.header.date=Erstellt
 table.header.description=Beschreibung
@@ -431,7 +450,7 @@ wizardsteptitleupload=Datei hochladen
 referencableSearch.cmd.searchEntries=Suchen
 cmd.import.ressource = Importieren
 cmd.create.ressource = Erstellen
-message.entry.selected = Die Lernressource {0} vom Typ {1} wurde erfolgreich zugeordnet.
+message.entry.selected = Die Lernressource "{0}" vom Typ "{1}" wurde erfolgreich zugeordnet.
 details.close.ressoure = Beenden
 title.prefix.closed = beendet
 wizard.closecourse.title = Assistent zum Beenden eines Kurses 
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_en.properties
index 353d0bfbcdd86c1976c4cba33af362dd69069c40..79710067b8b9a58a7a50e9d8d27b3a384d1fcdcd 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_en.properties
@@ -1,4 +1,4 @@
-#Fri Jan 21 19:17:54 CET 2011
+#Mon May 16 17:32:41 CEST 2011
 CourseModule=Course
 EPStructuredMapTemplate=Portfolio template
 Failed=The transmission of this file failed.
@@ -67,7 +67,9 @@ chelp.guest=<i>guest</i>
 chelp.img=<i>$org.olat.repository\:FileResource.IMAGE</i>
 chelp.iniAuth=$org.olat.repository\:cif.initialAuthor
 chelp.lang=<i>lang</i>
+chelp.m=<i>&laquo;$\:cif.access.membersonly&raquo;</i>\:
 chelp.mask=$org.olat.repository\:search.generic
+chelp.membersonly=$\:chelp.m Only members of this learning resource have access to this learning resource. Members are defined as the list of owners, coaches and participants. Select this configuration if you want to restrict access to this resource to a limited set of users. You can manage the members in the members management tool in the administration section.
 chelp.mov=<i>$org.olat.repository\:FileResource.MOVIE</i>
 chelp.na=$org.olat.repository\:cif.id.na\t
 chelp.noDownl=$org.olat.repository\:cif.canDownload.na
@@ -153,10 +155,12 @@ chkbx.chat.onoff=Use course chat
 chkbx.efficency.onoff=Use evidence of achievement
 chkbx.glossary.onoff=Use glossary
 cif.access=Access have
+cif.access.membersonly=Members only (owners, coaches, participants)
 cif.access.owners=Only owners of this learning resource
 cif.access.owners_authors=Owners and other OLAT authors
 cif.access.users=All registered OLAT users
 cif.access.users_guests=Registered OLAT users and guests
+cif.access.users_guests.warning=This configuration allows anonymous guests to access the learning resource without restrictions. Be aware that booking methods configured below will not apply to those anonymous guest users. If you configure booking methods, those booking methods will only apply to registered users who want to access the resource. Within the course you can prevent single course elements from beeing accessible to guest users.
 cif.author=Author
 cif.canCopy=Can be copied
 cif.canDownload=Can be downloaded
@@ -228,11 +232,15 @@ details.edit.error.references=This learning resource cannot be edited. There are
 details.entryinfoheader=Information on this entry
 details.extlinkheader=External link to this learning resource
 details.groups=Manage owners
+details.groups.participant=Manage participants
+details.groups.tutor=Manage owners
 details.header=Detailed view
 details.launch=Show content
+details.members=Members management
 details.noreferenceinfo=Not used in any course.
 details.notypeinfo=No type-specific information available.
 details.openeditor=Edit content
+details.orders=Bookings
 details.owner=Owner of learning resource
 details.referenceinfo=References
 details.referenceinfoheader=Information on usage
@@ -258,6 +266,10 @@ glossary.isconfigured=Selected glossary
 glossary.no.glossary=No glossary selected
 groups.header=Manage owners of this learning resource
 groups.intro=Assign any OLAT users to owners of the selected learning resource or remove previous owners.<br />Owners can read, modify, and delete learning resources as well as manage their owners.
+groups.participant.header=Manage participants of this learning resource
+groups.participant.intro=org.olat.resource.accesscontrol.ui\:members.participants.info
+groups.tutor.header=Manage coaches of this learning resource
+groups.tutor.intro=$org.olat.resource.accesscontrol.ui\:members.tutors.info
 heading.disabled=Function not available
 help.hover.meta.info.owner=Help regarding owners
 help.hover.rep.detail=Help regarding the information in the detailed view of learning resources
@@ -268,7 +280,7 @@ info.could.not.delete.entry=This entry could not be deleted.
 info.entry.deleted=Entry deleted.
 info.message.change.title=This course has been changed successfully to [Closed].
 launch.noaccess=You have not enough access rights to launch this learning resource.
-message.entry.selected=Learning resource {0} with type {1} allocated successfully.
+message.entry.selected=Learning resource "{0}" with type "{1}" allocated successfully.
 msg.warnusers=(There are {0} users currently using this resource)
 new.blog=Create blog
 new.blog.intro=Create new blog
@@ -317,6 +329,8 @@ search.blog=Blogs
 search.catalog=Catalog
 search.course=Courses
 search.cp=CP learning content
+search.filter.showAll=Show all
+search.filter.type=Type
 search.generic=Search form
 search.glossary=Glossary
 search.home=Learning resources
@@ -335,6 +349,7 @@ search.test=Tests
 search.wiki=Wikis
 sf.notconfigured=No resource folder selected
 sf.resourcetitle=Selected resource folder
+tab.accesscontrol=Access control
 tab.calendar=Calendar
 tab.chat=Course chat
 tab.efficencystatement=Evidence of achievement
@@ -345,10 +360,12 @@ tab.layout=Layout
 tab.log=Log files
 tab.public=General
 tab.sharedfolder=Resource folder
+table.header.ac=AC
 table.header.access=Access*
 table.header.access.author=<span class\="o_ochre">OA--</span>
 table.header.access.desc=*)<br />O\=<b>O</b>wners of this learning resource <span class\="o_ochre"> (not public)</span><br />A\=All OLAT <b>a</b>uthors <span class\="o_ochre"> (not public)</span><br />U\=Registered OLAT<b>u</b>sers <span class\="o_blue"> (public)</span><br />G\=<b>G</b>uests <span class\="o_blue"> (public)</span>
 table.header.access.guest=<span class\="o_blue">OAUG</span>
+table.header.access.membersonly=<span class\="o_blue">Members only</span>
 table.header.access.owner=<span class\="o_ochre">O---</span>
 table.header.access.user=<span class\="o_blue">OAU-</span>
 table.header.author=Author
diff --git a/src/main/java/org/olat/repository/async/AbstractBackgroundTask.java b/src/main/java/org/olat/repository/async/AbstractBackgroundTask.java
index dfc331b0091059ddbee82be660f8644063ff4064..3f1ad3bce9804f785abc528f2f30dfa665451242 100644
--- a/src/main/java/org/olat/repository/async/AbstractBackgroundTask.java
+++ b/src/main/java/org/olat/repository/async/AbstractBackgroundTask.java
@@ -132,7 +132,7 @@ public abstract class AbstractBackgroundTask implements BackgroundTask {
             }
 		}
 		if (counter >= COUNTER_LIMIT) {
-			log.error("waitForDone: Could not finish BackgroundTask");
+			log.error("waitForDone: Could not finish BackgroundTask this=" + this);
 		}
     }
 
diff --git a/src/main/java/org/olat/repository/async/SetAccessBackgroundTask.java b/src/main/java/org/olat/repository/async/SetAccessBackgroundTask.java
index 1b9dc9bde478d5b1206e88ba49dfd6701be47cf2..55c438d46b00ce76f0f4216f3915f8d1c6979530 100644
--- a/src/main/java/org/olat/repository/async/SetAccessBackgroundTask.java
+++ b/src/main/java/org/olat/repository/async/SetAccessBackgroundTask.java
@@ -35,10 +35,12 @@ public class SetAccessBackgroundTask extends AbstractBackgroundTask {
 	
 	private RepositoryEntry repositoryEntry;
 	private int access;
+	private boolean membersOnly;//fxdiff VCRP-1,2: access control of resources
 	
-	public SetAccessBackgroundTask(RepositoryEntry repositoryEntry, int access) {
+	public SetAccessBackgroundTask(RepositoryEntry repositoryEntry, int access, boolean membersOnly) {
 		this.repositoryEntry = repositoryEntry;
 		this.access = access;
+		this.membersOnly = membersOnly;
 	}
 	
 	public void executeTask() {
@@ -48,6 +50,7 @@ public class SetAccessBackgroundTask extends AbstractBackgroundTask {
 		if ( RepositoryManager.getInstance().lookupRepositoryEntry(repositoryEntry.getKey()) != null ) {
 			RepositoryEntry reloadedRe = (RepositoryEntry) DBFactory.getInstance().loadObject(repositoryEntry, true);
 			reloadedRe.setAccess(access);
+			reloadedRe.setMembersOnly(membersOnly);//fxdiff VCRP-1,2: access control of resources
 			RepositoryManager.getInstance().updateRepositoryEntry(reloadedRe);
 			log.debug("SetAccessBackgroundTask DONE for repositoryEntry=" + repositoryEntry + "  this=" + this);
 		} else {
diff --git a/src/main/java/org/olat/repository/controllers/RepositoryAddController.java b/src/main/java/org/olat/repository/controllers/RepositoryAddController.java
index 1279ddfa032e35ed547aa24b5a9f179de020444c..e7e1e0e6be621f624390f0db209d310c529b93b7 100644
--- a/src/main/java/org/olat/repository/controllers/RepositoryAddController.java
+++ b/src/main/java/org/olat/repository/controllers/RepositoryAddController.java
@@ -381,7 +381,8 @@ public class RepositoryAddController extends BasicController {
 		OLATResource ores = OLATResourceManager.getInstance().findOrPersistResourceable(addCallback.getResourceable());
 		addedEntry.setOlatResource(ores);
 		
-		// create security group
+		// create security groups
+		//security group for owners / authors
 		SecurityGroup newGroup = securityManager.createAndPersistSecurityGroup();
 		// member of this group may modify member's membership
 		securityManager.createAndPersistPolicy(newGroup, Constants.PERMISSION_ACCESS, newGroup);
@@ -391,6 +392,23 @@ public class RepositoryAddController extends BasicController {
 		securityManager.addIdentityToSecurityGroup(ureq.getIdentity(), newGroup);
 		addedEntry.setOwnerGroup(newGroup);
 		
+		//fxdiff VCRP-1,2: access control of resources
+		// security group for tutors / coaches
+		SecurityGroup tutorGroup = securityManager.createAndPersistSecurityGroup();
+		// member of this group may modify member's membership
+		securityManager.createAndPersistPolicy(tutorGroup, Constants.PERMISSION_ACCESS, addedEntry.getOlatResource());
+		// members of this group are always tutors also
+		securityManager.createAndPersistPolicy(tutorGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_TUTOR);
+		addedEntry.setTutorGroup(tutorGroup);
+		
+		// security group for participants
+		SecurityGroup participantGroup = securityManager.createAndPersistSecurityGroup();
+		// member of this group may modify member's membership
+		securityManager.createAndPersistPolicy(participantGroup, Constants.PERMISSION_ACCESS, addedEntry.getOlatResource());
+		// members of this group are always participants also
+		securityManager.createAndPersistPolicy(participantGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_PARTICIPANT);
+		addedEntry.setParticipantGroup(participantGroup);
+		
 		rm.saveRepositoryEntry(addedEntry);
 
 		removeAsListenerAndDispose(detailsController);
diff --git a/src/main/java/org/olat/repository/controllers/RepositoryCopyController.java b/src/main/java/org/olat/repository/controllers/RepositoryCopyController.java
index e3e24d6e9940f256405bee462f8098512a86eb14..adbef276cac9ba3db92967b1669b57424d9a90e3 100644
--- a/src/main/java/org/olat/repository/controllers/RepositoryCopyController.java
+++ b/src/main/java/org/olat/repository/controllers/RepositoryCopyController.java
@@ -25,7 +25,6 @@ import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.BaseSecurityManager;
 import org.olat.basesecurity.Constants;
 import org.olat.basesecurity.SecurityGroup;
-import org.olat.core.commons.persistence.DBFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.link.Link;
@@ -195,6 +194,24 @@ public class RepositoryCopyController extends BasicController {
 		
 		securityManager.addIdentityToSecurityGroup(ureq.getIdentity(), newGroup);
 		preparedEntry.setOwnerGroup(newGroup);
+		
+		//fxdiff VCRP-1,2: access control of resources
+		// security group for tutors / coaches
+		SecurityGroup tutorGroup = securityManager.createAndPersistSecurityGroup();
+		// member of this group may modify member's membership
+		securityManager.createAndPersistPolicy(tutorGroup, Constants.PERMISSION_ACCESS, preparedEntry.getOlatResource());
+		// members of this group are always tutors also
+		securityManager.createAndPersistPolicy(tutorGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_TUTOR);
+		preparedEntry.setTutorGroup(tutorGroup);
+		
+		// security group for participants
+		SecurityGroup participantGroup = securityManager.createAndPersistSecurityGroup();
+		// member of this group may modify member's membership
+		securityManager.createAndPersistPolicy(participantGroup, Constants.PERMISSION_ACCESS, preparedEntry.getOlatResource());
+		// members of this group are always participants also
+		securityManager.createAndPersistPolicy(participantGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_PARTICIPANT);
+		preparedEntry.setParticipantGroup(participantGroup);
+		
 
 		RepositoryManager.getInstance().saveRepositoryEntry(preparedEntry);
 		// copy image if available
@@ -211,21 +228,19 @@ public class RepositoryCopyController extends BasicController {
 		// load newEntry again from DB because it could be changed (Exception object modified)
 		//o_clusterREVIEW
 		if (newEntry != null) {
-			RepositoryEntry entry = RepositoryManager.getInstance().lookupRepositoryEntry(newEntry.getKey());
-			if (entry != null) {
+			newEntry = RepositoryManager.getInstance().lookupRepositoryEntry(newEntry.getKey());
+			if (newEntry != null) {
 				try {
 					log.debug("Cleanup : started");
-					newEntry = (RepositoryEntry) DBFactory.getInstance().loadObject(newEntry,true);
-					SecurityGroup secGroup = newEntry.getOwnerGroup();
+					//fxdiff FXOLAT-202: use the same code as to delete repo entry
 					RepositoryHandler repositoryHandler = RepositoryHandlerFactory.getInstance().getRepositoryHandler(newEntry);			
 					log.debug("Cleanup : repositoryHandler.cleanupOnDelete for olat-resource=" + newEntry.getOlatResource());
-					repositoryHandler.cleanupOnDelete(newEntry.getOlatResource());
+					
 					log.debug("Cleanup : deleteRepositoryEntry");
-					RepositoryManager.getInstance().deleteRepositoryEntry(newEntry);
-					if (secGroup != null) { // delete owner group
-						log.debug("Cleanup : deleteSecurityGroup secGroup=" + secGroup);
-						securityManager.deleteSecurityGroup(secGroup);
-					}
+					RepositoryManager.getInstance().deleteRepositoryEntryAndBasesecurity(newEntry);
+					
+					repositoryHandler.cleanupOnDelete(newEntry.getOlatResource());
+
 					newEntry = null;
 				} catch (DBRuntimeException ex) {
 					log.error("Can not cleanup properly ", ex);
diff --git a/src/main/java/org/olat/repository/controllers/RepositoryDetailsController.java b/src/main/java/org/olat/repository/controllers/RepositoryDetailsController.java
index 4562c34099ade9badf281343990ec03667c3ba47..f007b9a2a1f860af26e3eec1f9558195c735469e 100644
--- a/src/main/java/org/olat/repository/controllers/RepositoryDetailsController.java
+++ b/src/main/java/org/olat/repository/controllers/RepositoryDetailsController.java
@@ -21,6 +21,7 @@
 
 package org.olat.repository.controllers;
 
+import java.util.List;
 import java.util.Locale;
 
 import org.olat.ControllerFactory;
@@ -58,6 +59,7 @@ import org.olat.core.gui.control.generic.tool.ToolFactory;
 import org.olat.core.gui.media.MediaResource;
 import org.olat.core.gui.translator.PackageTranslator;
 import org.olat.core.helpers.Settings;
+import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.id.context.BusinessControlFactory;
 import org.olat.core.id.context.ContextEntry;
@@ -86,6 +88,7 @@ import org.olat.repository.handlers.RepositoryHandler;
 import org.olat.repository.handlers.RepositoryHandlerFactory;
 import org.olat.resource.OLATResource;
 import org.olat.resource.OLATResourceManager;
+import org.olat.resource.accesscontrol.ui.OrdersAdminController;
 import org.olat.resource.references.ReferenceManager;
 
 /**
@@ -107,6 +110,9 @@ public class RepositoryDetailsController extends BasicController implements Gene
 	private static final String ACTION_DELETE = "del";
 	private static final String ACTION_CLOSE_RESSOURCE = "close.ressource";
 	private static final String ACTION_GROUPS = "grp";
+	private static final String ACTION_GROUPS_TUTOR = "grptutor";
+	private static final String ACTION_GROUPS_PARTICIPANT = "grpparti";
+	private static final String ACTION_ORDERS = "orders";
 	private static final String ACTION_EDITDESC = "chdesc";
 	private static final String ACTION_EDITPROP = "chprop";
 
@@ -126,8 +132,9 @@ public class RepositoryDetailsController extends BasicController implements Gene
 	private Link launchButton;
 	private Link loginLink;
 	
-	private GroupController groupController, groupEditController;
-	private SecurityGroup ownerGroup;
+	private GroupController groupController;
+	private GroupController groupTutorEditController, groupParticipantEditController, groupEditController;
+	private OrdersAdminController ordersController;
 	private AddAndEditBookmarkController bookmarkController;
 	private ToolController detailsToolC = null;
 	private RepositoryCopyController copyController;
@@ -405,7 +412,14 @@ public class RepositoryDetailsController extends BasicController implements Gene
 				canBookmark = false;
 			detailsToolC.setEnabled(TOOL_BOOKMARK, canBookmark);
 		}
+		//fxdiff VCRP-1 : moved some things around here to split large toolbox into smaller pieces
+		if (isNewController)
+			detailsToolC.addLink(ACTION_CLOSE, translate("details.close"), null, "b_toolbox_close");
+
 		if (isAuthor || isOwner) {
+			if (isNewController) {
+				detailsToolC.addHeader(translate("edit"));
+			}
 			boolean canCopy = repositoryEntry.getCanCopy();
 			if (isOwner) {
 				if (isNewController) {
@@ -415,6 +429,8 @@ public class RepositoryDetailsController extends BasicController implements Gene
 						detailsToolC.addLink(ACTION_EDITPROP, translate("details.chprop"), TOOL_CHPROP, null);
 					}
 					detailsToolC.addLink(ACTION_ADD_CATALOG, translate("details.catadd"), TOOL_CATALOG, null);
+					
+					detailsToolC.addHeader(translate("table.action"));
 					if ((OresHelper.isOfType(repositoryEntry.getOlatResource(), CourseModule.class)) && (!RepositoryManager.getInstance().createRepositoryEntryStatus(repositoryEntry.getStatusCode()).isClosed())) {
 						detailsToolC.addLink(ACTION_CLOSE_RESSOURCE, translate("details.close.ressoure"), TOOL_CLOSE_RESSOURCE, null);
 					}
@@ -430,7 +446,11 @@ public class RepositoryDetailsController extends BasicController implements Gene
 			if (isOwner) {
 				if (isNewController) {
 					detailsToolC.addLink(ACTION_DELETE, translate("details.delete"));
+					detailsToolC.addHeader(translate("details.members"));
 					detailsToolC.addLink(ACTION_GROUPS, translate("details.groups"));
+					detailsToolC.addLink(ACTION_GROUPS_TUTOR, translate("details.groups.tutor"));
+					detailsToolC.addLink(ACTION_GROUPS_PARTICIPANT, translate("details.groups.participant"));
+					detailsToolC.addLink(ACTION_ORDERS, translate("details.orders"));
 				}
 				// enable
 				if(isAuthor) {
@@ -445,8 +465,6 @@ public class RepositoryDetailsController extends BasicController implements Gene
 				detailsToolC.setEnabled(TOOL_COPY, canCopy);
 			}
 		}
-		if (isNewController)
-			detailsToolC.addLink(ACTION_CLOSE, translate("details.close"), null, "b_toolbox_close");
 	}
 
 	/**
@@ -799,20 +817,36 @@ public class RepositoryDetailsController extends BasicController implements Gene
 			repositoryEntry = RepositoryManager.getInstance().lookupRepositoryEntry(repositoryEntry.getKey());
 		}
 		String cmd = event.getCommand();
-		if (source == groupEditController) {
+		if (source == groupEditController || source == groupTutorEditController || source == groupParticipantEditController) {
 			if(event instanceof IdentitiesAddEvent ) { //FIXME:chg: Move into seperate RepositoryOwnerGroupController like BusinessGroupEditController ?
 				IdentitiesAddEvent identitiesAddedEvent = (IdentitiesAddEvent) event;
 				RepositoryManager rm = RepositoryManager.getInstance();
 				//add to group and also adds identities really added to the event.
 				//this is then later used by the GroupController to determine if the 
 				//model should be updated or not.
-				rm.addOwners(ureq.getIdentity(),identitiesAddedEvent,repositoryEntry);
+				
+				if (source == groupEditController) {
+					rm.addOwners(ureq.getIdentity(),identitiesAddedEvent,repositoryEntry);
+				} else if (source == groupTutorEditController) {
+					rm.addTutors(ureq.getIdentity(), identitiesAddedEvent, repositoryEntry);
+				} else if (source == groupParticipantEditController) {
+					rm.addParticipants(ureq.getIdentity(), identitiesAddedEvent, repositoryEntry);
+				}
 			} else if (event instanceof IdentitiesRemoveEvent) {
 				IdentitiesRemoveEvent identitiesRemoveEvent = (IdentitiesRemoveEvent) event;
 				RepositoryManager rm = RepositoryManager.getInstance();
-        rm.removeOwners(ureq.getIdentity(),identitiesRemoveEvent.getRemovedIdentities(), repositoryEntry);
+				List<Identity> identitiesToRemove = identitiesRemoveEvent.getRemovedIdentities();
+				if (source == groupEditController) {
+					rm.removeOwners(ureq.getIdentity(),identitiesToRemove,repositoryEntry);
+				} else if (source == groupTutorEditController) {
+					rm.removeTutors(ureq.getIdentity(), identitiesToRemove, repositoryEntry);
+				} else if (source == groupParticipantEditController) {
+					rm.removeParticipants(ureq.getIdentity(), identitiesToRemove, repositoryEntry);
+				}
 			}
 			updateView(ureq);
+		} else if (source == ordersController) {
+			//
 		} else if (source == detailsToolC) {
 			if (cmd.equals(ACTION_DOWNLOAD)) { // download
 				doDownload(ureq);
@@ -855,20 +889,26 @@ public class RepositoryDetailsController extends BasicController implements Gene
 				return;
 			} else if (cmd.equals(ACTION_GROUPS)) { // edit authors group
 				if (!isOwner) throw new OLATSecurityException("Trying to access groupmanagement, but not allowed: user = " + ureq.getIdentity());
-				ownerGroup = repositoryEntry.getOwnerGroup();
-				
-				removeAsListenerAndDispose(groupEditController);
-				groupEditController = new GroupController(ureq, getWindowControl(), true, true, false, ownerGroup);
-				listenTo(groupEditController);
-				
-				VelocityContainer groupContainer = createVelocityContainer("groups");  
-				groupContainer.put("groupcomp", groupEditController.getInitialComponent());
-				
-				removeAsListenerAndDispose(cmc);
-				CloseableModalController cmc = new CloseableModalController(getWindowControl(), translate("close"), groupContainer);
-				listenTo(cmc);
-				
-				cmc.activate();
+				groupEditController = doManageSecurityGroup(ureq, true, repositoryEntry.getOwnerGroup(), "groups");
+				return;
+			}  else if (cmd.equals(ACTION_GROUPS_TUTOR)) { // edit tutor group
+				if (!isOwner) throw new OLATSecurityException("Trying to access groupmanagement, but not allowed: user = " + ureq.getIdentity());
+				if(repositoryEntry.getTutorGroup() == null){
+					RepositoryManager.getInstance().createTutorSecurityGroup(repositoryEntry);
+					RepositoryManager.getInstance().updateRepositoryEntry(repositoryEntry);
+				}
+				groupTutorEditController = doManageSecurityGroup(ureq, false, repositoryEntry.getTutorGroup(), "groups_tutor");
+				return;
+			} else if (cmd.equals(ACTION_GROUPS_PARTICIPANT)) { // edit tutor group
+				if (!isOwner) throw new OLATSecurityException("Trying to access groupmanagement, but not allowed: user = " + ureq.getIdentity());
+				if(repositoryEntry.getParticipantGroup() == null){
+					RepositoryManager.getInstance().createParticipantSecurityGroup(repositoryEntry);
+					RepositoryManager.getInstance().updateRepositoryEntry(repositoryEntry);
+				}
+				groupParticipantEditController = doManageSecurityGroup(ureq, false, repositoryEntry.getParticipantGroup(), "groups_participant");
+				return;
+			} else if (cmd.equals(ACTION_ORDERS)) {
+				doOrders(ureq);
 				return;
 			} else if (cmd.equals(ACTION_CLOSE_RESSOURCE)) {
 				doCloseResource(ureq);
@@ -990,6 +1030,41 @@ public class RepositoryDetailsController extends BasicController implements Gene
 			updateCategoriesTableC(ureq);
 		}
 	}
+	
+	private void doOrders(UserRequest ureq) {
+		removeAsListenerAndDispose(ordersController);
+
+		ordersController = new OrdersAdminController(ureq, getWindowControl(), repositoryEntry.getOlatResource());
+		listenTo(ordersController);
+
+		removeAsListenerAndDispose(cmc);
+		CloseableModalController cmc = new CloseableModalController(getWindowControl(), translate("close"), ordersController.getInitialComponent());
+		listenTo(cmc);
+		
+		cmc.activate();
+	}
+	
+	private GroupController doManageSecurityGroup(UserRequest ureq, boolean keepAtLeastOne, SecurityGroup secGroup, String template) {
+		removeAsListenerAndDispose(groupEditController);
+		removeAsListenerAndDispose(groupTutorEditController);
+		removeAsListenerAndDispose(groupParticipantEditController);
+		groupEditController = null;
+		groupTutorEditController = null;
+		groupParticipantEditController = null;
+
+		GroupController controller = new GroupController(ureq, getWindowControl(), true, keepAtLeastOne, false, secGroup);
+		listenTo(controller);
+		
+		VelocityContainer groupContainer = createVelocityContainer(template);  
+		groupContainer.put("groupcomp", controller.getInitialComponent());
+		
+		removeAsListenerAndDispose(cmc);
+		CloseableModalController cmc = new CloseableModalController(getWindowControl(), translate("close"), groupContainer);
+		listenTo(cmc);
+		
+		cmc.activate();
+		return controller;
+	}
 
 	/**
 	 * @param ureq
diff --git a/src/main/java/org/olat/repository/controllers/RepositoryEditPropertiesController.java b/src/main/java/org/olat/repository/controllers/RepositoryEditPropertiesController.java
index c0267c5facef0809fe67663cdb10b079aa91cf80..7c1c00849986c0d13b57d792744792193a65f2be 100644
--- a/src/main/java/org/olat/repository/controllers/RepositoryEditPropertiesController.java
+++ b/src/main/java/org/olat/repository/controllers/RepositoryEditPropertiesController.java
@@ -73,6 +73,7 @@ import org.olat.modules.glossary.GlossaryRegisterSettingsController;
 import org.olat.repository.PropPupForm;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryManager;
+import org.olat.resource.accesscontrol.ui.AccessConfigurationController;
 import org.olat.resource.references.ReferenceImpl;
 import org.olat.resource.references.ReferenceManager;
 import org.olat.util.logging.activity.LoggingResourceable;
@@ -101,6 +102,8 @@ public class RepositoryEditPropertiesController extends BasicController {
 	private CourseEfficencyStatementController ceffC;
 	private CourseCalendarConfigController calCfgCtr;
 	private CourseConfigGlossaryController cglosCtr;
+	//fxdiff VCRP-1,2: access control of resources
+	private AccessConfigurationController acCtr;
 	private TabbedPane tabbedPane;
 	private RepositoryEntry repositoryEntry;
 	
@@ -157,6 +160,15 @@ public class RepositoryEditPropertiesController extends BasicController {
 		propPupForm = new PropPupForm(ureq, wControl, entry);
 		listenTo(propPupForm);
 		editproptabpubVC.put("proppupform", propPupForm.getInitialComponent());
+		
+		//fxdiff VCRP-1,2: access control of resources
+	  acCtr = new AccessConfigurationController(ureq, getWindowControl(), repositoryEntry.getOlatResource(), repositoryEntry.getDisplayname());
+	  int access = propPupForm.getAccess();
+	  if(access == RepositoryEntry.ACC_USERS || access == RepositoryEntry.ACC_USERS_GUESTS) {
+	  	editproptabpubVC.put("accesscontrol", acCtr.getInitialComponent());
+	  	editproptabpubVC.contextPut("isGuestAccess", Boolean.valueOf(access == RepositoryEntry.ACC_USERS_GUESTS));
+	  }	  
+		
 		tabbedPane.addListener(this);
 		try {
 		if (repositoryEntry.getOlatResource().getResourceableTypeName().equals(CourseModule.getCourseTypeName())) {
@@ -264,7 +276,8 @@ public class RepositoryEditPropertiesController extends BasicController {
 			if(repositoryEntryChanged) {
 				if (DialogBoxUIFactory.isYesEvent(event)) {
 					RepositoryManager.getInstance().setProperties(repositoryEntry, propPupForm.canCopy(), propPupForm.canReference(), propPupForm.canLaunch(), propPupForm.canDownload() );		
-					RepositoryManager.getInstance().setAccess(repositoryEntry, propPupForm.getAccess());
+					//fxdiff VCRP-1,2: access control of resources
+					RepositoryManager.getInstance().setAccess(repositoryEntry, propPupForm.getAccess(), propPupForm.isMembersOnly());
 					repositoryEntry = RepositoryManager.getInstance().lookupRepositoryEntry(repositoryEntry.getKey());
 					repositoryEntryChanged = false;
 					
@@ -307,10 +320,10 @@ public class RepositoryEditPropertiesController extends BasicController {
 				}
 				
         		// CourseLayoutController 
-				if(!changedCourseConfig.getCssLayoutRef().equals(initialCourseConfig.getCssLayoutRef()) && clayoutC.getLoggingAction()!=null) {					
-					// log removing custom course layout
-					ThreadLocalUserActivityLogger.log(clayoutC.getLoggingAction(), getClass());					
-				}
+//				if(!changedCourseConfig.getCssLayoutRef().equals(initialCourseConfig.getCssLayoutRef()) && clayoutC.getLoggingAction()!=null) {					
+//					// log removing custom course layout
+//					ThreadLocalUserActivityLogger.log(clayoutC.getLoggingAction(), getClass());					
+//				}
         		// CourseSharedFolderController 
 				if(!changedCourseConfig.getSharedFolderSoftkey().equals(initialCourseConfig.getSharedFolderSoftkey()) && csfC.getLoggingAction()!=null) {
 					String logDetail = csfC.getSharedFolderRepositoryEntry()!=null ? csfC.getSharedFolderRepositoryEntry().getDisplayname() : null; 
@@ -396,18 +409,29 @@ public class RepositoryEditPropertiesController extends BasicController {
 			} else if (event == Event.DONE_EVENT) {
 				repositoryEntryChanged = true;				
 				// inform user about inconsistent configuration: doesn't make sense to set a repositoryEntry canReference=true if it is only accessible to owners
-				if (!repositoryEntry.getCanReference() && propPupForm.canReference() && propPupForm.getAccess() < RepositoryEntry.ACC_OWNERS_AUTHORS) {					
+				//fxdiff VCRP-1,2: access control of resources
+				if (!repositoryEntry.getCanReference() && propPupForm.canReference() && (propPupForm.getAccess() < RepositoryEntry.ACC_OWNERS_AUTHORS && !propPupForm.isMembersOnly())) {					
 					this.showError("warn.config.reference.no.access");
 				}	
 				//if not a course, update the repositoryEntry NOW!
 				if(!repositoryEntry.getOlatResource().getResourceableTypeName().equals(CourseModule.getCourseTypeName())) {
 					RepositoryManager.getInstance().setProperties(repositoryEntry, propPupForm.canCopy(), propPupForm.canReference(), propPupForm.canLaunch(), propPupForm.canDownload() );		
-					RepositoryManager.getInstance().setAccess(repositoryEntry, propPupForm.getAccess());		
+					//fxdiff VCRP-1,2: access control of resources
+					RepositoryManager.getInstance().setAccess(repositoryEntry, propPupForm.getAccess(), propPupForm.isMembersOnly());		
 					// inform anybody interrested about this change
 					MultiUserEvent modifiedEvent = new EntryChangedEvent(repositoryEntry, EntryChangedEvent.MODIFIED);
 					CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(modifiedEvent, repositoryEntry);			
 					fireEvent(ureq, Event.CHANGED_EVENT);
-				}				
+				}
+				
+				int access = propPupForm.getAccess();
+				if(access == RepositoryEntry.ACC_USERS || access == RepositoryEntry.ACC_USERS_GUESTS) {
+			  	editproptabpubVC.put("accesscontrol", acCtr.getInitialComponent());
+			  	editproptabpubVC.contextPut("isGuestAccess", Boolean.valueOf(access == RepositoryEntry.ACC_USERS_GUESTS));
+				} else {
+			  	editproptabpubVC.remove(acCtr.getInitialComponent());
+				}
+				
 				return;
 			}
 		}
diff --git a/src/main/java/org/olat/repository/controllers/RepositorySearchController.java b/src/main/java/org/olat/repository/controllers/RepositorySearchController.java
index 78e64212a8c539892454be85c3f0c1e5b14a582c..3bfa9fda439870fb05067700d8aba2c43b47d0f0 100644
--- a/src/main/java/org/olat/repository/controllers/RepositorySearchController.java
+++ b/src/main/java/org/olat/repository/controllers/RepositorySearchController.java
@@ -23,10 +23,14 @@ package org.olat.repository.controllers;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 
 import org.olat.core.dispatcher.DispatcherAction;
+import org.olat.core.gui.ShortName;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.link.Link;
@@ -83,6 +87,7 @@ public class RepositorySearchController extends BasicController implements Activ
 	private RepositoryEntry selectedEntry = null;
 	private boolean enableSearchforAllReferencalbeInSearchForm = false;
 	private Link loginLink;
+	private SearchType searchType;
 	
 	
 	/**
@@ -94,7 +99,8 @@ public class RepositorySearchController extends BasicController implements Activ
 	 * @param enableDirectLaunch
 	 */
 	public RepositorySearchController(String selectButtonLabel, UserRequest ureq, WindowControl myWControl, boolean withCancel, boolean enableDirectLaunch) {
-		super(ureq, myWControl);
+		//fxdiff VCRP-10: repository search with type filter
+		super(ureq, myWControl, Util.createPackageTranslator(RepositoryManager.class, ureq.getLocale()));
 		init(selectButtonLabel, ureq, withCancel, enableDirectLaunch, new String[]{});
 	}
 	
@@ -113,7 +119,8 @@ public class RepositorySearchController extends BasicController implements Activ
 
 	public RepositorySearchController(String selectButtonLabel, UserRequest ureq, WindowControl myWControl, boolean withCancel, boolean enableDirectLaunch,
 			String[] limitTypes) {
-		super(ureq, myWControl);
+		//fxdiff VCRP-10: repository search with type filter
+		super(ureq, myWControl, Util.createPackageTranslator(RepositoryManager.class, ureq.getLocale()));
 		init(selectButtonLabel, ureq, withCancel, enableDirectLaunch, limitTypes);
 	}
 	
@@ -121,7 +128,8 @@ public class RepositorySearchController extends BasicController implements Activ
 	 * @param myWControl
 	 */
 	public RepositorySearchController(UserRequest ureq, WindowControl myWControl) {
-		super(ureq, myWControl);
+		//fxdiff VCRP-10: repository search with type filter
+		super(ureq, myWControl, Util.createPackageTranslator(RepositoryManager.class, ureq.getLocale()));
 	}
 
 	private void init(String selectButtonLabel, UserRequest ureq, boolean withCancel, boolean enableDirectLaunch, String[] limitTypes) {
@@ -140,13 +148,18 @@ public class RepositorySearchController extends BasicController implements Activ
 		TableGuiConfiguration tableConfig = new TableGuiConfiguration();
 		if (selectButtonLabel != null) tableConfig.setPreferencesOffered(true, "repositorySearchResult");
 		
-		tableCtr = new TableController(tableConfig, ureq, getWindowControl(), translator, true);
+		//fxdiff VCRP-10: repository search with type filter
+		String filterTitle = translator.translate("search.filter.type");
+		String noFilterOption = translator.translate("search.filter.showAll");
+		tableCtr = new TableController(tableConfig, ureq, getWindowControl(), null, null, filterTitle, noFilterOption, true, translator);
+		
+		
 		listenTo(tableCtr);
 		
 		repoTableModel = new RepositoryTableModel(translator);
 		repoTableModel.addColumnDescriptors(tableCtr, selectButtonLabel, enableDirectLaunch);
 		tableCtr.setTableDataModel(repoTableModel);
-		tableCtr.setSortColumn(1, true);
+		tableCtr.setSortColumn(2, true);
 		vc.put("repotable", tableCtr.getInitialComponent());
 
 		vc.contextPut("isAuthor", Boolean.valueOf(roles.isAuthor()));
@@ -207,13 +220,24 @@ public class RepositorySearchController extends BasicController implements Activ
 	 * using the values from the form
 	 * @param ureq
 	 */
-	private void doSearch(UserRequest ureq) {
+	private void doSearch(UserRequest ureq, String limitType, boolean updateFilters) {
+		searchType = SearchType.searchForm;
 		RepositoryManager rm = RepositoryManager.getInstance();
-		Set s = searchForm.getRestrictedTypes();
-		List restrictedTypes = (s == null) ? null : new ArrayList(s);
-		List entries = rm.genericANDQueryWithRolesRestriction(searchForm.getDisplayName(), searchForm.getAuthor(),
-			searchForm.getDescription(), restrictedTypes, ureq.getUserSession().getRoles(), ureq.getIdentity().getUser().getProperty(UserConstants.INSTITUTIONALNAME, null));
+		Set<String> s = searchForm.getRestrictedTypes();
+		List<String> restrictedTypes;
+		if(limitType != null) {
+			restrictedTypes = Collections.singletonList(limitType);
+		} else {
+			restrictedTypes = (s == null) ? null : new ArrayList<String>(s);
+		}
+		//fxdiff VCRP-1,2: access control of resources
+		List<RepositoryEntry> entries = rm.genericANDQueryWithRolesRestriction(searchForm.getDisplayName(), searchForm.getAuthor(),
+			searchForm.getDescription(), restrictedTypes, ureq.getIdentity(), ureq.getUserSession().getRoles(), ureq.getIdentity().getUser().getProperty(UserConstants.INSTITUTIONALNAME, null));
 		repoTableModel.setObjects(entries);
+		//fxdiff VCRP-10: repository search with type filter
+		if(updateFilters) {
+			updateFilters(entries, null);
+		}
 		tableCtr.modelChanged();
 		displaySearchResults(ureq);
 	}
@@ -223,18 +247,28 @@ public class RepositorySearchController extends BasicController implements Activ
 	 * owned by the uer or set to referencable and have at lease BA settings
 	 * @param ureq
 	 */
-	private void doSearchAllReferencables(UserRequest ureq) {
+	private void doSearchAllReferencables(UserRequest ureq, String limitType, boolean updateFilters) {
+		searchType = SearchType.searchForm;
 		RepositoryManager rm = RepositoryManager.getInstance();
-		Set s = searchForm.getRestrictedTypes();
-		List restrictedTypes = (s == null) ? null : new ArrayList(s);
+		Set<String> s = searchForm.getRestrictedTypes();
+		List<String> restrictedTypes;
+		if(limitType != null) {
+			restrictedTypes = Collections.singletonList(limitType);
+		} else {
+			restrictedTypes = (s == null) ? null : new ArrayList<String>(s);
+		}
 		Roles roles = ureq.getUserSession().getRoles();
 		Identity ident = ureq.getIdentity();
 		String name = searchForm.getDisplayName();
 		String author = searchForm.getAuthor();
 		String desc = searchForm.getDescription();
 		
-		List entries = rm.queryReferencableResourcesLimitType(ident, roles, restrictedTypes, name, author, desc);
+		List<RepositoryEntry> entries = rm.queryReferencableResourcesLimitType(ident, roles, restrictedTypes, name, author, desc);
 		repoTableModel.setObjects(entries);
+		//fxdiff VCRP-10: repository search with type filter
+		if(updateFilters) {
+			updateFilters(entries, null);
+		}
 		tableCtr.modelChanged();
 		displaySearchResults(ureq);
 	}
@@ -265,24 +299,46 @@ public class RepositorySearchController extends BasicController implements Activ
 		List entries = rm.queryReferencableResourcesLimitType(owner, roles, restrictedTypes, null, null, null);
 		
 		repoTableModel.setObjects(entries);
+		//fxdiff VCRP-10: repository search with type filter
+		tableCtr.setFilters(null, null);
 		tableCtr.modelChanged();
 		displaySearchResults(null);
 	}
+	
+	/**
+	 * Search for all resources where identity is owner.
+	 * 
+	 * @param owner
+	 */
+	//fxdiff VCRP-10: repository search with type filter
+	public void doSearchByOwner(Identity owner) {
+		doSearchByOwnerLimitTypeInternal(owner, new String[] {}, true);
+	}
 
 	/**
 	 * Do search for all resources of a given type where identity is owner.
 	 * @param owner
 	 * @param limitType
 	 */
+	//fxdiff VCRP-10: repository search with type filter
 	public void doSearchByOwnerLimitType(Identity owner, String limitType) {
-		doSearchByOwnerLimitType(owner,new String[]{limitType});
+		doSearchByOwnerLimitTypeInternal(owner, new String[]{limitType}, true);
 	}
 	
 	public void doSearchByOwnerLimitType(Identity owner, String[] limitTypes) {
+		doSearchByOwnerLimitTypeInternal(owner, limitTypes, true);
+	}
+	
+	//fxdiff VCRP-10: repository search with type filter
+	private void doSearchByOwnerLimitTypeInternal(Identity owner, String[] limitTypes, boolean updateFilters) {
+		searchType = SearchType.byOwner;
 		RepositoryManager rm = RepositoryManager.getInstance();
-		List entries = rm.queryByOwner(owner, limitTypes);
+		List<RepositoryEntry> entries = rm.queryByOwner(owner, limitTypes);
+		if(updateFilters) {
+			updateFilters(entries, owner);
+		}
 		repoTableModel.setObjects(entries);
-		tableCtr.modelChanged();
+		tableCtr.modelChanged(updateFilters);
 		displaySearchResults(null);
 	}
 	
@@ -293,22 +349,16 @@ public class RepositorySearchController extends BasicController implements Activ
 	 */
 	public void doSearchByOwnerLimitAccess(Identity owner, int access) {
 		RepositoryManager rm = RepositoryManager.getInstance();
-		List entries = rm.queryByOwnerLimitAccess(owner, access);
-		
+		//fxdiff VCRP-1,2: access control of resources
+		List entries = rm.queryByOwnerLimitAccess(owner, access, Boolean.TRUE);
+
 		repoTableModel.setObjects(entries);
+		//fxdiff VCRP-10: repository search with type filter
+		tableCtr.setFilters(null, null);
 		tableCtr.modelChanged();
 		displaySearchResults(null);
 	}
 	
-	/**
-	 * Search for all resources where identity is owner.
-	 * 
-	 * @param owner
-	 */
-	public void doSearchByOwner(Identity owner) {
-		doSearchByOwnerLimitType(owner, new String[] {});
-	}
-	
 	/**
 	 * Package private. Used by repository main controller to execute predefined searches.
 	 * 
@@ -316,9 +366,12 @@ public class RepositorySearchController extends BasicController implements Activ
 	 * @param ureq
 	 */
 	void doSearchByTypeLimitAccess(String type, UserRequest ureq) {
+		searchType = null;
 		RepositoryManager rm = RepositoryManager.getInstance();
 		List entries = rm.queryByTypeLimitAccess(type, ureq);
 		repoTableModel.setObjects(entries);
+		//fxdiff VCRP-10: repository search with type filter
+		tableCtr.setFilters(null, null);
 		tableCtr.modelChanged();
 		displaySearchResults(ureq);
 	}
@@ -334,21 +387,66 @@ public class RepositorySearchController extends BasicController implements Activ
 	}
 
 	protected void doSearchMyCoursesStudent(UserRequest ureq){
+		doSearchMyCoursesStudent(ureq, null, true);
+	}
+		
+	protected void doSearchMyCoursesStudent(UserRequest ureq, String limitType, boolean updateFilters) {
+		searchType = SearchType.myAsStudent;
 		RepositoryManager rm = RepositoryManager.getInstance();
 		List<RepositoryEntry> entries = rm.getLearningResourcesAsStudent(ureq.getIdentity());
-		repoTableModel.setObjects(entries);
-		tableCtr.modelChanged();
-		displaySearchResults(ureq);
+		//fxdiff VCRP-10: repository search with type filter
+		doSearchMyRepositoryEntries(ureq, entries, limitType, updateFilters);
 	}
 	
 	protected void doSearchMyCoursesTeacher(UserRequest ureq){
+		doSearchMyCoursesTeacher(ureq, null, true);
+	}
+	
+	protected void doSearchMyCoursesTeacher(UserRequest ureq, String limitType, boolean updateFilters) {
+		searchType = SearchType.myAsTeacher;
 		RepositoryManager rm = RepositoryManager.getInstance();
 		List<RepositoryEntry> entries = rm.getLearningResourcesAsTeacher(ureq.getIdentity());
+		//fxdiff VCRP-10: repository search with type filter
+		doSearchMyRepositoryEntries(ureq, entries, limitType, updateFilters);
+	}
+
+	//fxdiff VCRP-10: repository search with type filter
+	protected void doSearchMyRepositoryEntries(UserRequest ureq, List<RepositoryEntry> entries, String limitType, boolean updateFilters) {
+		if(limitType != null) {
+			for(Iterator<RepositoryEntry> it=entries.iterator(); it.hasNext(); ) {
+				RepositoryEntry next = it.next();
+				if(!next.getOlatResource().getResourceableTypeName().equals(limitType)) {
+					it.remove();
+				}
+			}	
+		}
 		repoTableModel.setObjects(entries);
+		if(updateFilters) {
+			updateFilters(entries, null);
+		}
 		tableCtr.modelChanged();
 		displaySearchResults(ureq);
 	}
 	
+	protected void updateFilters(List<RepositoryEntry> entries, Identity owner) {
+		List<ShortName> restrictedTypes = new ArrayList<ShortName>();
+		Set<String> uniqueTypes = new HashSet<String>();
+		for(RepositoryEntry entry:entries) {
+			if(entry.getOlatResource() == null) continue;//no red screen for that
+			String type = entry.getOlatResource().getResourceableTypeName();
+			if(type != null && !uniqueTypes.contains(type)) {
+				String label = translate(type);
+				restrictedTypes.add(new TypeFilter(type, label, owner));
+				uniqueTypes.add(type);
+			}
+		}
+		if(restrictedTypes.size() > 1) {
+			tableCtr.setFilters(restrictedTypes, null);
+		} else {
+			tableCtr.setFilters(null, null);
+		}
+	}
+	
 	/**
 	 * @return Returns the selectedEntry.
 	 */
@@ -384,14 +482,46 @@ public class RepositorySearchController extends BasicController implements Activ
 	 */
 	public void event(UserRequest urequest, Controller source, Event event) {
 		if (source == tableCtr) { // process table actions
-			TableEvent te = (TableEvent)event;
-			selectedEntry =  (RepositoryEntry)tableCtr.getTableDataModel().getObject(te.getRowId());
-			if (te.getActionId().equals(RepositoryTableModel.TABLE_ACTION_SELECT_ENTRY)) {
-				fireEvent(urequest, new Event(RepositoryTableModel.TABLE_ACTION_SELECT_ENTRY));
-				return;
-			} else if (te.getActionId().equals(RepositoryTableModel.TABLE_ACTION_SELECT_LINK)) {
-				fireEvent(urequest, new Event(RepositoryTableModel.TABLE_ACTION_SELECT_LINK));
-				return;
+			//fxdiff VCRP-10: repository search with type filter
+			if(event instanceof TableEvent) {
+				TableEvent te = (TableEvent)event;
+				selectedEntry =  (RepositoryEntry)tableCtr.getTableDataModel().getObject(te.getRowId());
+				if (te.getActionId().equals(RepositoryTableModel.TABLE_ACTION_SELECT_ENTRY)) {
+					fireEvent(urequest, new Event(RepositoryTableModel.TABLE_ACTION_SELECT_ENTRY));
+					return;
+				} else if (te.getActionId().equals(RepositoryTableModel.TABLE_ACTION_SELECT_LINK)) {
+					fireEvent(urequest, new Event(RepositoryTableModel.TABLE_ACTION_SELECT_LINK));
+					return;
+				}
+			} else if (TableController.EVENT_FILTER_SELECTED.equals(event)) {
+				TypeFilter typeFilter = (TypeFilter) tableCtr.getActiveFilter();
+				if(searchType == SearchType.byOwner) {
+					doSearchByOwnerLimitTypeInternal(typeFilter.getOwner(), new String[]{typeFilter.getType()}, false);
+				} else if(searchType == SearchType.myAsStudent) {
+					doSearchMyCoursesStudent(urequest, typeFilter.getType(), false);
+				} else if(searchType == SearchType.myAsTeacher) {
+					doSearchMyCoursesTeacher(urequest, typeFilter.getType(), false);
+				} else if(searchType == SearchType.searchForm) {
+					if(enableSearchforAllReferencalbeInSearchForm) {
+						doSearchAllReferencables(urequest, typeFilter.getType(), false);
+					} else {
+						doSearch(urequest, typeFilter.getType(), false);
+					}
+				}
+			} else if (TableController.EVENT_NOFILTER_SELECTED.equals(event)) {
+				if(searchType == SearchType.byOwner) {
+					doSearchByOwnerLimitTypeInternal(getIdentity(), new String[]{}, false);
+				} else if(searchType == SearchType.myAsStudent) {
+					doSearchMyCoursesStudent(urequest);
+				} else if(searchType == SearchType.myAsTeacher) {
+					doSearchMyCoursesTeacher(urequest);
+				} else if(searchType == SearchType.searchForm) {
+					if(enableSearchforAllReferencalbeInSearchForm) {
+						doSearchAllReferencables(urequest, null, false);
+					} else {
+						doSearch(urequest, null, false);
+					}
+				}
 			}
 		} 
 		else if (event instanceof EntryChangedEvent) { // remove deleted entry
@@ -412,8 +542,8 @@ public class RepositorySearchController extends BasicController implements Activ
 		else if (source == searchForm) { // process search form events
 			if (event == Event.DONE_EVENT) {
 				if (searchForm.hasId())	doSearchById(searchForm.getId());
-				else if (enableSearchforAllReferencalbeInSearchForm) doSearchAllReferencables(urequest);
-				else doSearch(urequest);
+				else if (enableSearchforAllReferencalbeInSearchForm) doSearchAllReferencables(urequest, null, true);
+				else doSearch(urequest, null, true);
 				return;
 			} else if (event == Event.CANCELLED_EVENT) {
 				fireEvent(urequest, Event.CANCELLED_EVENT);
@@ -429,4 +559,55 @@ public class RepositorySearchController extends BasicController implements Activ
 	protected void doDispose() {
 		//
 	}
+	
+	//fxdiff VCRP-10: repository search with type filter
+	private class TypeFilter implements ShortName {
+		
+		private final String type;
+		private final String typeName;
+		private final Identity owner;
+
+		public TypeFilter(String type, String typeName, Identity owner) {
+			this.type = type;
+			this.typeName = typeName;
+			this.owner = owner;
+		}
+
+		public String getType() {
+			return type;
+		}
+		
+		public Identity getOwner() {
+			return owner;
+		}
+
+		@Override
+		public String getShortName() {
+			return typeName;
+		}
+		
+		@Override
+		public int hashCode() {
+			return type.hashCode();
+		}
+		
+		@Override
+		public boolean equals(Object obj) {
+			if(this == obj) {
+				return true;
+			}
+			if(obj instanceof TypeFilter) {
+				TypeFilter typeobj = (TypeFilter)obj;
+				return type != null && type.equals(typeobj.type);
+			}
+			return false;
+		}
+	}
+	
+	public enum SearchType {
+		byOwner,
+		myAsStudent,
+		myAsTeacher,
+		searchForm,
+	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/repository/controllers/WizardCloseCourseController.java b/src/main/java/org/olat/repository/controllers/WizardCloseCourseController.java
index 5173f31ee3365a7d7abc7ac77196a692b1ab5f8e..d596a2157c7feb95e1fb947517f0f63d33c7819c 100644
--- a/src/main/java/org/olat/repository/controllers/WizardCloseCourseController.java
+++ b/src/main/java/org/olat/repository/controllers/WizardCloseCourseController.java
@@ -265,6 +265,15 @@ public class WizardCloseCourseController extends WizardController implements Wiz
 				secGroupPartipiciant = ((BusinessGroup) bGroup).getPartipiciantGroup();
 				BusinessGroupManagerImpl.getInstance().removeParticipantsAndFireEvent(identity, securityManager.getIdentitiesOfSecurityGroup(secGroupPartipiciant), ((BusinessGroup) bGroup), flagsRightgroup);
 			}
+			//fxdiff VCRP-1,2: access control of resources
+			if(repositoryEntry.getParticipantGroup() != null) {
+				secGroupPartipiciant = repositoryEntry.getParticipantGroup();
+				BusinessGroupManagerImpl.getInstance().removeAndFireEvent(identity, securityManager.getIdentitiesOfSecurityGroup(secGroupPartipiciant), secGroupPartipiciant);
+			}
+			if(repositoryEntry.getTutorGroup() != null) {
+				secGroupPartipiciant = repositoryEntry.getTutorGroup();
+				BusinessGroupManagerImpl.getInstance().removeAndFireEvent(identity, securityManager.getIdentitiesOfSecurityGroup(secGroupPartipiciant), secGroupPartipiciant);
+			}
 		}
 	}
   
diff --git a/src/main/java/org/olat/repository/handlers/BlogHandler.java b/src/main/java/org/olat/repository/handlers/BlogHandler.java
index 104b21e47d8f0f66ba8da5f8f4c7ab494818cfbd..b2c36da24930c4bc67d89f74d60fa731752f3259 100644
--- a/src/main/java/org/olat/repository/handlers/BlogHandler.java
+++ b/src/main/java/org/olat/repository/handlers/BlogHandler.java
@@ -25,7 +25,6 @@ import java.util.List;
 
 import org.olat.core.commons.fullWebApp.LayoutMain3ColsController;
 import org.olat.core.gui.UserRequest;
-import org.olat.core.gui.components.Component;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.generic.layout.MainLayoutController;
@@ -43,6 +42,7 @@ import org.olat.fileresource.types.BlogFileResource;
 import org.olat.modules.webFeed.FeedResourceSecurityCallback;
 import org.olat.modules.webFeed.FeedSecurityCallback;
 import org.olat.modules.webFeed.managers.FeedManager;
+import org.olat.modules.webFeed.ui.FeedMainController;
 import org.olat.modules.webFeed.ui.blog.BlogUIFactory;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryManager;
@@ -50,6 +50,7 @@ import org.olat.repository.controllers.AddFileResourceController;
 import org.olat.repository.controllers.IAddController;
 import org.olat.repository.controllers.RepositoryAddCallback;
 import org.olat.repository.controllers.WizardCloseResourceController;
+import org.olat.resource.accesscontrol.ui.RepositoryMainAccessControllerWrapper;
 import org.olat.resource.references.ReferenceManager;
 
 /**
@@ -169,10 +170,14 @@ public class BlogHandler implements RepositoryHandler {
 		boolean isAdmin = ureq.getUserSession().getRoles().isOLATAdmin();
 		boolean isOwner = RepositoryManager.getInstance().isOwnerOfRepositoryEntry(ureq.getIdentity(), repoEntry);	
 		FeedSecurityCallback callback = new FeedResourceSecurityCallback(isAdmin, isOwner);
-		Controller blogCtr = BlogUIFactory.getInstance(ureq.getLocale()).createMainController(res, ureq, wControl, callback);
+		FeedMainController blogCtr = BlogUIFactory.getInstance(ureq.getLocale()).createMainController(res, ureq, wControl, callback);
 		LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(ureq, wControl, null, null, blogCtr.getInitialComponent(), null);
 		layoutCtr.addDisposableChildController(blogCtr);
-		return layoutCtr;
+		//fxdiff BAKS-7 Resume function
+		layoutCtr.addActivateableDelegate(blogCtr);
+		//fxdiff VCRP-1: access control of learn resources
+		RepositoryMainAccessControllerWrapper wrapper = new RepositoryMainAccessControllerWrapper(ureq, wControl, res, layoutCtr);
+		return wrapper;
 	}
 
 	/**
diff --git a/src/main/java/org/olat/repository/handlers/CourseHandler.java b/src/main/java/org/olat/repository/handlers/CourseHandler.java
index 6560b2a5084dd255dcd8199a5224eeae7ad8b0ff..3173b9702693f8c3f89e929ca4ae21aa061cc384 100644
--- a/src/main/java/org/olat/repository/handlers/CourseHandler.java
+++ b/src/main/java/org/olat/repository/handlers/CourseHandler.java
@@ -67,6 +67,7 @@ import org.olat.repository.controllers.WizardCloseCourseController;
 import org.olat.repository.controllers.WizardCloseResourceController;
 import org.olat.resource.OLATResource;
 import org.olat.resource.OLATResourceManager;
+import org.olat.resource.accesscontrol.ui.RepositoryMainAccessControllerWrapper;
 import org.olat.resource.references.ReferenceManager;
 import org.olat.user.UserManager;
 
@@ -133,7 +134,10 @@ public class CourseHandler implements RepositoryHandler {
 	 * @see org.olat.repository.handlers.RepositoryHandler#getLaunchController(org.olat.core.id.OLATResourceable java.lang.String, org.olat.core.gui.UserRequest, org.olat.core.gui.control.WindowControl)
 	 */
 	public MainLayoutController createLaunchController(OLATResourceable res, String initialViewIdentifier, UserRequest ureq, WindowControl wControl) {
-		return CourseFactory.createLaunchController(ureq, wControl, res, initialViewIdentifier);
+		MainLayoutController courseCtrl = CourseFactory.createLaunchController(ureq, wControl, res, initialViewIdentifier);
+		//fxdiff VCRP-1: access control of learn resources
+		RepositoryMainAccessControllerWrapper wrapper = new RepositoryMainAccessControllerWrapper(ureq, wControl, res, courseCtrl);
+		return wrapper;
 	}
 
 	/**
diff --git a/src/main/java/org/olat/repository/handlers/GlossaryHandler.java b/src/main/java/org/olat/repository/handlers/GlossaryHandler.java
index 6ccda798024873ba346571b3213f97d5c1dc590b..e7ecd9d8356fb01d91b9f52c653b53eb1efc31fc 100644
--- a/src/main/java/org/olat/repository/handlers/GlossaryHandler.java
+++ b/src/main/java/org/olat/repository/handlers/GlossaryHandler.java
@@ -51,6 +51,7 @@ import org.olat.repository.controllers.AddFileResourceController;
 import org.olat.repository.controllers.IAddController;
 import org.olat.repository.controllers.RepositoryAddCallback;
 import org.olat.repository.controllers.WizardCloseResourceController;
+import org.olat.resource.accesscontrol.ui.RepositoryMainAccessControllerWrapper;
 import org.olat.resource.references.ReferenceManager;
 
 
@@ -140,7 +141,10 @@ public class GlossaryHandler implements RepositoryHandler {
 		// use on column layout
 		LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(ureq, wControl, null, null, gctr.getInitialComponent(), null);
 		layoutCtr.addDisposableChildController(gctr); // dispose content on layout dispose
-		return layoutCtr;
+		
+		//fxdiff VCRP-1: access control of learn resources
+		RepositoryMainAccessControllerWrapper wrapper = new RepositoryMainAccessControllerWrapper(ureq, wControl, res, layoutCtr);
+		return wrapper;
 	}
 
 	/**
diff --git a/src/main/java/org/olat/repository/handlers/ImsCPHandler.java b/src/main/java/org/olat/repository/handlers/ImsCPHandler.java
index 533b397c42d8b3bb07ac8ac5a0069f49292360fb..bb9790a1f31d3ca54b678bd579deb98124195888 100644
--- a/src/main/java/org/olat/repository/handlers/ImsCPHandler.java
+++ b/src/main/java/org/olat/repository/handlers/ImsCPHandler.java
@@ -47,6 +47,7 @@ import org.olat.repository.RepositoryEntry;
 import org.olat.repository.controllers.IAddController;
 import org.olat.repository.controllers.RepositoryAddCallback;
 import org.olat.repository.controllers.WizardCloseResourceController;
+import org.olat.resource.accesscontrol.ui.RepositoryMainAccessControllerWrapper;
 
 
 /**
@@ -117,11 +118,11 @@ public class ImsCPHandler extends FileHandler implements RepositoryHandler {
 	public MainLayoutController createLaunchController(OLATResourceable res, String initialViewIdentifier, UserRequest ureq, WindowControl wControl) {
 		File cpRoot = FileResourceManager.getInstance().unzipFileResource(res);
 		LocalFolderImpl vfsWrapper = new LocalFolderImpl(cpRoot);
-		Controller realController = null;
 		
 		// jump to either the forum or the folder if the business-launch-path says so.
 		BusinessControl bc = wControl.getBusinessControl();
 		ContextEntry ce = bc.popLauncherContextEntry();
+		MainLayoutController layoutCtr;
 		if ( ce != null ) { // a context path is left for me
 			Tracing.logDebug("businesscontrol (for further jumps) would be:"+bc, CPRunController.class);
 			OLATResourceable ores = ce.getOLATResourceable();
@@ -132,14 +133,16 @@ public class ImsCPHandler extends FileHandler implements RepositoryHandler {
 			String path = typeName.substring("path=".length());
 			if  (path.length() > 0) {
 			  Tracing.logDebug("direct navigation to container-path=" + path, CPRunController.class);
-			 	return CPUIFactory.getInstance().createMainLayoutResourceableListeningWrapperController(res, ureq, wControl, vfsWrapper, true, false, path);
+			  layoutCtr = CPUIFactory.getInstance().createMainLayoutResourceableListeningWrapperController(res, ureq, wControl, vfsWrapper, true, false, path);
 			} else {
-				return CPUIFactory.getInstance().createMainLayoutResourceableListeningWrapperController(res, ureq, wControl, vfsWrapper);
+				layoutCtr = CPUIFactory.getInstance().createMainLayoutResourceableListeningWrapperController(res, ureq, wControl, vfsWrapper);
 			}
 		} else {
-			return CPUIFactory.getInstance().createMainLayoutResourceableListeningWrapperController(res, ureq, wControl, vfsWrapper);
+			layoutCtr = CPUIFactory.getInstance().createMainLayoutResourceableListeningWrapperController(res, ureq, wControl, vfsWrapper);
 		}
-		
+		//fxdiff VCRP-1: access control of learn resources
+		RepositoryMainAccessControllerWrapper wrapper = new RepositoryMainAccessControllerWrapper(ureq, wControl, res, layoutCtr);
+		return wrapper;
 	}
 
 
diff --git a/src/main/java/org/olat/repository/handlers/PodcastHandler.java b/src/main/java/org/olat/repository/handlers/PodcastHandler.java
index 6c9911d84084dc38d6d0f0cc1b858e450c28763f..8f0a2e56fc3c69e6372b2f290fbc00c639b5b731 100644
--- a/src/main/java/org/olat/repository/handlers/PodcastHandler.java
+++ b/src/main/java/org/olat/repository/handlers/PodcastHandler.java
@@ -25,7 +25,6 @@ import java.util.List;
 
 import org.olat.core.commons.fullWebApp.LayoutMain3ColsController;
 import org.olat.core.gui.UserRequest;
-import org.olat.core.gui.components.Component;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.generic.layout.MainLayoutController;
@@ -43,6 +42,7 @@ import org.olat.fileresource.types.PodcastFileResource;
 import org.olat.modules.webFeed.FeedResourceSecurityCallback;
 import org.olat.modules.webFeed.FeedSecurityCallback;
 import org.olat.modules.webFeed.managers.FeedManager;
+import org.olat.modules.webFeed.ui.FeedMainController;
 import org.olat.modules.webFeed.ui.podcast.PodcastUIFactory;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryManager;
@@ -50,6 +50,7 @@ import org.olat.repository.controllers.AddFileResourceController;
 import org.olat.repository.controllers.IAddController;
 import org.olat.repository.controllers.RepositoryAddCallback;
 import org.olat.repository.controllers.WizardCloseResourceController;
+import org.olat.resource.accesscontrol.ui.RepositoryMainAccessControllerWrapper;
 import org.olat.resource.references.ReferenceManager;
 
 /**
@@ -167,10 +168,15 @@ public class PodcastHandler implements RepositoryHandler {
 		boolean isAdmin = ureq.getUserSession().getRoles().isOLATAdmin();
 		boolean isOwner = RepositoryManager.getInstance().isOwnerOfRepositoryEntry(ureq.getIdentity(), repoEntry);	
 		FeedSecurityCallback callback = new FeedResourceSecurityCallback(isAdmin, isOwner);
-		Controller podcastCtr = PodcastUIFactory.getInstance(ureq.getLocale()).createMainController(res, ureq, wControl, callback);
+		FeedMainController podcastCtr = PodcastUIFactory.getInstance(ureq.getLocale()).createMainController(res, ureq, wControl, callback);
 		LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(ureq, wControl, null, null, podcastCtr.getInitialComponent(), null);
 		layoutCtr.addDisposableChildController(podcastCtr);
-		return layoutCtr;
+		//fxdiff BAKS-7 Resume function
+		layoutCtr.addActivateableDelegate(podcastCtr);
+		
+		//fxdiff VCRP-1: access control of learn resources
+		RepositoryMainAccessControllerWrapper wrapper = new RepositoryMainAccessControllerWrapper(ureq, wControl, res, layoutCtr);
+		return wrapper;
 	}
 
 	/**
diff --git a/src/main/java/org/olat/repository/handlers/PortfolioHandler.java b/src/main/java/org/olat/repository/handlers/PortfolioHandler.java
index c1316af686cb34d4e678f54b14b4458008055390..5ed106edb9da58a3dfe3a9a1cb729814e530ccf5 100644
--- a/src/main/java/org/olat/repository/handlers/PortfolioHandler.java
+++ b/src/main/java/org/olat/repository/handlers/PortfolioHandler.java
@@ -75,6 +75,7 @@ import org.olat.repository.controllers.IAddController;
 import org.olat.repository.controllers.RepositoryAddCallback;
 import org.olat.repository.controllers.WizardCloseResourceController;
 import org.olat.resource.references.ReferenceManager;
+import org.olat.resource.accesscontrol.ui.RepositoryMainAccessControllerWrapper;
 
 import com.thoughtworks.xstream.XStream;
 import com.thoughtworks.xstream.converters.collections.CollectionConverter;
@@ -319,7 +320,9 @@ public class PortfolioHandler implements RepositoryHandler {
 		Controller epCtr = EPUIFactory.createPortfolioStructureMapController(ureq, wControl, map, secCallback);
 		LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(ureq, wControl, null, null, epCtr.getInitialComponent(), null);
 		layoutCtr.addDisposableChildController(epCtr);
-		return layoutCtr;
+		//fxdiff VCRP-1: access control of learn resources
+		RepositoryMainAccessControllerWrapper wrapper = new RepositoryMainAccessControllerWrapper(ureq, wControl, res, layoutCtr);
+		return wrapper;
 	}
 
 	/**
diff --git a/src/main/java/org/olat/repository/handlers/SCORMCPHandler.java b/src/main/java/org/olat/repository/handlers/SCORMCPHandler.java
index 7eafdabe793a19de89653904853f75a130ba6987..f62adfaa5ed4d1f7599543bafdb715459436c60a 100644
--- a/src/main/java/org/olat/repository/handlers/SCORMCPHandler.java
+++ b/src/main/java/org/olat/repository/handlers/SCORMCPHandler.java
@@ -41,6 +41,7 @@ import org.olat.modules.scorm.ScormMainManager;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryManager;
 import org.olat.repository.controllers.WizardCloseResourceController;
+import org.olat.resource.accesscontrol.ui.RepositoryMainAccessControllerWrapper;
 import org.olat.util.logging.activity.LoggingResourceable;
 
 
@@ -111,8 +112,11 @@ public class SCORMCPHandler extends FileHandler implements RepositoryHandler {
 		if (re!=null) {
 			ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapScormRepositoryEntry(re));
 		}
+		//fxdiff FXOLAT-116: SCORM improvements
 		MainLayoutController realController = ScormMainManager.getInstance().createScormAPIandDisplayController(ureq, wControl, true, null, cpRoot, res.getResourceableId().toString(), null, "browse", "no-credit", false, false);
-		return realController; 
+		//fxdiff VCRP-1: access control of learn resources
+		RepositoryMainAccessControllerWrapper wrapper = new RepositoryMainAccessControllerWrapper(ureq, wControl, res, realController);
+		return wrapper; 
 	}
 
 	/**
diff --git a/src/main/java/org/olat/repository/handlers/SharedFolderHandler.java b/src/main/java/org/olat/repository/handlers/SharedFolderHandler.java
index 1978ebd210459da5e2b738153d3e85c4576961ce..87b3cbdd00c6a29c9c1b3b36efc685d41fd3e6aa 100644
--- a/src/main/java/org/olat/repository/handlers/SharedFolderHandler.java
+++ b/src/main/java/org/olat/repository/handlers/SharedFolderHandler.java
@@ -51,6 +51,7 @@ import org.olat.repository.RepositoryManager;
 import org.olat.repository.controllers.IAddController;
 import org.olat.repository.controllers.RepositoryAddCallback;
 import org.olat.repository.controllers.WizardCloseResourceController;
+import org.olat.resource.accesscontrol.ui.RepositoryMainAccessControllerWrapper;
 import org.olat.resource.references.ReferenceManager;
 
 
@@ -142,7 +143,9 @@ public class SharedFolderHandler implements RepositoryHandler {
 		// use on column layout
 		LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(ureq, wControl, null, null, sfdCtr.getInitialComponent(), null);
 		layoutCtr.addDisposableChildController(sfdCtr); // dispose content on layout dispose
-		return layoutCtr;
+		//fxdiff VCRP-1: access control of learn resources
+		RepositoryMainAccessControllerWrapper wrapper = new RepositoryMainAccessControllerWrapper(ureq, wControl, res, layoutCtr);
+		return wrapper;
 	}
 
 	/**
diff --git a/src/main/java/org/olat/repository/handlers/WikiHandler.java b/src/main/java/org/olat/repository/handlers/WikiHandler.java
index b6b0974f43fa41219e4c7ca55a66ae2ea2256e91..13237dde12c165a3bd4c30d09e3cac61c48d1d69 100644
--- a/src/main/java/org/olat/repository/handlers/WikiHandler.java
+++ b/src/main/java/org/olat/repository/handlers/WikiHandler.java
@@ -22,9 +22,7 @@
 package org.olat.repository.handlers;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
@@ -35,9 +33,9 @@ import org.olat.core.commons.fullWebApp.LayoutMain3ColsController;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.generic.dtabs.Activateable2;
 import org.olat.core.gui.control.generic.layout.MainLayoutController;
 import org.olat.core.gui.media.MediaResource;
-import org.olat.core.gui.translator.PackageTranslator;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
@@ -71,6 +69,7 @@ import org.olat.repository.controllers.AddFileResourceController;
 import org.olat.repository.controllers.IAddController;
 import org.olat.repository.controllers.RepositoryAddCallback;
 import org.olat.repository.controllers.WizardCloseResourceController;
+import org.olat.resource.accesscontrol.ui.RepositoryMainAccessControllerWrapper;
 import org.olat.resource.references.ReferenceManager;
 
 
@@ -178,7 +177,14 @@ public class WikiHandler implements RepositoryHandler {
 		// use on column layout
 		LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(ureq, wControl, null, null, controller.getInitialComponent(), null);
 		layoutCtr.addDisposableChildController(controller); // dispose content on layout dispose
-		return layoutCtr;
+		//fxdiff BAKS-7 Resume function
+		if(controller instanceof Activateable2) {
+			layoutCtr.addActivateableDelegate((Activateable2)controller);
+		}
+		
+		//fxdiff VCRP-1: access control of learn resources
+		RepositoryMainAccessControllerWrapper wrapper = new RepositoryMainAccessControllerWrapper(ureq, wControl, res, layoutCtr);	
+		return wrapper;
 	}
 
 	/**
diff --git a/src/main/java/org/olat/resource/accesscontrol/ACUIFactory.java b/src/main/java/org/olat/resource/accesscontrol/ACUIFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..6addb14ecaa36662efeeb169363f954b7b1c53d2
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ACUIFactory.java
@@ -0,0 +1,71 @@
+/**
+ * OLAT - Online Learning and Training<br>
+ * http://www.olat.org
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Copyright (c) 2008 frentix GmbH, Switzerland<br>
+ * <p>
+ */
+
+package org.olat.resource.accesscontrol;
+
+import java.util.List;
+
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.resource.OLATResource;
+import org.olat.resource.accesscontrol.method.AccessMethodHandler;
+import org.olat.resource.accesscontrol.model.OfferAccess;
+import org.olat.resource.accesscontrol.ui.AbstractConfigurationMethodController;
+import org.olat.resource.accesscontrol.ui.AccessListController;
+import org.olat.resource.accesscontrol.ui.OrdersAdminController;
+import org.olat.resource.accesscontrol.ui.OrdersController;
+
+/**
+ * 
+ * Description:<br>
+ * Factory for the controllers used by access control
+ * 
+ * <P>
+ * Initial Date: 18 avr. 2011 <br>
+ * 
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class ACUIFactory {
+
+	public static Controller createAccessController(UserRequest ureq, WindowControl wControl, List<OfferAccess> links) {
+		// Always use multi list for layouting purpose
+		AccessListController multiAccessCtrl = new AccessListController(ureq, wControl, links);
+		return multiAccessCtrl;
+	}
+
+	public static AbstractConfigurationMethodController createAccessConfigurationController(UserRequest ureq, WindowControl wControl,
+			OfferAccess link) {
+
+		AccessControlModule module = (AccessControlModule) CoreSpringFactory.getBean("acModule");
+		AccessMethodHandler handler = module.getAccessMethodHandler(link.getMethod().getType());
+		if (handler != null) { return handler.createConfigurationController(ureq, wControl, link); }
+		return null;
+	}
+
+	public static Controller createOrdersController(UserRequest ureq, WindowControl wControl) {
+		return new OrdersController(ureq, wControl);
+	}
+
+	public static Controller createOrdersAdminController(UserRequest ureq, WindowControl wControl, OLATResource resource) {
+		return new OrdersAdminController(ureq, wControl, resource);
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/AccessControlModule.java b/src/main/java/org/olat/resource/accesscontrol/AccessControlModule.java
new file mode 100644
index 0000000000000000000000000000000000000000..c3bc26916b2c96fde736c06fd516cc0911ef50e3
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/AccessControlModule.java
@@ -0,0 +1,281 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.configuration.AbstractOLATModule;
+import org.olat.core.configuration.ConfigOnOff;
+import org.olat.core.configuration.PersistedProperties;
+import org.olat.core.extensions.action.GenericActionExtension;
+import org.olat.core.gui.control.Event;
+import org.olat.core.util.StringHelper;
+import org.olat.core.util.event.FrameworkStartedEvent;
+import org.olat.core.util.event.FrameworkStartupEventChannel;
+import org.olat.resource.accesscontrol.manager.ACFrontendManager;
+import org.olat.resource.accesscontrol.method.AccessMethodHandler;
+import org.olat.resource.accesscontrol.model.FreeAccessMethod;
+import org.olat.resource.accesscontrol.model.TokenAccessMethod;
+
+/**
+ * 
+ * Description:<br>
+ * Module for access control of OLAT Resource
+ * 
+ * <P>
+ * Initial Date:  14 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class AccessControlModule extends AbstractOLATModule implements ConfigOnOff {
+	
+	public static final String AC_ENABLED = "resource.accesscontrol.enabled";
+	public static final String AC_HOME_ENABLED = "resource.accesscontrol.home.overview";
+	private static final String VAT_ENABLED = "vat.enabled";
+	private static final String VAT_RATE = "vat.rate";
+	private static final String VAT_NR = "vat.number";
+	
+	public static final String TOKEN_ENABLED = "method.token.enabled";
+	public static final String FREE_ENABLED = "method.free.enabled";
+
+	private boolean enabled;
+	private boolean freeEnabled;
+	private boolean tokenEnabled;
+	private boolean homeOverviewEnabled;
+	
+	private boolean vatEnabled;
+	private BigDecimal vatRate;
+	private String vatNumber;
+	
+	private final List<AccessMethodHandler> methodHandlers = new ArrayList<AccessMethodHandler>();
+	
+	private ACFrontendManager acFrontendManager;
+
+	/**
+	 * [Used by Spring]
+	 * @param methodManager
+	 */
+	public void setAcFrontendManager(ACFrontendManager acFrontendManager) {
+		this.acFrontendManager = acFrontendManager;
+	}
+
+	public AccessControlModule(){
+		FrameworkStartupEventChannel.registerForStartupEvent(this);
+	}
+	
+	private void enableExtensions(boolean enabled) {
+		try {
+			((GenericActionExtension) CoreSpringFactory.getBean("accesscontrol.actExt")).setEnabled(enabled);
+		} catch (Exception e) {
+			// do nothing when extension don't exist.
+		}
+	}
+
+	@Override
+	public void event(Event event) {
+		if (event instanceof FrameworkStartedEvent) {
+			enableExtensions(isEnabled());
+		} else {
+			super.event(event);
+		}
+	}
+
+	@Override
+	public void init() {
+		//module enabled/disabled
+		String enabledObj = getStringPropertyValue(AC_ENABLED, true);
+		if(StringHelper.containsNonWhitespace(enabledObj)) {
+			enabled = "true".equals(enabledObj);
+		}
+		
+		String tokenEnabledObj = getStringPropertyValue(TOKEN_ENABLED, true);
+		if(StringHelper.containsNonWhitespace(tokenEnabledObj)) {
+			tokenEnabled = "true".equals(tokenEnabledObj);
+		}
+		
+		String freeEnabledObj = getStringPropertyValue(FREE_ENABLED, true);
+		if(StringHelper.containsNonWhitespace(freeEnabledObj)) {
+			freeEnabled = "true".equals(freeEnabledObj);
+		}
+		
+		String homeEnabledObj = getStringPropertyValue(AC_HOME_ENABLED, true);
+		if(StringHelper.containsNonWhitespace(homeEnabledObj)) {
+			homeOverviewEnabled = "true".equals(homeEnabledObj);
+		}
+		
+		String vatEnabledObj = getStringPropertyValue(VAT_ENABLED, true);
+		if(StringHelper.containsNonWhitespace(vatEnabledObj)) {
+			vatEnabled = "true".equals(vatEnabledObj);
+		}
+		
+		String vatRateObj = getStringPropertyValue(VAT_RATE, true);
+		if(StringHelper.containsNonWhitespace(vatRateObj)) {
+			try {
+				vatRate = new BigDecimal(vatRateObj);
+			} catch (Exception e) {
+				logError("Error parsing the VAT: " + vatRateObj, e);
+			}
+		}
+		
+		String vatNrObj = getStringPropertyValue(VAT_NR, true);
+		if(StringHelper.containsNonWhitespace(vatNrObj)) {
+			vatNumber = vatNrObj;
+		}
+		enableExtensions(enabled);
+		
+		logInfo("Access control module is enabled: " + Boolean.toString(enabled));
+	}
+
+	@Override
+	public void setPersistedProperties(PersistedProperties persistedProperties) {
+		this.moduleConfigProperties = persistedProperties;
+	}
+
+	@Override
+	protected void initDefaultProperties() {
+		enabled = getBooleanConfigParameter(AC_ENABLED, true);
+		freeEnabled = getBooleanConfigParameter(FREE_ENABLED, true);
+		tokenEnabled = getBooleanConfigParameter(TOKEN_ENABLED, true);
+		homeOverviewEnabled = getBooleanConfigParameter(AC_HOME_ENABLED, true);
+		vatEnabled = getBooleanConfigParameter(VAT_ENABLED, true);
+		String vatRateStr = getStringConfigParameter(VAT_RATE, "", true);
+		if(StringHelper.containsNonWhitespace(vatRateStr)) {
+			try {
+				vatRate = new BigDecimal(vatRateStr);
+			} catch (Exception e) {
+				logError("Error parsing the VAT: " + vatRateStr, e);
+			}
+		}
+		vatNumber = getStringConfigParameter(VAT_NR, "", true);
+	}
+
+	@Override
+	protected void initFromChangedProperties() {
+		init();
+	}
+	
+	@Override
+	public boolean isEnabled() {
+		return enabled;
+	}
+	
+	public void setEnabled(boolean enabled) {
+		if(this.enabled != enabled) {
+			setStringProperty(AC_ENABLED, Boolean.toString(enabled), true);
+		}
+		enableExtensions(enabled);
+	}
+
+	public boolean isTokenEnabled() {
+		return tokenEnabled;
+	}
+
+	public void setTokenEnabled(boolean tokenEnabled) {
+		if(this.tokenEnabled != tokenEnabled) {
+			setStringProperty(TOKEN_ENABLED, Boolean.toString(tokenEnabled), true);
+		}
+		if(acFrontendManager != null) {
+			acFrontendManager.enableMethod(TokenAccessMethod.class, tokenEnabled);
+		}
+	}
+
+	public boolean isFreeEnabled() {
+		return freeEnabled;
+	}
+
+	public void setFreeEnabled(boolean freeEnabled) {
+		if(this.freeEnabled != freeEnabled) {
+			setStringProperty(FREE_ENABLED, Boolean.toString(freeEnabled), true);
+		}
+		if(acFrontendManager != null) {
+			acFrontendManager.enableMethod(FreeAccessMethod.class, freeEnabled);
+		}
+	}
+	
+	public boolean isHomeOverviewEnabled() {
+		return homeOverviewEnabled;
+	}
+
+	public void setHomeOverviewEnabled(boolean homeOverviewEnabled) {
+		if(this.homeOverviewEnabled != homeOverviewEnabled) {
+			setStringProperty(AC_HOME_ENABLED, Boolean.toString(homeOverviewEnabled), true);
+		}
+	}
+	
+	public boolean isVatEnabled() {
+		return vatEnabled;
+	}
+
+	public void setVatEnabled(boolean vatEnabled) {
+		if(this.vatEnabled != vatEnabled) {
+			setStringProperty(VAT_ENABLED, Boolean.toString(vatEnabled), true);
+		}
+	}
+
+	public BigDecimal getVat() {
+		return vatRate;
+	}
+
+	public void setVat(BigDecimal vatRate) {
+		setStringProperty(VAT_RATE, vatRate.toPlainString(), true);
+	}
+
+	public String getVatNumber() {
+		return vatNumber;
+	}
+
+	public void setVatNumber(String vatNumber) {
+		setStringProperty(VAT_NR, vatNumber, true);
+	}
+
+	public List<AccessMethodHandler> getMethodHandlers() {
+		return new ArrayList<AccessMethodHandler>(methodHandlers);
+	}
+	
+	public void setMethodHandlers(List<AccessMethodHandler> handlers) {
+		if(handlers != null) {
+			methodHandlers.addAll(handlers);
+		}
+	}
+	
+	public void addMethodHandler(AccessMethodHandler handler) {
+		if(handler != null) {
+			methodHandlers.add(handler);
+		}
+	}
+	
+	public void removeMethodHandler(AccessMethodHandler handler) {
+		if(handler != null) {
+			methodHandlers.remove(handler);
+		}
+	}
+
+	public AccessMethodHandler getAccessMethodHandler(String type) {
+		for(AccessMethodHandler handler:methodHandlers) {
+			if(handler.getType().equals(type)) {
+				return handler;
+			}
+		}
+		return null;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/AccessResult.java b/src/main/java/org/olat/resource/accesscontrol/AccessResult.java
new file mode 100644
index 0000000000000000000000000000000000000000..052d13fa88118dd6099a0daaaf58763f1b8b0640
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/AccessResult.java
@@ -0,0 +1,58 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.olat.resource.accesscontrol.model.OfferAccess;
+
+/**
+ * 
+ * Description:<br>
+ * Result of an attempt to access a resource
+ * 
+ * <P>
+ * Initial Date:  14 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class AccessResult {
+	
+	private final boolean accessible;
+	private List<OfferAccess> availableMethods;
+	
+	public AccessResult(boolean accessible) {
+		this(accessible, Collections.<OfferAccess>emptyList());
+	}
+	
+	public AccessResult(boolean accessible, List<OfferAccess> availableMethods) {
+		this.accessible = accessible;
+		this.availableMethods = availableMethods;
+	}
+
+	public boolean isAccessible() {
+		return accessible;
+	}
+
+	public List<OfferAccess> getAvailableMethods() {
+		return availableMethods;
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/_spring/acContext.xml b/src/main/java/org/olat/resource/accesscontrol/_spring/acContext.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d08854c2bd505256c08890396cb0ca9af05faf6a
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/_spring/acContext.xml
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xmlns:context="http://www.springframework.org/schema/context" 
+	xsi:schemaLocation="http://www.springframework.org/schema/beans 
+                        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
+                        http://www.springframework.org/schema/context 
+                        http://www.springframework.org/schema/context/spring-context-3.0.xsd">
+
+	<context:property-placeholder location="classpath:serviceconfig/olat.properties, classpath:olat.local.properties" />
+
+	<!-- MAIL CONFIGURATION -->
+	<!-- ========================= -->
+	
+	<bean id="acModule" class="org.olat.resource.accesscontrol.AccessControlModule" depends-on="org.olat.core.util.WebappHelper">
+		<property name="persistedProperties">
+	  	<bean class="org.olat.core.configuration.PersistedProperties" scope="prototype" init-method="init" destroy-method="destroy" 
+	  		depends-on="coordinatorManager,org.olat.core.util.WebappHelper">
+	    	<constructor-arg index="0" ref="coordinatorManager"/>
+	    	<constructor-arg index="1" ref="acModule" />
+	  	</bean>
+		</property>
+		<property name="methodHandlers">
+			<list>
+				<ref bean="freeAccessHandler"/>
+				<ref bean="tokenAccessHandler"/>
+			</list>
+		</property>
+		<property name="acFrontendManager" ref="acFrontendManager"/>
+	</bean>
+	
+	<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
+		<property name="targetObject" ref="acModule" />
+		<property name="targetMethod" value="init" />
+		<property name="arguments">
+			<value>
+				resource.accesscontrol.enabled=${resource.accesscontrol.enabled}
+				resource.accesscontrol.home.overview=${resource.accesscontrol.home.overview}
+				method.token.enabled=${method.token.enabled}
+				method.free.enabled=${method.free.enabled}
+			</value>
+		</property>
+	</bean>
+	
+	<!--  Extension for archiver -->
+	<bean class="org.olat.resource.accesscontrol.ui.OrdersActionExtension" init-method="initExtensionPoints">
+		<constructor-arg index="0" ref="acModule" />
+		<property name="actionController">	
+			<bean class="org.olat.core.gui.control.creator.AutoCreator" scope="prototype">
+				<property name="className" value="org.olat.resource.accesscontrol.ui.OrdersAdminController"/>
+			</bean>
+		</property>
+		
+		<property name="i18nActionKey" value="order.menu.title.alt"/>
+		<property name="i18nDescriptionKey" value="order.menu.title.alt"/>
+		<property name="translationPackage" value="org.olat.resource.accesscontrol.ui"/>
+		<property name="extensionPoints">
+			<list>	
+				<value>org.olat.course.archiver.ArchiverMainController</value>		
+			</list>
+		</property>
+		<property name="order" value="267" />
+	</bean>
+	
+	<bean id="acOfferManager" class="org.olat.resource.accesscontrol.manager.ACOfferManagerImpl">
+		<property name="dbInstance" ref="database"/>
+	</bean>
+	
+	<bean id="acFrontendManager" class="org.olat.resource.accesscontrol.manager.ACFrontendManager">
+		<property name="accessModule" ref="acModule" />
+		<property name="accessManager" ref="acOfferManager" />
+		<property name="securityManager" ref="baseSecurityManager"/>
+		<property name="methodManager" ref="acMethodManager"/>
+		<property name="orderManager" ref="acOrderManager"/>
+		<property name="transactionManager" ref="acTransactionManager"/>
+		<property name="repositoryManager" ref="repositoryManager"/>
+	</bean>
+	
+	<bean id="acMethodManager" class="org.olat.resource.accesscontrol.manager.ACMethodManagerImpl"
+		depends-on="acModule">
+		<constructor-arg index="0" ref="coordinatorManager" />
+		<constructor-arg index="1" ref="acModule" />
+		<property name="dbInstance" ref="database"/>
+	</bean>
+	
+	<bean id="acOrderManager" class="org.olat.resource.accesscontrol.manager.ACOrderManagerImpl">
+		<property name="dbInstance" ref="database"/>
+	</bean>
+	
+	<bean id="acTransactionManager" class="org.olat.resource.accesscontrol.manager.ACTransactionManagerImpl">
+		<property name="dbInstance" ref="database"/>
+	</bean>
+	
+	<bean id="freeAccessHandler" class="org.olat.resource.accesscontrol.method.FreeAccessHandler"/>
+	<bean id="tokenAccessHandler" class="org.olat.resource.accesscontrol.method.TokenAccessHandler"/>
+	
+	<bean id="resourceAccessDBMappings" class="org.olat.core.commons.persistence.AdditionalDBMappings">
+		<property name="xmlFiles">
+			<list>								
+				<value>org/olat/resource/accesscontrol/model/Offer.hbm.xml</value>
+				<value>org/olat/resource/accesscontrol/model/AccessMethod.hbm.xml</value>
+				<value>org/olat/resource/accesscontrol/model/AccessTransaction.hbm.xml</value>
+				<value>org/olat/resource/accesscontrol/model/OfferAccess.hbm.xml</value>
+				<value>org/olat/resource/accesscontrol/model/Order.hbm.xml</value>
+			</list>
+		</property>
+	</bean>
+	
+	
+	<!--  Orders admin panel -->
+	<bean class="org.olat.core.extensions.action.GenericActionExtension" init-method="initExtensionPoints">
+		<property name="actionController">	
+			<bean class="org.olat.core.gui.control.creator.AutoCreator" scope="prototype">
+				<property name="className" value="org.olat.resource.accesscontrol.ui.OrdersAdminController"/>
+			</bean>
+		</property>
+		<property name="navigationKey" value="booking" />
+		<property name="i18nActionKey" value="order.menu.title"/>
+		<property name="i18nDescriptionKey" value="order.menu.title.alt"/>
+		<property name="translationPackage" value="org.olat.resource.accesscontrol.ui"/>
+		<property name="extensionPoints">
+			<list>	
+				<value>org.olat.admin.SystemAdminMainController</value>		
+			</list>
+		</property>
+		<property name="order" value="302" />
+	</bean>
+
+</beans>
diff --git a/src/main/java/org/olat/resource/accesscontrol/manager/ACFrontendManager.java b/src/main/java/org/olat/resource/accesscontrol/manager/ACFrontendManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..b37dffa33e26936fb4c67c54953519e7149e2daf
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/manager/ACFrontendManager.java
@@ -0,0 +1,461 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.manager;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import org.olat.basesecurity.BaseSecurity;
+import org.olat.core.id.Identity;
+import org.olat.core.id.Roles;
+import org.olat.core.manager.BasicManager;
+import org.olat.group.BusinessGroup;
+import org.olat.group.BusinessGroupManagerImpl;
+import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryManager;
+import org.olat.resource.OLATResource;
+import org.olat.resource.OLATResourceManager;
+import org.olat.resource.accesscontrol.AccessControlModule;
+import org.olat.resource.accesscontrol.AccessResult;
+import org.olat.resource.accesscontrol.method.AccessMethodHandler;
+import org.olat.resource.accesscontrol.model.AccessMethod;
+import org.olat.resource.accesscontrol.model.AccessTransaction;
+import org.olat.resource.accesscontrol.model.BusinessGroupAccess;
+import org.olat.resource.accesscontrol.model.OLATResourceAccess;
+import org.olat.resource.accesscontrol.model.Offer;
+import org.olat.resource.accesscontrol.model.OfferAccess;
+import org.olat.resource.accesscontrol.model.Order;
+import org.olat.resource.accesscontrol.model.OrderStatus;
+import org.olat.resource.accesscontrol.model.PSPTransaction;
+
+/**
+ * 
+ * Description:<br>
+ * The access control is not intend for security check.
+ * 
+ * <P>
+ * Initial Date:  14 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class ACFrontendManager extends BasicManager {
+	
+	private BaseSecurity securityManager;
+	private RepositoryManager repositoryManager;
+	private AccessControlModule accessModule;
+	private ACOfferManager accessManager;
+	private ACMethodManager methodManager;
+	private ACOrderManager orderManager;
+	private ACTransactionManager transactionManager;
+	
+	private ACFrontendManager() {
+		//
+	}
+
+	/**
+	 * [used by Spring]
+	 * @param accessModule
+	 */
+	public void setAccessModule(AccessControlModule accessModule) {
+		this.accessModule = accessModule;
+	}
+	
+	/**
+	 * [used by Spring]
+	 * @param repositoryManager
+	 */
+	public void setRepositoryManager(RepositoryManager repositoryManager) {
+		this.repositoryManager = repositoryManager;
+	}
+
+	/**
+	 * [used by Spring]
+	 * @param accessmanager
+	 */
+	public void setAccessManager(ACOfferManager accessManager) {
+		this.accessManager = accessManager;
+	}
+	
+	/**
+	 * [used by Spring]
+	 * @param securityManager
+	 */
+	public void setSecurityManager(BaseSecurity securityManager) {
+		this.securityManager = securityManager;
+	}
+	
+	/**
+	 * [used by Spring]
+	 * @param methodManager
+	 */
+	public void setMethodManager(ACMethodManager methodManager) {
+		this.methodManager = methodManager;
+	}
+	
+	/**
+	 * [used by Spring]
+	 * @param orderManager
+	 */
+	public void setOrderManager(ACOrderManager orderManager) {
+		this.orderManager = orderManager;
+	}
+	
+	/**
+	 * [used by Spring]
+	 * @param transactionManager
+	 */
+	public void setTransactionManager(ACTransactionManager transactionManager) {
+		this.transactionManager = transactionManager;
+	}
+
+	/**
+	 * The rule to access the repository entry:<br/>
+	 * -No offer, access is free<br/>
+	 * -Owners have always access to the resource<br/>
+	 * -Tutors have access to the resource<br/>
+	 * -Participants have access to the resource<br/>
+	 * @param entry
+	 * @param forId
+	 * @return
+	 */
+	public AccessResult isAccessible(RepositoryEntry entry, Identity forId, boolean allowNonInteractiveAccess) {
+		if(!accessModule.isEnabled()) {
+			return new AccessResult(true);
+		}
+		
+		boolean member = repositoryManager.isMember(forId, entry);
+		if(member) {
+			return new AccessResult(true);
+		}
+		
+		List<Offer> offers = accessManager.findOfferByResource(entry.getOlatResource(), true, new Date());
+		if(offers.isEmpty()) {
+			if(methodManager.isValidMethodAvailable(entry.getOlatResource(), null)) {
+				//not open for the moment: no valid offer at this date but some methods are defined
+				return new AccessResult(false);
+			} else {
+				return new AccessResult(true);
+			}	
+		}
+		return isAccessible(forId, offers, allowNonInteractiveAccess);
+	}
+	
+	/**
+	 * 
+	 * @param resource
+	 * @param atDate 
+	 * @return
+	 */
+	public boolean isResourceAccessControled(OLATResource resource, Date atDate) {
+		return methodManager.isValidMethodAvailable(resource, atDate);
+	}
+	
+	/**
+	 * The rule to access a business group:<br/>
+	 * -No offer, access is free<br/>
+	 * -Owners have always access to the resource<br/>
+	 * -Tutors have access to the resource<br/>
+	 * -Participants have access to the resource<br/>
+	 * @param group
+	 * @param forId
+	 * @return
+	 */
+	public AccessResult isAccessible(BusinessGroup group, Identity forId, boolean allowNonInteractiveAccess) {
+		if(!accessModule.isEnabled()) {
+			return new AccessResult(true);
+		}
+
+		boolean tutor = securityManager.isIdentityInSecurityGroup(forId, group.getOwnerGroup());
+		if(tutor) {
+			return new AccessResult(true);
+		}
+		
+		if(group.getPartipiciantGroup() != null) {
+			boolean participant = securityManager.isIdentityInSecurityGroup(forId, group.getPartipiciantGroup());
+			if(participant) {
+				return new AccessResult(true);
+			}
+		}
+		
+		OLATResource resource = OLATResourceManager.getInstance().findResourceable(group);
+		List<Offer> offers = accessManager.findOfferByResource(resource, true, new Date());
+		if(offers.isEmpty()) {
+			if(methodManager.isValidMethodAvailable(resource, null)) {
+				//not open for the moment: no valid offer at this date but some methods are defined
+				return new AccessResult(false);
+			} else {
+				return new AccessResult(true);
+			}	
+		}
+		
+		return isAccessible(forId, offers, allowNonInteractiveAccess);
+	}
+	
+	protected AccessResult isAccessible(Identity identity, List<Offer> offers, boolean allowNonInteractiveAccess) {
+		List<OfferAccess> offerAccess = methodManager.getOfferAccess(offers, true);
+		if(offerAccess.isEmpty()) {
+			return new AccessResult(false);
+		}
+		if(allowNonInteractiveAccess && offerAccess.size() == 1) {
+			//is it a method without user interaction as the free access?
+			OfferAccess link = offerAccess.get(0);
+			if(!link.getMethod().isNeedUserInteraction()) {
+				return accessResource(identity, link, null);
+			}
+		}
+		return new AccessResult(false, offerAccess);
+	}
+	
+	public Offer createOffer(OLATResource resource, String resourceName) {
+		return accessManager.createOffer(resource, resourceName);
+	}
+	
+	public void deleteOffer(Offer offer) {
+		accessManager.deleteOffer(offer);
+	}
+	
+	public List<OLATResourceAccess> filterRepositoryEntriesWithAC(List<RepositoryEntry> repoEntries) {
+		List<Long> resourceKeys = new ArrayList<Long>();
+		for(RepositoryEntry entry:repoEntries) {
+			OLATResource ores = entry.getOlatResource();
+			resourceKeys.add(ores.getKey());
+		}
+		
+		List<OLATResourceAccess> resourceWithOffers = methodManager.getAccessMethodForResources(resourceKeys, true, new Date());
+		return resourceWithOffers;
+	}
+	
+	public Set<Long> filterResourcesWithAC(Collection<Long> resourceKeys) {
+		Set<Long> resourceWithOffers = accessManager.filterResourceWithOffer(resourceKeys);
+		return resourceWithOffers;
+	}
+	
+	public List<Offer> findOfferByResource(OLATResource resource, boolean valid, Date atDate) {
+		return accessManager.findOfferByResource(resource, valid, atDate);
+	}
+	
+	public List<BusinessGroupAccess> getOfferAccessForBusinessGroup(boolean valid, Date atDate) {
+		return methodManager.getAccessMethodForBusinessGroup(valid, atDate);
+	}
+	
+	public List<OLATResourceAccess> getAccessMethodForResources(Collection<Long> resourceKeys, boolean valid, Date atDate) {
+		return methodManager.getAccessMethodForResources(resourceKeys, valid, atDate);
+	}
+
+	/**
+	 * Get the list of access methods for a business group that are currently available
+	 * @param group 
+	 * @param valid 
+	 * @param atDate
+	 * @return The list of OfferAccess objects that represent available access methods
+	 */
+	public List<OfferAccess> getAccessMethodForBusinessGroup(BusinessGroup group, boolean valid, Date atDate) {
+		OLATResource resource = OLATResourceManager.getInstance().findResourceable(group);
+		List<Offer> offers = accessManager.findOfferByResource(resource, valid, atDate);
+		if(offers.isEmpty()) {
+			return Collections.<OfferAccess>emptyList();
+		}
+		List<OfferAccess> offerAccess = methodManager.getOfferAccess(offers, valid);
+		if(offerAccess.isEmpty()) {
+			return Collections.<OfferAccess>emptyList();
+		}
+		return offerAccess;
+	}
+	
+	public List<OfferAccess> getOfferAccessByResource(Collection<Long> resourceKeys, boolean valid, Date atDate) {
+		return methodManager.getOfferAccessByResource(resourceKeys, valid, atDate);
+	}
+	
+	public void save(Offer offer) {
+		accessManager.saveOffer(offer);
+	}
+	
+	public OfferAccess saveOfferAccess(OfferAccess link) {
+		accessManager.saveOffer(link.getOffer());
+		methodManager.save(link);
+		return link;
+	}
+	
+	public void saveOfferAccess(List<OfferAccess> links) {
+		for(OfferAccess link:links) {
+			accessManager.saveOffer(link.getOffer());
+			methodManager.save(link);
+		}
+	}
+	
+	public AccessResult accessResource(Identity identity, OfferAccess link, Object argument) {
+		if(link == null || link.getOffer() == null || link.getMethod() == null) {
+			logAudit("Access refused (no offer) to: " + link + " for " + identity);
+			return new AccessResult(false);
+		}
+		
+		AccessMethodHandler handler = accessModule.getAccessMethodHandler(link.getMethod().getType());
+		if(handler == null) {
+			logAudit("Access refused (no handler method) to: " + link + " for " + identity);
+			return new AccessResult(false);
+		}
+		
+		if(handler.checkArgument(link, argument)) {
+			if(allowAccesToResource(identity, link.getOffer())) {
+				Order order = orderManager.saveOneClick(identity, link);
+				AccessTransaction transaction = transactionManager.createTransaction(order, order.getParts().get(0), link.getMethod());
+				transactionManager.save(transaction);
+				logAudit("Access granted to: " + link + " for " + identity);
+				return new AccessResult(true);
+			} else {
+				logAudit("Access error to: " + link + " for " + identity);
+			}
+		} else {
+			logAudit("Access refused to: " + link + " for " + identity);
+		}
+		return new AccessResult(false);
+	}
+
+	public boolean allowAccesToResource(Identity identity, Offer offer) {
+		//check if offer is ok: key is stupid but further check as date, validity...
+		if(offer.getKey() == null) {
+			return false;
+		}
+		
+		//check the resource
+		OLATResource resource = offer.getResource();
+		if(resource == null || resource.getKey() == null || resource.getResourceableId() == null || resource.getResourceableTypeName() == null) {
+			return false;
+		}
+		
+		String resourceType = resource.getResourceableTypeName();
+		if("CourseModule".equals(resourceType)) {
+			RepositoryEntry entry = repositoryManager.lookupRepositoryEntry(resource, false);
+			if(entry != null) {
+				if(!securityManager.isIdentityInSecurityGroup(identity, entry.getParticipantGroup())) {
+					securityManager.addIdentityToSecurityGroup(identity, entry.getParticipantGroup());
+				}
+				return true;
+			}
+		} else if("BusinessGroup".equals(resourceType)) {
+			BusinessGroup group = BusinessGroupManagerImpl.getInstance().loadBusinessGroup(resource, false);
+			if(group != null) {
+				if(!securityManager.isIdentityInSecurityGroup(identity, group.getPartipiciantGroup())) {
+					securityManager.addIdentityToSecurityGroup(identity, group.getPartipiciantGroup());
+				}
+				return true;
+			}
+		}
+		return false;
+	}
+	
+	public boolean denyAccesToResource(Identity identity, Offer offer) {
+		//check if offer is ok: key is stupid but further check as date, validity...
+		if(offer.getKey() == null) {
+			return false;
+		}
+		
+		//check the resource
+		OLATResource resource = offer.getResource();
+		if(resource == null || resource.getKey() == null || resource.getResourceableId() == null || resource.getResourceableTypeName() == null) {
+			return false;
+		}
+		
+		String resourceType = resource.getResourceableTypeName();
+		if("CourseModule".equals(resourceType)) {
+			RepositoryEntry entry = repositoryManager.lookupRepositoryEntry(resource, false);
+			if(entry != null) {
+				if(securityManager.isIdentityInSecurityGroup(identity, entry.getParticipantGroup())) {
+					securityManager.removeIdentityFromSecurityGroup(identity, entry.getParticipantGroup());
+				}
+				return true;
+			}
+		} else if("BusinessGroup".equals(resourceType)) {
+			BusinessGroup group = BusinessGroupManagerImpl.getInstance().loadBusinessGroup(resource, false);
+			if(group != null) {
+				if(securityManager.isIdentityInSecurityGroup(identity, group.getPartipiciantGroup())) {
+					securityManager.removeIdentityFromSecurityGroup(identity, group.getPartipiciantGroup());
+				}
+				return true;
+			}
+		}
+		return false;
+	}
+	
+	public String resolveDisplayName(OLATResource resource) {
+		String resourceType = resource.getResourceableTypeName();
+		if("CourseModule".equals(resourceType)) {
+			RepositoryEntry entry = repositoryManager.lookupRepositoryEntry(resource, false);
+			if(entry != null) {
+				return entry.getDisplayname();
+			}
+		} else if("BusinessGroup".equals(resourceType)) {
+			BusinessGroup group = BusinessGroupManagerImpl.getInstance().loadBusinessGroup(resource, false);
+			if(group != null) {
+				return group.getName();
+			}
+		}
+		return null;
+	}
+	
+	public void enableMethod(Class<? extends AccessMethod> type, boolean enable) {
+		methodManager.enableMethod(type, enable);
+	}
+	
+	public List<AccessMethod> getAvailableMethods(Identity identity, Roles roles) {
+		return methodManager.getAvailableMethods(identity, roles);
+	}
+	
+	public OfferAccess createOfferAccess(Offer offer, AccessMethod method) {
+		return methodManager.createOfferAccess(offer, method);
+	}
+	
+	public void deletedLinkToMethod(OfferAccess link) {
+		methodManager.delete(link);
+	}
+	
+	public List<OfferAccess> getOfferAccess(Offer offer, boolean valid) {
+		return methodManager.getOfferAccess(offer, valid);
+	}
+	
+	public List<Order> findOrders(Identity delivery, OrderStatus... status) {
+		return orderManager.findOrdersByDelivery(delivery, status);
+	}
+	
+	public List<AccessTransaction> findAccessTransactions(List<Order> orders) {
+		return transactionManager.loadTransactionsForOrders(orders);
+	}
+	
+	public List<PSPTransaction> findPSPTransactions(List<Order> orders) {
+		List<AccessMethodHandler> handlers = accessModule.getMethodHandlers();
+		List<PSPTransaction> transactions = new ArrayList<PSPTransaction>();
+		for(AccessMethodHandler handler:handlers) {
+			transactions.addAll(handler.getPSPTransactions(orders));
+		}
+		return transactions;
+	}
+	
+	public List<Order> findOrders(OLATResource resource, Identity delivery, Long orderNr, Date from, Date to, OrderStatus... status) {
+		return orderManager.findOrders(resource, delivery, orderNr, from, to, status);
+	}
+	
+	public List<Order> findOrders(OLATResource resource, OrderStatus... status) {
+		return orderManager.findOrdersByResource(resource, status);
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/manager/ACMethodManager.java b/src/main/java/org/olat/resource/accesscontrol/manager/ACMethodManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..8ec448a08844219e66209597109c5f9cfa4cec65
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/manager/ACMethodManager.java
@@ -0,0 +1,121 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.manager;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+
+import org.olat.core.id.Identity;
+import org.olat.core.id.Roles;
+import org.olat.resource.OLATResource;
+import org.olat.resource.accesscontrol.model.AccessMethod;
+import org.olat.resource.accesscontrol.model.BusinessGroupAccess;
+import org.olat.resource.accesscontrol.model.OLATResourceAccess;
+import org.olat.resource.accesscontrol.model.Offer;
+import org.olat.resource.accesscontrol.model.OfferAccess;
+
+/**
+ * 
+ * Description:<br>
+ * Manage the access methods to the resources
+ * 
+ * <P>
+ * Initial Date:  18 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public interface ACMethodManager {
+	
+	/**
+	 * Enable/disable a type of access method
+	 * @param type
+	 * @param enable
+	 */
+	public void enableMethod(Class<? extends AccessMethod> type, boolean enable);
+	
+	
+	/**
+	 * Get the list of access methods which a user /author can use
+	 * @param identity
+	 * @return List of access methods
+	 */
+	public List<AccessMethod> getAvailableMethods(Identity identity, Roles roles);
+	
+	/**
+	 * Return the list of access methods of a specific type.
+	 * @param type
+	 * @return List of access methods
+	 */
+	public List<AccessMethod> getAvailableMethodsByType(Class<? extends AccessMethod> type);
+	
+	/**
+	 * Return a list of links offer to method for the specified offer.
+	 * @param offer
+	 * @param valid
+	 * @return List of link offer to method
+	 */
+	public List<OfferAccess> getOfferAccess(Offer offer, boolean valid);
+	
+	/**
+	 * Return a list of links offer to access method for the specified offers.
+	 * @param offer
+	 * @param valid
+	 * @return List of link offer to access method
+	 */
+	public List<OfferAccess> getOfferAccess(Collection<Offer> offers, boolean valid);
+	
+	public List<OfferAccess> getOfferAccessByResource(Collection<Long> resourceKeys, boolean valid, Date atDate);
+	
+	
+	/**
+	 * Return true if the resource has a method valid
+	 * @param resource The resource
+	 * @param atDate The date for the access (optional)
+	 * @return
+	 */
+	public boolean isValidMethodAvailable(OLATResource resource, Date atDate);
+	
+	public List<BusinessGroupAccess> getAccessMethodForBusinessGroup(boolean valid, Date atDate);
+	
+	public List<OLATResourceAccess> getAccessMethodForResources(Collection<Long> resourceKeys, boolean valid, Date atDate);
+	
+	/**
+	 * Create a link between offer and access method. The link is not persisted
+	 * on the database with this method.
+	 * @param offer
+	 * @param method
+	 * @return
+	 */
+	public OfferAccess createOfferAccess(Offer offer, AccessMethod method);
+	
+	/**
+	 * The link is not really deleted on the database but set as invalid.
+	 * @param link
+	 */
+	public void delete(OfferAccess link);
+	
+	/**
+	 * Persist/update the link offer to access method.
+	 * @param link
+	 */
+	public void save(OfferAccess link);
+
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/manager/ACMethodManagerImpl.java b/src/main/java/org/olat/resource/accesscontrol/manager/ACMethodManagerImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..108c7c003c8a32134cdab325640e95cd4897516b
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/manager/ACMethodManagerImpl.java
@@ -0,0 +1,392 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.manager;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.commons.persistence.DBQuery;
+import org.olat.core.gui.control.Event;
+import org.olat.core.id.Identity;
+import org.olat.core.id.Roles;
+import org.olat.core.manager.BasicManager;
+import org.olat.core.util.coordinate.CoordinatorManager;
+import org.olat.core.util.event.FrameworkStartedEvent;
+import org.olat.core.util.event.FrameworkStartupEventChannel;
+import org.olat.core.util.event.GenericEventListener;
+import org.olat.group.BusinessGroup;
+import org.olat.group.BusinessGroupImpl;
+import org.olat.group.BusinessGroupManagerImpl;
+import org.olat.resource.OLATResource;
+import org.olat.resource.OLATResourceImpl;
+import org.olat.resource.accesscontrol.AccessControlModule;
+import org.olat.resource.accesscontrol.method.AccessMethodHandler;
+import org.olat.resource.accesscontrol.model.AbstractAccessMethod;
+import org.olat.resource.accesscontrol.model.AccessMethod;
+import org.olat.resource.accesscontrol.model.AccessMethodSecurityCallback;
+import org.olat.resource.accesscontrol.model.BusinessGroupAccess;
+import org.olat.resource.accesscontrol.model.FreeAccessMethod;
+import org.olat.resource.accesscontrol.model.OLATResourceAccess;
+import org.olat.resource.accesscontrol.model.Offer;
+import org.olat.resource.accesscontrol.model.OfferAccess;
+import org.olat.resource.accesscontrol.model.OfferAccessImpl;
+import org.olat.resource.accesscontrol.model.Price;
+import org.olat.resource.accesscontrol.model.PriceMethodBundle;
+import org.olat.resource.accesscontrol.model.TokenAccessMethod;
+
+/**
+ * 
+ * Description:<br>
+ * This class manages the methods available to access the resource.
+ * As standard "static" (static as singleton), there is Token  and Free
+ * based access.
+ * 
+ * <P>
+ * Initial Date:  18 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class ACMethodManagerImpl extends BasicManager implements ACMethodManager, GenericEventListener {
+
+	private DB dbInstance;
+	private final AccessControlModule acModule;
+	
+	public ACMethodManagerImpl(CoordinatorManager coordinatorManager, AccessControlModule acModule) {
+		this.acModule = acModule;
+		coordinatorManager.getCoordinator().getEventBus().registerFor(this, null, FrameworkStartupEventChannel.getStartupEventChannel());
+	}
+
+	/**
+	 * [used by Spring]
+	 * @param dbInstance
+	 */
+	public void setDbInstance(DB dbInstance) {
+		this.dbInstance = dbInstance;
+	}
+	
+	@Override
+	public void event(Event event) {
+		if (event instanceof FrameworkStartedEvent && ((FrameworkStartedEvent) event).isEventOnThisNode()) {
+			enableMethod(TokenAccessMethod.class, acModule.isTokenEnabled());
+			enableMethod(FreeAccessMethod.class, acModule.isFreeEnabled());
+			dbInstance.commitAndCloseSession();
+		}
+	}
+
+	@Override
+	public void enableMethod(Class<? extends AccessMethod> type, boolean enable) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select method from ").append(AbstractAccessMethod.class.getName())
+			.append(" method where method.class=").append(type.getName());
+		
+		DBQuery query = dbInstance.createQuery(sb.toString());
+		List<AccessMethod> methods = query.list();
+		if(methods.isEmpty() && enable) {
+			try {
+				dbInstance.saveObject(type.newInstance());
+			} catch (InstantiationException e) {
+				logError("Failed to instantiate an access method", e);
+			} catch (IllegalAccessException e) {
+				logError("Failed to instantiate an access method", e);
+			}
+		} else {
+			for(AccessMethod method:methods) {
+				if(method.isEnabled() != enable) {
+					((AbstractAccessMethod)method).setEnabled(enable);
+					dbInstance.updateObject(method);
+				}
+			}
+		}
+	}
+
+	@Override
+	public boolean isValidMethodAvailable(OLATResource resource, Date atDate) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select count(access.method) from ").append(OfferAccessImpl.class.getName()).append(" access ")
+			.append(" inner join access.offer offer")
+			.append(" inner join offer.resource oResource")
+			.append(" where access.valid=true")
+			.append(" and offer.valid=true")
+			.append(" and oResource.key=:resourceKey");
+		if(atDate != null) {
+			sb.append(" and (offer.validFrom is null or offer.validFrom<=:atDate)")
+				.append(" and (offer.validTo is null or offer.validTo>=:atDate)");
+		}
+
+		DBQuery query = dbInstance.createQuery(sb.toString());
+		query.setLong("resourceKey", resource.getKey());
+		if(atDate != null) {
+			query.setTimestamp("atDate", atDate);
+		}
+
+		Number methods = (Number)query.uniqueResult();
+		return methods.intValue() > 0;
+	}
+
+	@Override
+	public List<AccessMethod> getAvailableMethods(Identity identity, Roles roles) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select method from ").append(AbstractAccessMethod.class.getName()).append(" method")
+			.append(" where method.valid=true and method.enabled=true");
+		
+		DBQuery query = dbInstance.createQuery(sb.toString());
+		if(identity != null) {
+			//query.setLong("identityKey", identity.getKey());
+		}
+	
+		List<AccessMethod> methods = query.list();
+		List<AccessMethod> allowedMethods = new ArrayList<AccessMethod>();
+		for(AccessMethod method:methods) {
+			AccessMethodHandler handler = acModule.getAccessMethodHandler(method.getType());
+			AccessMethodSecurityCallback secCallback = handler.getSecurityCallback(identity, roles);
+			if(secCallback.canUse()) {
+				allowedMethods.add(method);
+			}
+		}
+		return allowedMethods;
+	}
+	
+	public List<AccessMethod> getAvailableMethodsByType(Class<? extends AccessMethod> type) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select method from ").append(AbstractAccessMethod.class.getName()).append(" method")
+			.append(" where method.valid=true")
+			.append(" and method.class=").append(type.getName());
+		
+		DBQuery query = dbInstance.createQuery(sb.toString());
+		List<AccessMethod> methods = query.list();
+		return methods;
+	}
+
+	@Override
+	public List<OfferAccess> getOfferAccess(Offer offer, boolean valid) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select access from ").append(OfferAccessImpl.class.getName()).append(" access")
+			.append(" where access.offer=:offer")
+			.append(" and access.valid=").append(valid);
+
+		DBQuery query = dbInstance.createQuery(sb.toString());
+		query.setEntity("offer", offer);
+		
+		List<OfferAccess> methods = query.list();
+		return methods;
+	}
+	
+	@Override
+	public List<OfferAccess> getOfferAccess(Collection<Offer> offers, boolean valid) {
+		if(offers == null || offers.isEmpty()) return Collections.emptyList();
+
+		StringBuilder sb = new StringBuilder();
+		sb.append("select access from ").append(OfferAccessImpl.class.getName()).append(" access")
+			.append(" where access.offer in (:offers)")
+			.append(" and access.valid=").append(valid);
+		
+
+		DBQuery query = dbInstance.createQuery(sb.toString());
+		query.setParameterList("offers", offers);
+		
+		List<OfferAccess> methods = query.list();
+		return methods;
+	}
+	
+	@Override
+	public List<OfferAccess> getOfferAccessByResource(Collection<Long> resourceKeys, boolean valid, Date atDate) {
+		if(resourceKeys == null || resourceKeys.isEmpty()) return Collections.emptyList();
+
+		StringBuilder sb = new StringBuilder();
+		sb.append("select access from ").append(OfferAccessImpl.class.getName()).append(" access")
+			.append(" inner join access.offer offer")
+			.append(" inner join offer.resource resource")
+			.append(" where resource.key in (:resourceKeys)")
+			.append(" and access.valid=").append(valid)
+			.append(" and offer.valid=").append(valid);
+		if(atDate != null) {
+			sb.append(" and (offer.validFrom is null or offer.validFrom<=:atDate)")
+				.append(" and (offer.validTo is null or offer.validTo>=:atDate)");
+		}
+
+		DBQuery query = dbInstance.createQuery(sb.toString());
+		query.setParameterList("resourceKeys", resourceKeys);
+		if(atDate != null) {
+			query.setTimestamp("atDate", atDate);
+		}
+		
+		List<OfferAccess> methods = query.list();
+		return methods;
+	}
+	
+	@Override
+	public List<BusinessGroupAccess> getAccessMethodForBusinessGroup(boolean valid, Date atDate) {
+
+		StringBuilder sb = new StringBuilder();
+		sb.append("select access.method, group.key, offer.price from ").append(OfferAccessImpl.class.getName()).append(" access, ")
+			.append(BusinessGroupImpl.class.getName()).append(" group, ")
+			.append(OLATResourceImpl.class.getName()).append(" gResource")
+			.append(" inner join access.offer offer")
+			.append(" inner join offer.resource oResource")
+			.append(" where access.valid=").append(valid)
+			.append(" and offer.valid=").append(valid)
+			.append(" and group.key=gResource.resId and gResource.resName='BusinessGroup' and oResource.key=gResource.key");
+		if(atDate != null) {
+			sb.append(" and (offer.validFrom is null or offer.validFrom<=:atDate)")
+				.append(" and (offer.validTo is null or offer.validTo>=:atDate)");
+		}
+
+		DBQuery query = dbInstance.createQuery(sb.toString());
+		if(atDate != null) {
+			query.setTimestamp("atDate", atDate);
+		}
+		
+		List<Object[]> rawResults = query.list();
+		Map<Long,List<PriceMethodBundle>> rawResultsMap = new HashMap<Long,List<PriceMethodBundle>>();
+		for(Object[] rawResult:rawResults) {
+			AccessMethod method = (AccessMethod)rawResult[0];
+			Long groupKey = (Long)rawResult[1];
+			Price price = (Price)rawResult[2];
+			if(!rawResultsMap.containsKey(groupKey)) {
+				rawResultsMap.put(groupKey, new ArrayList<PriceMethodBundle>(3));
+			}
+			rawResultsMap.get(groupKey).add(new PriceMethodBundle(price, method));	
+		}
+		
+		List<BusinessGroup> groups = BusinessGroupManagerImpl.getInstance().findBusinessGroups(rawResultsMap.keySet());
+		List<BusinessGroupAccess> groupAccess = new ArrayList<BusinessGroupAccess>();
+		for(BusinessGroup group:groups) {
+			List<PriceMethodBundle> methods = rawResultsMap.get(group.getKey());
+			if(methods != null && !methods.isEmpty()) {
+				groupAccess.add(new BusinessGroupAccess(group, methods));
+			}
+		}
+		return groupAccess;
+	}
+	
+	@Override
+	public List<OLATResourceAccess> getAccessMethodForResources(Collection<Long> resourceKeys, boolean valid, Date atDate) {
+		if(resourceKeys == null || resourceKeys.isEmpty()) return Collections.emptyList();
+		
+		StringBuilder sb = new StringBuilder();
+		sb.append("select access.method, resource, offer.price from ").append(OfferAccessImpl.class.getName()).append(" access, ")
+			.append(OLATResourceImpl.class.getName()).append(" resource")
+			.append(" inner join access.offer offer")
+			.append(" inner join offer.resource oResource")
+			.append(" where access.valid=").append(valid)
+			.append(" and offer.valid=").append(valid)
+			.append(" and resource.key in (:resourceKeys) and oResource.key=resource.key");
+		if(atDate != null) {
+			sb.append(" and (offer.validFrom is null or offer.validFrom<=:atDate)")
+				.append(" and (offer.validTo is null or offer.validTo>=:atDate)");
+		}
+
+		DBQuery query = dbInstance.createQuery(sb.toString());
+		if(atDate != null) {
+			query.setTimestamp("atDate", atDate);
+		}
+		query.setParameterList("resourceKeys", resourceKeys);
+		
+		List<Object[]> rawResults = query.list();
+		Map<Long,OLATResourceAccess> rawResultsMap = new HashMap<Long,OLATResourceAccess>();
+		for(Object[] rawResult:rawResults) {
+			AccessMethod method = (AccessMethod)rawResult[0];
+			OLATResource resource = (OLATResource)rawResult[1];
+			Price price = (Price)rawResult[2];
+			if(rawResultsMap.containsKey(resource.getKey())) {
+				rawResultsMap.get(resource.getKey()).addBundle(price, method);
+			} else {
+				rawResultsMap.put(resource.getKey(), new OLATResourceAccess(resource, price, method));
+			}
+		}
+		
+		List<OLATResourceAccess> groupAccess = new ArrayList<OLATResourceAccess>(rawResultsMap.values());
+		return groupAccess;
+	}
+
+	@Override
+	public OfferAccess createOfferAccess(Offer offer, AccessMethod method) {
+		OfferAccessImpl access = new OfferAccessImpl();
+		access.setOffer(offer);
+		access.setMethod(method);
+		access.setValid(true);
+		return access;
+	}
+	
+	@Override
+	public void save(OfferAccess link) {
+		if(link.getKey() == null) {
+			dbInstance.saveObject(link);
+		} else {
+			dbInstance.updateObject(link);
+		}
+	}
+	
+	@Override
+	public void delete(OfferAccess link) {
+		OfferAccessImpl access = (OfferAccessImpl)link;
+		access.setValid(false);
+	
+		if(link.getKey() == null) return;
+		dbInstance.updateObject(access);
+	}
+	
+	/**
+	 * Activate the token method if not already configured.
+	 */
+	protected void activateTokenMethod(boolean enable) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select method from ").append(AbstractAccessMethod.class.getName())
+			.append(" method where method.class=").append(TokenAccessMethod.class.getName());
+		
+		DBQuery query = dbInstance.createQuery(sb.toString());
+		List<AccessMethod> methods = query.list();
+		if(methods.isEmpty() && enable) {
+			dbInstance.saveObject(new TokenAccessMethod());
+		} else {
+			for(AccessMethod method:methods) {
+				if(method.isEnabled() != enable) {
+					((AbstractAccessMethod)method).setEnabled(enable);
+					dbInstance.updateObject(method);
+				}
+			}
+		}
+	}
+	
+	protected void activateFreeMethod(boolean enable) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select method from ").append(AbstractAccessMethod.class.getName())
+			.append(" method where method.class=").append(FreeAccessMethod.class.getName());
+		
+		DBQuery query = dbInstance.createQuery(sb.toString());
+		List<AccessMethod> methods = query.list();
+		if(methods.isEmpty() && enable) {
+			dbInstance.saveObject(new FreeAccessMethod());
+		} else {
+			for(AccessMethod method:methods) {
+				if(method.isEnabled() != enable) {
+					((AbstractAccessMethod)method).setEnabled(enable);
+					dbInstance.updateObject(method);
+				}
+			}
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/manager/ACOfferManager.java b/src/main/java/org/olat/resource/accesscontrol/manager/ACOfferManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..d154bec0c8a826f81a288e5479261a8d26cdc317
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/manager/ACOfferManager.java
@@ -0,0 +1,87 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.manager;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import org.olat.resource.OLATResource;
+import org.olat.resource.accesscontrol.model.BusinessGroupAccess;
+import org.olat.resource.accesscontrol.model.Offer;
+
+/**
+ * 
+ * Description:<br>
+ * 
+ * <P>
+ * Initial Date:  14 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public interface ACOfferManager {
+	
+	/**
+	 * Find the offers related to the specified resource
+	 * @param resource
+	 * @param valid Valid/invalid offer
+	 * @param date Valid at the given date
+	 * @return List of offers or empty list
+	 */
+	public List<Offer> findOfferByResource(OLATResource resource, boolean valid, Date date);
+	
+	/**
+	 * Load an offer by primary key
+	 * @param key The primary key of the offer
+	 * @return An offer or null if not found
+	 */
+	public Offer loadOfferByKey(Long key);
+	
+	/**
+	 * Filter the list of given resource primary keys and return only the ones
+	 * which as a valid offer at this time.
+	 * @param resourceKeys
+	 * @return A set of resource primary keys
+	 */
+	public Set<Long> filterResourceWithOffer(Collection<Long> resourceKeys);
+	
+	/**
+	 * Create an offer to access for a resource. The resource name is saved
+	 * in the case of the deletion of the resource as fallback.
+	 * @param resource
+	 * @param resourceName
+	 * @return
+	 */
+	public Offer createOffer(OLATResource resource, String resourceName);
+	
+	/**
+	 * Set the offer as invalid, but not delete it really on the database. In
+	 * the case of a payment, the offer msut survive for the orders.
+	 * @param offer
+	 */
+	public void deleteOffer(Offer offer);
+	
+	/**
+	 * Persist/update the offer on the database
+	 * @param offer
+	 */
+	public void saveOffer(Offer offer);
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/manager/ACOfferManagerImpl.java b/src/main/java/org/olat/resource/accesscontrol/manager/ACOfferManagerImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..54ee3656d045b103d38769ddc7d92d5853919556
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/manager/ACOfferManagerImpl.java
@@ -0,0 +1,164 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.manager;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.commons.persistence.DBQuery;
+import org.olat.core.manager.BasicManager;
+import org.olat.resource.OLATResource;
+import org.olat.resource.accesscontrol.model.Offer;
+import org.olat.resource.accesscontrol.model.OfferImpl;
+
+/**
+ * 
+ * Description:<br>
+ * 
+ * <P>
+ * Initial Date:  14 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class ACOfferManagerImpl extends BasicManager implements ACOfferManager {
+	
+	private DB dbInstance;
+
+	private ACOfferManagerImpl() {
+		//
+	}
+	
+	/**
+	 * [used by Spring]
+	 * @param dbInstance
+	 */
+	public void setDbInstance(DB dbInstance) {
+		this.dbInstance = dbInstance;
+	}
+	
+	@Override
+	public List<Offer> findOfferByResource(OLATResource resource, boolean valid, Date atDate) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select offer from ").append(OfferImpl.class.getName()).append(" offer")
+			.append(" inner join offer.resource resource")
+			.append(" where resource.key=:resourceKey")
+			.append(" and offer.valid=").append(valid);
+		if(atDate != null) {
+			sb.append(" and (offer.validFrom is null or offer.validFrom<=:atDate)")
+				.append(" and (offer.validTo is null or offer.validTo>=:atDate)");
+		}
+
+		DBQuery query = dbInstance.createQuery(sb.toString());
+		query.setLong("resourceKey", resource.getKey());
+		if(atDate != null) {
+			query.setTimestamp("atDate", atDate);
+		}
+	
+		List<Offer> offers = query.list();
+		return offers;
+	}
+
+	@Override
+	public Offer loadOfferByKey(Long key) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select offer from ").append(OfferImpl.class.getName()).append(" offer")
+			.append(" where offer.key=:offerKey");
+
+		DBQuery query = dbInstance.createQuery(sb.toString());
+		query.setLong("offerKey", key);
+
+	
+		List<Offer> offers = query.list();
+		if(offers.isEmpty()) return null;
+		return offers.get(0);
+	}
+
+	public Set<Long> filterResourceWithOffer(Collection<Long> resourceKeys) {
+		if(resourceKeys == null || resourceKeys.isEmpty()) return Collections.emptySet();
+		
+		StringBuilder sb = new StringBuilder();
+		sb.append("select offer.resource.key from ").append(OfferImpl.class.getName()).append(" offer")
+			.append(" inner join offer.resource resource")
+			.append(" where resource.key in (:resourceKeys)");
+		DBQuery query = dbInstance.createQuery(sb.toString());
+
+		Set<Long> resourceWithOffers = new HashSet<Long>();
+		List<Long> keys = new ArrayList<Long>(resourceKeys);
+		
+		//too much in with hibernate can generate a stack overflow
+		int hibernateInBatch = 500;
+		int firstResult = 0;
+		do {
+			int toIndex = Math.min(firstResult + hibernateInBatch, keys.size());
+			List<Long> inParameter = keys.subList(firstResult, toIndex);
+			query.setParameterList("resourceKeys", inParameter);
+			firstResult += inParameter.size();
+			
+			List<Long> offerKeys = query.list();
+			resourceWithOffers.addAll(offerKeys);
+		} while(firstResult < keys.size());
+
+		return resourceWithOffers;
+	}
+	
+	@Override
+	public Offer createOffer(OLATResource resource, String resourceName) {
+		OfferImpl offer = new OfferImpl();
+		offer.setResource(resource);
+		offer.setValid(true);
+		if(resourceName != null && resourceName.length() > 255) {
+			resourceName = resourceName.substring(0, 250);
+		}
+		offer.setResourceDisplayName(resourceName);
+		offer.setResourceId(resource.getResourceableId());
+		String resourceTypeName = resource.getResourceableTypeName();
+		if(resourceTypeName != null && resourceTypeName.length() > 255) {
+			resourceTypeName = resourceTypeName.substring(0, 250);
+		}
+		offer.setResourceTypeName(resourceTypeName);
+		return offer;
+	}
+	
+	@Override
+	public void deleteOffer(Offer offer) {
+		if(offer instanceof OfferImpl) {
+			((OfferImpl)offer).setValid(false);
+		}
+		saveOffer(offer);
+	}
+
+	@Override
+	public void saveOffer(Offer offer) {
+		if(offer instanceof OfferImpl) {
+			((OfferImpl)offer).setLastModified(new Date());
+		}
+		if(offer.getKey() == null) {
+			dbInstance.saveObject(offer);
+		} else {
+			dbInstance.updateObject(offer);
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/manager/ACOrderManager.java b/src/main/java/org/olat/resource/accesscontrol/manager/ACOrderManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..ffb5ccd6bcc454e54cb91b9f23574dd103a6181f
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/manager/ACOrderManager.java
@@ -0,0 +1,139 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.manager;
+
+import java.util.Date;
+import java.util.List;
+
+import org.olat.core.id.Identity;
+import org.olat.resource.OLATResource;
+import org.olat.resource.accesscontrol.model.Offer;
+import org.olat.resource.accesscontrol.model.OfferAccess;
+import org.olat.resource.accesscontrol.model.Order;
+import org.olat.resource.accesscontrol.model.OrderLine;
+import org.olat.resource.accesscontrol.model.OrderPart;
+import org.olat.resource.accesscontrol.model.OrderStatus;
+
+/**
+ * 
+ * Description:<br>
+ * Manage the orders. An order is a part of the confirmation of an
+ * access which inlude the resource being access and an acnhor point
+ * for the transaction (payment or other).
+ * 
+ * <P>
+ * Initial Date:  19 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public interface ACOrderManager {
+	
+	/**
+	 * Create an order for the specified identity. The order
+	 * is not persisted on the database.
+	 * @param delivery
+	 * @return The order
+	 */
+	public Order createOrder(Identity delivery);
+	
+	/**
+	 * An order part is a subset of the order with the same access
+	 * method and resolved to a single valid transaction (single is
+	 * the normal case but it's not a constraint).
+	 * @param order
+	 * @return The order part
+	 */
+	public OrderPart addOrderPart(Order order);
+	
+	/**
+	 * Add an order line
+	 * @param part
+	 * @param offer
+	 * @return The order line
+	 */
+	public OrderLine addOrderLine(OrderPart part, Offer offer);
+	
+	/**
+	 * Persist the order on the database
+	 * @param order
+	 * @return The order
+	 */
+	public Order save(Order order);
+	
+	/**
+	 * Persist the order on the database
+	 * @param order
+	 * @return The order
+	 */
+	public Order save(Order order, OrderStatus status);
+	
+	/**
+	 * Save a simple order for a single pair offer/access method and set the status to payed.
+	 * @param delivery
+	 * @param link
+	 * @return
+	 */
+	public Order saveOneClick(Identity delivery, OfferAccess link);
+	
+	/**
+	 * Save a simple order for a single pair offer/access method and set the status.
+	 * @param delivery
+	 * @param link
+	 * @param status
+	 * @return
+	 */
+	public Order saveOneClick(Identity delivery, OfferAccess link, OrderStatus status);
+	
+	/**
+	 * Load an order by its primary key.
+	 * @param orderKey
+	 * @return The order
+	 */
+	public Order loadOrderByKey(Long orderKey);
+	
+	/**
+	 * Load an order by its primary key.
+	 * @param orderKey
+	 * @return The order
+	 */
+	public Order loadOrderByNr(String orderNr);
+	
+	/**
+	 * Load the orders of a specific identity.
+	 * @param delivery The identity
+	 * @return List of orders
+	 */
+	public List<Order> findOrders(OLATResource resource, Identity delivery, Long orderNr, Date from, Date to, OrderStatus... status);
+	
+	/**
+	 * Load the orders of a specific identity.
+	 * @param delivery The identity
+	 * @return List of orders
+	 */
+	public List<Order> findOrdersByDelivery(Identity delivery, OrderStatus... status);
+	
+	/**
+	 * Load the orders related to a specified resource.
+	 * @param resource
+	 * @return List of orders
+	 */
+	public List<Order> findOrdersByResource(OLATResource resource, OrderStatus... status);
+
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/manager/ACOrderManagerImpl.java b/src/main/java/org/olat/resource/accesscontrol/manager/ACOrderManagerImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..1dfa27b408671e4e1ef17371bdfd101f177a269b
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/manager/ACOrderManagerImpl.java
@@ -0,0 +1,292 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.manager;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.commons.persistence.DBQuery;
+import org.olat.core.id.Identity;
+import org.olat.core.manager.BasicManager;
+import org.olat.resource.OLATResource;
+import org.olat.resource.accesscontrol.model.Offer;
+import org.olat.resource.accesscontrol.model.OfferAccess;
+import org.olat.resource.accesscontrol.model.Order;
+import org.olat.resource.accesscontrol.model.OrderImpl;
+import org.olat.resource.accesscontrol.model.OrderLine;
+import org.olat.resource.accesscontrol.model.OrderLineImpl;
+import org.olat.resource.accesscontrol.model.OrderPart;
+import org.olat.resource.accesscontrol.model.OrderPartImpl;
+import org.olat.resource.accesscontrol.model.OrderStatus;
+
+/**
+ * 
+ * Description:<br>
+ * manager for the order. Orders are a part of the confirmation of an access
+ * to a resource. The second part is the transaction.
+ * 
+ * <P>
+ * Initial Date:  19 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class ACOrderManagerImpl extends BasicManager implements ACOrderManager {
+	
+	private DB dbInstance;
+	
+	private ACOrderManagerImpl() {
+		//
+	}
+
+	/**
+	 * [used by Spring]
+	 * @param dbInstance
+	 */
+	public void setDbInstance(DB dbInstance) {
+		this.dbInstance = dbInstance;
+	}
+	
+	@Override
+	public OrderImpl createOrder(Identity delivery) {
+		OrderImpl order = new OrderImpl();
+		order.setDelivery(delivery);
+		order.setOrderStatus(OrderStatus.NEW);
+		dbInstance.saveObject(order);
+		return order;
+	}
+
+	@Override
+	public OrderPart addOrderPart(Order order) {
+		OrderPartImpl orderPart = new OrderPartImpl();
+		dbInstance.saveObject(orderPart);
+		order.getParts().add(orderPart);
+		return orderPart;
+	}
+
+	@Override
+	public OrderLine addOrderLine(OrderPart part, Offer offer) {
+		OrderLineImpl line = new OrderLineImpl();
+		line.setOffer(offer);
+		line.setUnitPrice(offer.getPrice().clone());
+		line.setTotal(line.getUnitPrice().clone());
+		dbInstance.saveObject(line);
+		part.getOrderLines().add(line);
+		return line;
+	}
+	
+	@Override
+	public Order save(Order order) {
+		if(order.getKey() == null) {
+			dbInstance.saveObject(order);
+		} else {
+			dbInstance.updateObject(order);
+		}
+		return order;
+	}
+	
+	@Override
+	public Order save(Order order, OrderStatus status) {
+		((OrderImpl)order).setOrderStatus(status);
+		if(order.getKey() == null) {
+			dbInstance.saveObject(order);
+		} else {
+			dbInstance.updateObject(order);
+		}
+		return order;
+	}
+	
+	@Override
+	public Order saveOneClick(Identity delivery, OfferAccess link) {
+		return saveOneClick(delivery, link, OrderStatus.PAYED);
+	}
+	
+	@Override
+	public Order saveOneClick(Identity delivery, OfferAccess link, OrderStatus status) {
+		OrderImpl order = createOrder(delivery);
+		order.setOrderStatus(status);
+		if(link.getOffer().getPrice().isEmpty()) {
+			order.setCurrencyCode("CHF");
+		} else {
+			order.setCurrencyCode(link.getOffer().getPrice().getCurrencyCode());
+		}
+		OrderPart part = addOrderPart(order);
+		addOrderLine(part, link.getOffer());
+		order.recalculate();
+		
+		dbInstance.updateObject(order);
+		dbInstance.updateObject(part);
+		
+		return order;
+	}
+	
+	@Override
+	public List<Order> findOrdersByDelivery(Identity delivery, OrderStatus... status) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select order from ").append(OrderImpl.class.getName()).append(" order")
+			.append(" where order.delivery.key=:deliveryKey");
+		if(status != null && status.length > 0) {
+			sb.append(" and order.orderStatusStr in (:status)");
+		}
+		
+		DBQuery query = dbInstance.createQuery(sb.toString());
+		query.setLong("deliveryKey", delivery.getKey());
+		if(status != null && status.length > 0) {
+			List<String> statusStr = new ArrayList<String>();
+			for(OrderStatus s:status) {
+				statusStr.add(s.name());
+			}
+			query.setParameterList("status", statusStr);
+		}
+	
+		List<Order> orders = query.list();
+		return orders;
+	}
+
+	@Override
+	public List<Order> findOrdersByResource(OLATResource resource, OrderStatus... status) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select distinct(o) from ").append(OrderImpl.class.getName()).append(" o")
+			.append(" inner join o.parts orderPart ")
+			.append(" inner join orderPart.orderLines orderLine ")
+			.append(" inner join orderLine.offer offer ")
+			.append(" where offer.resource.key=:resourceKey");
+		if(status != null && status.length > 0) {
+			sb.append(" and o.orderStatusStr in (:status)");
+		}
+		
+		DBQuery query = dbInstance.createQuery(sb.toString());
+		query.setLong("resourceKey", resource.getKey());
+		if(status != null && status.length > 0) {
+			List<String> statusStr = new ArrayList<String>();
+			for(OrderStatus s:status) {
+				statusStr.add(s.name());
+			}
+			query.setParameterList("status", statusStr);
+		}
+	
+		List<Order> orders = query.list();
+		return orders;
+	}
+	
+	@Override
+	public List<Order> findOrders(OLATResource resource, Identity delivery, Long orderNr, Date from, Date to, OrderStatus... status) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select distinct(o) from ").append(OrderImpl.class.getName()).append(" o");
+		if(resource != null) {
+			sb.append(" inner join o.parts orderPart ")
+				.append(" inner join orderPart.orderLines orderLine ")
+				.append(" inner join orderLine.offer offer");
+		}
+
+		boolean where = false;
+		if(resource != null) {
+			where = appendAnd(sb, where);
+			sb.append("offer.resource.key=:resourceKey");
+		}
+		if(delivery != null) {
+			where = appendAnd(sb, where);
+			sb.append("order.delivery.key=:deliveryKey");
+		}
+		if(status != null && status.length > 0) {
+			where = appendAnd(sb, where);
+			sb.append("o.orderStatusStr in (:status)");
+		}
+		if(from != null) {
+			where = appendAnd(sb, where);
+			sb.append("o.creationDate >=:from");
+		}
+		if(to != null) {
+			where = appendAnd(sb, where);
+			sb.append("o.creationDate <=:to");
+		}
+		if(orderNr != null) {
+			where = appendAnd(sb, where);
+			sb.append("o.key=:orderNr");
+		}
+
+		DBQuery query = dbInstance.createQuery(sb.toString());
+		if(status != null && status.length > 0) {
+			List<String> statusStr = new ArrayList<String>();
+			for(OrderStatus s:status) {
+				statusStr.add(s.name());
+			}
+			query.setParameterList("status", statusStr);
+		}
+		if(resource != null) {
+			query.setLong("resourceKey", resource.getKey());
+		}
+		if(delivery != null) {
+			query.setLong("deliveryKey", delivery.getKey());
+		}
+		if(orderNr != null) {
+			query.setLong("orderNr", orderNr);
+		}
+		if(from != null) {
+			Calendar cal = Calendar.getInstance();
+			cal.setTime(from);
+			cal.set(Calendar.HOUR, 0);
+			cal.set(Calendar.MINUTE, 0);
+			cal.set(Calendar.SECOND, 0);
+			cal.set(Calendar.MILLISECOND, 0);
+			query.setTimestamp("from", cal.getTime());
+		}
+		if(to != null) {
+			Calendar cal = Calendar.getInstance();
+			cal.setTime(to);
+			cal.set(Calendar.HOUR, 23);
+			cal.set(Calendar.MINUTE, 59);
+			cal.set(Calendar.SECOND, 59);
+			cal.set(Calendar.MILLISECOND, 0);
+			query.setTimestamp("to", cal.getTime());
+		}
+	
+		List<Order> orders = query.list();
+		return orders;
+	}
+	
+	private boolean appendAnd(StringBuilder sb, boolean where) {
+		if(where) sb.append(" and ");
+		else sb.append(" where ");
+		return true;
+	}
+
+	@Override
+	public Order loadOrderByKey(Long orderKey) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select order from ").append(OrderImpl.class.getName()).append(" order")
+			.append(" where order.key=:orderKey");
+		
+		DBQuery query = dbInstance.createQuery(sb.toString());
+		query.setLong("orderKey", orderKey);
+	
+		List<Order> orders = query.list();
+		if(orders.isEmpty()) return null;
+		return orders.get(0);
+	}
+	
+	@Override
+	public Order loadOrderByNr(String orderNr) {
+		Long orderKey = new Long(orderNr);
+		return loadOrderByKey(orderKey);
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/manager/ACTransactionManager.java b/src/main/java/org/olat/resource/accesscontrol/manager/ACTransactionManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..5ff0167d03049f22fc1ca790a3a3b5b2ce05b681
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/manager/ACTransactionManager.java
@@ -0,0 +1,83 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.manager;
+
+import java.util.List;
+
+import org.olat.resource.accesscontrol.model.AccessMethod;
+import org.olat.resource.accesscontrol.model.AccessTransaction;
+import org.olat.resource.accesscontrol.model.AccessTransactionStatus;
+import org.olat.resource.accesscontrol.model.Order;
+import org.olat.resource.accesscontrol.model.OrderPart;
+
+/**
+ * 
+ * Description:<br>
+ * this is the second part of the confirmation of an access to a resource.
+ * The transaction log the attempt to access the resource. There is normally
+ * one transaction for an order part. But if the user canceled, retry, pay 
+ * severals time the same order part. All the transactions will be logged and
+ * easily tracked for an admin (administrator of the resource)
+ * 
+ * <P>
+ * Initial Date:  19 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public interface ACTransactionManager {
+	
+	/**
+	 * Create a transaction but not persist it on the database.
+	 * @param order
+	 * @param orderPart
+	 * @param method
+	 * @return The transaction
+	 */
+	public AccessTransaction createTransaction(Order order, OrderPart orderPart, AccessMethod method);
+	
+	/**
+	 * Persist the transaction to the database.
+	 * @param transaction
+	 * @return The transaction
+	 */
+	public AccessTransaction save(AccessTransaction transaction);
+	
+	/**
+	 * Update the transaction to the database.
+	 * @param transaction
+	 * @return The transaction
+	 */
+	public AccessTransaction update(AccessTransaction transaction, AccessTransactionStatus status);
+	
+	/**
+	 * Load a transaction by its primary key.
+	 * @param key
+	 * @return The transaction
+	 */
+	public AccessTransaction loadTransactionByKey(Long key);
+	
+	/**
+	 * Quick load of a list of transactions.
+	 * @param orders
+	 * @return List of transactions
+	 */
+	public List<AccessTransaction> loadTransactionsForOrders(List<Order> orders);
+
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/manager/ACTransactionManagerImpl.java b/src/main/java/org/olat/resource/accesscontrol/manager/ACTransactionManagerImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..0e57bb0988bd70d6b7049d8f8904cddf29e2eb95
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/manager/ACTransactionManagerImpl.java
@@ -0,0 +1,114 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.manager;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.commons.persistence.DBQuery;
+import org.olat.core.manager.BasicManager;
+import org.olat.resource.accesscontrol.model.AccessMethod;
+import org.olat.resource.accesscontrol.model.AccessTransaction;
+import org.olat.resource.accesscontrol.model.AccessTransactionImpl;
+import org.olat.resource.accesscontrol.model.AccessTransactionStatus;
+import org.olat.resource.accesscontrol.model.Order;
+import org.olat.resource.accesscontrol.model.OrderPart;
+
+/**
+ * 
+ * Description:<br>
+ * TODO: srosse Class Description for ACTransactionManagerImpl
+ * 
+ * <P>
+ * Initial Date:  19 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class ACTransactionManagerImpl extends BasicManager implements ACTransactionManager {
+	
+	private DB dbInstance;
+	
+	private ACTransactionManagerImpl() {
+		//
+	}
+	
+	/**
+	 * [used by Spring]
+	 * @param dbInstance
+	 */
+	public void setDbInstance(DB dbInstance) {
+		this.dbInstance = dbInstance;
+	}
+	
+	@Override
+	public AccessTransaction createTransaction(Order order, OrderPart orderPart, AccessMethod method) {
+		AccessTransactionImpl transaction = new AccessTransactionImpl();
+		transaction.setOrder(order);
+		transaction.setOrderPart(orderPart);
+		transaction.setMethod(method);
+		return transaction;
+	}
+
+	@Override
+	public AccessTransaction save(AccessTransaction transaction) {
+		if(transaction.getKey() == null) {
+			dbInstance.saveObject(transaction);
+		} else {
+			dbInstance.updateObject(transaction);
+		}
+		return transaction;
+	}
+	
+	@Override
+	public AccessTransaction update(AccessTransaction transaction, AccessTransactionStatus status) {
+		((AccessTransactionImpl)transaction).setStatus(status);
+		return save(transaction);
+	}
+	
+	@Override
+	public AccessTransaction loadTransactionByKey(Long transactionKey) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select trx from ").append(AccessTransactionImpl.class.getName()).append(" trx")
+			.append(" where trx.key=:transactionKey");
+		
+		DBQuery query = dbInstance.createQuery(sb.toString());
+		query.setLong("transactionKey", transactionKey);
+	
+		List<AccessTransaction> transactions = query.list();
+		if(transactions.isEmpty()) return null;
+		return transactions.get(0);
+	}
+	
+	@Override
+	public List<AccessTransaction> loadTransactionsForOrders(List<Order> orders) {
+		if(orders == null || orders.isEmpty()) return Collections.emptyList();
+		
+		StringBuilder sb = new StringBuilder();
+		sb.append("select trx from ").append(AccessTransactionImpl.class.getName()).append(" trx")
+			.append(" where trx.order in (:orders)");
+		
+		DBQuery query = dbInstance.createQuery(sb.toString());
+		query.setParameterList("orders", orders);
+	
+		List<AccessTransaction> transactions = query.list();
+		return transactions;
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/method/AccessMethodHandler.java b/src/main/java/org/olat/resource/accesscontrol/method/AccessMethodHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..b00209cc05d6673c269193a465994b58df103514
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/method/AccessMethodHandler.java
@@ -0,0 +1,71 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.method;
+
+import java.util.List;
+import java.util.Locale;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.impl.Form;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.id.Identity;
+import org.olat.core.id.Roles;
+import org.olat.resource.accesscontrol.model.AccessMethod;
+import org.olat.resource.accesscontrol.model.AccessMethodSecurityCallback;
+import org.olat.resource.accesscontrol.model.OfferAccess;
+import org.olat.resource.accesscontrol.model.Order;
+import org.olat.resource.accesscontrol.model.OrderPart;
+import org.olat.resource.accesscontrol.model.PSPTransaction;
+import org.olat.resource.accesscontrol.ui.AbstractConfigurationMethodController;
+import org.olat.resource.accesscontrol.ui.FormController;
+
+/**
+ * 
+ * Description:<br>
+ * A method handler must impements this interface
+ * 
+ * <P>
+ * Initial Date:  18 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public interface AccessMethodHandler {
+	
+	public String getType();
+	
+	public String getMethodName(Locale locale);
+	
+	public AccessMethodSecurityCallback getSecurityCallback(Identity identity, Roles roles);
+	
+	public FormController createAccessController(UserRequest ureq, WindowControl wControl, OfferAccess link, Form form);
+	
+	public AbstractConfigurationMethodController createConfigurationController(UserRequest ureq, WindowControl wControl, OfferAccess link);
+
+	public FormController createTransactionDetailsController(UserRequest ureq, WindowControl wControl, Order order, OrderPart part, AccessMethod method, Form form);
+	
+	
+	
+	//access worklow
+	public boolean checkArgument(OfferAccess link, Object argument);
+	
+	//control
+	public List<PSPTransaction> getPSPTransactions(List<Order> orders);
+	
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/method/FreeAccessHandler.java b/src/main/java/org/olat/resource/accesscontrol/method/FreeAccessHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..b8d5666957c6286995f91f693394a11fdd2d65de
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/method/FreeAccessHandler.java
@@ -0,0 +1,106 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.method;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.impl.Form;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.translator.Translator;
+import org.olat.core.id.Identity;
+import org.olat.core.id.Roles;
+import org.olat.core.util.Util;
+import org.olat.resource.accesscontrol.model.AccessMethod;
+import org.olat.resource.accesscontrol.model.AccessMethodSecurityCallback;
+import org.olat.resource.accesscontrol.model.DefaultACSecurityCallback;
+import org.olat.resource.accesscontrol.model.OfferAccess;
+import org.olat.resource.accesscontrol.model.Order;
+import org.olat.resource.accesscontrol.model.OrderPart;
+import org.olat.resource.accesscontrol.model.PSPTransaction;
+import org.olat.resource.accesscontrol.ui.AbstractConfigurationMethodController;
+import org.olat.resource.accesscontrol.ui.FormController;
+import org.olat.resource.accesscontrol.ui.FreeAccessConfigurationController;
+import org.olat.resource.accesscontrol.ui.FreeAccessController;
+import org.olat.resource.accesscontrol.ui.TokenAccessController;
+
+/**
+ * 
+ * Description:<br>
+ * Implementation of the access handler for the free method
+ * 
+ * <P>
+ * Initial Date:  18 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class FreeAccessHandler implements AccessMethodHandler {
+	
+	public static final String METHOD_TYPE = "free.method";
+	public static final String METHOD_CSS_CLASS = "b_access_method_free";
+
+	@Override
+	public String getType() {
+		return METHOD_TYPE;
+	}
+
+	@Override
+	public String getMethodName(Locale locale) {
+		Translator translator = Util.createPackageTranslator(TokenAccessController.class, locale);
+		return translator.translate("free.method");
+	}
+	
+	@Override
+	public AccessMethodSecurityCallback getSecurityCallback(Identity identity, Roles roles) {
+		return new DefaultACSecurityCallback(roles);
+	}
+
+	@Override
+	public FreeAccessController createAccessController(UserRequest ureq, WindowControl wControl, OfferAccess link, Form form) {
+		if(form == null) {
+			return new FreeAccessController(ureq, wControl, link);
+		} else {
+			return new FreeAccessController(ureq, wControl, link, form);
+		}
+	}
+
+	@Override
+	public AbstractConfigurationMethodController createConfigurationController(UserRequest ureq, WindowControl wControl, OfferAccess link) {
+		return new FreeAccessConfigurationController(ureq, wControl, link);
+	}
+	
+	@Override
+	public FormController createTransactionDetailsController(UserRequest ureq, WindowControl wControl, Order order, OrderPart part, AccessMethod method, Form form) {
+		return null;
+	}
+	
+
+	@Override
+	public boolean checkArgument(OfferAccess link, Object argument) {
+		return true;
+	}
+
+	@Override
+	public List<PSPTransaction> getPSPTransactions(List<Order> orders) {
+		return Collections.emptyList();
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/method/TokenAccessHandler.java b/src/main/java/org/olat/resource/accesscontrol/method/TokenAccessHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..5cc858d852984cb1a48afaa090daed05b3c5194f
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/method/TokenAccessHandler.java
@@ -0,0 +1,113 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.method;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.impl.Form;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.translator.Translator;
+import org.olat.core.id.Identity;
+import org.olat.core.id.Roles;
+import org.olat.core.util.StringHelper;
+import org.olat.core.util.Util;
+import org.olat.resource.accesscontrol.model.AccessMethod;
+import org.olat.resource.accesscontrol.model.AccessMethodSecurityCallback;
+import org.olat.resource.accesscontrol.model.DefaultACSecurityCallback;
+import org.olat.resource.accesscontrol.model.Offer;
+import org.olat.resource.accesscontrol.model.OfferImpl;
+import org.olat.resource.accesscontrol.model.OfferAccess;
+import org.olat.resource.accesscontrol.model.Order;
+import org.olat.resource.accesscontrol.model.OrderPart;
+import org.olat.resource.accesscontrol.model.PSPTransaction;
+import org.olat.resource.accesscontrol.ui.FormController;
+import org.olat.resource.accesscontrol.ui.TokenAccessConfigurationController;
+import org.olat.resource.accesscontrol.ui.TokenAccessController;
+
+/**
+ * 
+ * Description:<br>
+ * TODO: srosse Class Description for TokenAccessHandler
+ * 
+ * <P>
+ * Initial Date:  18 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class TokenAccessHandler implements AccessMethodHandler {
+	
+	public static final String METHOD_TYPE = "token.method";
+	public static final String METHOD_CSS_CLASS = "b_access_method_token";
+
+	@Override
+	public String getType() {
+		return METHOD_TYPE;
+	}
+
+	@Override
+	public String getMethodName(Locale locale) {
+		Translator translator = Util.createPackageTranslator(TokenAccessController.class, locale);
+		return translator.translate("token.method");
+	}
+	
+	@Override
+	public AccessMethodSecurityCallback getSecurityCallback(Identity identity, Roles roles) {
+		return new DefaultACSecurityCallback(roles);
+	}
+
+	@Override
+	public TokenAccessController createAccessController(UserRequest ureq, WindowControl wControl, OfferAccess link, Form form) {
+		if(form == null) {
+			return new TokenAccessController(ureq, wControl, link);
+		} else {
+			return new TokenAccessController(ureq, wControl, link, form);
+		}
+		
+	}
+
+	@Override
+	public TokenAccessConfigurationController createConfigurationController(UserRequest ureq, WindowControl wControl, OfferAccess link) {
+		return new TokenAccessConfigurationController(ureq, wControl, link);
+	}
+	
+	@Override
+	public FormController createTransactionDetailsController(UserRequest ureq, WindowControl wControl, Order order, OrderPart part, AccessMethod method, Form form) {
+		return null;
+	}
+
+	@Override
+	public boolean checkArgument(OfferAccess link, Object argument) {
+		if(argument instanceof String && StringHelper.containsNonWhitespace((String)argument)) {
+			Offer offer = link.getOffer();
+			if(offer instanceof OfferImpl && argument.equals(((OfferImpl)offer).getToken())) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	@Override
+	public List<PSPTransaction> getPSPTransactions(List<Order> orders) {
+		return Collections.emptyList();
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/AbstractAccessMethod.java b/src/main/java/org/olat/resource/accesscontrol/model/AbstractAccessMethod.java
new file mode 100644
index 0000000000000000000000000000000000000000..21b7832a978b7fd13487c156c7cd11f9e7a052c1
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/AbstractAccessMethod.java
@@ -0,0 +1,93 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.model;
+
+import java.util.Date;
+
+import org.olat.core.commons.persistence.PersistentObject;
+import org.olat.core.id.ModifiedInfo;
+
+/**
+ * 
+ * Description:<br>
+ * The root object for access method. The concret implementation must inherent for this
+ * and use the subclass of hibernate to map the object on the DB. 
+ * 
+ * <P>
+ * Initial Date:  18 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public abstract class AbstractAccessMethod extends PersistentObject implements AccessMethod, ModifiedInfo  {
+	
+	private boolean valid = true;
+	private boolean enabled = true;
+	
+	private Date lastModified;
+	private Date validFrom;
+	private Date validTo;
+	
+	@Override
+	public boolean isValid() {
+		return valid;
+	}
+
+	public void setValid(boolean valid) {
+		this.valid = valid;
+	}
+	
+	@Override
+	public boolean isEnabled() {
+		return enabled;
+	}
+
+	public void setEnabled(boolean enabled) {
+		this.enabled = enabled;
+	}
+
+	@Override
+	public abstract String getType();
+
+	@Override
+	public Date getLastModified() {
+		return lastModified;
+	}
+
+	@Override
+	public void setLastModified(Date lastModified) {
+		this.lastModified = lastModified;
+	}
+
+	public Date getValidFrom() {
+		return validFrom;
+	}
+
+	public void setValidFrom(Date validFrom) {
+		this.validFrom = validFrom;
+	}
+
+	public Date getValidTo() {
+		return validTo;
+	}
+
+	public void setValidTo(Date validTo) {
+		this.validTo = validTo;
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/AccessMethod.hbm.xml b/src/main/java/org/olat/resource/accesscontrol/model/AccessMethod.hbm.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e20faa29f5835c5aa24fa491ef89f76abd53ed75
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/AccessMethod.hbm.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+	
+	<class name="org.olat.resource.accesscontrol.model.AbstractAccessMethod" table="o_ac_method">
+		<id name="key" column="method_id" type="long" unsaved-value="null">
+			<generator class="hilo"/>
+		</id>
+    <discriminator column="access_method" type="string"/>
+		
+		<version name="version" access="field" column="version" type="int"/>
+		<property name="lastModified" column="lastmodified" type="timestamp" />
+	  <property name="creationDate" column="creationdate" type="timestamp" />
+	  <property name="valid" column="is_valid" type="boolean" />
+	  <property name="enabled" column="is_enabled" type="boolean" />
+
+	  <property name="validFrom" column="validfrom" type="timestamp" />
+	  <property name="validTo" column="validto" type="timestamp" />
+	  
+	  <subclass name="org.olat.resource.accesscontrol.model.TokenAccessMethod" discriminator-value="token.method">
+		
+		</subclass>
+		
+	  <subclass name="org.olat.resource.accesscontrol.model.FreeAccessMethod" discriminator-value="free.method">
+		
+		</subclass>
+	</class>
+	
+</hibernate-mapping>
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/AccessMethod.java b/src/main/java/org/olat/resource/accesscontrol/model/AccessMethod.java
new file mode 100644
index 0000000000000000000000000000000000000000..f222aa6afbe9f77f5ced2d680b2fb888f1f5a71d
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/AccessMethod.java
@@ -0,0 +1,50 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.model;
+
+import java.util.Date;
+
+
+/**
+ * 
+ * Description:<br>
+ * Interface for payment method
+ * 
+ * <P>
+ * Initial Date:  18 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public interface AccessMethod {
+	
+	public Long getKey();
+	
+	public Date getCreationDate();
+	
+	public boolean isValid();
+	
+	public boolean isEnabled();
+	
+	public String getType();
+	
+	public boolean isNeedUserInteraction();
+
+	public String getMethodCssClass();
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/AccessMethodSecurityCallback.java b/src/main/java/org/olat/resource/accesscontrol/model/AccessMethodSecurityCallback.java
new file mode 100644
index 0000000000000000000000000000000000000000..49a06ed23f3dab6a6ef2fd4a92d23b231e644eb1
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/AccessMethodSecurityCallback.java
@@ -0,0 +1,37 @@
+/**
+ * OLAT - Online Learning and Training<br>
+ * http://www.olat.org
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Copyright (c) frentix GmbH<br>
+ * http://www.frentix.com<br>
+ * <p>
+ */
+package org.olat.resource.accesscontrol.model;
+
+/**
+ * 
+ * Description:<br>
+ * Security callback to access a payment method as an author of
+ * a resource.
+ * 
+ * <P>
+ * Initial Date:  27 mai 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public interface AccessMethodSecurityCallback {
+	
+	public boolean canUse();
+
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/AccessTransaction.hbm.xml b/src/main/java/org/olat/resource/accesscontrol/model/AccessTransaction.hbm.xml
new file mode 100644
index 0000000000000000000000000000000000000000..dbe0210db3e0a9f580509f20abcd3cd66e4ccb28
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/AccessTransaction.hbm.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+
+	<class name="org.olat.resource.accesscontrol.model.AccessTransactionImpl" table="o_ac_transaction">
+		<id name="key" column="transaction_id" type="long" unsaved-value="null">
+			<generator class="hilo"/>
+		</id>
+		
+		<version name="version" access="field" column="version" type="int"/>
+	  <property name="creationDate" column="creationdate" type="timestamp" />
+	  
+	  <property name="statusStr" column="trx_status" type="string" not-null="false" length="32" />
+	  
+	  <!-- price in the future -->
+	  <component name="amount" class="org.olat.resource.accesscontrol.model.PriceImpl">
+   		<property name="currencyCode" column="amount_currency_code" type="string"/> 
+   		<property name="amount" column="amount_amount" type="big_decimal"/>
+   	</component>
+	  
+	  <many-to-one name="order"
+                 column="fk_order_id"
+                 class="org.olat.resource.accesscontrol.model.OrderImpl" 
+                 outer-join="true"   
+                 unique="false" 
+                 cascade="none"/>
+                 
+	  <many-to-one name="orderPart"
+                 column="fk_order_part_id"
+                 class="org.olat.resource.accesscontrol.model.OrderPartImpl" 
+                 outer-join="true"   
+                 unique="false" 
+                 cascade="none"/>
+                 
+	  <many-to-one name="method"
+                 column="fk_method_id"
+                 class="org.olat.resource.accesscontrol.model.AbstractAccessMethod" 
+                 outer-join="true"   
+                 unique="false" 
+                 cascade="none"/>  
+	</class>
+	
+</hibernate-mapping>
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/AccessTransaction.java b/src/main/java/org/olat/resource/accesscontrol/model/AccessTransaction.java
new file mode 100644
index 0000000000000000000000000000000000000000..fcf0f816c29577809c5e4c4436a38f3065254c85
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/AccessTransaction.java
@@ -0,0 +1,21 @@
+package org.olat.resource.accesscontrol.model;
+
+import java.util.Date;
+
+public interface AccessTransaction {
+
+	public Long getKey();
+
+	public Date getCreationDate();
+	
+	public AccessTransactionStatus getStatus();
+	
+	public Price getAmount();
+	
+	public Order getOrder();
+	
+	public OrderPart getOrderPart();
+	
+	public AccessMethod getMethod();
+	
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/AccessTransactionImpl.java b/src/main/java/org/olat/resource/accesscontrol/model/AccessTransactionImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..36f831f19989106e8311369c209d577ea5ba89f7
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/AccessTransactionImpl.java
@@ -0,0 +1,94 @@
+package org.olat.resource.accesscontrol.model;
+
+import org.olat.core.commons.persistence.PersistentObject;
+import org.olat.core.util.StringHelper;
+
+public class AccessTransactionImpl extends PersistentObject implements AccessTransaction {
+
+	private Price amount;
+	private Order order;
+	private OrderPart orderPart;
+	
+	private AccessMethod method;
+	private String statusStr = AccessTransactionStatus.NEW.name();
+	
+	public AccessTransactionImpl(){
+		//
+	}
+	
+	@Override
+	public AccessMethod getMethod() {
+		return method;
+	}
+	
+	public void setMethod(AccessMethod method) {
+		this.method = method;
+	}
+	
+	@Override
+	public Price getAmount() {
+		return amount;
+	}
+
+	public void setAmount(Price amount) {
+		this.amount = amount;
+	}
+
+	@Override
+	public Order getOrder() {
+		return order;
+	}
+	
+	public void setOrder(Order order) {
+		this.order = order;
+	}
+	
+	@Override
+	public OrderPart getOrderPart() {
+		return orderPart;
+	}
+	
+	public void setOrderPart(OrderPart orderPart) {
+		this.orderPart = orderPart;
+	}
+	
+	public AccessTransactionStatus getStatus() {
+		if(StringHelper.containsNonWhitespace(statusStr)) {
+			return AccessTransactionStatus.valueOf(statusStr);
+		}
+		return null;
+	}
+
+	public void setStatus(AccessTransactionStatus status) {
+		if(status == null) {
+			statusStr = null;
+		} else {
+			statusStr = status.name();
+		}
+	}
+
+	public String getStatusStr() {
+		return statusStr;
+	}
+
+	public void setStatusStr(String statusStr) {
+		this.statusStr = statusStr;
+	}
+
+	@Override
+	public int hashCode() {
+		return getKey() == null ? 93791 : getKey().hashCode();
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+		if(this == obj) {
+			return true;
+		}
+		if(obj instanceof AccessTransactionImpl) {
+			AccessTransactionImpl accessTransaction = (AccessTransactionImpl)obj;
+			return equalsByPersistableKey(accessTransaction);
+		}
+		return false;
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/AccessTransactionStatus.java b/src/main/java/org/olat/resource/accesscontrol/model/AccessTransactionStatus.java
new file mode 100644
index 0000000000000000000000000000000000000000..d46f3a5836508ff7179ba61546d3a780092208b7
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/AccessTransactionStatus.java
@@ -0,0 +1,16 @@
+package org.olat.resource.accesscontrol.model;
+
+/**
+ * 
+ * Description:<br>
+ * 
+ * <P>
+ * Initial Date:  27 mai 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public enum AccessTransactionStatus {
+	NEW,
+	SUCCESS,
+	CANCELED,
+	ERROR
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/AuthorACSecurityCallback.java b/src/main/java/org/olat/resource/accesscontrol/model/AuthorACSecurityCallback.java
new file mode 100644
index 0000000000000000000000000000000000000000..2ff0af3e556e996d298a80da148e44a1c5d19dce
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/AuthorACSecurityCallback.java
@@ -0,0 +1,47 @@
+/**
+ * OLAT - Online Learning and Training<br>
+ * http://www.olat.org
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Copyright (c) frentix GmbH<br>
+ * http://www.frentix.com<br>
+ * <p>
+ */
+package org.olat.resource.accesscontrol.model;
+
+import org.olat.core.id.Roles;
+
+/**
+ * 
+ * Description:<br>
+ * Allowed for author, admin and isntitional manager
+ * 
+ * <P>
+ * Initial Date:  27 mai 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class AuthorACSecurityCallback implements AccessMethodSecurityCallback {
+	
+	private final Roles roles;
+	
+	public AuthorACSecurityCallback(Roles roles) {
+		this.roles = roles;
+	}
+
+	@Override
+	public boolean canUse() {
+		return roles.isAuthor() || roles.isInstitutionalResourceManager() || roles.isOLATAdmin();
+	}
+
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/BusinessGroupAccess.java b/src/main/java/org/olat/resource/accesscontrol/model/BusinessGroupAccess.java
new file mode 100644
index 0000000000000000000000000000000000000000..2c15aee83b958ed3b05ee40d1affceecd7db2485
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/BusinessGroupAccess.java
@@ -0,0 +1,35 @@
+package org.olat.resource.accesscontrol.model;
+
+import java.util.List;
+
+import org.olat.group.BusinessGroup;
+
+public class BusinessGroupAccess {
+	
+	private BusinessGroup group;
+	private List<PriceMethodBundle> methods;
+	
+	public BusinessGroupAccess() {
+		//
+	}
+	
+	public BusinessGroupAccess(BusinessGroup group, List<PriceMethodBundle> methods) {
+		this.group = group;
+		this.methods = methods;
+	}
+	
+	public BusinessGroup getGroup() {
+		return group;
+	}
+	
+	public void setGroup(BusinessGroup group) {
+		this.group = group;
+	}
+	
+	public List<PriceMethodBundle> getMethods() {
+		return methods;
+	}
+	
+	
+
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/DefaultACSecurityCallback.java b/src/main/java/org/olat/resource/accesscontrol/model/DefaultACSecurityCallback.java
new file mode 100644
index 0000000000000000000000000000000000000000..28f3ad1fcc443792991e2786f571a0035df93e1c
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/DefaultACSecurityCallback.java
@@ -0,0 +1,48 @@
+/**
+ * OLAT - Online Learning and Training<br>
+ * http://www.olat.org
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Copyright (c) frentix GmbH<br>
+ * http://www.frentix.com<br>
+ * <p>
+ */
+package org.olat.resource.accesscontrol.model;
+
+import org.olat.core.id.Roles;
+
+
+/**
+ * 
+ * Description:<br>
+ * Allow all but invitee and guest
+ * 
+ * <P>
+ * Initial Date:  27 mai 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class DefaultACSecurityCallback implements AccessMethodSecurityCallback {
+	
+	private Roles roles;
+	
+	public DefaultACSecurityCallback(Roles roles) {
+		this.roles = roles;
+	}
+
+	@Override
+	public boolean canUse() {
+		return !roles.isGuestOnly() && !roles.isInvitee();
+	}
+
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/FreeAccessMethod.java b/src/main/java/org/olat/resource/accesscontrol/model/FreeAccessMethod.java
new file mode 100644
index 0000000000000000000000000000000000000000..e7b0583c1e3fe516899ca5443416520c844a45a1
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/FreeAccessMethod.java
@@ -0,0 +1,71 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.model;
+
+import org.olat.resource.accesscontrol.method.FreeAccessHandler;
+
+
+/**
+ * 
+ * Description:<br>
+ * This a "static" payment method. There is only one instance.
+ * 
+ * <P>
+ * Initial Date:  27 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class FreeAccessMethod extends AbstractAccessMethod {
+	
+	
+	
+	@Override
+	public String getType() {
+		return FreeAccessHandler.METHOD_TYPE;
+	}
+
+	@Override
+	public String getMethodCssClass() {
+		return FreeAccessHandler.METHOD_CSS_CLASS;
+	}
+
+	@Override
+	public boolean isNeedUserInteraction() {
+		return false;
+	}
+
+	@Override
+	public int hashCode() {
+		return getKey() == null ? 3464 : getKey().hashCode();
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+		if(this == obj) {
+			return true;
+		}
+		if(obj instanceof FreeAccessMethod) {
+			FreeAccessMethod method = (FreeAccessMethod)obj;
+			return getKey() != null && getKey().equals(method.getKey());
+		}
+		return false;
+	}
+
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/OLATResourceAccess.java b/src/main/java/org/olat/resource/accesscontrol/model/OLATResourceAccess.java
new file mode 100644
index 0000000000000000000000000000000000000000..ecce21c45565e4dec34e4eb8c581a76e1c55395f
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/OLATResourceAccess.java
@@ -0,0 +1,44 @@
+package org.olat.resource.accesscontrol.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.olat.resource.OLATResource;
+
+public class OLATResourceAccess {
+	
+	private OLATResource resource;
+	private List<PriceMethodBundle> methods = new ArrayList<PriceMethodBundle>(3);
+	
+	public OLATResourceAccess() {
+		//
+	}
+	
+	public OLATResourceAccess(OLATResource resource, Price price, AccessMethod method) {
+		this.resource = resource;
+		
+		if(method != null) {
+			this.methods.add(new PriceMethodBundle(price, method));
+		}
+	}
+
+	public OLATResource getResource() {
+		return resource;
+	}
+	
+	public void setResource(OLATResource resource) {
+		this.resource = resource;
+	}
+	
+	public List<PriceMethodBundle> getMethods() {
+		return methods;
+	}
+	
+	public void addBundle(Price price, AccessMethod method) {
+		if(method != null) {
+			this.methods.add(new PriceMethodBundle(price, method));
+		}
+	}
+
+
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/Offer.hbm.xml b/src/main/java/org/olat/resource/accesscontrol/model/Offer.hbm.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5709d22a24ba3b29f33d0629bd2658e8de9e5807
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/Offer.hbm.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+	<class name="org.olat.resource.accesscontrol.model.OfferImpl" table="o_ac_offer">
+		<id name="key" column="offer_id" type="long" unsaved-value="null">
+			<generator class="hilo"/>
+		</id>
+		
+		<version name="version" access="field" column="version" type="int"/>
+		<property  name="lastModified" column="lastmodified" type="timestamp" />
+	  <property  name="creationDate" column="creationdate" type="timestamp" />
+	  <property  name="valid" column="is_valid" type="boolean" />
+	  
+	  <property  name="resourceId" column="resourceid" type="long" />
+	  <property  name="resourceTypeName" column="resourcetypename" type="string" length="255" />
+	  <property  name="resourceDisplayName" column="resourcedisplayname" type="string" length="255" />
+	  
+	  <property  name="validFrom" column="validfrom" type="timestamp" />
+	  <property  name="validTo" column="validto" type="timestamp" />
+	  
+	  <property  name="token" column="token" type="string" length="255"/>
+	  <property  name="description" column="offer_desc" type="string" length="2000"/>
+	  
+	  <!-- price in the future -->
+	  <component name="price" class="org.olat.resource.accesscontrol.model.PriceImpl">
+   		<property name="currencyCode" column="price_currency_code" type="string"/> 
+   		<property name="amount" column="price_amount" type="big_decimal"/>
+   	</component>
+
+		<many-to-one name="resource"
+                     column="fk_resource_id"
+                     foreign-key="none"
+                     class="org.olat.resource.OLATResourceImpl"
+                     outer-join="true"
+                     unique="false"
+                     not-found="ignore"
+                     cascade="none"/>
+
+	</class>
+</hibernate-mapping>
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/Offer.java b/src/main/java/org/olat/resource/accesscontrol/model/Offer.java
new file mode 100644
index 0000000000000000000000000000000000000000..ceaade04ad6fc33f7531a3607da8b377d5473b39
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/Offer.java
@@ -0,0 +1,66 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.model;
+
+import java.util.Date;
+
+import org.olat.resource.OLATResource;
+
+/**
+ * 
+ * Description:<br>
+ * 
+ * 
+ * <P>
+ * Initial Date:  14 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public interface Offer {
+	
+	public Long getKey();
+	
+	public OLATResource getResource();
+	
+	public String getResourceTypeName();
+	
+	public Long getResourceId();
+	
+	public String getResourceDisplayName();
+	
+	public Date getValidFrom();
+
+	public void setValidFrom(Date validFrom);
+
+	public Date getValidTo();
+
+	public void setValidTo(Date validTo);
+	
+	public boolean isValid();
+	
+	public Price getPrice();
+	
+	public void setPrice(Price price);
+	
+	public String getDescription();
+	
+	public void setDescription(String description);
+
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/OfferAccess.hbm.xml b/src/main/java/org/olat/resource/accesscontrol/model/OfferAccess.hbm.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1747f31224288d71a3e85debd7089be574846315
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/OfferAccess.hbm.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+	<class name="org.olat.resource.accesscontrol.model.OfferAccessImpl" table="o_ac_offer_access">
+		<id name="key" column="offer_method_id" type="long" unsaved-value="null">
+			<generator class="hilo"/>
+		</id>
+		
+		<version name="version" access="field" column="version" type="int"/>
+	  <property  name="creationDate" column="creationdate" type="timestamp" />
+	  <property  name="valid" column="is_valid" type="boolean" />
+	  
+	  <property  name="validFrom" column="validfrom" type="timestamp" />
+	  <property  name="validTo" column="validto" type="timestamp" />
+
+		<many-to-one name="offer"
+                     column="fk_offer_id"
+                     class="org.olat.resource.accesscontrol.model.OfferImpl" 
+                     outer-join="true"   
+                     unique="false" 
+                     cascade="none"/>
+                     
+		<many-to-one name="method"
+                     column="fk_method_id"
+                     class="org.olat.resource.accesscontrol.model.AbstractAccessMethod" 
+                     outer-join="true"   
+                     unique="false" 
+                     cascade="none"/>               
+
+	</class>
+</hibernate-mapping>
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/OfferAccess.java b/src/main/java/org/olat/resource/accesscontrol/model/OfferAccess.java
new file mode 100644
index 0000000000000000000000000000000000000000..166a766051be200e60d132ed9f8ca28a74019d32
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/OfferAccess.java
@@ -0,0 +1,52 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.model;
+
+import java.util.Date;
+
+
+/**
+ * 
+ * Description:<br>
+ * Link beetwen an offer and a method to access the resource
+ * 
+ * <P>
+ * Initial Date:  18 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public interface OfferAccess {
+	
+	public Long getKey();
+	
+	public boolean isValid();
+	
+	public Offer getOffer();
+	
+	public AccessMethod getMethod();
+	
+	public Date getValidFrom();
+
+	public void setValidFrom(Date validFrom);
+
+	public Date getValidTo();
+
+	public void setValidTo(Date validTo);
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/OfferAccessImpl.java b/src/main/java/org/olat/resource/accesscontrol/model/OfferAccessImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..39de7c55d102fb6da583af213f2d5e562ea48a68
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/OfferAccessImpl.java
@@ -0,0 +1,124 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.model;
+
+import java.util.Date;
+
+import org.olat.core.commons.persistence.PersistentObject;
+
+/**
+ * 
+ * Description:<br>
+ * 
+ * 
+ * <P>
+ * Initial Date:  14 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class OfferAccessImpl extends PersistentObject implements OfferAccess {
+	
+	private Offer offer;
+	private AccessMethod method;
+	private boolean valid;
+	private Date validFrom;
+	private Date validTo;
+
+	public OfferAccessImpl() {
+		//
+	}
+
+	@Override
+	public boolean isValid() {
+		return valid;
+	}
+
+	public void setValid(boolean valid) {
+		this.valid = valid;
+	}
+
+	@Override
+	public Offer getOffer() {
+		return offer;
+	}
+
+	public void setOffer(Offer offer) {
+		this.offer = offer;
+	}
+
+	@Override
+	public AccessMethod getMethod() {
+		return method;
+	}
+
+	public void setMethod(AccessMethod method) {
+		this.method = method;
+	}
+	
+	@Override
+	public Date getValidFrom() {
+		return validFrom;
+	}
+	
+	@Override
+	public void setValidFrom(Date validFrom) {
+		this.validFrom = validFrom;
+	}
+	
+	@Override
+	public Date getValidTo() {
+		return validTo;
+	}
+	
+	@Override
+	public void setValidTo(Date validTo) {
+		this.validTo = validTo;
+	}
+	
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder();
+		sb.append("OfferAccess[key=").append(getKey()).append("]")
+			.append("[method=").append(method == null ? "null" : method.getClass().getSimpleName()).append("]");
+		if(offer == null) {
+			sb.append("[resource=null]");
+		} else {
+			sb.append("[resource=").append(offer.getResourceId()).append(":").append(offer.getResourceTypeName()).append(":").append(offer.getResourceDisplayName()).append("]");
+		}
+		return sb.toString();
+	}
+
+	@Override
+	public int hashCode() {
+		return getKey() == null ? 9191 : getKey().hashCode();
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+		if(this == obj) {
+			return true;
+		}
+		if(obj instanceof OfferAccessImpl) {
+			OfferAccessImpl o = (OfferAccessImpl)obj;
+			return equalsByPersistableKey(o);
+		}
+		return false;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/OfferImpl.java b/src/main/java/org/olat/resource/accesscontrol/model/OfferImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..d9b7941163d9fac28c629fc32cda6a004359c1cf
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/OfferImpl.java
@@ -0,0 +1,183 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.model;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+import org.olat.core.commons.persistence.PersistentObject;
+import org.olat.core.id.ModifiedInfo;
+import org.olat.resource.OLATResource;
+
+/**
+ * 
+ * Description:<br>
+ * 
+ * 
+ * <P>
+ * Initial Date:  14 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class OfferImpl extends PersistentObject implements Offer, ModifiedInfo {
+	
+	private boolean valid = true;
+	
+	private Date lastModified;
+	private Date validFrom;
+	private Date validTo;
+	
+	private String token;
+	
+	private Long resourceId;
+	private String resourceTypeName;
+	private String resourceDisplayName;
+	
+	private Price price;
+	private OLATResource resource;
+	
+	private String description;
+
+	public OfferImpl() {
+		//
+	}
+
+	public boolean isValid() {
+		return valid;
+	}
+
+	public void setValid(boolean valid) {
+		this.valid = valid;
+	}
+
+	@Override
+	public Date getLastModified() {
+		return lastModified;
+	}
+
+	@Override
+	public void setLastModified(Date lastModified) {
+		this.lastModified = lastModified;
+	}
+
+	@Override
+	public Date getValidFrom() {
+		return validFrom;
+	}
+
+	@Override
+	public void setValidFrom(Date validFrom) {
+		this.validFrom = validFrom;
+	}
+
+	@Override
+	public Date getValidTo() {
+		return validTo;
+	}
+
+	@Override
+	public void setValidTo(Date validTo) {
+		this.validTo = validTo;
+	}
+
+	public Long getResourceId() {
+		return resourceId;
+	}
+
+	public void setResourceId(Long resourceId) {
+		this.resourceId = resourceId;
+	}
+
+	public String getResourceTypeName() {
+		return resourceTypeName;
+	}
+
+	public void setResourceTypeName(String resourceTypeName) {
+		this.resourceTypeName = resourceTypeName;
+	}
+
+	public String getResourceDisplayName() {
+		return resourceDisplayName;
+	}
+
+	public void setResourceDisplayName(String resourceDisplayName) {
+		this.resourceDisplayName = resourceDisplayName;
+	}
+	
+	@Override
+	public String getDescription() {
+		return description;
+	}
+
+	@Override
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+	public String getToken() {
+		return token;
+	}
+
+	public void setToken(String token) {
+		this.token = token;
+	}
+	
+	@Override
+	public OLATResource getResource() {
+		return resource;
+	}
+	
+	public void setResource(OLATResource resource) {
+		this.resource = resource;
+	}
+
+	@Override
+	public Price getPrice() {
+		if(price == null) {
+			PriceImpl p = new PriceImpl();
+			p.setAmount(BigDecimal.ZERO);
+			p.setCurrencyCode("CHF");
+			price = p;
+		}
+		return price;
+	}
+
+	@Override
+	public void setPrice(Price price) {
+		this.price = price;
+	}
+
+	@Override
+	public int hashCode() {
+		return getKey() == null ? 93791 : getKey().hashCode();
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+		if(this == obj) {
+			return true;
+		}
+		if(obj instanceof OfferImpl) {
+			OfferImpl offer = (OfferImpl)obj;
+			return equalsByPersistableKey(offer);
+		}
+		return false;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/Order.hbm.xml b/src/main/java/org/olat/resource/accesscontrol/model/Order.hbm.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7bae9efdf43720f5e9d54eecfb6ebd2c7bde2aeb
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/Order.hbm.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+<hibernate-mapping default-lazy="false">
+	
+	<class name="org.olat.resource.accesscontrol.model.OrderImpl" table="o_ac_order">
+		<id name="key" column="order_id" type="long" unsaved-value="null">
+			<generator class="hilo"/>
+		</id>
+		
+		<version name="version" access="field" column="version" type="int"/>
+		<property name="lastModified" column="lastmodified" type="timestamp" />
+	  <property name="creationDate" column="creationdate" type="timestamp" />
+	  <property name="valid" column="is_valid" type="boolean" />
+	  <property name="orderStatusStr" column="order_status" type="string" length="32" />
+	  
+	  <component name="total" class="org.olat.resource.accesscontrol.model.PriceImpl">
+   		<property name="currencyCode" column="total_currency_code" type="string"/> 
+   		<property name="amount" column="total_amount" type="big_decimal"/>
+   	</component>
+   	
+	  <component name="totalOrderLines" class="org.olat.resource.accesscontrol.model.PriceImpl">
+   		<property name="currencyCode" column="total_lines_currency_code" type="string"/> 
+   		<property name="amount" column="total_lines_amount" type="big_decimal"/>
+   	</component>
+   	
+	  <component name="discount" class="org.olat.resource.accesscontrol.model.PriceImpl">
+   		<property name="currencyCode" column="discount_currency_code" type="string"/> 
+   		<property name="amount" column="discount_amount" type="big_decimal"/>
+   	</component>
+
+		<list name="parts">
+			<key column="fk_order_id"/>
+	   	<list-index column="pos"/>
+	    <one-to-many class="org.olat.resource.accesscontrol.model.OrderPartImpl"/>
+		</list>
+		
+	  <many-to-one name="delivery"
+                 column="fk_delivery_id"
+                 class="org.olat.basesecurity.IdentityImpl" 
+                 outer-join="true"   
+                 unique="false" 
+                 cascade="none"/>
+
+	</class>
+	
+	<class name="org.olat.resource.accesscontrol.model.OrderPartImpl" table="o_ac_order_part">
+		<id name="key" column="order_part_id" type="long" unsaved-value="null">
+			<generator class="hilo"/>
+		</id>
+		
+		<version name="version" access="field" column="version" type="int"/>
+	  <property name="creationDate" column="creationdate" type="timestamp" />
+	  
+	  <component name="total" class="org.olat.resource.accesscontrol.model.PriceImpl">
+   		<property name="currencyCode" column="total_currency_code" type="string"/> 
+   		<property name="amount" column="total_amount" type="big_decimal"/>
+   	</component>
+   	
+	  <component name="totalOrderLines" class="org.olat.resource.accesscontrol.model.PriceImpl">
+   		<property name="currencyCode" column="total_lines_currency_code" type="string"/> 
+   		<property name="amount" column="total_lines_amount" type="big_decimal"/>
+   	</component>
+	  
+	  <list name="orderLines">
+			<key column="fk_order_part_id"/>
+	   	<list-index column="pos"/>
+	    <one-to-many class="org.olat.resource.accesscontrol.model.OrderLineImpl"/>
+		</list>
+	</class>
+	
+	<class name="org.olat.resource.accesscontrol.model.OrderLineImpl" table="o_ac_order_line">
+		<id name="key" column="order_item_id" type="long" unsaved-value="null">
+			<generator class="hilo"/>
+		</id>
+		
+		<version name="version" access="field" column="version" type="int"/>
+	  <property name="creationDate" column="creationdate" type="timestamp" />
+	  
+	  <component name="total" class="org.olat.resource.accesscontrol.model.PriceImpl">
+   		<property name="currencyCode" column="total_currency_code" type="string"/> 
+   		<property name="amount" column="total_amount" type="big_decimal"/>
+   	</component>
+   	
+	  <component name="unitPrice" class="org.olat.resource.accesscontrol.model.PriceImpl">
+   		<property name="currencyCode" column="unit_price_currency_code" type="string"/> 
+   		<property name="amount" column="unit_price_amount" type="big_decimal"/>
+   	</component>
+	  
+	  <many-to-one name="offer"
+                 column="fk_offer_id"
+                 class="org.olat.resource.accesscontrol.model.OfferImpl" 
+                 outer-join="true"   
+                 unique="false" 
+                 cascade="none"/>
+	</class>
+	
+</hibernate-mapping>
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/Order.java b/src/main/java/org/olat/resource/accesscontrol/model/Order.java
new file mode 100644
index 0000000000000000000000000000000000000000..51a70d2e214758193d93928475aa24776ea82720
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/Order.java
@@ -0,0 +1,62 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.model;
+
+import java.util.Date;
+import java.util.List;
+
+import org.olat.core.id.Identity;
+
+/**
+ * 
+ * Description:<br>
+ * TODO: srosse Class Description for Order
+ * 
+ * <P>
+ * Initial Date:  19 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public interface Order {
+	
+	public Long getKey();
+	
+	public String getOrderNr();
+	
+	public boolean isValid();
+	
+	public Date getCreationDate();
+	
+	public OrderStatus getOrderStatus();
+	
+	public Identity getDelivery();
+	
+	public String getCurrencyCode();
+	
+	public Price getTotal();
+
+	public Price getTotalOrderLines();
+
+	public Price getDiscount();
+	
+	public List<OrderPart> getParts();
+	
+	public void recalculate();
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/OrderImpl.java b/src/main/java/org/olat/resource/accesscontrol/model/OrderImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..d693dbe2d51e332704ffd9c2c1263bb13eae020b
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/OrderImpl.java
@@ -0,0 +1,193 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.model;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.olat.core.commons.persistence.PersistentObject;
+import org.olat.core.id.Identity;
+import org.olat.core.id.ModifiedInfo;
+import org.olat.core.util.StringHelper;
+
+/**
+ * 
+ * Description:<br>
+ * The order contains a list of order part. Every Order part links
+ * a set of order lines to a payment.
+ * 
+ * <P>
+ * Initial Date:  19 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class OrderImpl extends PersistentObject implements Order, ModifiedInfo {
+
+	private boolean valid;
+	private Date lastModified;
+	private Identity delivery;
+	private String orderStatus;
+	
+	private Price total;
+	private Price totalOrderLines;
+	private Price discount;
+	
+	private String currencyCode;
+	
+	private List<OrderPart> parts;
+	
+	@Override
+	public String getOrderNr() {
+		return getKey() == null ? "" : getKey().toString();
+	}
+
+	@Override
+	public boolean isValid() {
+		return valid;
+	}
+
+	public void setValid(boolean valid) {
+		this.valid = valid;
+	}
+	
+	@Override
+	public Identity getDelivery() {
+		return delivery;
+	}
+
+	public void setDelivery(Identity delivery) {
+		this.delivery = delivery;
+	}
+
+	@Override
+	public OrderStatus getOrderStatus() {
+		if(StringHelper.containsNonWhitespace(orderStatus)) {
+			return OrderStatus.valueOf(orderStatus);
+		}
+		return null;
+	}
+	
+	public void setOrderStatus(OrderStatus status) {
+		if(status == null) {
+			orderStatus = null;
+		} else {
+			orderStatus = status.name();
+		}
+	}
+
+	public String getOrderStatusStr() {
+		return orderStatus;
+	}
+
+	public void setOrderStatusStr(String orderStatus) {
+		this.orderStatus = orderStatus;
+	}
+
+	@Override
+	public Date getLastModified() {
+		return lastModified;
+	}
+
+	@Override
+	public void setLastModified(Date lastModified) {
+		this.lastModified = lastModified;
+	}
+	
+	@Override
+	public String getCurrencyCode() {
+		return currencyCode;
+	}
+	
+	public void setCurrencyCode(String currencyCode) {
+		this.currencyCode = currencyCode;
+	}
+
+	@Override
+	public Price getTotal() {
+		return total;
+	}
+
+	public void setTotal(Price total) {
+		this.total = total;
+	}
+
+	@Override
+	public Price getTotalOrderLines() {
+		return totalOrderLines;
+	}
+
+	public void setTotalOrderLines(Price totalOrderLines) {
+		this.totalOrderLines = totalOrderLines;
+	}
+
+	@Override
+	public Price getDiscount() {
+		return discount;
+	}
+
+	public void setDiscount(Price discount) {
+		this.discount = discount;
+	}
+
+	@Override
+	public List<OrderPart> getParts() {
+		if(parts == null) {
+			parts = new ArrayList<OrderPart>();
+		}
+		return parts;
+	}
+
+	public void setParts(List<OrderPart> parts) {
+		this.parts = parts;
+	}
+	
+	public void recalculate() {
+		totalOrderLines = new PriceImpl(BigDecimal.ZERO, getCurrencyCode());
+		for(OrderPart part : getParts()) {
+			((OrderPartImpl)part).recalculate(getCurrencyCode());
+			totalOrderLines = totalOrderLines.add(part.getTotalOrderLines());
+		}
+
+		total = totalOrderLines.clone();
+		
+		if(discount == null) {
+			discount = new PriceImpl(BigDecimal.ZERO, getCurrencyCode());
+		}
+	}
+
+	@Override
+	public int hashCode() {
+		return getKey() == null ? 27591 : getKey().hashCode();
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if(this == obj) {
+			return true;
+		}
+		if(obj instanceof OrderImpl) {
+			OrderImpl order = (OrderImpl)obj;
+			return equalsByPersistableKey(order);
+		}
+		return false;
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/OrderLine.java b/src/main/java/org/olat/resource/accesscontrol/model/OrderLine.java
new file mode 100644
index 0000000000000000000000000000000000000000..45d846b5d64216572b421ad696838a245ac816ed
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/OrderLine.java
@@ -0,0 +1,41 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.model;
+
+/**
+ * 
+ * Description:<br>
+ * The order line for a specific offer.
+ * 
+ * <P>
+ * Initial Date:  19 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public interface OrderLine {
+
+	public Long getKey();
+	
+	public Offer getOffer();
+	
+	public Price getUnitPrice();
+	
+	public Price getTotal();
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/OrderLineImpl.java b/src/main/java/org/olat/resource/accesscontrol/model/OrderLineImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..afc15f49496b629918f13fb9dd7de00f4b76953a
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/OrderLineImpl.java
@@ -0,0 +1,82 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.model;
+
+import org.olat.core.commons.persistence.PersistentObject;
+
+/**
+ * 
+ * Description:<br>
+ * An implementation of the OrderLine interface
+ * 
+ * <P>
+ * Initial Date:  19 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class OrderLineImpl extends PersistentObject implements OrderLine {
+
+	private Offer offer;
+	private Price unitPrice;
+	private Price totalPrice;
+	
+	public Offer getOffer() {
+		return offer;
+	}
+
+	public void setOffer(Offer offer) {
+		this.offer = offer;
+	}
+
+	@Override
+	public Price getUnitPrice() {
+		return unitPrice;
+	}
+
+	public void setUnitPrice(Price unitPrice) {
+		this.unitPrice = unitPrice;
+	}
+
+	@Override
+	public Price getTotal() {
+		return totalPrice;
+	}
+
+	public void setTotal(Price totalPrice) {
+		this.totalPrice = totalPrice;
+	}
+
+	@Override
+	public int hashCode() {
+		return getKey() == null ? 27591 : getKey().hashCode();
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if(this == obj) {
+			return true;
+		}
+		if(obj instanceof OrderLineImpl) {
+			OrderLineImpl order = (OrderLineImpl)obj;
+			return equalsByPersistableKey(order);
+		}
+		return false;
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/OrderPart.java b/src/main/java/org/olat/resource/accesscontrol/model/OrderPart.java
new file mode 100644
index 0000000000000000000000000000000000000000..d099cd43104b55b5991d6281db9f3938ed7087cf
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/OrderPart.java
@@ -0,0 +1,44 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.model;
+
+import java.util.List;
+
+/**
+ * 
+ * Description:<br>
+ * TODO: srosse Class Description for OrderPart
+ * 
+ * <P>
+ * Initial Date:  19 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public interface OrderPart {
+	
+	public Long getKey();
+	
+	public List<OrderLine> getOrderLines();
+	
+	public Price getTotal();
+
+	public Price getTotalOrderLines();
+
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/OrderPartImpl.java b/src/main/java/org/olat/resource/accesscontrol/model/OrderPartImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..22191de52113421416e969db987513c7bbc2db99
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/OrderPartImpl.java
@@ -0,0 +1,99 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.model;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.olat.core.commons.persistence.PersistentObject;
+
+/**
+ * 
+ * Description:<br>
+ * Implementation of the interface OrderPart
+ * 
+ * <P>
+ * Initial Date:  19 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class OrderPartImpl extends PersistentObject implements OrderPart {
+
+	private Price total;
+	private Price totalOrderLines;
+	
+	private List<OrderLine> lines;
+	
+	@Override
+	public Price getTotal() {
+		return total;
+	}
+
+	public void setTotal(Price total) {
+		this.total = total;
+	}
+
+	@Override
+	public Price getTotalOrderLines() {
+		return totalOrderLines;
+	}
+
+	public void setTotalOrderLines(Price totalOrderLines) {
+		this.totalOrderLines = totalOrderLines;
+	}
+
+	public List<OrderLine> getOrderLines() {
+		if(lines == null) {
+			lines = new ArrayList<OrderLine>();
+		}
+		return lines;
+	}
+
+	public void setOrderLines(List<OrderLine> lines) {
+		this.lines = lines;
+	}
+	
+	public void recalculate(String currencyCode) {
+		totalOrderLines = new PriceImpl(BigDecimal.ZERO, currencyCode);
+		for(OrderLine orderLine : getOrderLines()) {
+			totalOrderLines = totalOrderLines.add(orderLine.getTotal());
+		}
+		
+		total = totalOrderLines.clone();
+	}
+
+	@Override
+	public int hashCode() {
+		return getKey() == null ? 27591 : getKey().hashCode();
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if(this == obj) {
+			return true;
+		}
+		if(obj instanceof OrderPartImpl) {
+			OrderPartImpl order = (OrderPartImpl)obj;
+			return equalsByPersistableKey(order);
+		}
+		return false;
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/OrderStatus.java b/src/main/java/org/olat/resource/accesscontrol/model/OrderStatus.java
new file mode 100644
index 0000000000000000000000000000000000000000..94ea5f7f9e96d0b76f53399082d3056704a78954
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/OrderStatus.java
@@ -0,0 +1,31 @@
+/**
+ * OLAT - Online Learning and Training<br>
+ * http://www.olat.org
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Copyright (c) frentix GmbH<br>
+ * http://www.frentix.com<br>
+ * <p>
+ */
+package org.olat.resource.accesscontrol.model;
+
+public enum OrderStatus {
+	
+	NEW,
+	PREPAYMENT,
+	PAYED,
+	CANCELED,
+	ERROR,
+
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/PSPTransaction.java b/src/main/java/org/olat/resource/accesscontrol/model/PSPTransaction.java
new file mode 100644
index 0000000000000000000000000000000000000000..9a16dd4fc1998c6fde078fa6d5ae7c09931682ff
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/PSPTransaction.java
@@ -0,0 +1,19 @@
+package org.olat.resource.accesscontrol.model;
+
+/**
+ * 
+ * Description:<br>
+ * TODO: srosse Class Description for PSPTransaction
+ * 
+ * <P>
+ * Initial Date:  15 juin 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com
+ */
+public interface PSPTransaction {
+	
+	public Long getOrderId();
+	
+	public Long getOrderPartId();
+	
+	public PSPTransactionStatus getSimplifiedStatus();
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/PSPTransactionStatus.java b/src/main/java/org/olat/resource/accesscontrol/model/PSPTransactionStatus.java
new file mode 100644
index 0000000000000000000000000000000000000000..4ae01dbb4ada5d87ce701d1dd61e82c455535559
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/PSPTransactionStatus.java
@@ -0,0 +1,16 @@
+package org.olat.resource.accesscontrol.model;
+
+/**
+ * 
+ * Description:<br>
+ * TODO: srosse Class Description for PSPTransactionStatus
+ * 
+ * <P>
+ * Initial Date:  15 juin 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public enum PSPTransactionStatus {
+	OK,
+	WARNING,
+	ERROR
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/Price.java b/src/main/java/org/olat/resource/accesscontrol/model/Price.java
new file mode 100644
index 0000000000000000000000000000000000000000..6d977364ec382d3e6d19afb63b3ef08c06781df4
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/Price.java
@@ -0,0 +1,58 @@
+/**
+ * OLAT - Online Learning and Training<br>
+ * http://www.olat.org
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Copyright (c) frentix GmbH<br>
+ * http://www.frentix.com<br>
+ * <p>
+ */
+package org.olat.resource.accesscontrol.model;
+
+import java.math.BigDecimal;
+
+/**
+ * 
+ * Description:<br>
+ * Price interface
+ * 
+ * <P>
+ * Initial Date:  26 mai 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public interface Price extends Cloneable {
+	
+	public BigDecimal getAmount();
+	
+	public void setAmount(BigDecimal amount);
+	
+	public String getCurrencyCode();
+	
+	public void setCurrencyCode(String currencyCode);
+	
+	public Price add(Price price);
+	
+	public Price substract(Price price);
+	
+	public Price multiply(int multiplicand);
+	
+	public Price multiply(BigDecimal multiplicand);
+	
+	public Price divide(BigDecimal divisor);
+	
+	public boolean isEmpty();
+	
+	public Price clone();
+
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/PriceImpl.java b/src/main/java/org/olat/resource/accesscontrol/model/PriceImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..b2fd2138902f52315ccc8d019a2d81ec8a5d55a3
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/PriceImpl.java
@@ -0,0 +1,131 @@
+/**
+ * OLAT - Online Learning and Training<br>
+ * http://www.olat.org
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Copyright (c) frentix GmbH<br>
+ * http://www.frentix.com<br>
+ * <p>
+ */
+package org.olat.resource.accesscontrol.model;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
+
+/**
+ * 
+ * Description:<br>
+ * 
+ * 
+ * <P>
+ * Initial Date:  23 mai 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class PriceImpl implements Price {
+	
+	private static final OLog log = Tracing.createLoggerFor(PriceImpl.class);
+	
+	private BigDecimal amount;
+	private String currencyCode;
+	
+	public PriceImpl() {
+		//
+	}
+	
+	public PriceImpl(BigDecimal amount, String currencyCode) {
+		this.amount = amount;
+		this.currencyCode = currencyCode;
+	}
+	
+	
+	@Override
+	public BigDecimal getAmount() {
+		return amount;
+	}
+	
+	public void setAmount(BigDecimal amount) {
+		this.amount = amount;
+	}
+	
+	@Override
+	public String getCurrencyCode() {
+		return currencyCode;
+	}
+	
+	public void setCurrencyCode(String currencyCode) {
+		this.currencyCode = currencyCode;
+	}
+
+	@Override
+	public boolean isEmpty() {
+		if(amount == null) {
+			return true;
+		} else if(BigDecimal.ZERO.compareTo(amount) >= 0) {
+			return true;
+		}
+		return false;
+	}
+	
+	public Price add(Price price) {
+		//replace with the multi currency manager
+		if(currencyCode != null && price.getCurrencyCode() != null && !currencyCode.equals(price.getCurrencyCode())) {
+			log.warn("Problem: two differents iso currency codes");
+		}
+		return new PriceImpl(amount.add(price.getAmount()), currencyCode);
+	}
+	
+	public Price substract(Price price) {
+		//replace with the multi currency manager
+		if(currencyCode != null && price.getCurrencyCode() != null && !currencyCode.equals(price.getCurrencyCode())) {
+			log.warn("Problem: two differents iso currency codes");
+		}
+		return new PriceImpl(amount.subtract(price.getAmount()), currencyCode);
+	}
+	
+	public Price multiply(int multiplicand) {
+		if(amount == null) {
+			return new PriceImpl(BigDecimal.ZERO, currencyCode);
+		}
+		
+		BigDecimal bigMultiplicand = new BigDecimal(multiplicand);
+		return new PriceImpl(amount.multiply(bigMultiplicand), currencyCode);
+	}
+	
+	public Price multiply(BigDecimal multiplicand) {
+		BigDecimal v = amount.multiply(multiplicand);
+		v = v.setScale(2, RoundingMode.HALF_UP);
+		return new PriceImpl(v, currencyCode);
+	}
+	
+	public Price divide(BigDecimal divisor) {
+		BigDecimal v = amount.divide(divisor, 2, RoundingMode.HALF_UP);
+		return new PriceImpl(v, currencyCode);
+	}
+	
+	@Override
+	public Price clone() {
+		PriceImpl clone = new PriceImpl();
+		clone.setAmount(amount);
+		clone.setCurrencyCode(currencyCode);
+		return clone;
+	}
+
+	@Override
+	public String toString() {
+		return currencyCode + '\u00A0' + (amount == null ? "" : amount.setScale(2, BigDecimal.ROUND_HALF_EVEN).toString());
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/PriceMethodBundle.java b/src/main/java/org/olat/resource/accesscontrol/model/PriceMethodBundle.java
new file mode 100644
index 0000000000000000000000000000000000000000..a33a3c39bf9f9727b8e9f3d4a40f25c7c07e68f7
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/PriceMethodBundle.java
@@ -0,0 +1,50 @@
+/**
+ * OLAT - Online Learning and Training<br>
+ * http://www.olat.org
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Copyright (c) frentix GmbH<br>
+ * http://www.frentix.com<br>
+ * <p>
+ */
+package org.olat.resource.accesscontrol.model;
+
+/**
+ * 
+ * Description:<br>
+ * Helper class to bundle a method to access content and its price
+ * 
+ * <P>
+ * Initial Date:  30 mai 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class PriceMethodBundle {
+	
+	private final Price price;
+	private final AccessMethod method;
+	
+	public PriceMethodBundle(Price price, AccessMethod method) {
+		this.price = price;
+		this.method = method;
+	}
+
+	public Price getPrice() {
+		return price;
+	}
+
+	public AccessMethod getMethod() {
+		return method;
+	}
+
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/model/TokenAccessMethod.java b/src/main/java/org/olat/resource/accesscontrol/model/TokenAccessMethod.java
new file mode 100644
index 0000000000000000000000000000000000000000..d58615dff08ea18ba9839ea698befd309bcd882f
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/model/TokenAccessMethod.java
@@ -0,0 +1,68 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.model;
+
+import org.olat.resource.accesscontrol.method.TokenAccessHandler;
+
+
+/**
+ * 
+ * Description:<br>
+ * This a "static" payment method. There is only one instance.
+ * 
+ * <P>
+ * Initial Date:  18 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class TokenAccessMethod extends AbstractAccessMethod {
+	
+	@Override
+	public String getType() {
+		return TokenAccessHandler.METHOD_TYPE;
+	}	
+	
+	@Override
+	public String getMethodCssClass() {
+		return TokenAccessHandler.METHOD_CSS_CLASS;
+	}
+	
+	@Override
+	public boolean isNeedUserInteraction() {
+		return true;
+	}
+
+	@Override
+	public int hashCode() {
+		return getKey() == null ? 34688 : getKey().hashCode();
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+		if(this == obj) {
+			return true;
+		}
+		if(obj instanceof TokenAccessMethod) {
+			TokenAccessMethod method = (TokenAccessMethod)obj;
+			return getKey() != null && getKey().equals(method.getKey());
+		}
+		return false;
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/AbstractConfigurationMethodController.java b/src/main/java/org/olat/resource/accesscontrol/ui/AbstractConfigurationMethodController.java
new file mode 100644
index 0000000000000000000000000000000000000000..20daf67b9f775e036fafb959adf6101f44f61104
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/AbstractConfigurationMethodController.java
@@ -0,0 +1,114 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.ui;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.impl.Form;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.translator.Translator;
+import org.olat.resource.accesscontrol.model.AccessMethod;
+import org.olat.resource.accesscontrol.model.OfferAccess;
+
+/**
+ * 
+ * Description:<br>
+ * TODO: srosse Class Description for AbstractConfigurationMethodController
+ * 
+ * <P>
+ * Initial Date:  18 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public abstract class AbstractConfigurationMethodController extends FormBasicController {
+	
+	private String name;
+	private boolean embbed = false;
+	
+	public AbstractConfigurationMethodController(UserRequest ureq, WindowControl wControl) {
+		super(ureq, wControl);
+	}
+
+	public AbstractConfigurationMethodController(UserRequest ureq, WindowControl wControl, String pageName) {
+		super(ureq, wControl, pageName);
+	}
+
+	public AbstractConfigurationMethodController(UserRequest ureq, WindowControl wControl, String pageName, Translator fallbackTranslator) {
+		super(ureq, wControl, pageName, fallbackTranslator);
+	}
+
+	protected AbstractConfigurationMethodController(UserRequest ureq, WindowControl wControl, int layout){
+		super(ureq, wControl, layout);
+	}
+
+	protected AbstractConfigurationMethodController(UserRequest ureq, WindowControl wControl, int layout, String customLayoutPageName, Form externalMainForm) {
+		super(ureq, wControl, layout, customLayoutPageName, externalMainForm);
+		embbed = (externalMainForm != null);
+	}
+	
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		if(!embbed) {
+			
+			final FormLayoutContainer buttonGroupLayout = FormLayoutContainer.createButtonLayout("buttonLayout", getTranslator());
+			buttonGroupLayout.setRootForm(mainForm);
+			formLayout.add(buttonGroupLayout);
+			
+			uifactory.addFormSubmitButton("create", buttonGroupLayout);
+			uifactory.addFormCancelButton("cancel", buttonGroupLayout, ureq, getWindowControl());
+		}
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+	
+	public abstract OfferAccess commitChanges();
+	
+	public abstract AccessMethod getMethod();
+
+	public FormItem getInitialFormItem() {
+		return flc;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+	
+	@Override
+	protected void formOK(UserRequest ureq) {
+		fireEvent(ureq, Event.DONE_EVENT);
+	}
+
+	@Override
+	protected void formCancelled(UserRequest ureq) {
+		fireEvent(ureq, Event.CANCELLED_EVENT);
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/AccessConfigurationController.java b/src/main/java/org/olat/resource/accesscontrol/ui/AccessConfigurationController.java
new file mode 100644
index 0000000000000000000000000000000000000000..7be01d48115b011531402c8278bd8731617fab66
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/AccessConfigurationController.java
@@ -0,0 +1,357 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.ui;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.DateChooser;
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
+import org.olat.core.gui.components.form.flexible.impl.Form;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.components.link.Link;
+import org.olat.core.gui.components.link.LinkFactory;
+import org.olat.core.gui.components.velocity.VelocityContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.generic.closablewrapper.CloseableCalloutWindowController;
+import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
+import org.olat.core.util.StringHelper;
+import org.olat.resource.OLATResource;
+import org.olat.resource.accesscontrol.ACUIFactory;
+import org.olat.resource.accesscontrol.AccessControlModule;
+import org.olat.resource.accesscontrol.manager.ACFrontendManager;
+import org.olat.resource.accesscontrol.method.AccessMethodHandler;
+import org.olat.resource.accesscontrol.model.AccessMethod;
+import org.olat.resource.accesscontrol.model.Offer;
+import org.olat.resource.accesscontrol.model.OfferAccess;
+import org.olat.resource.accesscontrol.model.OfferImpl;
+
+/**
+ * 
+ * Description:<br>
+ * 
+ * 
+ * <P>
+ * Initial Date:  14 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class AccessConfigurationController extends FormBasicController {
+
+	private List<Link> addMethods = new ArrayList<Link>();
+	private final String displayName;
+	private final OLATResource resource;
+	private final AccessControlModule acModule;
+	private final ACFrontendManager acFrontendManager;
+	
+	private FormLink createLink;
+	private FormLayoutContainer confControllerContainer;
+	private CloseableCalloutWindowController createCalloutCtrl;
+	private CloseableModalController cmc;
+	private AbstractConfigurationMethodController newMethodCtrl;
+	
+	private final List<AccessInfo> confControllers = new ArrayList<AccessInfo>();
+	
+	private final boolean embbed;
+	private final boolean emptyConfigGrantsFullAccess;
+	
+	public AccessConfigurationController(UserRequest ureq, WindowControl wControl, OLATResource resource, String displayName) {
+		super(ureq, wControl, "access_configuration");
+		
+		this.resource = resource;
+		this.displayName = displayName;
+		acModule = (AccessControlModule)CoreSpringFactory.getBean("acModule");
+		acFrontendManager = (ACFrontendManager)CoreSpringFactory.getBean("acFrontendManager");
+		embbed = false;
+		emptyConfigGrantsFullAccess = true; 
+		
+		initForm(ureq);
+	}
+		
+	public AccessConfigurationController(UserRequest ureq, WindowControl wControl, OLATResource resource, String displayName, Form form) {
+		super(ureq, wControl, FormBasicController.LAYOUT_CUSTOM, "access_configuration", form);
+		
+		this.resource = resource;
+		this.displayName = displayName;
+		acModule = (AccessControlModule)CoreSpringFactory.getBean("acModule");
+		acFrontendManager = (ACFrontendManager)CoreSpringFactory.getBean("acFrontendManager");
+		embbed = true;
+		emptyConfigGrantsFullAccess = false;
+		
+		initForm(ureq);
+	}
+	
+	public FormItem getInitialFormItem() {
+		return flc;
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		createLink = uifactory.addFormLink("add.accesscontrol", formLayout, Link.BUTTON);
+		
+		String confPage = velocity_root + "/configuration_list.html";
+		confControllerContainer = FormLayoutContainer.createCustomFormLayout("conf-controllers", getTranslator(), confPage);
+		confControllerContainer.setRootForm(mainForm);
+		formLayout.add(confControllerContainer);
+		
+		loadConfigurations();
+		
+		confControllerContainer.contextPut("confControllers", confControllers);
+		
+		if(!embbed) {
+			setFormTitle("accesscontrol.title");
+			setFormDescription("accesscontrol.desc");
+			setFormContextHelp(AccessConfigurationController.class.getPackage().getName(), "accesscontrol.html", "chelp.accesscontrol.hover");
+			
+			final FormLayoutContainer buttonGroupLayout = FormLayoutContainer.createButtonLayout("buttonLayout", getTranslator());
+			buttonGroupLayout.setRootForm(mainForm);
+			formLayout.add(buttonGroupLayout);
+			formLayout.add("buttonLayout", buttonGroupLayout);
+			
+			uifactory.addFormSubmitButton("save", buttonGroupLayout);
+		}
+		
+		confControllerContainer.contextPut("emptyConfigGrantsFullAccess", Boolean.valueOf(emptyConfigGrantsFullAccess));		
+	}
+	
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	public void event(UserRequest ureq, Component source, Event event) {
+		if(addMethods.contains(source)) {
+			AccessMethod method = (AccessMethod)((Link)source).getUserObject();
+			addMethod(ureq, method);
+		} else {
+			super.event(ureq, source, event);
+		}
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Controller source, Event event) {
+		if(newMethodCtrl == source) {
+			if(event.equals(Event.DONE_EVENT)) {
+				OfferAccess newLink = newMethodCtrl.commitChanges();
+				newLink = acFrontendManager.saveOfferAccess(newLink);
+				addConfiguration(newLink);
+			}
+			cmc.deactivate();
+			removeAsListenerAndDispose(newMethodCtrl);
+			removeAsListenerAndDispose(cmc);
+			newMethodCtrl = null;
+			cmc = null;
+		} else if (cmc == source) {
+			removeAsListenerAndDispose(newMethodCtrl);
+			removeAsListenerAndDispose(cmc);
+			newMethodCtrl = null;
+			cmc = null;
+		} else {
+			super.event(ureq, source, event);
+		}
+	}
+
+	@Override
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if(addMethods.contains(source)) {
+			AccessMethod method = (AccessMethod)source.getUserObject();
+			addMethod(ureq, method);
+		} else if (source == createLink) {
+			popupCallout(ureq);
+		} else if (source.getName().startsWith("del_")) {
+			AccessInfo infos = (AccessInfo)source.getUserObject();
+			acFrontendManager.deleteOffer(infos.getLink().getOffer());
+			confControllers.remove(infos);
+		}
+		super.formInnerEvent(ureq, source, event);
+	}
+
+	@Override
+	public void formOK(UserRequest ureq) {
+		Map<String,FormItem> formItemMap = confControllerContainer.getFormComponents();
+		
+		List<OfferAccess> links = new ArrayList<OfferAccess>();
+		for(AccessInfo info:confControllers) {
+			FormItem dateFrom = formItemMap.get("from_" + info.getLink().getKey());
+			if(dateFrom instanceof DateChooser) {
+				Date from = ((DateChooser)dateFrom).getDate();
+				info.getLink().setValidFrom(from);
+				info.getLink().getOffer().setValidFrom(from);
+			}
+			
+			FormItem dateTo = formItemMap.get("to_" + info.getLink().getKey());
+			if(dateTo instanceof DateChooser) {
+				Date to = ((DateChooser)dateTo).getDate();
+				info.getLink().setValidTo(to);
+				info.getLink().getOffer().setValidTo(to);
+			}
+			
+			links.add(info.getLink());
+		}
+		acFrontendManager.saveOfferAccess(links);
+	}
+	
+	protected void popupCallout(UserRequest ureq) {
+		addMethods.clear();
+		
+		VelocityContainer mapCreateVC = createVelocityContainer("createAccessCallout");
+		List<AccessMethod> methods = acFrontendManager.getAvailableMethods(getIdentity(), ureq.getUserSession().getRoles());
+		for(AccessMethod method:methods) {
+			AccessMethodHandler handler = acModule.getAccessMethodHandler(method.getType());
+			Link add = LinkFactory.createLink("create." + handler.getType(), mapCreateVC, this);
+			add.setCustomDisplayText(handler.getMethodName(getLocale()));
+			add.setUserObject(method);
+			add.setCustomEnabledLinkCSS("b_with_small_icon_left " + method.getMethodCssClass() + "_icon");
+			addMethods.add(add);
+			mapCreateVC.put(add.getComponentName(), add);
+		}
+		mapCreateVC.contextPut("methods", addMethods);
+		
+		String title = translate("add.accesscontrol");
+		removeAsListenerAndDispose(createCalloutCtrl);
+		createCalloutCtrl = new CloseableCalloutWindowController(ureq, getWindowControl(), mapCreateVC, createLink, title, true, null);
+		listenTo(createCalloutCtrl);
+		createCalloutCtrl.activate();
+		mainForm.setDirtyMarking(false);
+	}
+	
+	protected void loadConfigurations() {
+		List<Offer> offers = acFrontendManager.findOfferByResource(resource, true, null);
+		for(Offer offer:offers) {
+			List<OfferAccess> offerAccess = acFrontendManager.getOfferAccess(offer, true);
+			for(OfferAccess access:offerAccess) {
+				addConfiguration(access);
+			}
+		}
+	}
+	
+	protected void addConfiguration(OfferAccess link) {
+		AccessMethodHandler handler = acModule.getAccessMethodHandler(link.getMethod().getType());
+		AccessInfo infos = new AccessInfo(handler.getMethodName(getLocale()), null, link);
+		confControllers.add(infos);
+
+		DateChooser dateFrom = uifactory.addDateChooser("from_" + link.getKey(), "from", "", confControllerContainer);
+		dateFrom.setUserObject(infos);
+		dateFrom.setDate(link.getValidFrom());
+		confControllerContainer.add(dateFrom.getName(), dateFrom);
+		
+		DateChooser dateTo = uifactory.addDateChooser("to_" + link.getKey(), "to", "", confControllerContainer);
+		dateTo.setUserObject(infos);
+		dateTo.setDate(link.getValidTo());
+		confControllerContainer.add(dateTo.getName(), dateTo);
+		
+		FormLink delLink = uifactory.addFormLink("del_" + link.getKey(), "delete", null, confControllerContainer, Link.LINK);
+		delLink.setUserObject(infos);
+		delLink.setCustomEnabledLinkCSS("b_with_small_icon_left b_delete_icon");
+		confControllerContainer.add(delLink.getName(), delLink);
+	}
+	
+	protected void addMethod(UserRequest ureq, AccessMethod method) {
+		createCalloutCtrl.deactivate();
+		
+		Offer offer = acFrontendManager.createOffer(resource, displayName);
+		OfferAccess link = acFrontendManager.createOfferAccess(offer, method);
+		
+		removeAsListenerAndDispose(newMethodCtrl);
+		newMethodCtrl = ACUIFactory.createAccessConfigurationController(ureq, getWindowControl(), link);
+		if(newMethodCtrl != null) {
+			listenTo(newMethodCtrl);
+
+			AccessMethodHandler handler = acModule.getAccessMethodHandler(method.getType());
+			String title = handler.getMethodName(getLocale());
+		
+			cmc = new CloseableModalController(getWindowControl(), translate("close"), newMethodCtrl.getInitialComponent(), true, title);
+			cmc.activate();
+			listenTo(cmc);
+		} else {
+			OfferAccess newLink = acFrontendManager.saveOfferAccess(link);
+			addConfiguration(newLink);
+		}
+	}
+	
+	public class AccessInfo {
+		private String name;
+		private String infos;
+		private OfferAccess link;
+		
+		public AccessInfo(String name, String infos, OfferAccess link) {
+			this.name = name;
+			this.infos = infos;
+			this.link = link;
+		}
+		
+		public String getName() {
+			return name;
+		}
+		
+		public void setName(String name) {
+			this.name = name;
+		}
+		
+		public String getInfos() {
+			if(infos == null && link.getOffer() != null) {
+				OfferImpl casted = (OfferImpl)link.getOffer();
+				if(StringHelper.containsNonWhitespace(casted.getToken())) {
+					return casted.getToken();
+				}
+				if(!link.getOffer().getPrice().isEmpty()) {
+					String price = PriceFormat.fullFormat(link.getOffer().getPrice());
+					if(acModule.isVatEnabled()) {
+						BigDecimal vat = acModule.getVat();
+						String vatStr = vat == null ? "" : vat.setScale(3, BigDecimal.ROUND_HALF_EVEN).toPlainString();
+						return translate("access.info.price.vat", new String[]{price, vatStr});
+						
+					} else {
+						return translate("access.info.price.noVat", new String[]{price});
+					}
+				}
+			}
+			if(StringHelper.containsNonWhitespace(infos)) {
+				return infos;
+			}
+			return "";
+		}
+		
+		public void setInfos(String infos) {
+			this.infos = infos;
+		}
+
+		public OfferAccess getLink() {
+			return link;
+		}
+
+		public void setLink(OfferAccess link) {
+			this.link = link;
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/AccessEvent.java b/src/main/java/org/olat/resource/accesscontrol/ui/AccessEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..8e2c1d58415623b8dbf3997191e87f9d6fbc0ca4
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/AccessEvent.java
@@ -0,0 +1,77 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.ui;
+
+import org.olat.core.gui.control.Event;
+
+/**
+ * 
+ * Description:<br>
+ * 
+ * 
+ * <P>
+ * Initial Date:  15 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class AccessEvent extends Event {
+	
+	public static final String ACCESS_FAILED = "access-failed";
+	public static final String ACCESS_OK = "access-ok";
+	
+	public static final AccessEvent ACCESS_FAILED_EVENT = new AccessEvent();
+	public static final AccessEvent ACCESS_OK_EVENT = new AccessEvent(ACCESS_OK);
+	
+	private final String message;
+	
+	public AccessEvent() {
+		this(ACCESS_FAILED, null);
+	}
+	
+	public AccessEvent(String cmd) {
+		this(cmd, null);
+	}
+	
+	public AccessEvent(String cmd, String message) {
+		super(cmd);
+		this.message = message;
+	}
+	
+	public String getMessage() {
+		return message;
+	}
+
+	@Override
+	public int hashCode() {
+		return getCommand().hashCode();
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if(this == obj) {
+			return true;
+		}
+		if( obj instanceof AccessEvent) {
+			AccessEvent e = (AccessEvent)obj;
+			return getCommand() != null && getCommand().equals(e.getCommand());
+		}
+		return false;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/AccessListController.java b/src/main/java/org/olat/resource/accesscontrol/ui/AccessListController.java
new file mode 100644
index 0000000000000000000000000000000000000000..89010429f2034276ed1279e959e83974b1742d02
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/AccessListController.java
@@ -0,0 +1,108 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.ui;
+
+import java.util.ArrayList;
+import java.util.List;
+
+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;
+import org.olat.core.gui.control.Controller;
+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.util.StringHelper;
+import org.olat.resource.accesscontrol.AccessControlModule;
+import org.olat.resource.accesscontrol.manager.ACFrontendManager;
+import org.olat.resource.accesscontrol.method.AccessMethodHandler;
+import org.olat.resource.accesscontrol.model.OfferAccess;
+
+/**
+ * 
+ * Description:<br>
+ * A simple step to choose the way to access a resource if
+ * several methods are available
+ * 
+ * <P>
+ * Initial Date:  27 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class AccessListController extends BasicController {
+	
+	private final VelocityContainer mainVC;
+	private final List<Controller> accessCtrls = new ArrayList<Controller>();
+	
+	private final AccessControlModule acModule;
+	private final ACFrontendManager acFrontendManager;
+
+
+
+	public AccessListController(UserRequest ureq, WindowControl wControl, List<OfferAccess> links) {
+		super(ureq, wControl);
+		
+		acModule = (AccessControlModule)CoreSpringFactory.getBean("acModule");
+		acFrontendManager = (ACFrontendManager)CoreSpringFactory.getBean("acFrontendManager");
+		
+		mainVC = createVelocityContainer("access_method_list");
+		
+		for(OfferAccess link:links) {
+			AccessMethodHandler handler = acModule.getAccessMethodHandler(link.getMethod().getType());
+			Controller accessCtrl = handler.createAccessController(ureq, getWindowControl(), link, null);
+			listenTo(accessCtrl);
+			accessCtrls.add(accessCtrl);
+			mainVC.put("ac_" + link.getKey(), accessCtrl.getInitialComponent());
+		}
+		mainVC.contextPut("links", links);
+		
+		putInitialPanel(mainVC);
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+	
+	@Override
+	protected void event(UserRequest ureq, Component source, Event event) {
+		//
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Controller source, Event event) {
+		if(accessCtrls.contains(source)) {
+			if(event instanceof AccessEvent) {
+				if(event.equals(AccessEvent.ACCESS_OK_EVENT)) {
+					fireEvent(ureq, AccessEvent.ACCESS_OK_EVENT);
+				} else {
+					String msg = ((AccessEvent)event).getMessage();
+					if(StringHelper.containsNonWhitespace(msg)) {
+						getWindowControl().setError(msg);
+					} else {
+						showError("error.accesscontrol");
+					}
+				}
+			}
+		}
+		super.event(ureq, source, event);
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/AccessMethodRenderer.java b/src/main/java/org/olat/resource/accesscontrol/ui/AccessMethodRenderer.java
new file mode 100644
index 0000000000000000000000000000000000000000..f8b7b358645b18b8e52f977565a5ee7a2bc5a8cf
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/AccessMethodRenderer.java
@@ -0,0 +1,80 @@
+/**
+ * OLAT - Online Learning and Training<br>
+ * http://www.olat.org
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Copyright (c) frentix GmbH<br>
+ * http://www.frentix.com<br>
+ * <p>
+ */
+package org.olat.resource.accesscontrol.ui;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
+import org.olat.core.gui.components.table.CustomCellRenderer;
+import org.olat.core.gui.render.Renderer;
+import org.olat.core.gui.render.StringOutput;
+import org.olat.resource.accesscontrol.AccessControlModule;
+import org.olat.resource.accesscontrol.method.AccessMethodHandler;
+import org.olat.resource.accesscontrol.model.AccessTransaction;
+
+/**
+ * 
+ * Description:<br>
+ * Render the type of an access method
+ * 
+ * <P>
+ * Initial Date:  27 mai 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class AccessMethodRenderer implements CustomCellRenderer {
+	
+	private final AccessControlModule acModule;
+	
+	public AccessMethodRenderer(AccessControlModule acModule) {
+		this.acModule = acModule;
+	}
+	
+	@Override
+	public void render(StringOutput sb, Renderer renderer, Object val, Locale locale, int alignment, String action) {
+		
+		if(val instanceof AccessTransaction) {
+			AccessTransaction transaction = (AccessTransaction)val;
+			Set<String> uniqueType = new HashSet<String>(3);
+			render(sb, transaction, uniqueType, locale);
+		} else if (val instanceof List) {
+			List<AccessTransaction> transactions = (List<AccessTransaction>)val;
+			Set<String> uniqueType = new HashSet<String>((transactions.size() * 2) + 1);
+			for(AccessTransaction transaction : transactions) {
+				render(sb, transaction, uniqueType, locale);
+			}
+		}
+	}
+	
+	private void render(StringOutput sb, AccessTransaction transaction, Set<String> uniqueType, Locale locale) {
+		String type = transaction.getMethod().getType();
+		if(uniqueType.contains(type)) return;
+		uniqueType.add(type);
+		
+		AccessMethodHandler handler = acModule.getAccessMethodHandler(type);
+		sb.append("<span class='b_with_small_icon_left ");
+		sb.append(transaction.getMethod().getMethodCssClass());
+		sb.append("_icon'>");
+		sb.append(handler.getMethodName(locale));
+		sb.append("</span>");
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/FormController.java b/src/main/java/org/olat/resource/accesscontrol/ui/FormController.java
new file mode 100644
index 0000000000000000000000000000000000000000..114318b07dcd82094e29c3e1ea5db19927c6ad07
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/FormController.java
@@ -0,0 +1,39 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.ui;
+
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.control.Controller;
+
+/**
+ * 
+ * Description:<br>
+ * TODO: srosse Class Description for FormController
+ * 
+ * <P>
+ * Initial Date:  27 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public interface FormController extends Controller {
+	
+	public FormItem getInitialFormItem();
+
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/FreeAccessConfigurationController.java b/src/main/java/org/olat/resource/accesscontrol/ui/FreeAccessConfigurationController.java
new file mode 100644
index 0000000000000000000000000000000000000000..412b97786ba5f003ce10a0a09a63921013aa3d38
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/FreeAccessConfigurationController.java
@@ -0,0 +1,76 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.ui;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.TextElement;
+import org.olat.core.gui.components.form.flexible.impl.Form;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.resource.accesscontrol.model.AccessMethod;
+import org.olat.resource.accesscontrol.model.OfferAccess;
+
+/**
+ * 
+ * Description:<br>
+ * Configuration for a free acces
+ * 
+ * <P>
+ * Initial Date:  31 mai 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class FreeAccessConfigurationController extends AbstractConfigurationMethodController {
+
+	private TextElement descEl;
+	private final OfferAccess link;
+	
+	public FreeAccessConfigurationController(UserRequest ureq, WindowControl wControl, OfferAccess link) {
+		super(ureq, wControl);
+		this.link = link;
+		initForm(ureq);
+	}
+
+	public FreeAccessConfigurationController(UserRequest ureq, WindowControl wControl, OfferAccess link, Form form) {
+		super(ureq, wControl, LAYOUT_DEFAULT, null, form);
+		this.link = link;
+		initForm(ureq);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		
+		descEl = uifactory.addTextAreaElement("offer-desc", "offer.description", 2000, 6, 80, false, null, formLayout);
+
+		super.initForm(formLayout, listener, ureq);
+	}
+	
+	@Override
+	public AccessMethod getMethod() {
+		return link.getMethod();
+	}
+
+	@Override
+	public OfferAccess commitChanges() {
+		link.getOffer().setDescription(descEl.getValue());
+		return link;
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/FreeAccessController.java b/src/main/java/org/olat/resource/accesscontrol/ui/FreeAccessController.java
new file mode 100644
index 0000000000000000000000000000000000000000..4b9108cc4e2465f9652fa803ee03e78cb091f0eb
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/FreeAccessController.java
@@ -0,0 +1,112 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.ui;
+
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.impl.Form;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.util.StringHelper;
+import org.olat.resource.accesscontrol.AccessResult;
+import org.olat.resource.accesscontrol.manager.ACFrontendManager;
+import org.olat.resource.accesscontrol.model.OfferAccess;
+
+
+/**
+ * 
+ * Description:<br>
+ * Free access
+ * 
+ * <P>
+ * Initial Date:  15 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class FreeAccessController extends FormBasicController implements FormController {
+	
+	private final OfferAccess link;
+	private final ACFrontendManager acFrontendManager;
+
+	public FreeAccessController(UserRequest ureq, WindowControl wControl, OfferAccess link) {
+		super(ureq, wControl);
+		
+		this.link = link;
+		acFrontendManager = (ACFrontendManager)CoreSpringFactory.getBean("acFrontendManager");
+			
+		initForm(ureq);
+	}
+	
+	public FreeAccessController(UserRequest ureq, WindowControl wControl, OfferAccess link, Form form) {
+		super(ureq, wControl, LAYOUT_DEFAULT, null, form);
+		
+		this.link = link;
+		acFrontendManager = (ACFrontendManager)CoreSpringFactory.getBean("acFrontendManager");
+			
+		initForm(ureq);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		setFormTitle("access.free.title");
+		setFormDescription("access.free.desc");
+		
+		String description = link.getOffer().getDescription();
+		if(StringHelper.containsNonWhitespace(description)) {
+			uifactory.addStaticTextElement("offer.description", description, formLayout);
+		}
+		
+		final FormLayoutContainer buttonGroupLayout = FormLayoutContainer.createButtonLayout("buttonLayout", getTranslator());
+		buttonGroupLayout.setRootForm(mainForm);
+		formLayout.add(buttonGroupLayout);
+			
+		uifactory.addFormSubmitButton("access.button", buttonGroupLayout);
+	}
+		
+	@Override
+	protected void doDispose() {
+			//
+	}
+
+	@Override
+	protected boolean validateFormLogic(UserRequest ureq) {
+		return true;
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		AccessResult result = acFrontendManager.accessResource(getIdentity(), link, null);
+		
+		if(result.isAccessible()) {
+			fireEvent(ureq, AccessEvent.ACCESS_OK_EVENT);
+		} else {
+			fireEvent(ureq, new AccessEvent(AccessEvent.ACCESS_FAILED));
+		}
+	}
+
+	@Override
+	public FormItem getInitialFormItem() {
+		return flc;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/MainAccessController.java b/src/main/java/org/olat/resource/accesscontrol/ui/MainAccessController.java
new file mode 100644
index 0000000000000000000000000000000000000000..39359fe6c480e22d78cd423afc946ab78955d411
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/MainAccessController.java
@@ -0,0 +1,161 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.ui;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.components.link.Link;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.util.StringHelper;
+import org.olat.resource.accesscontrol.AccessControlModule;
+import org.olat.resource.accesscontrol.AccessResult;
+import org.olat.resource.accesscontrol.manager.ACFrontendManager;
+import org.olat.resource.accesscontrol.method.AccessMethodHandler;
+import org.olat.resource.accesscontrol.model.OfferAccess;
+
+/**
+ * 
+ * Description:<br>
+ * A simple step to choose the way to access a resource if
+ * several methods are available
+ * 
+ * <P>
+ * Initial Date:  27 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class MainAccessController extends FormBasicController {
+	
+	private FormLink backLink;
+	private final List<OfferAccess> links;
+	private final List<FormLink> accessButtons = new ArrayList<FormLink>();
+	private final AccessControlModule acModule;
+	private final ACFrontendManager acFrontendManager;
+	
+	private FormController accessCtrl;
+
+	public MainAccessController(UserRequest ureq, WindowControl wControl, List<OfferAccess> links) {
+		super(ureq, wControl, "choose_access_method");
+		
+		this.links = links;
+		acModule = (AccessControlModule)CoreSpringFactory.getBean("acModule");
+		acFrontendManager = (ACFrontendManager)CoreSpringFactory.getBean("acFrontendManager");
+			
+		initForm(ureq);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		backLink = uifactory.addFormLink("back", formLayout, Link.LINK_BACK);
+		
+		FormLayoutContainer methodChooseContainer = FormLayoutContainer.createDefaultFormLayout("methodChooser", getTranslator());
+		methodChooseContainer.setRootForm(mainForm);
+		formLayout.add("methodChooser", methodChooseContainer);
+
+		for(OfferAccess link:links) {
+			AccessMethodHandler handler = acModule.getAccessMethodHandler(link.getMethod().getType());
+			String methodName = handler.getMethodName(getLocale());
+			FormLink accessButton = uifactory.addFormLink("m_" + link.getKey(), methodName, null, methodChooseContainer, Link.BUTTON + Link.NONTRANSLATED);
+			accessButton.setUserObject(link);
+			accessButtons.add(accessButton);
+		}
+	}
+	
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Controller source, Event event) {
+		if(source == accessCtrl) {
+			if(event instanceof AccessEvent) {
+				if(event.equals(AccessEvent.ACCESS_OK_EVENT)) {
+					fireEvent(ureq, AccessEvent.ACCESS_OK_EVENT);
+				} else {
+					String msg = ((AccessEvent)event).getMessage();
+					if(StringHelper.containsNonWhitespace(msg)) {
+						getWindowControl().setError(msg);
+					} else {
+						showError("error.accesscontrol");
+					}
+				}
+			}
+			flc.remove(accessCtrl.getInitialFormItem());
+			removeAsListenerAndDispose(accessCtrl);
+			accessCtrl = null;
+		}
+		super.event(ureq, source, event);
+	}
+
+	@Override
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if(backLink == source) {
+			if(accessCtrl != null) {
+				flc.remove(accessCtrl.getInitialComponent());
+				removeAsListenerAndDispose(accessCtrl);
+				accessCtrl = null;
+			}
+		} else if(accessButtons.contains(source)) {
+			methodChoosed(ureq, (OfferAccess)source.getUserObject());
+		}
+		super.formInnerEvent(ureq, source, event);
+	}
+	
+	protected void methodChoosed(UserRequest ureq, OfferAccess link) {
+		if(link.getMethod().isNeedUserInteraction()) {
+			AccessControlModule module = (AccessControlModule)CoreSpringFactory.getBean("acModule");
+			AccessMethodHandler handler = module.getAccessMethodHandler(link.getMethod().getType());
+			if(handler != null) {
+				accessCtrl = handler.createAccessController(ureq, getWindowControl(), link, mainForm);
+				listenTo(accessCtrl);
+				flc.add("accessCmp", accessCtrl.getInitialFormItem());
+			}
+		} else {
+			doAccessResource(ureq, link);
+		}
+	}
+	
+	protected void doAccessResource(UserRequest ureq, OfferAccess link) {
+		AccessResult result = acFrontendManager.accessResource(getIdentity(), link, null);
+		if(result.isAccessible()) {
+			fireEvent(ureq, AccessEvent.ACCESS_OK_EVENT);
+		} else {
+			fireEvent(ureq, new AccessEvent(AccessEvent.ACCESS_FAILED));
+			showError("error.accesscontrol");
+		}
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		//
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/OrderDetailController.java b/src/main/java/org/olat/resource/accesscontrol/ui/OrderDetailController.java
new file mode 100644
index 0000000000000000000000000000000000000000..0d7060d96a6ab869565048c2ec64caa91e59334e
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/OrderDetailController.java
@@ -0,0 +1,342 @@
+package org.olat.resource.accesscontrol.ui;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import org.olat.NewControllerFactory;
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.gui.ShortName;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.components.link.Link;
+import org.olat.core.gui.components.table.ColumnDescriptor;
+import org.olat.core.gui.components.table.CustomRenderColumnDescriptor;
+import org.olat.core.gui.components.table.DefaultColumnDescriptor;
+import org.olat.core.gui.components.table.StaticColumnDescriptor;
+import org.olat.core.gui.components.table.Table;
+import org.olat.core.gui.components.table.TableController;
+import org.olat.core.gui.components.table.TableDataModel;
+import org.olat.core.gui.components.table.TableEvent;
+import org.olat.core.gui.components.table.TableGuiConfiguration;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
+import org.olat.core.id.OLATResourceable;
+import org.olat.core.id.User;
+import org.olat.core.id.UserConstants;
+import org.olat.core.id.context.BusinessControl;
+import org.olat.core.id.context.BusinessControlFactory;
+import org.olat.core.util.Formatter;
+import org.olat.core.util.StringHelper;
+import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryManager;
+import org.olat.resource.OLATResource;
+import org.olat.resource.accesscontrol.AccessControlModule;
+import org.olat.resource.accesscontrol.manager.ACFrontendManager;
+import org.olat.resource.accesscontrol.model.AccessTransaction;
+import org.olat.resource.accesscontrol.model.Order;
+import org.olat.resource.accesscontrol.model.OrderLine;
+import org.olat.resource.accesscontrol.model.OrderPart;
+
+public class OrderDetailController extends FormBasicController {
+	
+	private static final String CMD_SELECT = "sel";
+	
+	private FormLink backLink;
+	private FormLink selectResourceLink;
+	private TableController tableCtr;
+	private CloseableModalController cmc;
+	private TransactionDetailsController detailsCtlr;
+	
+	private final Order order;
+	private Collection<AccessTransaction> transactions;
+	
+	private final AccessControlModule acModule;
+	private final ACFrontendManager acFrontendManager;
+	
+	public OrderDetailController(UserRequest ureq, WindowControl wControl, Order order, Collection<AccessTransaction> transactions) {
+		super(ureq, wControl, "order");
+		
+		this.order = order;
+		this.transactions = transactions;
+		acModule = (AccessControlModule)CoreSpringFactory.getBean("acModule");
+		acFrontendManager = (ACFrontendManager)CoreSpringFactory.getBean("acFrontendManager");
+		
+		initForm(ureq);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		backLink = uifactory.addFormLink("back", formLayout, Link.LINK_BACK);
+		
+		FormLayoutContainer mainLayout = FormLayoutContainer.createDefaultFormLayout("mainCmp", getTranslator());
+		mainLayout.setRootForm(mainForm);
+		formLayout.add("mainCmp", mainLayout);
+		
+		String orderNr = order.getOrderNr();
+		uifactory.addStaticTextElement("order-nr", "order.nr", orderNr, mainLayout);	
+
+		Date creationDate = order.getCreationDate();
+		String creationDateStr = Formatter.getInstance(getLocale()).formatDateAndTime(creationDate);
+		uifactory.addStaticTextElement("creation-date", "order.creationDate", creationDateStr, mainLayout);
+		
+		String orderTotal = PriceFormat.fullFormat(order.getTotal());
+		String orderTotalStr;
+		if(acModule.isVatEnabled()) {
+			BigDecimal vat = acModule.getVat();
+			String vatStr = vat == null ? "" : vat.setScale(3, BigDecimal.ROUND_HALF_EVEN).toPlainString();
+			orderTotalStr = translate("access.info.price.vat", new String[]{orderTotal, vatStr});
+		} else {
+			orderTotalStr = translate("access.info.price.noVat", new String[]{orderTotal});
+		}
+		uifactory.addStaticTextElement("order-total", "order.total", orderTotalStr, mainLayout);
+		
+		OrderItemsDataModel tableModel = getOrderItemsDataModel();
+		
+		if(tableModel.getRowCount() == 1) {
+			OrderItemWrapper wrapper = tableModel.getObject(0);
+			if(wrapper.getItem().getOffer().getResource() != null) {
+				//resource is null if the resource has been deleted
+				String linkName = wrapper.getDisplayName();
+				selectResourceLink = uifactory.addFormLink("resource", linkName, translate("order.item"), mainLayout, Link.NONTRANSLATED);
+				selectResourceLink.setUserObject(wrapper);
+			}
+		}
+
+		User user = order.getDelivery().getUser();
+		String delivery = user.getProperty(UserConstants.FIRSTNAME, null) + " " + user.getProperty(UserConstants.LASTNAME, null);
+		uifactory.addStaticTextElement("delivery", "order.delivery", delivery, mainLayout);
+
+		if(formLayout instanceof FormLayoutContainer) {
+			TableGuiConfiguration tableConfig = new TableGuiConfiguration();
+			tableConfig.setDownloadOffered(false);		
+			tableConfig.setTableEmptyMessage(translate("orders.empty"));
+
+			tableCtr = new TableController(tableConfig, ureq, getWindowControl(), Collections.<ShortName>emptyList(), null, null , null, false, getTranslator());
+			tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("order.item.name", 0, null, getLocale()));
+			tableCtr.addColumnDescriptor(new CustomRenderColumnDescriptor("order.part.payment", 1, null, getLocale(), 
+					ColumnDescriptor.ALIGNMENT_LEFT, new AccessMethodRenderer(acModule)));
+			tableCtr.addColumnDescriptor(new StaticColumnDescriptor(CMD_SELECT, "table.order.details", getTranslator().translate("order.details")));
+			
+			tableCtr.setTableDataModel(tableModel);
+			listenTo(tableCtr);
+			
+			FormLayoutContainer layoutContainer = (FormLayoutContainer)formLayout;
+			layoutContainer.put("orderItemList", tableCtr.getInitialComponent());
+		}
+	}
+	
+	private OrderItemsDataModel getOrderItemsDataModel() {
+		List<OrderItemWrapper> items = new ArrayList<OrderItemWrapper>();
+		for(OrderPart part: order.getParts()) {
+			boolean first = true;
+			
+			AccessTransaction transaction = null;
+			if(transactions != null) {
+				for(AccessTransaction trx:transactions) {
+					if(trx.getOrderPart().equals(part)) {
+						transaction = trx;
+						break;
+					}
+				}
+			}
+
+			for(OrderLine line:part.getOrderLines()) {
+				OLATResource resource = line.getOffer().getResource();
+				String displayName;
+				if(resource == null) {
+					displayName = line.getOffer().getResourceDisplayName();
+				} else {
+					displayName = acFrontendManager.resolveDisplayName(resource);
+				}
+				OrderItemWrapper wrapper = new OrderItemWrapper(part, line, transaction, displayName, first);
+				items.add(wrapper);
+				first = false;
+			}
+		}
+		
+		return new OrderItemsDataModel(items);
+	}
+	
+	@Override
+	protected void doDispose() {
+		//
+	}
+	
+	@Override
+	protected void event(UserRequest ureq, Controller source, Event event) {
+		if(source == tableCtr) {
+			if (event.getCommand().equals(Table.COMMANDLINK_ROWACTION_CLICKED)) {
+				TableEvent te = (TableEvent) event;
+				String actionid = te.getActionId();
+				int rowid = te.getRowId();
+				OrderItemWrapper wrapper = (OrderItemWrapper)tableCtr.getTableDataModel().getObject(rowid);
+				if(CMD_SELECT.equals(actionid)) {
+					popupTransactionDetails(ureq, wrapper);
+				}
+			}
+		} else if (source == detailsCtlr) {
+			cmc.deactivate();
+			removeAsListenerAndDispose(detailsCtlr);
+			removeAsListenerAndDispose(cmc);
+			detailsCtlr = null;
+			cmc = null;
+		}
+	}
+	
+	@Override
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if(source == backLink) {
+			fireEvent(ureq, Event.BACK_EVENT);
+		} else if (source == selectResourceLink) {
+			OrderItemWrapper wrapper = (OrderItemWrapper)source.getUserObject();
+			final Long resourceId = wrapper.getItem().getOffer().getResourceId();
+			final String type = wrapper.getItem().getOffer().getResourceTypeName();
+
+			String url;
+			if("BusinessGroup".equals(type)) {
+				url = "[" + type + ":" + resourceId + "]";
+			} else {
+				OLATResourceable ores = wrapper.getOLATResourceable();
+				RepositoryEntry re = RepositoryManager.getInstance().lookupRepositoryEntry(ores, false);
+				url = "[RepositoryEntry:" + re.getKey() + "]";
+			}
+			BusinessControl bc = BusinessControlFactory.getInstance().createFromString(url);
+		  WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(bc, getWindowControl());
+			NewControllerFactory.getInstance().launch(ureq, bwControl);
+		}
+		super.formInnerEvent(ureq, source, event);
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		//
+	}
+	
+	private void popupTransactionDetails(UserRequest ureq, OrderItemWrapper wrapper) {
+		if(wrapper.getTransaction() == null) {
+			//no transaction???
+		} else {
+			detailsCtlr = new TransactionDetailsController(ureq, getWindowControl(), order, wrapper);
+			listenTo(detailsCtlr);
+			cmc = new CloseableModalController(getWindowControl(), translate("close"), detailsCtlr.getInitialComponent());
+			listenTo(cmc);
+			cmc.activate();
+		}
+	}
+	
+	public class OrderItemsDataModel implements TableDataModel {
+		
+		private List<OrderItemWrapper> items;
+		
+		public OrderItemsDataModel(List<OrderItemWrapper> items) {
+			this.items = items;
+		}
+
+		@Override
+		public int getColumnCount() {
+			return 2;
+		}
+
+		@Override
+		public int getRowCount() {
+			return items == null ? 0 : items.size();
+		}
+
+		@Override
+		public Object getValueAt(int row, int col) {
+			OrderItemWrapper wrapper = getObject(row);
+			switch(col) {
+				case 0: {
+					String name = wrapper.getDisplayName();
+					if(StringHelper.containsNonWhitespace(name)) {
+						return name;
+					}
+					return "-";
+				}
+				case 1: {
+					if(wrapper.isFirst() && wrapper.getTransaction() != null) {
+						return wrapper.getTransaction();
+					}
+					return null;
+				}
+				default: return wrapper;
+			}
+		}
+
+		@Override
+		public OrderItemWrapper getObject(int row) {
+			return items.get(row);
+		}
+
+		@Override
+		public void setObjects(List objects) {
+			this.items = objects;
+		}
+
+		@Override
+		public OrderItemsDataModel createCopyWithEmptyList() {
+			return new OrderItemsDataModel(Collections.<OrderItemWrapper>emptyList());
+		}
+	}
+	
+	public class OrderItemWrapper {
+		
+		private final boolean first;
+		private final OrderPart part;
+		private final OrderLine item;
+		private final AccessTransaction transaction;
+		private final String displayName;
+		
+		public OrderItemWrapper(OrderPart part, OrderLine item, AccessTransaction transaction, String displayName,  boolean first) {
+			this.part = part;
+			this.item = item;
+			this.first = first;
+			this.transaction = transaction;
+			this.displayName = displayName;
+		}
+
+		public boolean isFirst() {
+			return first;
+		}
+
+		public String getDisplayName() {
+			return displayName;
+		}
+
+		public OrderPart getPart() {
+			return part;
+		}
+
+		public OrderLine getItem() {
+			return item;
+		}
+		
+		public AccessTransaction getTransaction() {
+			return transaction;
+		}
+		
+		public OLATResourceable getOLATResourceable() {
+			return new OLATResourceable() {
+				@Override
+				public String getResourceableTypeName() {
+					return item.getOffer().getResourceTypeName();
+				}
+				@Override
+				public Long getResourceableId() {
+					return item.getOffer().getResourceId();
+				}
+			};
+		}
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/OrderStatusContextShortName.java b/src/main/java/org/olat/resource/accesscontrol/ui/OrderStatusContextShortName.java
new file mode 100644
index 0000000000000000000000000000000000000000..4f66faa2c2d348c1189f8aab58ec054024ea5394
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/OrderStatusContextShortName.java
@@ -0,0 +1,61 @@
+/**
+ * OLAT - Online Learning and Training<br>
+ * http://www.olat.org
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Copyright (c) frentix GmbH<br>
+ * http://www.frentix.com<br>
+ * <p>
+ */
+package org.olat.resource.accesscontrol.ui;
+
+import org.olat.core.gui.ShortName;
+import org.olat.resource.accesscontrol.model.OrderStatus;
+
+/**
+ * 
+ * Description:<br>
+ * Short name for filters by order status
+ * 
+ * <P>
+ * Initial Date:  27 mai 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class OrderStatusContextShortName implements ShortName {
+	private String contextName;
+	private OrderStatus[] status;
+	
+	public OrderStatusContextShortName(String contextName, OrderStatus status) {
+		this.contextName = contextName;
+		this.status = new OrderStatus[]{status};
+	}
+	
+	public OrderStatusContextShortName(String contextName, OrderStatus... status) {
+		this.contextName = contextName;
+		this.status = status;
+	}
+	
+	@Override
+	public String getShortName() {
+		return contextName;
+	}
+
+	public OrderStatus[] getStatus() {
+		return status;
+	}
+	
+	public String getContextName() {
+		return contextName;
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/OrderStatusRenderer.java b/src/main/java/org/olat/resource/accesscontrol/ui/OrderStatusRenderer.java
new file mode 100644
index 0000000000000000000000000000000000000000..33736d999993df92bfd2c280d68ac079709fd9ad
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/OrderStatusRenderer.java
@@ -0,0 +1,63 @@
+/**
+ * OLAT - Online Learning and Training<br>
+ * http://www.olat.org
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Copyright (c) frentix GmbH<br>
+ * http://www.frentix.com<br>
+ * <p>
+ */
+package org.olat.resource.accesscontrol.ui;
+
+import java.util.Locale;
+
+import org.olat.core.gui.components.table.CustomCellRenderer;
+import org.olat.core.gui.render.Renderer;
+import org.olat.core.gui.render.StringOutput;
+import org.olat.resource.accesscontrol.model.OrderStatus;
+
+/**
+ * 
+ * Description:<br>
+ * Render the status or the simplified status of an order
+ * 
+ * <P>
+ * Initial Date:  27 mai 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class OrderStatusRenderer implements CustomCellRenderer {
+
+	public OrderStatusRenderer() {
+		//
+	}
+	
+	@Override
+	public void render(StringOutput sb, Renderer renderer, Object val, Locale locale, int alignment, String action) {
+		if(val instanceof OrderStatus) {
+			OrderStatus status = (OrderStatus)val;
+			String name = status.name().toLowerCase();
+			sb.append("<span class='b_with_small_icon_left b_order_status_");
+			sb.append(name);
+			sb.append("_icon'></span>");
+		} else if (val instanceof OrderTableItem) {
+			OrderTableItem item = (OrderTableItem)val;
+			switch(item.getStatus()) {
+				case ERROR: sb.append("<span class='b_with_small_icon_left b_order_status_error_icon'></span>"); break;
+				case WARNING: sb.append("<span class='b_with_small_icon_left b_order_status_warning_icon'></span>"); break;
+				case CANCELED: sb.append("<span class='b_with_small_icon_left b_order_status_canceled_icon'></span>"); break;
+				default: sb.append("<span class='b_with_small_icon_left b_order_status_payed_icon'></span>");
+			}
+		}
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/OrderTableItem.java b/src/main/java/org/olat/resource/accesscontrol/ui/OrderTableItem.java
new file mode 100644
index 0000000000000000000000000000000000000000..836da039a46dcaa151c2bdddb3d4875195632a35
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/OrderTableItem.java
@@ -0,0 +1,130 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.ui;
+
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashSet;
+
+import org.olat.resource.accesscontrol.model.AccessTransaction;
+import org.olat.resource.accesscontrol.model.AccessTransactionStatus;
+import org.olat.resource.accesscontrol.model.Order;
+import org.olat.resource.accesscontrol.model.OrderStatus;
+import org.olat.resource.accesscontrol.model.PSPTransaction;
+import org.olat.resource.accesscontrol.model.PSPTransactionStatus;
+
+/**
+ * 
+ * Description:<br>
+ * Wrapper for the OrdersDataModel
+ * 
+ * <P>
+ * Initial Date:  20 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class OrderTableItem {
+	
+	private static final OrderTableItemStatusComparator statusComparator = new OrderTableItemStatusComparator();
+	
+	private final Order order;
+	private final Collection<AccessTransaction> transactions = new HashSet<AccessTransaction>();
+	private final Collection<PSPTransaction> pspTransactions = new HashSet<PSPTransaction>();
+	
+	public OrderTableItem(Order order) {
+		this.order = order;
+	}
+	
+	public Order getOrder() {
+		return order;
+	}
+	
+	public Collection<AccessTransaction> getTransactions() {
+		return transactions;
+	}
+	
+	public Collection<PSPTransaction> getPSPTransactions() {
+		return pspTransactions;
+	}
+	
+	public Status getStatus() {
+		boolean warning = false;
+		boolean error = false;
+		boolean canceled = false;
+		
+		if(getOrder().getOrderStatus() == OrderStatus.CANCELED) {
+			canceled = true;
+		} else if(getOrder().getOrderStatus() == OrderStatus.ERROR) {
+			error = true;
+		} else if(getOrder().getOrderStatus() == OrderStatus.PREPAYMENT) {
+			warning = true;
+		}
+		
+		for(AccessTransaction transaction:getTransactions()) {
+			if(transaction.getStatus() == AccessTransactionStatus.CANCELED) {
+				canceled = true;
+			} else if(transaction.getStatus() == AccessTransactionStatus.ERROR) {
+				error = true;
+			}
+		}
+		
+		for(PSPTransaction transaction:getPSPTransactions()) {
+			if(transaction.getSimplifiedStatus() == PSPTransactionStatus.ERROR) {
+				error = true;
+			} else if(transaction.getSimplifiedStatus() == PSPTransactionStatus.WARNING) {
+				warning = true;
+			}
+		}
+		
+		if(error) {
+			return Status.ERROR;
+		} else if (warning) {
+			return Status.WARNING;
+		} else if(canceled) {
+			return Status.CANCELED;
+		} else {
+			return Status.OK;
+		}	
+	}
+	
+	public int compareStatusTo(OrderTableItem item) {
+		return statusComparator.compare(this, item);
+	}
+	
+	public enum Status {
+		ERROR,
+		WARNING,
+		OK,
+		CANCELED,
+	}
+	
+	public static class OrderTableItemStatusComparator implements Comparator<OrderTableItem> {
+		@Override
+		public int compare(OrderTableItem o1, OrderTableItem o2) {
+			Status s1 = o1.getStatus();
+			Status s2 = o2.getStatus();
+			
+			if(s1 == null) return -1;
+			if(s2 == null) return 1;
+			return s1.ordinal() - s2.ordinal();
+		}
+
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/OrdersActionExtension.java b/src/main/java/org/olat/resource/accesscontrol/ui/OrdersActionExtension.java
new file mode 100644
index 0000000000000000000000000000000000000000..a451961d9d94a318ad173f122701c5b88641e593
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/OrdersActionExtension.java
@@ -0,0 +1,65 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS,
+* <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2009 frentix GmbH, Switzerland<br>
+* <p>
+*/
+package org.olat.resource.accesscontrol.ui;
+
+import org.olat.core.extensions.action.GenericActionExtension;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.course.ICourse;
+import org.olat.resource.OLATResource;
+import org.olat.resource.OLATResourceManager;
+import org.olat.resource.accesscontrol.ACUIFactory;
+import org.olat.resource.accesscontrol.AccessControlModule;
+
+/**
+ * 
+ * Description:<br>
+ * ActionExtension for the administration of Orders by Resource
+ * 
+ * <P>
+ * Initial Date:  19 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class OrdersActionExtension extends GenericActionExtension {
+	
+	private final AccessControlModule acModule;
+	
+	public OrdersActionExtension(AccessControlModule acModule) {
+		this.acModule = acModule;
+	}
+	
+
+	@Override
+	public Controller createController(UserRequest ureq, WindowControl wControl, Object arg) {
+		if(arg instanceof ICourse) {
+			ICourse course = (ICourse)arg;
+			OLATResource resource = OLATResourceManager.getInstance().findResourceable(course);
+			return ACUIFactory.createOrdersAdminController(ureq, wControl, resource);
+		}
+		return super.createController(ureq, wControl, arg);
+	}
+
+	@Override
+	public boolean isEnabled() {
+		return acModule.isEnabled();
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/OrdersAdminController.java b/src/main/java/org/olat/resource/accesscontrol/ui/OrdersAdminController.java
new file mode 100644
index 0000000000000000000000000000000000000000..5fd3bd55576d2c8c11ab09b5f9b36f17ee5c5c91
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/OrdersAdminController.java
@@ -0,0 +1,224 @@
+package org.olat.resource.accesscontrol.ui;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.gui.ShortName;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.panel.Panel;
+import org.olat.core.gui.components.table.ColumnDescriptor;
+import org.olat.core.gui.components.table.CustomRenderColumnDescriptor;
+import org.olat.core.gui.components.table.DefaultColumnDescriptor;
+import org.olat.core.gui.components.table.StaticColumnDescriptor;
+import org.olat.core.gui.components.table.Table;
+import org.olat.core.gui.components.table.TableController;
+import org.olat.core.gui.components.table.TableEvent;
+import org.olat.core.gui.components.table.TableGuiConfiguration;
+import org.olat.core.gui.components.velocity.VelocityContainer;
+import org.olat.core.gui.control.Controller;
+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.gui.control.generic.dtabs.Activateable2;
+import org.olat.core.id.OLATResourceable;
+import org.olat.core.id.context.ContextEntry;
+import org.olat.core.id.context.StateEntry;
+import org.olat.core.util.resource.OresHelper;
+import org.olat.portfolio.model.artefacts.AbstractArtefact;
+import org.olat.resource.OLATResource;
+import org.olat.resource.accesscontrol.AccessControlModule;
+import org.olat.resource.accesscontrol.manager.ACFrontendManager;
+import org.olat.resource.accesscontrol.model.AccessTransaction;
+import org.olat.resource.accesscontrol.model.Order;
+import org.olat.resource.accesscontrol.model.OrderStatus;
+import org.olat.resource.accesscontrol.model.PSPTransaction;
+import org.olat.resource.accesscontrol.ui.OrdersDataModel.Col;
+
+/**
+ * 
+ * Description:<br>
+ * Controller to manage the orders, limited or not the an OLAT resource.
+ * 
+ * <P>
+ * Initial Date:  30 mai 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class OrdersAdminController extends BasicController implements Activateable2  {
+	
+	private static final String CMD_SELECT = "sel";
+
+	private final Panel mainPanel;
+	private final VelocityContainer mainVC;
+	private final TableController tableCtr;
+	private OrdersSearchForm searchForm;
+	private OrderDetailController detailController;
+	
+	private final AccessControlModule acModule;
+	private final ACFrontendManager acFrontendManager;
+	private final OLATResource resource;
+	
+	public OrdersAdminController(UserRequest ureq, WindowControl wControl) {
+		this(ureq, wControl, null);
+	}
+	
+	public OrdersAdminController(UserRequest ureq, WindowControl wControl, OLATResource resource) {
+		super(ureq, wControl);
+
+		acModule = (AccessControlModule)CoreSpringFactory.getBean("acModule");
+		acFrontendManager = (ACFrontendManager)CoreSpringFactory.getBean("acFrontendManager");
+		this.resource = resource;
+		
+		if(resource == null) {
+			searchForm = new OrdersSearchForm(ureq, wControl);
+			listenTo(searchForm);
+		}
+
+		TableGuiConfiguration tableConfig = new TableGuiConfiguration();
+		tableConfig.setDownloadOffered(true);
+		tableConfig.setPreferencesOffered(true, "Orders");		
+		tableConfig.setTableEmptyMessage(translate("table.order.empty"));
+		
+		List<ShortName> statusList = new ArrayList<ShortName>();
+		OrderStatusContextShortName allStatus = new OrderStatusContextShortName("-", OrderStatus.values());
+		OrderStatusContextShortName newStatus = new OrderStatusContextShortName(translate("order.status.new"), OrderStatus.NEW);
+		OrderStatusContextShortName preStatus = new OrderStatusContextShortName(translate("order.status.prepayment"), OrderStatus.PREPAYMENT);
+		OrderStatusContextShortName payedStatus = new OrderStatusContextShortName(translate("order.status.payed"), OrderStatus.PAYED);
+		OrderStatusContextShortName cancelStatus = new OrderStatusContextShortName(translate("order.status.canceled"), OrderStatus.CANCELED);
+		OrderStatusContextShortName errorStatus = new OrderStatusContextShortName(translate("order.status.error"), OrderStatus.ERROR);
+		statusList.add(allStatus);
+		statusList.add(newStatus);
+		statusList.add(preStatus);
+		statusList.add(payedStatus);
+		statusList.add(cancelStatus);
+		statusList.add(errorStatus);
+
+		tableCtr = new TableController(tableConfig, ureq, wControl, statusList, payedStatus, translate("order.status"), null, false, getTranslator());
+		tableCtr.addColumnDescriptor(new CustomRenderColumnDescriptor("order.status", Col.status.ordinal(), null, getLocale(),
+				ColumnDescriptor.ALIGNMENT_LEFT, new OrderStatusRenderer()) {
+					@Override
+					public int compareTo(int rowa, int rowb) {
+						OrderTableItem a = (OrderTableItem)table.getTableDataModel().getValueAt(rowa, dataColumn);
+						OrderTableItem b = (OrderTableItem)table.getTableDataModel().getValueAt(rowb, dataColumn);
+						return a.compareStatusTo(b);
+					}
+		});
+		tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("order.nr", Col.orderNr.ordinal(), CMD_SELECT, getLocale()));
+		tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("order.creationDate", Col.creationDate.ordinal(), null, getLocale()));
+		tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("order.summary", Col.summary.ordinal(), null, getLocale()));
+		tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("order.delivery", Col.delivery.ordinal(), null, getLocale()));
+		tableCtr.addColumnDescriptor(new CustomRenderColumnDescriptor("order.part.payment", Col.methods.ordinal(), null, getLocale(), 
+				ColumnDescriptor.ALIGNMENT_LEFT, new AccessMethodRenderer(acModule)));
+		tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("order.total", Col.total.ordinal(), null, getLocale()));
+		tableCtr.addColumnDescriptor(new StaticColumnDescriptor(CMD_SELECT, "table.order.details", getTranslator().translate("select")));
+		
+		listenTo(tableCtr);
+		
+		loadModel();
+		
+		mainVC = createVelocityContainer("orders");
+		if(searchForm != null) {
+			mainVC.put("searchForm", searchForm.getInitialComponent());
+		}
+		mainVC.put("orderList", tableCtr.getInitialComponent());
+		mainVC.contextPut("title", translate("orders.admin.my"));
+		mainVC.contextPut("description", translate("orders.admin.my.desc"));
+
+		mainPanel = putInitialPanel(mainVC);
+	}
+	
+	private void loadModel() {
+		OrderStatusContextShortName filter = (OrderStatusContextShortName)tableCtr.getActiveFilter();
+		List<Order> orders;
+		if(resource == null) {
+			Date from = searchForm.getFrom();
+			Date to = searchForm.getTo();
+			Long orderNr = searchForm.getRefNo();
+			orders = acFrontendManager.findOrders(null, null, orderNr, from, to, filter.getStatus());
+		} else {
+			orders = acFrontendManager.findOrders(resource, filter.getStatus());
+		}
+		List<AccessTransaction> transactions = acFrontendManager.findAccessTransactions(orders);
+		List<PSPTransaction> pspTransactions = acFrontendManager.findPSPTransactions(orders);
+		List<OrderTableItem> items = OrdersDataModel.create(orders, transactions, pspTransactions);
+		tableCtr.setTableDataModel(new OrdersDataModel(items, getLocale()));
+	}
+	
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Component source, Event event) {
+		//
+	}
+	
+	@Override
+	protected void event(UserRequest ureq, Controller source, Event event) {
+		if(source == tableCtr) {
+			if (event.getCommand().equals(Table.COMMANDLINK_ROWACTION_CLICKED)) {
+				TableEvent te = (TableEvent) event;
+				String actionid = te.getActionId();
+				int rowid = te.getRowId();
+				OrderTableItem order = (OrderTableItem)tableCtr.getTableDataModel().getObject(rowid);
+				if(CMD_SELECT.equals(actionid)) {
+					selectOrder(ureq, order);
+				}
+			} else if (TableController.EVENT_FILTER_SELECTED == event) {
+				loadModel();
+				addToHistory(ureq, getWindowControl());
+			}
+		} else if (source == searchForm) {
+			if(event == Event.DONE_EVENT) {
+				loadModel();
+				addSearchToHistory(ureq);
+			}
+		} else if (source == detailController) {
+			if(event == Event.BACK_EVENT) {
+				mainPanel.setContent(mainVC);
+				removeAsListenerAndDispose(detailController);
+				detailController = null;
+				addSearchToHistory(ureq);
+			}
+		}
+	}
+	
+	protected void addSearchToHistory(UserRequest ureq) {
+		StateEntry state = searchForm == null ? null : searchForm.getStateEntry(); 
+		ContextEntry currentEntry = getWindowControl().getBusinessControl().getCurrentContextEntry();
+		if(currentEntry != null) {
+			currentEntry.setTransientState(state);
+		}
+		addToHistory(ureq, getWindowControl());
+	}
+	
+	protected void selectOrder(UserRequest ureq, OrderTableItem order) {
+		removeAsListenerAndDispose(detailController);
+		
+		OLATResourceable ores = OresHelper.createOLATResourceableInstance(Order.class, order.getOrder().getKey());
+		WindowControl bwControl = addToHistory(ureq, ores, null);
+		detailController = new OrderDetailController(ureq, bwControl, order.getOrder(), order.getTransactions());
+		listenTo(detailController);
+		mainPanel.setContent(detailController.getInitialComponent());
+	}
+
+	@Override
+	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
+		if(state != null) {
+			if(searchForm.setStateEntry(state)) {
+				loadModel();
+			}
+		}
+
+		if(entries == null || entries.isEmpty()) return;
+		
+		Long orderKey = entries.get(0).getOLATResourceable().getResourceableId();
+		OrdersDataModel model = (OrdersDataModel)tableCtr.getTableDataModel();
+		OrderTableItem order = model.getItem(orderKey);
+		if(order != null) {
+			selectOrder(ureq, order);
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/OrdersController.java b/src/main/java/org/olat/resource/accesscontrol/ui/OrdersController.java
new file mode 100644
index 0000000000000000000000000000000000000000..d706eb73f2b2f938f4c26a0d760b2a9a1c609147
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/OrdersController.java
@@ -0,0 +1,195 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.ui;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.gui.ShortName;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.panel.Panel;
+import org.olat.core.gui.components.table.ColumnDescriptor;
+import org.olat.core.gui.components.table.CustomRenderColumnDescriptor;
+import org.olat.core.gui.components.table.DefaultColumnDescriptor;
+import org.olat.core.gui.components.table.StaticColumnDescriptor;
+import org.olat.core.gui.components.table.Table;
+import org.olat.core.gui.components.table.TableController;
+import org.olat.core.gui.components.table.TableEvent;
+import org.olat.core.gui.components.table.TableGuiConfiguration;
+import org.olat.core.gui.components.velocity.VelocityContainer;
+import org.olat.core.gui.control.Controller;
+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.gui.control.generic.dtabs.Activateable2;
+import org.olat.core.id.OLATResourceable;
+import org.olat.core.id.context.ContextEntry;
+import org.olat.core.id.context.StateEntry;
+import org.olat.core.util.resource.OresHelper;
+import org.olat.resource.accesscontrol.AccessControlModule;
+import org.olat.resource.accesscontrol.manager.ACFrontendManager;
+import org.olat.resource.accesscontrol.model.AccessTransaction;
+import org.olat.resource.accesscontrol.model.Order;
+import org.olat.resource.accesscontrol.model.OrderStatus;
+import org.olat.resource.accesscontrol.model.PSPTransaction;
+import org.olat.resource.accesscontrol.ui.OrdersDataModel.Col;
+
+/**
+ * 
+ * Description:<br>
+ * List the orders
+ * 
+ * <P>
+ * Initial Date:  20 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class OrdersController extends BasicController implements Activateable2 {
+	
+	private static final String CMD_SELECT = "sel";
+
+	private final Panel mainPanel;
+	private final VelocityContainer mainVC;
+	private final TableController tableCtr;
+	private OrderDetailController detailController;
+	
+	private final AccessControlModule acModule;
+	private final ACFrontendManager acFrontendManager;
+	
+	public OrdersController(UserRequest ureq, WindowControl wControl) {
+		super(ureq, wControl);
+
+		acModule = (AccessControlModule)CoreSpringFactory.getBean("acModule");
+		acFrontendManager = (ACFrontendManager)CoreSpringFactory.getBean("acFrontendManager");
+
+		TableGuiConfiguration tableConfig = new TableGuiConfiguration();
+		tableConfig.setDownloadOffered(true);
+		tableConfig.setPreferencesOffered(true, "Orders");		
+		tableConfig.setTableEmptyMessage(translate("table.order.empty"));
+		
+		List<ShortName> statusList = new ArrayList<ShortName>(); 
+		OrderStatusContextShortName payedStatus = new OrderStatusContextShortName(translate("order.status.payed"), OrderStatus.PAYED);
+		OrderStatusContextShortName errorStatus = new OrderStatusContextShortName(translate("order.status.error"), OrderStatus.ERROR);
+		statusList.add(payedStatus);
+		statusList.add(errorStatus);
+
+		tableCtr = new TableController(tableConfig, ureq, wControl, statusList, payedStatus, translate("order.status"), null, false, getTranslator());
+		tableCtr.addColumnDescriptor(new CustomRenderColumnDescriptor("order.status", Col.status.ordinal(), null, getLocale(),
+				ColumnDescriptor.ALIGNMENT_LEFT, new OrderStatusRenderer()) {
+			@Override
+			public int compareTo(int rowa, int rowb) {
+				OrderTableItem a = (OrderTableItem)table.getTableDataModel().getValueAt(rowa, dataColumn);
+				OrderTableItem b = (OrderTableItem)table.getTableDataModel().getValueAt(rowb, dataColumn);
+				return a.compareStatusTo(b);
+			}
+		});
+		tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("order.nr", Col.orderNr.ordinal(), CMD_SELECT, getLocale()));
+		tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("order.creationDate", Col.creationDate.ordinal(), null, getLocale()));
+		tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("order.summary", Col.summary.ordinal(), null, getLocale()));
+		tableCtr.addColumnDescriptor(new CustomRenderColumnDescriptor("order.part.payment", Col.methods.ordinal(), null, getLocale(), 
+				ColumnDescriptor.ALIGNMENT_LEFT, new AccessMethodRenderer(acModule)));
+		
+		tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("order.total", Col.total.ordinal(), null, getLocale()));
+		
+		tableCtr.addColumnDescriptor(new StaticColumnDescriptor(CMD_SELECT, "table.order.details", getTranslator().translate("order.details")));
+		
+		listenTo(tableCtr);
+		
+		loadModel();
+		
+		mainVC = createVelocityContainer("orders");
+		mainVC.put("orderList", tableCtr.getInitialComponent());
+		mainVC.contextPut("title", translate("orders.my"));
+		mainVC.contextPut("description", translate("orders.my.desc"));
+
+		mainPanel = putInitialPanel(mainVC);
+	}
+	
+	private void loadModel() {
+		OrderStatusContextShortName filter = (OrderStatusContextShortName)tableCtr.getActiveFilter();
+		List<Order> orders = acFrontendManager.findOrders(getIdentity(), filter.getStatus());
+		List<AccessTransaction> transactions = acFrontendManager.findAccessTransactions(orders);
+		List<PSPTransaction> pspTransactions = acFrontendManager.findPSPTransactions(orders);
+		List<OrderTableItem> items = OrdersDataModel.create(orders, transactions, pspTransactions);
+		tableCtr.setTableDataModel(new OrdersDataModel(items, getLocale()));
+	}
+	
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Component source, Event event) {
+		//
+	}
+	
+	@Override
+	protected void event(UserRequest ureq, Controller source, Event event) {
+		if(source == tableCtr) {
+			if (event.getCommand().equals(Table.COMMANDLINK_ROWACTION_CLICKED)) {
+				TableEvent te = (TableEvent) event;
+				String actionid = te.getActionId();
+				int rowid = te.getRowId();
+				OrderTableItem order = (OrderTableItem)tableCtr.getTableDataModel().getObject(rowid);
+				if(CMD_SELECT.equals(actionid)) {
+					selectOrder(ureq, order);
+				}
+			} else if (TableController.EVENT_FILTER_SELECTED == event) {
+				loadModel();
+			}
+		} else if (source == detailController) {
+			if(event == Event.BACK_EVENT) {
+				mainPanel.setContent(mainVC);
+				removeAsListenerAndDispose(detailController);
+				detailController = null;
+			}
+		}
+	}
+	
+	@Override
+	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
+		if(entries == null || entries.isEmpty()) return;
+		
+		ContextEntry entry = entries.get(0);
+		String type = entry.getOLATResourceable().getResourceableTypeName();
+		if(Order.class.getSimpleName().equals(type)) {
+			for(int i=tableCtr.getTableDataModel().getRowCount(); i-->0; ) {
+				OrderTableItem order = (OrderTableItem)tableCtr.getTableDataModel().getObject(i);
+				if(order.getOrder().getKey().equals(entry.getOLATResourceable().getResourceableId())) {
+					selectOrder(ureq, order);
+					break;
+				}
+			}
+		}
+	}
+
+	protected void selectOrder(UserRequest ureq, OrderTableItem order) {
+		removeAsListenerAndDispose(detailController);
+
+		//fxdiff BAKS-7 Resume function
+		OLATResourceable ores = OresHelper.createOLATResourceableInstance(Order.class, order.getOrder().getKey());
+		WindowControl bwControl = addToHistory(ureq, ores, null);
+		detailController = new OrderDetailController(ureq, bwControl, order.getOrder(), order.getTransactions());
+		listenTo(detailController);
+		mainPanel.setContent(detailController.getInitialComponent());
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/OrdersDataModel.java b/src/main/java/org/olat/resource/accesscontrol/ui/OrdersDataModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..ae393a0493808f384829b92f6ad4b2abad9c9bcf
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/OrdersDataModel.java
@@ -0,0 +1,172 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.ui;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.gui.components.table.TableDataModel;
+import org.olat.core.id.User;
+import org.olat.core.id.UserConstants;
+import org.olat.core.util.StringHelper;
+import org.olat.resource.accesscontrol.AccessControlModule;
+import org.olat.resource.accesscontrol.model.AccessTransaction;
+import org.olat.resource.accesscontrol.model.Order;
+import org.olat.resource.accesscontrol.model.OrderLine;
+import org.olat.resource.accesscontrol.model.OrderPart;
+import org.olat.resource.accesscontrol.model.PSPTransaction;
+
+/**
+ * 
+ * Description:<br>
+ * A data model which hold the orders and their transactions
+ * 
+ * <P>
+ * Initial Date:  20 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class OrdersDataModel implements TableDataModel {
+	
+	private final Locale locale;
+	private List<OrderTableItem> orders;
+	private final AccessControlModule acModule;
+	
+	public OrdersDataModel(List<OrderTableItem> orders, Locale locale) {
+		this.orders = orders;
+		this.locale = locale;
+		acModule = (AccessControlModule)CoreSpringFactory.getBean("acModule");
+	}
+
+	@Override
+	public int getColumnCount() {
+		return 1;
+	}
+
+	@Override
+	public int getRowCount() {
+		return orders.size();
+	}
+
+	@Override
+	public Object getValueAt(int row, int col) {
+		OrderTableItem order = orders.get(row);
+		switch(Col.get(col)) {
+			case status: {
+				return order;
+			}
+			case orderNr: return order.getOrder().getOrderNr();
+			case creationDate: return order.getOrder().getCreationDate();
+			case delivery: {
+				User user = order.getOrder().getDelivery().getUser();
+				return user.getProperty(UserConstants.FIRSTNAME, null) + " " + user.getProperty(UserConstants.LASTNAME, null);
+			}
+			case methods: {
+				return order.getTransactions();
+			}
+			case total: {
+				String total = PriceFormat.fullFormat(order.getOrder().getTotal());
+				if(StringHelper.containsNonWhitespace(total)) {
+					return total;
+				}
+				return "-";
+			}
+			case summary: {
+				StringBuilder sb = new StringBuilder();
+				for(OrderPart part:order.getOrder().getParts()) {
+					for(OrderLine lines:part.getOrderLines()) {
+						String displayName = lines.getOffer().getResourceDisplayName();
+						if(sb.length() > 0) {
+							sb.append(", ");
+						}
+						sb.append(displayName);
+					}
+				}
+				return sb.toString();
+			}
+			default: return order;
+		}
+	}
+
+	@Override
+	public OrderTableItem getObject(int row) {
+		return orders.get(row);
+	}
+	
+	public OrderTableItem getItem(Long key) {
+		if(orders == null) return null;
+		for(OrderTableItem item:orders) {
+			if(item.getOrder().getKey().equals(key)) {
+				return item;
+			}
+		}
+		return null;
+	}
+
+	@Override
+	public void setObjects(List objects) {
+		this.orders = objects;
+	}
+
+	@Override
+	public Object createCopyWithEmptyList() {
+		return new OrdersDataModel(Collections.<OrderTableItem>emptyList(), locale);
+	}
+	
+	
+	public static List<OrderTableItem> create(List<Order> orders, List<AccessTransaction> transactions, List<PSPTransaction> pspTransactions) {
+		List<OrderTableItem> items = new ArrayList<OrderTableItem>();
+		
+		for(Order order:orders) {
+			OrderTableItem item = new OrderTableItem(order);
+			for(AccessTransaction transaction:transactions) {
+				if(transaction.getOrder().equals(order)) {
+					item.getTransactions().add(transaction);
+				}
+			}
+			for(PSPTransaction transaction:pspTransactions) {
+				if(transaction.getOrderId().equals(order.getKey())) {
+					item.getPSPTransactions().add(transaction);
+				}
+			}
+			
+			items.add(item);
+		}
+		
+		return items;
+	}
+	
+	public enum Col {
+		orderNr,
+		creationDate,
+		delivery,
+		methods,
+		total,
+		summary,
+		status;
+
+		public static Col get(int index) {
+			return values()[index];
+		}
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/OrdersSearchForm.java b/src/main/java/org/olat/resource/accesscontrol/ui/OrdersSearchForm.java
new file mode 100644
index 0000000000000000000000000000000000000000..729fdabc7ba3b91dedba36e93b2dc0e603458f56
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/OrdersSearchForm.java
@@ -0,0 +1,145 @@
+/**
+ * OLAT - Online Learning and Training<br>
+ * http://www.olat.org
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Copyright (c) frentix GmbH<br>
+ * http://www.frentix.com<br>
+ * <p>
+ */
+package org.olat.resource.accesscontrol.ui;
+
+import java.util.Date;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.DateChooser;
+import org.olat.core.gui.components.form.flexible.elements.TextElement;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.id.context.StateEntry;
+import org.olat.core.id.context.StateMapped;
+import org.olat.core.util.StringHelper;
+
+/**
+ * 
+ * Description:<br>
+ * The mask to search for orders
+ * 
+ * <P>
+ * Initial Date:  30 mai 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class OrdersSearchForm extends FormBasicController {
+
+	private DateChooser toEl;
+	private DateChooser fromEl;
+	private TextElement refNoEl;
+	
+	public OrdersSearchForm(UserRequest ureq, WindowControl wControl) {
+		super(ureq, wControl);
+		
+		initForm(ureq);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		refNoEl = uifactory.addTextElement("order.nr", "order.nr", 32, "", formLayout);
+		fromEl = uifactory.addDateChooser("order.from", null, formLayout);
+		toEl = uifactory.addDateChooser("order.to", null, formLayout);
+		
+		FormLayoutContainer buttonCont = FormLayoutContainer.createButtonLayout("searchLayout", getTranslator());
+		buttonCont.setRootForm(mainForm);
+		formLayout.add(buttonCont);
+		uifactory.addFormSubmitButton("search", "search", buttonCont);
+		
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+	
+	public StateEntry getStateEntry() {
+		StateMapped entry = new StateMapped();
+		Long refNo = getRefNo();
+		if(refNo != null) {
+			entry.getDelegate().put("refNo", refNo.toString());
+		}
+		String fromStr = fromEl.getValue();
+		if(StringHelper.containsNonWhitespace(fromStr)) {
+			entry.getDelegate().put("from", fromStr);
+		}
+		String toStr = toEl.getValue();
+		if(StringHelper.containsNonWhitespace(toStr)) {
+			entry.getDelegate().put("to", toStr);
+		}
+		return entry;
+	}
+	
+	public boolean setStateEntry(StateEntry state) {
+		boolean changed = false;
+		
+		if(state instanceof StateMapped) {
+			StateMapped map = (StateMapped)state;
+			String refNo = map.getDelegate().get("refNo");
+			if(StringHelper.containsNonWhitespace(refNo)) {
+				refNoEl.setValue(refNo);
+				changed = true;
+			}
+			
+			String fromStr = map.getDelegate().get("from");
+			if(StringHelper.containsNonWhitespace(fromStr)) {
+				fromEl.setValue(fromStr);
+				changed = true;
+			}
+			
+			String toStr = map.getDelegate().get("to");
+			if(StringHelper.containsNonWhitespace(toStr)) {
+				toEl.setValue(toStr);
+				changed = true;
+			}
+		}
+		
+		return changed;
+	}
+	
+	public Long getRefNo() {
+		String no = refNoEl.getValue();
+		if(StringHelper.containsNonWhitespace(no)) {
+			try {
+				return Long.parseLong(no);
+			} catch (NumberFormatException e) {
+				//
+			}
+		}
+		return null;
+	}
+
+	public Date getTo() {
+		return toEl.getDate();
+	}
+
+	public Date getFrom() {
+		return fromEl.getDate();
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		fireEvent(ureq, Event.DONE_EVENT);
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/PriceCellRenderer.java b/src/main/java/org/olat/resource/accesscontrol/ui/PriceCellRenderer.java
new file mode 100644
index 0000000000000000000000000000000000000000..bb58f3f2e16b8ff4a5ae60fbd6289786b926bd47
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/PriceCellRenderer.java
@@ -0,0 +1,53 @@
+/**
+ * OLAT - Online Learning and Training<br>
+ * http://www.olat.org
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Copyright (c) frentix GmbH<br>
+ * http://www.frentix.com<br>
+ * <p>
+ */
+package org.olat.resource.accesscontrol.ui;
+
+import java.util.Locale;
+
+import org.olat.core.gui.components.table.CustomCellRenderer;
+import org.olat.core.gui.render.Renderer;
+import org.olat.core.gui.render.StringOutput;
+import org.olat.resource.accesscontrol.model.Price;
+
+/**
+ * 
+ * Description:<br>
+ * Render the type of an access method
+ * 
+ * <P>
+ * Initial Date:  27 mai 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class PriceCellRenderer implements CustomCellRenderer {
+
+	public PriceCellRenderer() {
+		//
+	}
+	
+	@Override
+	public void render(StringOutput sb, Renderer renderer, Object val, Locale locale, int alignment, String action) {
+		if(val instanceof Price) {
+			Price amount = (Price)val;
+			sb.append(PriceFormat.fullFormat(amount));
+		}
+	}
+
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/PriceFormat.java b/src/main/java/org/olat/resource/accesscontrol/ui/PriceFormat.java
new file mode 100644
index 0000000000000000000000000000000000000000..bb6f627af5d0a9df7a1959cd3bfb29994a2c7504
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/PriceFormat.java
@@ -0,0 +1,114 @@
+/**
+ * OLAT - Online Learning and Training<br>
+ * http://www.olat.org
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Copyright (c) frentix GmbH<br>
+ * http://www.frentix.com<br>
+ * <p>
+ */
+package org.olat.resource.accesscontrol.ui;
+
+import java.math.BigDecimal;
+
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
+import org.olat.resource.accesscontrol.model.Price;
+
+/**
+ * 
+ * Description:<br>
+ * Format the price
+ * 
+ * <P>
+ * Initial Date:  26 mai 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, htttp://www.frentix.com
+ */
+public class PriceFormat {
+	private static final OLog log = Tracing.createLoggerFor(PriceFormat.class);
+
+
+	//private static final String[] tests = new String[]{"1'000.00", "1'000,00","1,000,-","1,000.-","1.000","1000","1000.00","1000,00","1000.-","1000,-"};
+
+	public static void parse(Price price, String value) {
+		try {
+			if(value != null && value.length() > 0) {
+				value = extractNumbers(value);
+			}
+				
+			if(value != null && value.length() > 0) {
+				double val = Double.parseDouble(value);
+				BigDecimal bd = new BigDecimal(val);
+				price.setAmount(bd.setScale(2, BigDecimal.ROUND_HALF_UP));
+			} else {
+				price.setAmount(BigDecimal.ZERO);
+			}
+		} catch (NumberFormatException e) {
+			log.error("Cannot format this value: " + value);
+		}  
+	}
+	
+	public static BigDecimal parse(String value) {
+		if(value != null && value.length() > 0) {
+			value = extractNumbers(value);
+			
+			double val = Double.parseDouble(value);
+			BigDecimal bd = new BigDecimal(val);
+			return bd.setScale(2, BigDecimal.ROUND_HALF_UP);
+		}
+		return BigDecimal.ZERO;
+	}
+	
+	private static String extractNumbers(String value) {
+		StringBuffer buffer = new StringBuffer();
+		for(int i=0; i<value.length(); i++) {
+			char ch = value.charAt(i);
+			if(Character.isDigit(ch)) {
+				buffer.append(ch);
+			} else if(ch == '.') {
+				buffer.append(ch);
+			} else if(ch == ',') {
+				buffer.append('.');
+			}
+		}
+		return buffer.toString();
+	}
+	
+	public static String format(Price price) {
+		if(price == null) {
+			return "";
+		}
+		if(price.getAmount() == null) {
+			return "";
+		}
+		return format(price.getAmount());
+	}
+	
+	public static String format(BigDecimal value) {
+		return value.setScale(2).toString();
+	}
+	
+	public static String fullFormat(Price price) {
+		if(price == null || price.getAmount() == null) {
+			return "";
+		}
+		
+		String isoCurrencyCode = price.getCurrencyCode();
+		if (isoCurrencyCode == null) {
+			isoCurrencyCode = "CHF";
+		}
+
+		return isoCurrencyCode + '\u00A0' + price.getAmount().setScale(2, BigDecimal.ROUND_HALF_EVEN).toString();
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/RepositoryMainAccessControllerWrapper.java b/src/main/java/org/olat/resource/accesscontrol/ui/RepositoryMainAccessControllerWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..9cea0d687ddf55cc52800a396f21c4a7323e3971
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/RepositoryMainAccessControllerWrapper.java
@@ -0,0 +1,139 @@
+package org.olat.resource.accesscontrol.ui;
+
+import java.util.List;
+
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.htmlheader.jscss.CustomCSS;
+import org.olat.core.gui.components.panel.Panel;
+import org.olat.core.gui.components.velocity.VelocityContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.controller.MainLayoutBasicController;
+import org.olat.core.gui.control.generic.dtabs.Activateable;
+import org.olat.core.gui.control.generic.dtabs.Activateable2;
+import org.olat.core.gui.control.generic.layout.MainLayoutController;
+import org.olat.core.id.OLATResourceable;
+import org.olat.core.id.context.ContextEntry;
+import org.olat.core.id.context.StateEntry;
+import org.olat.core.util.StringHelper;
+import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryManager;
+import org.olat.resource.accesscontrol.ACUIFactory;
+import org.olat.resource.accesscontrol.AccessResult;
+import org.olat.resource.accesscontrol.manager.ACFrontendManager;
+
+/**
+ * 
+ * Description:<br>
+ *  It's a wrapper to manage the acces to repository entries
+ * 
+ * <P>
+ * Initial Date:  9 mai 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class RepositoryMainAccessControllerWrapper extends MainLayoutBasicController implements Activateable, Activateable2 {
+
+	private final Panel contentP;
+	private VelocityContainer mainVC;
+	private Controller accessController;
+	private final MainLayoutController resController;
+
+	public RepositoryMainAccessControllerWrapper(UserRequest ureq, WindowControl wControl, OLATResourceable res, MainLayoutController resController) {
+		super(ureq, wControl);
+		
+		contentP = new Panel("wrapperPanel");
+		this.resController = resController;
+		
+		if(ureq.getUserSession().getRoles().isOLATAdmin()) {
+			contentP.setContent(resController.getInitialComponent());
+		} else {
+			RepositoryEntry re = RepositoryManager.getInstance().lookupRepositoryEntry(res, false);
+			// guest are allowed to see resource with BARG 
+			if(re.getAccess() == RepositoryEntry.ACC_USERS_GUESTS && ureq.getUserSession().getRoles().isGuestOnly()) {
+				contentP.setContent(resController.getInitialComponent());
+			} else {
+				ACFrontendManager acFrontendManager = (ACFrontendManager)CoreSpringFactory.getBean("acFrontendManager");
+				AccessResult acResult = acFrontendManager.isAccessible(re, getIdentity(), false);
+				if(acResult.isAccessible()) {
+					contentP.setContent(resController.getInitialComponent());
+				} else if (re != null && acResult.getAvailableMethods().size() > 0) {
+					accessController = ACUIFactory.createAccessController(ureq, getWindowControl(), acResult.getAvailableMethods());
+					listenTo(accessController);
+					mainVC = createVelocityContainer("access_wrapper");
+					mainVC.put("accessPanel", accessController.getInitialComponent());
+					contentP.setContent(mainVC);
+				} else {
+					mainVC = createVelocityContainer("access_refused");
+					contentP.setContent(mainVC);
+					wControl.setWarning(translate("course.closed"));
+				}
+			}
+		}
+		putInitialPanel(contentP);
+	}
+	
+	protected void openContent(UserRequest ureq) {
+		contentP.setContent(resController.getInitialComponent());
+	}
+	
+	@Override
+	public CustomCSS getCustomCSS() {
+		return resController == null ? null : resController.getCustomCSS();
+	}
+
+	@Override
+	public void setCustomCSS(CustomCSS newCustomCSS) {
+		if(resController != null) {
+			resController.setCustomCSS(newCustomCSS);
+		}
+	}
+	
+	@Override
+	public void activate(UserRequest ureq, String viewIdentifier) {
+		if(resController instanceof Activateable) {
+			((Activateable)resController).activate(ureq, viewIdentifier);
+		}
+	}
+
+	@Override
+	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
+		if(resController instanceof Activateable2) {
+			((Activateable2)resController).activate(ureq, entries, state);
+		}
+	}
+
+	@Override
+	protected void doDispose() {
+		if(resController != null && !resController.isDisposed()) {
+			resController.dispose();
+		}
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Component source, Event event) {
+		if(source == resController) {
+			fireEvent(ureq, event);
+		}
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Controller source, Event event) {
+		if (source == accessController) {
+			if(event.equals(AccessEvent.ACCESS_OK_EVENT)) {
+				openContent(ureq);
+				removeAsListenerAndDispose(accessController);
+				accessController = null;
+			} else if(event.equals(AccessEvent.ACCESS_FAILED_EVENT)) {
+				String msg = ((AccessEvent)event).getMessage();
+				if(StringHelper.containsNonWhitespace(msg)) {
+					getWindowControl().setError(msg);
+				} else {
+					showError("error.accesscontrol");
+				}
+			}
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/SecurityGroupMembersController.java b/src/main/java/org/olat/resource/accesscontrol/ui/SecurityGroupMembersController.java
new file mode 100644
index 0000000000000000000000000000000000000000..07875730287720d8ceb8cae121afd20732795e35
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/SecurityGroupMembersController.java
@@ -0,0 +1,87 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.ui;
+
+import org.olat.admin.securitygroup.gui.GroupController;
+import org.olat.admin.securitygroup.gui.IdentitiesAddEvent;
+import org.olat.admin.securitygroup.gui.IdentitiesRemoveEvent;
+import org.olat.basesecurity.SecurityGroup;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.velocity.VelocityContainer;
+import org.olat.core.gui.control.Controller;
+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.util.StringHelper;
+
+/**
+ * 
+ * Description:<br>
+ * Show and manage the members of a security group
+ * 
+ * <P>
+ * Initial Date:  15 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class SecurityGroupMembersController extends BasicController {
+
+	private final VelocityContainer mainVC;
+	
+	public SecurityGroupMembersController(UserRequest ureq, WindowControl wControl, SecurityGroup secGroup, 
+			String title, String info, boolean mayModifierMembers, boolean keepAtLeastOne) {
+		super(ureq, wControl);
+
+		mainVC = createVelocityContainer("members");
+
+		GroupController groupController = new GroupController(ureq, wControl, mayModifierMembers, keepAtLeastOne, false, secGroup);
+		listenTo(groupController);
+		
+		mainVC.put("memberList", groupController.getInitialComponent());
+		if(StringHelper.containsNonWhitespace(title)) {
+			mainVC.contextPut("title", title);			
+		}
+		if(StringHelper.containsNonWhitespace(info)) {
+			mainVC.contextPut("info", info);			
+		}
+		putInitialPanel(mainVC);
+	}
+	
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Controller source, Event event) {
+		if(event instanceof IdentitiesAddEvent) {
+			fireEvent(ureq, event);
+		} else if(event instanceof IdentitiesRemoveEvent) {
+			fireEvent(ureq, event);
+		} else {
+			super.event(ureq, source, event);
+		}
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Component source, Event event) {
+		//
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/SecurityGroupsRepositoryMainController.java b/src/main/java/org/olat/resource/accesscontrol/ui/SecurityGroupsRepositoryMainController.java
new file mode 100644
index 0000000000000000000000000000000000000000..206f0b835a9d64357c69d9cf6578982bd9525de3
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/SecurityGroupsRepositoryMainController.java
@@ -0,0 +1,344 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.ui;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.olat.admin.securitygroup.gui.IdentitiesAddEvent;
+import org.olat.admin.securitygroup.gui.IdentitiesRemoveEvent;
+import org.olat.basesecurity.BaseSecurity;
+import org.olat.basesecurity.BaseSecurityManager;
+import org.olat.basesecurity.SecurityGroup;
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.commons.fullWebApp.LayoutMain3ColsController;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.panel.Panel;
+import org.olat.core.gui.components.tree.GenericTreeModel;
+import org.olat.core.gui.components.tree.GenericTreeNode;
+import org.olat.core.gui.components.tree.MenuTree;
+import org.olat.core.gui.components.tree.TreeNode;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.controller.MainLayoutBasicController;
+import org.olat.core.gui.control.generic.tool.ToolController;
+import org.olat.core.gui.control.generic.tool.ToolFactory;
+import org.olat.core.id.Identity;
+import org.olat.core.logging.activity.ActionType;
+import org.olat.core.util.nodes.INode;
+import org.olat.course.CourseFactory;
+import org.olat.course.ICourse;
+import org.olat.course.groupsandrights.CourseGroupManager;
+import org.olat.group.BusinessGroup;
+import org.olat.group.BusinessGroupAddResponse;
+import org.olat.group.BusinessGroupManager;
+import org.olat.group.BusinessGroupManagerImpl;
+import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryManager;
+import org.olat.resource.accesscontrol.AccessControlModule;
+import org.olat.util.logging.activity.LoggingResourceable;
+
+/**
+ * 
+ * Description:<br>
+ * Show and manage security groups of a repository entry
+ * 
+ * <P>
+ * Initial Date:  20 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class SecurityGroupsRepositoryMainController extends MainLayoutBasicController {
+	
+	private static final String CMD_CLOSE = "cmd.close";
+	private static final String CMD_OWNERS = "owners";
+	private static final String CMD_TUTORS = "tutors";
+	private static final String CMD_PARTICIPANTS = "participants";
+	private static final String CMD_ORDERS = "orders";
+
+	private LayoutMain3ColsController columnLayoutCtr;
+	private MenuTree menuTree;
+	private ToolController toolC;
+
+	private final Panel mainPanel;
+	private SecurityGroupMembersController ownersController;
+	private SecurityGroupMembersController tutorsController;
+	private SecurityGroupMembersController participantsController;
+	private OrdersAdminController ordersController;
+	
+	private final RepositoryEntry repoEntry;
+	private final RepositoryManager rm;
+	private final BusinessGroupManager bgm;
+	private final BaseSecurity securityManager;
+	private final AccessControlModule acModule;
+	
+	private final boolean mayModifyMembers;
+	
+	/**
+	 * Constructor for the course group management main controller
+	 * 
+	 * @param ureq
+	 * @param wControl
+	 * @param course
+	 * @param groupType
+	 */
+	public SecurityGroupsRepositoryMainController(UserRequest ureq, WindowControl wControl, ICourse course,
+			RepositoryEntry repoEntry, boolean mayModifyMembers) {
+		super(ureq, wControl);
+		
+		this.repoEntry = repoEntry;
+		this.mayModifyMembers = mayModifyMembers;
+		bgm = BusinessGroupManagerImpl.getInstance();
+		securityManager = BaseSecurityManager.getInstance();
+		acModule = (AccessControlModule)CoreSpringFactory.getBean("acModule");
+		
+		getUserActivityLogger().setStickyActionType(ActionType.admin);
+		
+		addLoggingResourceable(LoggingResourceable.wrap(course));
+		
+		//lazy build security groups
+		rm = RepositoryManager.getInstance();
+		if(repoEntry.getParticipantGroup() == null || repoEntry.getTutorGroup() == null){
+			lazyUpdateRepositoryEntry();
+		}
+		
+		// Navigation menu
+		menuTree = new MenuTree("menuTree");
+		menuTree.setTreeModel(buildTreeModel());
+		menuTree.addListener(this);
+		INode firstChild = menuTree.getTreeModel().getRootNode().getChildAt(0);
+		if (firstChild != null) {
+			menuTree.setSelectedNodeId(firstChild.getIdent());			
+		}
+		
+		//add tools (close)
+		toolC = ToolFactory.createToolController(getWindowControl());
+		listenTo(toolC);
+		toolC.addHeader(translate("cmd.title"));
+		toolC.addLink(CMD_CLOSE, translate(CMD_CLOSE), null, "b_toolbox_close");
+		
+		//now build layout controller
+		mainPanel = new Panel("MainSecGroups");
+		columnLayoutCtr = new LayoutMain3ColsController(ureq, getWindowControl(), menuTree, toolC.getInitialComponent(), mainPanel, "SecGroups" + repoEntry.getKey());
+		listenTo(columnLayoutCtr);
+		
+		//select the initial controller
+		TreeNode initialNode = menuTree.getSelectedNode();
+		if(initialNode != null) {
+			Object cmd = initialNode.getDelegate() != null ? initialNode.getDelegate().getUserObject() : initialNode.getUserObject(); 
+			selectSecurityGroup(ureq, cmd);
+		} else {
+			mainPanel.setContent(new Panel("empty"));
+		}
+
+		putInitialPanel(columnLayoutCtr.getInitialComponent());
+	}
+	
+	private void lazyUpdateRepositoryEntry() {
+		if(repoEntry.getTutorGroup() == null){
+			rm.createTutorSecurityGroup(repoEntry);
+		}
+		if(repoEntry.getParticipantGroup() == null) {
+			rm.createParticipantSecurityGroup(repoEntry);
+		}
+		rm.updateRepositoryEntry(repoEntry);
+	}
+
+	private GenericTreeModel buildTreeModel() {
+		GenericTreeModel gtm = new GenericTreeModel();
+		GenericTreeNode root = new GenericTreeNode();
+		root.setTitle(translate("members.title"));
+		root.setAltText(translate("members.title.alt"));
+		gtm.setRootNode(root);
+		
+		if(repoEntry.getOwnerGroup() != null) {
+			GenericTreeNode node = new GenericTreeNode(translate("members.owners"), CMD_OWNERS);
+			node.setAltText(translate("members.owners.alt"));
+			root.addChild(node);
+			root.setDelegate(node);
+		}
+		
+		if(repoEntry.getTutorGroup() != null) {
+			GenericTreeNode node = new GenericTreeNode(translate("members.tutors"), CMD_TUTORS);
+			node.setAltText(translate("members.tutors.alt"));
+			root.addChild(node);
+			if(root.getDelegate() == null) {
+				root.setDelegate(node);
+			}
+		}
+		
+		if(repoEntry.getParticipantGroup() != null) {
+			GenericTreeNode node = new GenericTreeNode(translate("members.participants"), CMD_PARTICIPANTS);
+			node.setAltText(translate("members.participants.alt"));
+			root.addChild(node);
+			if(root.getDelegate() == null) {
+				root.setDelegate(node);
+			}
+		}
+		
+		if(acModule.isEnabled()) {
+			GenericTreeNode node = new GenericTreeNode(translate("menu.orders"), CMD_ORDERS);
+			node.setAltText(translate("menu.orders.alt"));
+			root.addChild(node);
+			if(root.getDelegate() == null) {
+				root.setDelegate(node);
+			}
+		}
+		
+		return gtm;
+	}
+	
+	protected void doDispose() {
+		//
+	}
+
+	/**
+	 * @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)
+	 */
+	public void event(UserRequest ureq, Component source, Event event) {
+		if (source == menuTree) {
+			if (event.getCommand().equals(MenuTree.COMMAND_TREENODE_CLICKED)) {
+				TreeNode selTreeNode = menuTree.getSelectedNode();				
+				Object cmd = selTreeNode.getUserObject();
+				selectSecurityGroup(ureq, cmd);
+	
+				// visually select delegate
+				if (selTreeNode.getDelegate() != null) {
+					menuTree.setSelectedNodeId(selTreeNode.getDelegate().getIdent());
+				}
+			}
+		}
+	}
+	
+	private void selectSecurityGroup(UserRequest ureq, Object cmd) {
+		if(CMD_OWNERS.equals(cmd)) {
+			if(ownersController != null) {
+				removeAsListenerAndDispose(ownersController);
+			}
+			String title = translate("members.owners");
+			String info = translate("members.owners.info");
+			ownersController = new SecurityGroupMembersController(ureq, getWindowControl(), repoEntry.getOwnerGroup(), title, info, mayModifyMembers, true);
+			listenTo(ownersController);
+			mainPanel.setContent(ownersController.getInitialComponent());
+		} else if(CMD_TUTORS.equals(cmd)) {
+			if(tutorsController != null) {
+				removeAsListenerAndDispose(tutorsController);
+			}
+			String title = translate("members.tutors");
+			String info = translate("members.tutors.info");
+			tutorsController = new SecurityGroupMembersController(ureq, getWindowControl(), repoEntry.getTutorGroup(), title, info, mayModifyMembers, false);
+			listenTo(tutorsController);
+			mainPanel.setContent(tutorsController.getInitialComponent());
+		} else  if(CMD_PARTICIPANTS.equals(cmd)) {
+			if(participantsController != null) {
+				removeAsListenerAndDispose(participantsController);
+			}
+			String title = translate("members.participants");
+			String info = translate("members.participants.info");
+			participantsController = new SecurityGroupMembersController(ureq, getWindowControl(), repoEntry.getParticipantGroup(), title, info, mayModifyMembers, false);
+			listenTo(participantsController);
+			mainPanel.setContent(participantsController.getInitialComponent());
+		} else if (CMD_ORDERS.equals(cmd)) {
+			if(ordersController != null) {
+				removeAsListenerAndDispose(ordersController);
+			}
+
+			ordersController = new OrdersAdminController(ureq, getWindowControl(), repoEntry.getOlatResource());
+			listenTo(ordersController);
+			mainPanel.setContent(ordersController.getInitialComponent());
+		}
+	}
+
+	/**
+	 * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest,
+	 *      org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event)
+	 */
+	public void event(UserRequest ureq, Controller source, Event event) {
+		if (source == toolC) {
+			if (event.getCommand().equals(CMD_CLOSE)) {
+				fireEvent(ureq, Event.DONE_EVENT);
+			}
+		} else if(event instanceof IdentitiesAddEvent) {
+			IdentitiesAddEvent identitiesAddedEvent = (IdentitiesAddEvent) event;
+			SecurityGroup secGroup = null;
+			if (source == ownersController) {
+				secGroup = repoEntry.getOwnerGroup();
+			} else if (source == tutorsController) {
+				secGroup = repoEntry.getTutorGroup();
+			} else if (source == participantsController) {
+				secGroup = repoEntry.getParticipantGroup();							
+			}
+			BusinessGroupAddResponse response = bgm.addToSecurityGroupAndFireEvent(ureq.getIdentity(), identitiesAddedEvent.getAddIdentities(), secGroup);
+			identitiesAddedEvent.setIdentitiesAddedEvent(response.getAddedIdentities());
+			identitiesAddedEvent.setIdentitiesWithoutPermission(response.getIdentitiesWithoutPermission());
+			identitiesAddedEvent.setIdentitiesAlreadyInGroup(response.getIdentitiesAlreadyInGroup());			
+			fireEvent(ureq, Event.CHANGED_EVENT );
+		} else if(event instanceof IdentitiesRemoveEvent) {
+			IdentitiesRemoveEvent identitiesRemoveEvent = (IdentitiesRemoveEvent)event;
+			List<Identity> identitiesToRemove = identitiesRemoveEvent.getRemovedIdentities();
+			if (source == ownersController) {
+				SecurityGroup ownerGroup = repoEntry.getOwnerGroup();
+				bgm.removeAndFireEvent(ureq.getIdentity(), identitiesToRemove, ownerGroup);
+			} else if (source == tutorsController) {
+				SecurityGroup tutorGroup = repoEntry.getTutorGroup();
+				bgm.removeAndFireEvent(ureq.getIdentity(), identitiesToRemove, tutorGroup);
+				removeTutors(identitiesToRemove);
+			} else if (source == participantsController) {
+				SecurityGroup participantGroup = repoEntry.getParticipantGroup();	
+				bgm.removeAndFireEvent(ureq.getIdentity(), identitiesToRemove, participantGroup);	
+				removeParticipants(identitiesToRemove);
+			}
+		}
+		super.event(ureq, source, event);
+	}
+	
+	private void removeTutors(List<Identity> identitiesToRemove) {
+		for(BusinessGroup group:getCourseGroups()) {
+			for(Identity identityToRemove : identitiesToRemove) {
+				if(securityManager.isIdentityInSecurityGroup(identityToRemove, group.getOwnerGroup())) {
+					securityManager.removeIdentityFromSecurityGroup(identityToRemove, group.getOwnerGroup());
+				}
+			}
+		}
+	}
+	
+	private void removeParticipants(List<Identity> identitiesToRemove) {
+		for(BusinessGroup group:getCourseGroups()) {
+			for(Identity identityToRemove : identitiesToRemove) {
+				if(securityManager.isIdentityInSecurityGroup(identityToRemove, group.getPartipiciantGroup())) {
+					securityManager.removeIdentityFromSecurityGroup(identityToRemove, group.getPartipiciantGroup());
+				}
+			}
+		}
+	}
+	
+	private List<BusinessGroup> getCourseGroups() {
+		if("CourseModule".equals(repoEntry.getOlatResource().getResourceableTypeName())) {
+			ICourse course = CourseFactory.loadCourse(repoEntry.getOlatResource());
+			CourseGroupManager gm = course.getCourseEnvironment().getCourseGroupManager();
+			List<BusinessGroup> groups = gm.getAllLearningGroupsFromAllContexts();
+			return groups;
+		}
+		return Collections.emptyList();
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/TokenAccessConfigurationController.java b/src/main/java/org/olat/resource/accesscontrol/ui/TokenAccessConfigurationController.java
new file mode 100644
index 0000000000000000000000000000000000000000..64e87aed4885edd2064846b49fecfec3fd79e783
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/TokenAccessConfigurationController.java
@@ -0,0 +1,101 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.ui;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.TextElement;
+import org.olat.core.gui.components.form.flexible.impl.Form;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.resource.accesscontrol.model.AccessMethod;
+import org.olat.resource.accesscontrol.model.OfferImpl;
+import org.olat.resource.accesscontrol.model.OfferAccess;
+
+/**
+ * 
+ * Description:<br>
+ * Configuration for a token
+ * 
+ * <P>
+ * Initial Date:  15 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class TokenAccessConfigurationController extends AbstractConfigurationMethodController {
+
+	private TextElement descEl;
+	private TextElement tokenEl;
+	private final OfferAccess link;
+	
+	public TokenAccessConfigurationController(UserRequest ureq, WindowControl wControl, OfferAccess link) {
+		super(ureq, wControl);
+		this.link = link;
+		initForm(ureq);
+	}
+
+	public TokenAccessConfigurationController(UserRequest ureq, WindowControl wControl, OfferAccess link, Form form) {
+		super(ureq, wControl, LAYOUT_DEFAULT, null, form);
+		this.link = link;
+		initForm(ureq);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		
+		descEl = uifactory.addTextAreaElement("offer-desc", "offer.description", 2000, 6, 80, false, null, formLayout);
+		
+		String token = "";
+		if(link.getOffer() instanceof OfferImpl) {
+			token = ((OfferImpl)link.getOffer()).getToken();
+		}
+		tokenEl = uifactory.addTextElement("token", "accesscontrol.token", 255, token, formLayout);
+		
+		super.initForm(formLayout, listener, ureq);
+	}
+	
+	@Override
+	public AccessMethod getMethod() {
+		return link.getMethod();
+	}
+
+	@Override
+	public OfferAccess commitChanges() {
+		if(link.getOffer() instanceof OfferImpl) {
+			((OfferImpl)link.getOffer()).setToken(tokenEl.getValue());
+		}
+		link.getOffer().setDescription(descEl.getValue());
+		return link;
+	}
+
+	@Override
+	protected boolean validateFormLogic(UserRequest ureq) {
+		boolean allOk = true;
+		
+		String token = tokenEl.getValue();
+		tokenEl.clearError();
+		if(token == null || token.length() < 2) {
+			tokenEl.setErrorKey("invalid.token.format", null);
+			allOk = false;
+		}
+		
+		return allOk && super.validateFormLogic(ureq);
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/TokenAccessController.java b/src/main/java/org/olat/resource/accesscontrol/ui/TokenAccessController.java
new file mode 100644
index 0000000000000000000000000000000000000000..81a2e879cb721af71fd19e09e9ea988146438485
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/TokenAccessController.java
@@ -0,0 +1,127 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) 2008 frentix GmbH, Switzerland<br>
+* <p>
+*/
+
+package org.olat.resource.accesscontrol.ui;
+
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.TextElement;
+import org.olat.core.gui.components.form.flexible.impl.Form;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.util.StringHelper;
+import org.olat.resource.accesscontrol.AccessResult;
+import org.olat.resource.accesscontrol.manager.ACFrontendManager;
+import org.olat.resource.accesscontrol.model.OfferAccess;
+
+
+/**
+ * 
+ * Description:<br>
+ * Ask for the token
+ * 
+ * <P>
+ * Initial Date:  15 avr. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class TokenAccessController extends FormBasicController implements FormController {
+	
+	private TextElement tokenEl;
+	private final OfferAccess link;
+	private final ACFrontendManager acFrontendManager;
+
+	public TokenAccessController(UserRequest ureq, WindowControl wControl, OfferAccess link) {
+		super(ureq, wControl);
+		
+		this.link = link;
+		acFrontendManager = (ACFrontendManager)CoreSpringFactory.getBean("acFrontendManager");
+			
+		initForm(ureq);
+	}
+	
+	public TokenAccessController(UserRequest ureq, WindowControl wControl, OfferAccess link, Form form) {
+		super(ureq, wControl, LAYOUT_DEFAULT, null, form);
+		
+		this.link = link;
+		acFrontendManager = (ACFrontendManager)CoreSpringFactory.getBean("acFrontendManager");
+			
+		initForm(ureq);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		setFormTitle("access.token.title");
+		setFormDescription("access.token.desc");
+		
+		String description = link.getOffer().getDescription();
+		if(StringHelper.containsNonWhitespace(description)) {
+			uifactory.addStaticTextElement("offer.description", description, formLayout);
+		}
+			
+		tokenEl = uifactory.addTextElement("token", "accesscontrol.token", 255, "", formLayout);
+			
+		final FormLayoutContainer buttonGroupLayout = FormLayoutContainer.createButtonLayout("buttonLayout", getTranslator());
+		buttonGroupLayout.setRootForm(mainForm);
+		formLayout.add(buttonGroupLayout);
+			
+		uifactory.addFormSubmitButton("access.button", formLayout);
+	}
+		
+	@Override
+	protected void doDispose() {
+			//
+	}
+
+	@Override
+	protected boolean validateFormLogic(UserRequest ureq) {
+		boolean allOk = true;
+		
+		String token = tokenEl.getValue();
+		tokenEl.clearError();
+		if(token == null || token.length() < 2) {
+			tokenEl.setErrorKey("invalid.token.format", null);
+			allOk = false;
+		}
+		
+		return allOk && super.validateFormLogic(ureq);
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		String token = tokenEl.getValue();
+		AccessResult result = acFrontendManager.accessResource(getIdentity(), link, token);
+		
+		if(result.isAccessible()) {
+			fireEvent(ureq, AccessEvent.ACCESS_OK_EVENT);
+		} else {
+			String msg = translate("invalid.token");
+			fireEvent(ureq, new AccessEvent(AccessEvent.ACCESS_FAILED, msg));
+		}
+	}
+
+	@Override
+	public FormItem getInitialFormItem() {
+		return flc;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/TransactionDetailsController.java b/src/main/java/org/olat/resource/accesscontrol/ui/TransactionDetailsController.java
new file mode 100644
index 0000000000000000000000000000000000000000..045303f31e7488e15aa0a4b4bb50a69625400783
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/TransactionDetailsController.java
@@ -0,0 +1,136 @@
+/**
+ * OLAT - Online Learning and Training<br>
+ * http://www.olat.org
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Copyright (c) frentix GmbH<br>
+ * http://www.frentix.com<br>
+ * <p>
+ */
+package org.olat.resource.accesscontrol.ui;
+
+import java.util.Date;
+
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.impl.Form;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.util.Formatter;
+import org.olat.resource.accesscontrol.AccessControlModule;
+import org.olat.resource.accesscontrol.method.AccessMethodHandler;
+import org.olat.resource.accesscontrol.model.AccessMethod;
+import org.olat.resource.accesscontrol.model.AccessTransaction;
+import org.olat.resource.accesscontrol.model.Order;
+import org.olat.resource.accesscontrol.ui.OrderDetailController.OrderItemWrapper;
+
+/**
+ * 
+ * Description:<br>
+ * show the details of the OLAT transaction, plus look up a specific
+ * controller for the ugly details of a PSP transaction as Paypal
+ * 
+ * <P>
+ * Initial Date:  27 mai 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class TransactionDetailsController extends FormBasicController {
+	
+	private final Order order;
+	private final OrderItemWrapper wrapper;
+	private final AccessControlModule acModule;
+	
+	public TransactionDetailsController(UserRequest ureq, WindowControl wControl, Order order, OrderItemWrapper wrapper) {
+		super(ureq, wControl, FormBasicController.LAYOUT_VERTICAL);
+		
+		this.order = order;
+		this.wrapper = wrapper;
+		acModule = (AccessControlModule)CoreSpringFactory.getBean("acModule");
+
+		initForm(ureq);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		setFormTitle("transaction.details.title");
+
+		String page = velocity_root + "/transaction_details.html";
+		FormLayoutContainer detailsLayout = FormLayoutContainer.createCustomFormLayout("transaction-details-layout", getTranslator(), page);
+		formLayout.add(detailsLayout);
+		detailsLayout.setRootForm(mainForm);
+		
+		AccessTransaction transaction = wrapper.getTransaction();
+		DetailsForm detailsForm = new DetailsForm(ureq, getWindowControl(), transaction, mainForm);
+		detailsLayout.add("simple", detailsForm.getInitialFormItem());
+
+		AccessMethod method = transaction.getMethod();
+		AccessMethodHandler handler = acModule.getAccessMethodHandler(method.getType());
+		FormController controller = handler.createTransactionDetailsController(ureq, getWindowControl(), order, wrapper.getPart(), method, mainForm);
+		if(controller != null) {
+			uifactory.addSpacerElement("details-spacer", detailsLayout, false);
+			detailsLayout.add("custom", controller.getInitialFormItem());
+		}
+	}
+	
+	@Override
+	protected void doDispose() {
+		//
+	}
+	
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		fireEvent(ureq, Event.DONE_EVENT);
+	}
+	
+	private class DetailsForm extends FormBasicController implements FormController {
+		
+		private final AccessTransaction transaction;
+	
+		public DetailsForm(UserRequest ureq, WindowControl wControl, AccessTransaction transaction, Form form) {
+			super(ureq, wControl, LAYOUT_DEFAULT, null, form);
+			
+			this.transaction = transaction;
+			
+			initForm(ureq);
+		}
+		
+		@Override
+		protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+			Date date = transaction.getCreationDate();
+			String dateStr = Formatter.getInstance(getLocale()).formatDateAndTime(date);
+			uifactory.addStaticTextElement("transaction.date", dateStr, formLayout);
+		}
+		
+		@Override
+		protected void doDispose() {
+			//
+		}
+
+		@Override
+		public FormItem getInitialFormItem() {
+			return flc;
+		}
+
+		@Override
+		protected void formOK(UserRequest ureq) {
+			//
+		}
+	}
+}
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_chelp/accesscontrol.html b/src/main/java/org/olat/resource/accesscontrol/ui/_chelp/accesscontrol.html
new file mode 100644
index 0000000000000000000000000000000000000000..af871e8531def269d7cf1f92968de0cece3c0fa8
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/_chelp/accesscontrol.html
@@ -0,0 +1,32 @@
+<p>
+	$r.translate("chelp.accesscontrol.intro")
+</p>
+<p>
+	$r.translate("chelp.accesscontrol.access")
+	<ol>
+ 		<li>$r.translate("chelp.accesscontrol.access.free")</li>
+ 		<li>$r.translate("chelp.accesscontrol.access.order")</li>
+	</ol>
+</p>
+<p>
+	$r.translate("chelp.accesscontrol.access.member")
+</p>
+<p>
+	$r.translate("chelp.accesscontrol.methods")
+</p>
+<div class="b_access_create">
+	<ul>
+		<li><b class="b_with_small_icon_left b_access_method_free_icon">$r.translate("free.method")</b>: $r.translate("chelp.accesscontrol.method.free")</li>
+ 		<li><b class="b_with_small_icon_left b_access_method_token_icon">$r.translate("token.method")</b>: $r.translate("chelp.accesscontrol.method.token")</li>
+ 		<li><b class="b_with_small_icon_left fx_access_method_paypal_icon">$r.translateWithPackage("com.frentix.olat.accesscontrol.paypal.ui", "paypal.method")</b>: $r.translateWithPackage("com.frentix.olat.accesscontrol.paypal.ui", "chelp.accesscontrol.method.paypal")</li>
+	</ul>	
+</div>
+<p>
+	$r.translate("chelp.accesscontrol.dates")	 
+</p>
+<p>
+	$r.translate("chelp.accesscontrol.manual") 
+</p>
+<p>
+	$r.translate("chelp.accesscontrol.delete") 
+</p>
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_chelp/accesscontrol_group.html b/src/main/java/org/olat/resource/accesscontrol/ui/_chelp/accesscontrol_group.html
new file mode 100644
index 0000000000000000000000000000000000000000..b7f45d1f36fe6986ab93117cc7e5d9003c502b6c
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/_chelp/accesscontrol_group.html
@@ -0,0 +1,25 @@
+<p>
+	$r.translate("chelp.accesscontrol_group.intro")
+</p>
+<p>
+	$r.translate("chelp.accesscontrol_group.access")
+</p>
+<p>
+	$r.translate("chelp.accesscontrol_group.methods")
+</p>
+<div class="b_access_create">
+	<ul>
+		<li><b class="b_with_small_icon_left b_access_method_free_icon">$r.translate("free.method")</b>: $r.translate("chelp.accesscontrol_group.method.free")</li>
+ 		<li><b class="b_with_small_icon_left b_access_method_token_icon">$r.translate("token.method")</b>: $r.translate("chelp.accesscontrol_group.method.token")</li>
+ 		<li><b class="b_with_small_icon_left fx_access_method_paypal_icon">$r.translateWithPackage("com.frentix.olat.accesscontrol.paypal.ui", "paypal.method")</b>: $r.translateWithPackage("com.frentix.olat.accesscontrol.paypal.ui", "chelp.accesscontrol_group.method.paypal")</li>
+	</ul>	
+</div>
+<p>
+	$r.translate("chelp.accesscontrol_group.dates")	 
+</p>
+<p>
+	$r.translate("chelp.accesscontrol_group.manual") 
+</p>
+<p>
+	$r.translate("chelp.accesscontrol_group.delete") 
+</p>
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_content/access_configuration.html b/src/main/java/org/olat/resource/accesscontrol/ui/_content/access_configuration.html
new file mode 100644
index 0000000000000000000000000000000000000000..64463aa072bf8ebeec9a62383cec28d8160cb592
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/_content/access_configuration.html
@@ -0,0 +1,25 @@
+<div class="b_form b_clearfix">
+#if ($off_title) <fieldset><legend>$off_title</legend> #end
+#if ($off_chelp_package) $r.contextHelpWithWrapper("$off_chelp_package","$off_chelp_page","$off_chelp_hover") #end
+#if ($off_desc) <div class="b_form_desc">$off_desc</div> #end
+#if ($off_warn) <div class="b_warning">$off_warn</div> #end
+#if ($off_info) <div class="b_info">$off_info</div> #end
+
+	<div class="b_clearfix">
+		<div class="b_float_right">
+			$r.render("add.accesscontrol")
+		</div>
+	</div>
+	<div class="b_clearfix">
+		$r.render("conf-controllers")
+	</div>
+	#if($r.available("buttonLayout"))
+		<div class="b_form_element_wrapper b_clearfix">
+			<div class="b_form_element">
+				$r.render("buttonLayout")
+			</div>
+		</div>
+	#end
+
+#if ($off_title) </fieldset> #end
+</div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_content/access_method_list.html b/src/main/java/org/olat/resource/accesscontrol/ui/_content/access_method_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..142dbc96e47c5d68b73356a7c78d06d56e4efdc3
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/_content/access_method_list.html
@@ -0,0 +1,11 @@
+<div class="b_access_method_list">
+	<h3 class="b_with_small_icon_left b_order_icon">$r.translate("access.title")</h3>
+	<p class="b_info">
+		$r.translate("access.desc")
+	</p>
+	#foreach($link in $links)
+		<div class="b_clearfix b_access_method $link.getMethod().getMethodCssClass()">
+			$r.render("ac_$link.key")
+		</div>
+	#end
+</div>
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_content/access_refused.html b/src/main/java/org/olat/resource/accesscontrol/ui/_content/access_refused.html
new file mode 100644
index 0000000000000000000000000000000000000000..6662be153515e06e1f42a9f2f769e4a8cedc5cfa
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/_content/access_refused.html
@@ -0,0 +1,19 @@
+<div id="b_main" class="">
+	<div id="b_main_access_control">
+		<h3 class="b_with_small_icon_left b_order_icon">$r.translate("access.title")</h3>
+		<p class="b_info">
+			$r.translate("access.refused.desc")
+		</p>
+		<div class="b_clearfix"><br/><br/></div>
+	</div>
+</div>
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_content/access_wrapper.html b/src/main/java/org/olat/resource/accesscontrol/ui/_content/access_wrapper.html
new file mode 100644
index 0000000000000000000000000000000000000000..9857fc40901db0a7162d119843ab9b17847ecd8e
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/_content/access_wrapper.html
@@ -0,0 +1,17 @@
+<div id="b_main" class="">
+	<div id="b_main_access_control">
+		#if($r.available("accessPanel"))
+			$r.render("accessPanel")
+		#end
+	</div>
+</div>
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_content/choose_access_method.html b/src/main/java/org/olat/resource/accesscontrol/ui/_content/choose_access_method.html
new file mode 100644
index 0000000000000000000000000000000000000000..0b5fd7ae7d297bcd856085e5da3db5dcd0d24e6f
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/_content/choose_access_method.html
@@ -0,0 +1,6 @@
+#if($r.available("accessCmp"))
+	$r.render("back")
+	$r.render("accessCmp")
+#else
+	$r.render("methodChooser")
+#end
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_content/configuration_list.html b/src/main/java/org/olat/resource/accesscontrol/ui/_content/configuration_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..9c3a677b816df703333ca3a3d44a835be82e7d74
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/_content/configuration_list.html
@@ -0,0 +1,40 @@
+#if ($confControllers.size() > 0)
+<table class="b_access_method">
+	<thead>
+			<tr>
+				<th>$r.translate("accesscontrol.table.method")</th>
+				<th></th>
+				<th>$r.translate("accesscontrol.table.from")</th>
+				<th>$r.translate("accesscontrol.table.to")</th>
+				<th></th>
+			</tr>	
+	</thead>
+	<tbody>
+		#foreach($confController in $confControllers)
+			#set($css = $confController.getLink().getMethod().getMethodCssClass())
+			<tr class="$css">
+				<td><span class="b_with_small_icon_left ${css}_icon">$confController.name</span></td>
+				<td><span class="b_access_infos">$confController.infos</span></td>
+				<td><div class="b_form_element">$r.render("from_$confController.link.key")</div></td>
+				<td><div class="b_form_element">$r.render("to_$confController.link.key")</div></td>
+				<td>$r.render("del_$confController.link.key")</td>
+			</tr>
+			<tr class="$css b_access_desc">
+				<td colspan="5">$confController.getLink().getOffer().getDescription()</td>
+			</tr>
+		#end
+	</tbody>
+</table>
+#else
+	#if ($emptyConfigGrantsFullAccess) 
+		<div class="b_warning">
+			$r.translate("accesscontrol.no.methods.full.access")		
+		</div>
+	#else 	
+		<div class="b_important">
+			$r.translate("accesscontrol.no.methods.no.access")
+		</div>
+	#end
+#end
+
+
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_content/createAccessCallout.html b/src/main/java/org/olat/resource/accesscontrol/ui/_content/createAccessCallout.html
new file mode 100644
index 0000000000000000000000000000000000000000..dc867405ea1fe3feee4ad1cbeec22d1e4c3d721d
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/_content/createAccessCallout.html
@@ -0,0 +1,8 @@
+<div class="b_access_create">
+	<p>$r.translate("add.accesscontrol.intro")</p>
+	<ul>
+		#foreach($method in $methods)
+			<li>$r.render($method.componentName)</li>
+		#end
+	</ul>
+</div>
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_content/members.html b/src/main/java/org/olat/resource/accesscontrol/ui/_content/members.html
new file mode 100644
index 0000000000000000000000000000000000000000..ec8423cd1f83998185273f39ad56ab3ab1c914d5
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/_content/members.html
@@ -0,0 +1,9 @@
+#if($title)
+	<h4>$title</h4>
+#end
+#if($info)
+	<p class="b_info">
+		$info
+	</p>
+#end
+$r.render("memberList")
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_content/order.html b/src/main/java/org/olat/resource/accesscontrol/ui/_content/order.html
new file mode 100644
index 0000000000000000000000000000000000000000..1c5437f89059cf57e4236ca6aa6b786a450c07e7
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/_content/order.html
@@ -0,0 +1,9 @@
+#if($r.available("back"))
+	$r.render("back")
+#end
+<div class="b_order_details">
+	$r.render("mainCmp")
+	
+	$r.render("orderItemList")
+</div>
+
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_content/orders.html b/src/main/java/org/olat/resource/accesscontrol/ui/_content/orders.html
new file mode 100644
index 0000000000000000000000000000000000000000..24a9e8c03334a65eff88d4940118fce630300458
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/_content/orders.html
@@ -0,0 +1,9 @@
+<h4 class="b_with_small_icon_left b_order_icon">$title</h4>
+<p class="b_info">
+	$description
+</p>
+
+#if($r.available("searchForm"))
+	$r.render("searchForm")
+#end
+$r.render("orderList")
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_content/repo_members.html b/src/main/java/org/olat/resource/accesscontrol/ui/_content/repo_members.html
new file mode 100644
index 0000000000000000000000000000000000000000..1109d2386d212a7d60bca55702cf0c073202bbc5
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/_content/repo_members.html
@@ -0,0 +1,3 @@
+#if($r.available("mainCmp"))
+	$r.render("mainCmp")
+#end
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_content/transaction_details.html b/src/main/java/org/olat/resource/accesscontrol/ui/_content/transaction_details.html
new file mode 100644
index 0000000000000000000000000000000000000000..cdae9133ae709f530862808c7792a5b168d70c24
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/_content/transaction_details.html
@@ -0,0 +1,6 @@
+$r.render("simple")
+
+#if($r.available("custom"))
+	$r.render("details-spacer")
+	$r.render("custom")
+#end
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_de.properties
new file mode 100644
index 0000000000000000000000000000000000000000..ba4219001c4f311ffa8304a8ccb34a1c73a57c83
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_de.properties
@@ -0,0 +1,108 @@
+#Mon Mar 02 09:54:04 CET 2009
+accesscontrol.title=Buchungsmethoden konfigurieren
+accesscontrol.desc=Sie können die Buchungsmethoden für den Zugang zu dieser Ressource konfigurieren. Wählen Sie die Schaltfläche "$:add.accesscontrol" um aus der Liste der verfügbaren Buchungsmethoden eine oder mehrere auszuwählen. Optional können Buchungsmethoden mit einem Gültigkeitsdatum versehen werden.
+accesscontrol.token=Zugangscode
+accesscontrol.table.method=Buchungsmethode
+accesscontrol.table.from=gültig von
+accesscontrol.table.to=bis
+accesscontrol.no.methods.full.access = Es ist noch keine Buchungsmethode konfiguriert. Der Zugang zu dieser Ressource steht allen Systembenutzern ohne Buchung offen. Wählen Sie die Schaltfläche "$:add.accesscontrol" um den Zugang einzuschränken und/oder eine Buchung zu erzwingen. 
+accesscontrol.no.methods.no.access = Es ist noch keine Buchungsmethode konfiguriert. Diese Ressource kann nur von den Teilnehmer der Ressource verwendet werden. Wählen Sie die Schaltfläche "$:add.accesscontrol" um eine Buchungsmethode zu wählen und die Ressource zu veröffentlichen.
+add.token=Zugangscode erstellen
+add.accesscontrol=Buchungsmethode hinzufügen
+add.accesscontrol.intro=W\u00E4hlen Sie eine Buchungsmethode für die Zugangskontrolle dieser Ressource. Sie können mehrere Buchungsmethoden mit unterschiedlichen Datumseinschränkungen wählen. 
+token.method=Zugangscode
+free.method=Frei verfügbar
+invalid.token.format=Der Zugangscode muss aus mindestens einem Zeichen bestehen
+invalid.token=Falscher Zugangscode
+access.title = Ressource buchen
+access.desc = Diese Ressource wurde von Ihnen noch nicht gebucht. Eine Buchung ist notwendig um diese Ressource aufrufen zu können. Wählen Sie eine der unten aufgeführen Buchungsmethoden auf um sich zu registrieren.
+access.token.title=Geschützte Ressource
+access.token.desc=Diese Ressource ist mit einem Zugangscode geschützt. Geben Sie einen Zugangscode ein und wählen Sie die Schaltfläche "$:access.button" um sich für den Zugang zu registrieren. Den Zugangscode erhalten Sie von dem Betreiber dieser Ressource.
+access.button=Buchen
+access.free.title=Freie Ressource 
+access.free.desc=Diese Ressource ist für Sie frei verfügbar. Wählen Sie die Schaltfläche "$:access.button" um sich für den Zugang zu registrieren.
+access.refused.desc=Diese Ressource kann zur Zeit nicht gebucht werden. Bitte versuchen Sie es später noch einmal oder kontaktieren Sie den Besitzer dieser Ressource.
+cmd.title=Zugangskontrolle
+cmd.close=Schliessen
+members.name=Name
+members.empty=Es gibt keine Benutzer in dieser Liste
+members.title=Mitgliederverwaltung
+members.title.alt=Verwalten von Besitzern, Betreuern und Teilnehmern dieser Lernressource
+members.owners=Besitzer
+members.owners.alt=Benutzer mit Besitzerrechten für diese Lernressource
+members.owners.info=Diese Liste zeigt die Benutzer mit Besitzerrechten für diese Lernressource. Diese Personen haben vollen Zugang zu allen administrativen Werkzeugen der Ressource inklusive der Verwaltung der Besitzer. Wählen Sie die Schaltfläche "$:members.add" oder "$:members.import" um einem bzw. mehreren Benutzern die Besitzerrechte zuzuteilen. 
+members.tutors=Betreuer
+members.tutors.alt=Benutzer mit Betreuungsfunktionen für diese Lernressource
+members.tutors.info=Diese Liste zeigt die Benutzer mit Betreuungsrechten für diese Lernressource. Diese Personen haben Zugang zu der Lernressource wenn sie veröffentlicht wurde analog zu den Teilnehmern. In Kursen stehen den Betreuern Werkzeuge wie z.B. das Bewertungswerkzeug zur Verfügung. Wählen Sie die Schaltfläche "$:members.add" oder "$:members.import" um einem bzw. mehreren Benutzern die Betreuungsrechte zuzuteilen. <br />Wenn Sie mit Lerngruppen arbeiten, dann werden Betreuer von Lerngruppen dieser Lernressource automatisch auch in die Liste der Betreuer eingetragen. 
+members.participants=Teilnehmer
+members.participants.alt=Benutzer mit normalen Teilnehmerfunktionen
+members.participants.info=Diese Liste zeigt die Benutzer mit Teilnehmerrechten für diese Lernressource. Diese Personen haben Zugang zu der Lernressource wenn sie veröffentlicht wurde. Wählen Sie die Schaltfläche "$:members.add" oder "$:members.import" um einem bzw. mehreren Benutzern den Zugang zu gestatten.  <br />Wenn Sie mit Lerngruppen arbeiten, dann werden Teilnehmer von Lerngruppen dieser Lernressource automatisch auch in die Teilnehmerliste eingetragen. <br /> Wenn Sie mit Buchungen arbeiten, dann werden Teilnehmer die diese Lernressource buchen automatisch in diese Teilnehmerliste eingetragen. <br /> Sie können eine Person jederzeit aus dieser Liste austragen. Die Person hat anschliessend keinen Zugang mehr zu dieser Lernressource. 
+members.add=Benutzer hinzuf\u00FCgen
+members.import=Importieren
+members.confirm.remove=Entfernen bestätigen
+members.owners.confirm.remove=Bitte bestätigen Sie, dass Sie die Autoren "{0}" aus allen Gruppen austragen wollen:
+members.tutors.confirm.remove=Bitte bestätigen Sie, dass Sie die Betreuer "{0}" aus allen Gruppen austragen wollen:
+members.participants.confirm.remove=Bitte bestätigen Sie, dass Sie die Teilnehmer "{0}" aus allen Gruppen austragen wollen:
+membership.delete.title=Benutzer entfernen
+membership.delete.desc=Bitte bestätigen Sie, dass der gewählte Benutzer aus dieser Liste entfernt werden soll:
+info.membership.deleted=Der Benutzer wurde erfolgreich aus der Liste entfernt.
+offer.description=Beschreibung
+order.nr=Buchungsnummer
+order.creationDate=Datum
+order.delivery=Gebucht von
+order.item=Ressource
+order.item.name=Ressourcenname
+order.part.payment=Buchungsmethode
+order.summary=Inhalt
+order.from=Von
+order.to=An
+order.total=Total
+order.status=Status
+order.status.new=Neu
+order.status.prepayment=In Zahlungsprozess
+order.status.payed=Bezahlt
+order.status.canceled=Abgebrochen
+order.status.error=Fehler
+orders.my=Meine Buchungen
+orders.my.desc=Im folgenden sehen Sie alle Ressourcen die Sie gebucht haben. Wählen Sie eine Buchung um weitere Detailinformationen anzuzueigen.
+orders.admin.my=Buchungen dieser Ressource
+orders.admin.my.desc=Diese Ressource wurde von den folgenden Benutzern gebucht. Wählen Sie eine Buchung um weitere Detailinformationen anzuzeigen.
+order.menu.title=Buchungen
+order.menu.title.alt=Buchungen
+order.details=Detailinformationen
+transaction.details.title=Details über Transaktion
+transaction.date=Erstellt am
+table.order.empty=Sie haben zur Zeit keine Buchungen.
+table.order.details=Ausw\u00E4hlen
+menu.orders=Buchungen
+menu.orders.alt=Buchungen
+from=Von:
+to=Bis:
+create=Erstellen
+access.info.price.vat={0} (inkl. {1}% MwSt)
+access.info.price.noVat={0}
+
+chelp.accesscontrol.title= Ressourcen Zugangskontrolle und Buchungsmethode
+chelp.accesscontrol.hover= Hilfe zur Konfiguration der Zugangskontrolle und der Buchungsmethode
+chelp.accesscontrol.intro=Im Bereich "$:accesscontrol.title" können Sie festlegen, wann und unter welchen Voraussetzungen die Benutzer des Systems eine Ressource buchen können. Buchen kann als Synonym für Belegen, Einschreiben, Einkaufen verstanden werden.
+chelp.accesscontrol.access=Ist eine Lernressource für alle registrierten Benutzer freigeschaltet, so können Sie hier festlegen unter welchen Bedingungen Benutzer diese Ressource aufrufen können:
+chelp.accesscontrol.access.free=Die Ressource ist ohne jegliche Einschränkung oder Buchung aufrufbar. In dem Fall wissen Sie nicht wer die Lernressource besucht hat und Sie können keine Laufzeitdaten wie Testresultate abfragen (nur im Kurs). Dies ist der Standardmodus. 
+chelp.accesscontrol.access.order=Es ist eine Buchungsmethode konfiguriert und der Benutzer kann selbst die Buchung der Ressource vornehmen. In dem Fall haben Sie in der Mitgliederverwaltung eine Übersicht über die Nutzer Ihrer Ressourcen. Weiter unten lernen Sie welche Buchungsmethoden Ihnen zur Verfügung stehen. 
+chelp.accesscontrol.access.member=Möchten Sie die Ressource hingegen einem geschlossenen Kreis von Benutzern freigeben, so wählen Sie nicht die Einstellung "Für alle Benutzer" sondern "Nur für Mitglieder". Sie können dann in der Administrationsumgebung die Teilnehmer (oder Betreuer) direkt administrieren.
+chelp.accesscontrol.methods=Wählen Sie die Schaltfläche "$:add.accesscontrol" um eine der folgenden Buchungsmethode zu wählen:
+chelp.accesscontrol.method.free=Wählen Sie die freie Buchungsmethode wenn keine weiteren Einschräkungen gelten. Alle Systembenutzer können die Ressource buchen.
+chelp.accesscontrol.method.token=Wählen Sie die Zugangscode Buchungsmethode um die Buchung auf einen bestimmten Personenkreis einzuschränken. Bei dieser Buchungsmethode können Sie einen Zugangscode definieren. Nur Personen die über diesen Zugangscode verfügen können die Ressource buchen.
+chelp.accesscontrol.dates=Sie können mehrere Buchungsmethoden konfigurieren. Diese gelten als verschiedene Optionen, aus denen der Benutzer wählen kann. Optional kann einer Buchungskonfiguration ein Start- und Endtatum beigefügt werden. Diese Konfiguration ist dann nur zwischen dem konfigurierten Datum gültig. Sie können auch nur ein Start- oder nur ein Enddatum angeben. Möchten sie keine zeitliche Einschränkung vorgeben so lassen Sie dieses Feld leer.
+chelp.accesscontrol.manual=Achtung: Dieses Start- und Enddatum bezieht sich ausschliesslich auf den Buchungsprozess. Hat ein Benutzer eine Ressource gebucht, so wird die Person in der Teilnehmerliste dieser Ressource eingetragen. Von dem Zeitpunt an entscheided das System einzig über die Teilnehmerliste ob eine Person Zugang zu einer Ressource hat. Abgelaufene Buchungskonfigurationen haben daher keinen Einfluss auf eine Teilnehmerschaft. Als Besitzer der Ressource können Sie auch jederzeit eine Person zu der Teilnehmerliste hinzufügen bzw. austragen. In dem zweiten Fall kann der Benutzer durch erneutes Buchen sich wieder in die Ressource als Teilnehmer eintragen.
+chelp.accesscontrol.delete=Sie können die konfigurierten Buchungsmethoden jederzeit problemlos löschen. Die bereits getätigten Buchungen bleiben bestehen und sind davon nicht weiter tangiert.
+
+chelp.accesscontrol_group.title=Arbeitsgruppen Veröffentlichen und Buchungsmethode
+chelp.accesscontrol_group.hover=Hilfe zur Veröffentlichung von Arbeitsgruppen und der Buchungsmethode
+chelp.accesscontrol_group.intro=Im Bereich "$:accesscontrol.title" können Sie festlegen, wann und unter welchen Voraussetzungen die Benutzer des Systems eine Arbeitsgruppe buchen können. Buchen kann als Synonym für Belegen, Einschreiben, Einkaufen verstanden werden.
+chelp.accesscontrol_group.access=Solange für eine Arbeitsgruppe keine Buchungsmethode definiert, so sehen nur die Mitglieder der Gruppe diese Gruppe. 
+chelp.accesscontrol_group.methods=Um eine Gruppe für alle Benutzer sichtbar zu machen wählen Sie eine oder mehrere der folgenden Buchungsmethoden aus:
+chelp.accesscontrol_group.method.free=$:chelp.accesscontrol.method.free
+chelp.accesscontrol_group.method.token=$:chelp.accesscontrol.method.token
+chelp.accesscontrol_group.dates=$:chelp.accesscontrol.dates
+chelp.accesscontrol_group.manual=$:chelp.accesscontrol.manual
+chelp.accesscontrol_group.delete=$:chelp.accesscontrol.delete
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_en.properties
new file mode 100644
index 0000000000000000000000000000000000000000..81b3bd3245ac3f6d8ed0d7e3658eb3c85eace3e6
--- /dev/null
+++ b/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_en.properties
@@ -0,0 +1,106 @@
+#Thu Jun 30 11:32:23 CEST 2011
+access.button=Order
+access.desc=This resource is not yet booked by you. A booking is necessary to launch this resource. Select one of the available booking methods below to register for this resource.
+access.free.desc=This resource is freely available. Select the button "$\:access.button" to register and get access.
+access.free.title=Free resource
+access.info.price.noVat={0}
+access.info.price.vat={0} (incl. {1}% VAT)
+access.refused.desc=This resource is currently available for booking. Please try again later or contact the owner of this resource.
+access.title=Book resource
+access.token.desc=This resource is protected by an access code. Enter the access code and select the button "$\:access.button" to register for getting access. The access code will be provided by the operator of this resource.
+access.token.title=Protected resource
+accesscontrol.desc=You can configure booking methods for accessing this resource. Select the button "$\:add.accesscontrol" to select one or more booking methods. As an option you can also define the period in which each booking method is valid.
+accesscontrol.no.methods.full.access=There is no booking method configured to restrict access. This resource can be accessed by all known users without an explicit booking. Select the button "$\:add.accesscontrol"  to restrict access and/or to require an explicit booking.
+accesscontrol.no.methods.no.access=There is no booking method configured. This resource can only be accessed by explicit members of this resource. Select the button "$\:add.accesscontrol" to add a booking method and to publish the resource.
+accesscontrol.table.from=valid from
+accesscontrol.table.method=Booking method
+accesscontrol.table.to=to
+accesscontrol.title=Configure booking methods
+accesscontrol.token=Access code
+add.accesscontrol=Add booking method
+add.accesscontrol.intro=Select a booking method to control access to this resource. You can add multiple booking methods and configure different validation periods for each booking method.
+add.token=Create access code
+chelp.accesscontrol.access=If a learning resource is published for all registered users you can specify the terms to launch this resource here.
+chelp.accesscontrol.access.free=The resource can be launched by all users with no restrictions and no explicit booking. In this case you will not know who launched this learning resource and you will have no access to run-time data like test results (only available in courses). This is the default behavior.
+chelp.accesscontrol.access.member=On the other hand, if you want to publish the resource to a well defined list of users, then choose "Members only" instead. In this case you can administrate your participants and coaches list in the administration section.
+chelp.accesscontrol.access.order=A booking method is configured and the user himself can book the resource. In this case you will have an overview of the resource participants in the member management area. Read below to learn which booking methods are available at your disposal.
+chelp.accesscontrol.dates=You can configure multiple booking methods. These methods serve as different options the users can choose from. Optionally you can configure a start and end validity date to each booking method. In that case the booking method is only available during this period. It is also possible to specify just a start or just an end time. If you don't want to restrict the booking method to a specified period just leave the fields empty.
+chelp.accesscontrol.delete=You can delete configured booking methods at any time. The already booked orders will not be affected by this.
+chelp.accesscontrol.hover=Help about configuration of access control and booking methods
+chelp.accesscontrol.intro=Under area "$\:accesscontrol.title" you can define the conditions to allow booking of resources by users. Booking can be understood as a synonym for register, enroll or buying.
+chelp.accesscontrol.manual=Attention\: the start and end date is only valid for the booking process. Once a resource has been booked by a user he will be added to the resource members list. From that moment the members list grants access to the user. When a booking method is no longer valid or has been deleted users on the members list will still have access to the resource. As an owner of the resource you can add or remove users to/from the resource members list at any time.
+chelp.accesscontrol.method.free=Select the free booking method if no other restrictions shall apply. All users can book the resource.
+chelp.accesscontrol.method.token=Select the access code booking methods if the booking shall be restricted to people in possession of the access code. In this method you can specify an access code. Only users who can provide this access code will be able to book the resource.
+chelp.accesscontrol.methods=Select the button "$\:add.accesscontrol" to add one of the following booking methods\:
+chelp.accesscontrol.title=Resource access control and booking methods
+chelp.accesscontrol_group.access=Only members of this project group are allowed to see this group if there is no booking method is configured.
+chelp.accesscontrol_group.dates=$\:chelp.accesscontrol.dates
+chelp.accesscontrol_group.delete=$\:chelp.accesscontrol.delete
+chelp.accesscontrol_group.hover=Help about publishing of project groups and booking methods
+chelp.accesscontrol_group.intro=Under "$\:accesscontrol.title" you can specify when and under which conditions users can book a project group. Booking can be understood as a synonym of register, enroll or buying.
+chelp.accesscontrol_group.manual=$\:chelp.accesscontrol.manual
+chelp.accesscontrol_group.method.free=$\:chelp.accesscontrol.method.free
+chelp.accesscontrol_group.method.token=$\:chelp.accesscontrol.method.token
+chelp.accesscontrol_group.methods=To make a group visible to all users you have to select one or multiple of the following booking methods\:
+chelp.accesscontrol_group.title=Publish project groups and booking methods
+cmd.close=Close
+cmd.title=Access control
+create=Create
+free.method=Freely available
+from=From\:
+info.membership.deleted=The user has successfully been removed from the list.
+invalid.token=Wrong access code
+invalid.token.format=The access code must consist of at least one symbol
+members.add=Add user
+members.confirm.remove=Confirm removal
+members.empty=This list contains no user
+members.import=Import
+members.name=Name
+members.owners=Owner
+members.owners.alt=User with owner rights for this learning resource
+members.owners.confirm.remove=Please confirm that you want to remove the author "{0}" from all groups\:
+members.owners.info=This list shows the users with owner rights for this learning resource. Those users have full access to all administrative tools of this resource including the members management tool. Select the button "$\:members.add" or "$\:members.import" to add one or multiple users to grant owner rights.
+members.participants=Participants
+members.participants.alt=Users with participant rights
+members.participants.confirm.remove=Please confirm that you want to remove the participant "{0}" from all groups\:
+members.participants.info=This list shows the users with participant rights this learning resource. Those users have access to the learning resource when the resource has been published. Select the button "$\:members.add" or "$\:members.import" to add one or multiple users to grant participant rights. <br />If you work with learning groups, all participants of the learning groups will automatically be added to this participant list. <br />If you work with bookings, all participants who are booking the resource will be automatically be added to this participant list. <br /> You can remove users from this list at any time. Users will then have no more access to this resource.
+members.title=Members management
+members.title.alt=Manager resource owners, coaches and participants
+members.tutors=Coaches
+members.tutors.alt=Users with coaching rights for this learning resource
+members.tutors.confirm.remove=Please confirm that you want to remove the coach "{0}" from all groups\:
+members.tutors.info=This list shows the users with coaching rights this learning resource. Those users have access to the learning resource when the resource has been published analog to the participants. In courses the coaches have access to the assessment tool. Select the button "$\:members.add" or "$\:members.import" to add one or multiple users to grant coaching rights. <br />If you work with learning groups, all coaches of the learning groups will automatically be added to this coaches list.
+membership.delete.desc=Please confirm that you want to remove the selected user from the list\:
+membership.delete.title=Remove user
+menu.orders=Bookings
+menu.orders.alt=Bookings
+offer.description=Description
+order.creationDate=Date
+order.delivery=Booked by
+order.details=Detail information
+order.from=From
+order.item=Resource
+order.item.name=Resource name
+order.menu.title=Bookings
+order.menu.title.alt=Bookings
+order.nr=Booking number
+order.part.payment=Booking method
+order.status=Status
+order.status.canceled=Aborted
+order.status.error=Error
+order.status.new=New
+order.status.payed=Payed
+order.status.prepayment=In payment process
+order.summary=Content
+order.to=To
+order.total=Total
+orders.admin.my=Bookings of this resource
+orders.admin.my.desc=This resource has been booked by the following people. Select a booking to see the booking details.
+orders.my=My bookings
+orders.my.desc=In the following list you see all the resources to have booked. Select a booking to see the booking details.
+table.order.details=Select
+table.order.empty=There are no bookings at this time to display.
+to=To\:
+token.method=Access code
+transaction.date=Created at
+transaction.details.title=Transation details
diff --git a/src/main/java/org/olat/restapi/group/LearningGroupWebService.java b/src/main/java/org/olat/restapi/group/LearningGroupWebService.java
index ed45519e3efdcc1d11506a3db59698635c5b9c37..9d97a9bbb030fc9b80a2bfbe6438fdda62ecc1bd 100644
--- a/src/main/java/org/olat/restapi/group/LearningGroupWebService.java
+++ b/src/main/java/org/olat/restapi/group/LearningGroupWebService.java
@@ -673,8 +673,8 @@ public class LearningGroupWebService {
 	 * @return value bigger or equal than 0
 	 */
 	private static final Integer normalize(Integer integer) {
-		if(integer == null) return new Integer(0);
-		if(integer.intValue() < 0) return new Integer(0);
+		if(integer == null) return null;
+		if(integer.intValue() <= 0) return null;
 		return integer;
 	}
 }
diff --git a/src/main/java/org/olat/restapi/repository/RepositoryEntriesResource.java b/src/main/java/org/olat/restapi/repository/RepositoryEntriesResource.java
index 41e5b7859060d1d3a11327768a10bbb1e7a96234..c85d6c41d7525c81b89a3c3ad04d6c3473a96fa0 100644
--- a/src/main/java/org/olat/restapi/repository/RepositoryEntriesResource.java
+++ b/src/main/java/org/olat/restapi/repository/RepositoryEntriesResource.java
@@ -117,8 +117,11 @@ public class RepositoryEntriesResource {
 		try {
 			// list of courses open for everybody
 			Roles roles = getRoles(httpRequest);
+			Identity identity = getIdentity(httpRequest);
+			
 			List<String> types = new ArrayList<String>();
-			List<RepositoryEntry> coursRepos = RepositoryManager.getInstance().genericANDQueryWithRolesRestriction(null, null, null, types, roles, null, 0, -1, false);
+			//fxdiff VCRP-1,2: access control of resources
+			List<RepositoryEntry> coursRepos = RepositoryManager.getInstance().genericANDQueryWithRolesRestriction(null, null, null, types, identity, roles, null, 0, -1, false);
 			
 			StringBuilder sb = new StringBuilder();
 			sb.append("Course List\n");
@@ -159,18 +162,19 @@ public class RepositoryEntriesResource {
 		try {
 			// list of courses open for everybody
 			Roles roles = getRoles(httpRequest);
+			Identity identity = getIdentity(httpRequest);
 			RepositoryManager rm = RepositoryManager.getInstance();
 			
 			List<String> types = Collections.emptyList();
 			if(MediaTypeVariants.isPaged(httpRequest, request)) {
-				int totalCount = rm.countGenericANDQueryWithRolesRestriction(null, null, null, types, roles, null, true);
-				List<RepositoryEntry> res = rm.genericANDQueryWithRolesRestriction(null, null, null, types, roles, null, start, limit, true);
+				int totalCount = rm.countGenericANDQueryWithRolesRestriction(null, null, null, types, identity, roles, null, true);
+				List<RepositoryEntry> res = rm.genericANDQueryWithRolesRestriction(null, null, null, types, identity, roles, null, start, limit, true);
 				RepositoryEntryVOes voes = new RepositoryEntryVOes();
 				voes.setRepositoryEntries(toArrayOfVOes(res));
 				voes.setTotalCount(totalCount);
 				return Response.ok(voes).build();
 			} else {
-				List<RepositoryEntry> res = rm.genericANDQueryWithRolesRestriction(null, null, null, types, roles, null, 0, -1, false);
+				List<RepositoryEntry> res = rm.genericANDQueryWithRolesRestriction(null, null, null, types, identity, roles, null, 0, -1, false);
 				RepositoryEntryVO[] voes = toArrayOfVOes(res);
 				return Response.ok(voes).build();
 			}
@@ -236,7 +240,8 @@ public class RepositoryEntriesResource {
 			} else {
 				List<String> types = new ArrayList<String>(1);
 				if(restrictedType) types.add(type);
-				List<RepositoryEntry> lstRepos = rm.genericANDQueryWithRolesRestriction(name, author, null, restrictedType ? types : null, roles, null, 0, -1, false);
+
+				List<RepositoryEntry> lstRepos = rm.genericANDQueryWithRolesRestriction(name, author, null, restrictedType ? types : null, identity, roles, null, 0, -1, false);
 				if(!lstRepos.isEmpty()) reposFound.addAll(lstRepos);
 			}
 			
@@ -341,6 +346,24 @@ public class RepositoryEntriesResource {
 
 			securityManager.addIdentityToSecurityGroup(identity, newGroup);
 			addedEntry.setOwnerGroup(newGroup);
+			
+			//fxdiff VCRP-1,2: access control of resources
+			// security group for tutors / coaches
+			SecurityGroup tutorGroup = securityManager.createAndPersistSecurityGroup();
+			// member of this group may modify member's membership
+			securityManager.createAndPersistPolicy(tutorGroup, Constants.PERMISSION_ACCESS, addedEntry.getOlatResource());
+			// members of this group are always tutors also
+			securityManager.createAndPersistPolicy(tutorGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_TUTOR);
+			addedEntry.setTutorGroup(tutorGroup);
+			
+			// security group for participants
+			SecurityGroup participantGroup = securityManager.createAndPersistSecurityGroup();
+			// member of this group may modify member's membership
+			securityManager.createAndPersistPolicy(participantGroup, Constants.PERMISSION_ACCESS, addedEntry.getOlatResource());
+			// members of this group are always participants also
+			securityManager.createAndPersistPolicy(participantGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_PARTICIPANT);
+			addedEntry.setParticipantGroup(participantGroup);
+			
 			// Do set access for owner at the end, because unfinished course should be
 			// invisible
 			addedEntry.setAccess(RepositoryEntry.ACC_OWNERS);
diff --git a/src/main/java/org/olat/restapi/repository/course/CourseAssessmentWebService.java b/src/main/java/org/olat/restapi/repository/course/CourseAssessmentWebService.java
index fa595a23e9da873a5ce8b39347a12f17f50a1e4c..83bad772e7c3adba2c4c07039d7dc19633f6d20b 100644
--- a/src/main/java/org/olat/restapi/repository/course/CourseAssessmentWebService.java
+++ b/src/main/java/org/olat/restapi/repository/course/CourseAssessmentWebService.java
@@ -57,7 +57,6 @@ import org.olat.core.id.IdentityEnvironment;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.assessment.AssessmentManager;
-import org.olat.course.groupsandrights.CourseGroupManager;
 import org.olat.course.nodes.AssessableCourseNode;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.IQTESTCourseNode;
@@ -83,6 +82,8 @@ import org.olat.ims.qti.process.AssessmentInstance;
 import org.olat.modules.ModuleConfiguration;
 import org.olat.modules.iq.IQManager;
 import org.olat.properties.Property;
+import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryManager;
 import org.olat.restapi.security.RestSecurityHelper;
 import org.olat.restapi.support.vo.AssessableResultsVO;
 
@@ -143,8 +144,8 @@ public class CourseAssessmentWebService {
 		if(course == null) {
 			return Response.serverError().status(Status.NOT_FOUND).build();
 		}
-
-		List<Identity> courseUsers = loadUsers(course.getCourseEnvironment().getCourseGroupManager());
+		//fxdiff VCRP-1,2: access control of resources
+		List<Identity> courseUsers = loadUsers(course);
 		int i=0;
 		
 		Date lastModified = null;
@@ -247,8 +248,8 @@ public class CourseAssessmentWebService {
 		} else if (!isAuthorEditor(course, httpRequest)) {
 			return Response.serverError().status(Status.UNAUTHORIZED).build();
 		}
-
-		List<Identity> courseUsers = loadUsers(course.getCourseEnvironment().getCourseGroupManager());
+		//fxdiff VCRP-1,2: access control of resources
+		List<Identity> courseUsers = loadUsers(course);
 		int i=0;
 		Date lastModified = null;
 		AssessableResultsVO[] results = new AssessableResultsVO[courseUsers.size()];
@@ -576,11 +577,12 @@ public class CourseAssessmentWebService {
 		}
 		return null;
 	}
-	
-	private List<Identity> loadUsers(CourseGroupManager gm) {
+
+	//fxdiff VCRP-1,2: access control of resources
+	private List<Identity> loadUsers(ICourse course) {
 		List<Identity> identites = new ArrayList<Identity>();
 		BaseSecurity securityManager = BaseSecurityManager.getInstance();
-		List<BusinessGroup> groups = gm.getAllLearningGroupsFromAllContexts();
+		List<BusinessGroup> groups = course.getCourseEnvironment().getCourseGroupManager().getAllLearningGroupsFromAllContexts();
 
 		Set<Long> check = new HashSet<Long>();
 		for(BusinessGroup group:groups) {
@@ -593,6 +595,18 @@ public class CourseAssessmentWebService {
 				}
 			}
 		}
+		//fxdiff VCRP-1,2: access control of resources
+		RepositoryEntry re = RepositoryManager.getInstance().lookupRepositoryEntry(course, false);
+		if(re != null && re.getParticipantGroup() != null) {
+			List<Identity> ids = securityManager.getIdentitiesOfSecurityGroup(re.getParticipantGroup());
+			for(Identity id:ids) {
+				if(!check.contains(id.getKey())) {
+					identites.add(id);
+					check.add(id.getKey());
+				}
+			}
+		}
+
 		return identites;
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/restapi/repository/course/CourseWebService.java b/src/main/java/org/olat/restapi/repository/course/CourseWebService.java
index 2784a17c5c61be30d7e36da3931528692725deb7..7147e4dc7588e437b3218156299e41ec1abcedf7 100644
--- a/src/main/java/org/olat/restapi/repository/course/CourseWebService.java
+++ b/src/main/java/org/olat/restapi/repository/course/CourseWebService.java
@@ -57,11 +57,16 @@ import org.olat.basesecurity.BaseSecurityManager;
 import org.olat.basesecurity.Constants;
 import org.olat.basesecurity.SecurityGroup;
 import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.tree.TreeNode;
+import org.olat.core.gui.control.WindowBackOffice;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.info.WindowControlInfo;
 import org.olat.core.gui.media.MediaResource;
 import org.olat.core.helpers.Settings;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
+import org.olat.core.id.context.BusinessControl;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.StringHelper;
@@ -190,7 +195,8 @@ public class CourseWebService {
 			 //only owners can the see course
 			 //RepositoryEntry.ACC_OWNERS_AUTHORS //only owners and authors can the see course
 			 //RepositoryEntry.ACC_USERS_GUESTS // users and guests can see the course
-			 publishProcess.changeGeneralAccess(null, newAccess);
+			 //fxdiff VCRP-1,2: access control of resources
+			 publishProcess.changeGeneralAccess(null, newAccess, false);
 			 
 			 if (publishTreeModel.hasPublishableChanges()) {
 				 List<String>nodeToPublish = new ArrayList<String>();
diff --git a/src/main/java/org/olat/restapi/repository/course/CoursesWebService.java b/src/main/java/org/olat/restapi/repository/course/CoursesWebService.java
index 751a62203167185e9fb0a34bb3a3985828aaecd1..bb7e0d4f88a7bcee5ce97b6693a42825e6865079 100644
--- a/src/main/java/org/olat/restapi/repository/course/CoursesWebService.java
+++ b/src/main/java/org/olat/restapi/repository/course/CoursesWebService.java
@@ -22,6 +22,7 @@ package org.olat.restapi.repository.course;
 
 import static org.olat.restapi.security.RestSecurityHelper.getRoles;
 import static org.olat.restapi.security.RestSecurityHelper.getUserRequest;
+import static org.olat.restapi.security.RestSecurityHelper.getIdentity;
 import static org.olat.restapi.security.RestSecurityHelper.isAuthor;
 
 import java.util.ArrayList;
@@ -125,19 +126,21 @@ public class CoursesWebService {
 			@QueryParam("limit") @DefaultValue("25") Integer limit, @Context HttpServletRequest httpRequest,
 			@Context Request request) {
 		RepositoryManager rm = RepositoryManager.getInstance();
-		
+
+		//fxdiff VCRP-1,2: access control of resources
 		Roles roles = getRoles(httpRequest);
+		Identity identity = getIdentity(httpRequest);
 		List<String> courseType = Collections.singletonList(CourseModule.getCourseTypeName());
 		if(MediaTypeVariants.isPaged(httpRequest, request)) {
-			int totalCount = rm.countGenericANDQueryWithRolesRestriction(null, null, null, courseType, roles, null, true);
-			List<RepositoryEntry> repoEntries = rm.genericANDQueryWithRolesRestriction(null, null, null, courseType, roles, null, start, limit, true);
+			int totalCount = rm.countGenericANDQueryWithRolesRestriction(null, null, null, courseType, identity, roles, null, true);
+			List<RepositoryEntry> repoEntries = rm.genericANDQueryWithRolesRestriction(null, null, null, courseType, identity, roles, null, start, limit, true);
 			CourseVO[] vos = toCourseVo(repoEntries);
 			CourseVOes voes = new CourseVOes();
 			voes.setCourses(vos);
 			voes.setTotalCount(totalCount);
 			return Response.ok(voes).build();
 		} else {
-			List<RepositoryEntry> repoEntries = rm.genericANDQueryWithRolesRestriction(null, null, null, courseType, roles, null, 0, -1, false);
+			List<RepositoryEntry> repoEntries = rm.genericANDQueryWithRolesRestriction(null, null, null, courseType, identity, roles, null, 0, -1, false);
 			CourseVO[] vos = toCourseVo(repoEntries);
 			return Response.ok(vos).build();
 		}
@@ -305,6 +308,23 @@ public class CoursesWebService {
 
 		securityManager.addIdentityToSecurityGroup(identity, newGroup);
 		addedEntry.setOwnerGroup(newGroup);
+			
+		//fxdiff VCRP-1,2: access control of resources
+		// security group for tutors / coaches
+		SecurityGroup tutorGroup = securityManager.createAndPersistSecurityGroup();
+		// member of this group may modify member's membership
+		securityManager.createAndPersistPolicy(tutorGroup, Constants.PERMISSION_ACCESS, addedEntry.getOlatResource());
+		// members of this group are always tutors also
+		securityManager.createAndPersistPolicy(tutorGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_TUTOR);
+		addedEntry.setTutorGroup(tutorGroup);
+			
+		// security group for participants
+		SecurityGroup participantGroup = securityManager.createAndPersistSecurityGroup();
+		// member of this group may modify member's membership
+		securityManager.createAndPersistPolicy(participantGroup, Constants.PERMISSION_ACCESS, addedEntry.getOlatResource());
+		// members of this group are always participants also
+		securityManager.createAndPersistPolicy(participantGroup, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_PARTICIPANT);
+		addedEntry.setParticipantGroup(participantGroup);
 		// Do set access for owner at the end, because unfinished course should be invisible
 		addedEntry.setAccess(RepositoryEntry.ACC_OWNERS);
 		RepositoryManager.getInstance().saveRepositoryEntry(addedEntry);
diff --git a/src/main/java/org/olat/restapi/security/RestApiLoginFilter.java b/src/main/java/org/olat/restapi/security/RestApiLoginFilter.java
index fed3dad61e970f41136bc30e006a0c8c882b4946..97afb84a1c01e44df87299ca7dde85990ec831c6 100644
--- a/src/main/java/org/olat/restapi/security/RestApiLoginFilter.java
+++ b/src/main/java/org/olat/restapi/security/RestApiLoginFilter.java
@@ -335,6 +335,7 @@ public class RestApiLoginFilter implements Filter {
 			openUrls.add(context + "/application.wadl");
 			openUrls.add(context + "/application.html");
 			openUrls.add(context + "/wadl");
+			openUrls.add(context + "/registration");
 		}
 		return openUrls;
 	}
diff --git a/src/main/java/org/olat/search/service/indexer/repository/RepositoryIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/RepositoryIndexer.java
index e6dd9a59d574472aed16b24ae94d7df7bce88de5..ec33be29a9d32fa764cc53ffa05a9238d0c1ac94 100644
--- a/src/main/java/org/olat/search/service/indexer/repository/RepositoryIndexer.java
+++ b/src/main/java/org/olat/search/service/indexer/repository/RepositoryIndexer.java
@@ -73,7 +73,8 @@ public class RepositoryIndexer implements Indexer {
   public void doIndex(SearchResourceContext parentResourceContext, Object businessObj, OlatFullIndexer indexWriter) throws IOException,InterruptedException {
   	Roles roles = new Roles(true, true, true, true, false, true, false);
   	int counter = 0;
-  	List repositoryList = repositoryManager.genericANDQueryWithRolesRestriction(null,null,null,null,roles, null);
+  	//fxdiff VCRP-1,2: access control of resources
+  	List repositoryList = repositoryManager.genericANDQueryWithRolesRestriction(null,null,null,null,null,roles, null);
   	if (Tracing.isDebugEnabled(RepositoryIndexer.class)) Tracing.logDebug("RepositoryIndexer repositoryList.size=" + repositoryList.size(), RepositoryIndexer.class);
   	// loop over all repository-entries
 		Iterator iter = repositoryList.iterator();
diff --git a/src/main/java/org/olat/search/service/indexer/repository/SharedFolderRepositoryIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/SharedFolderRepositoryIndexer.java
index 648d1863e5cded1c48088a9a23c2b1779938a7e5..cbf13c5c3a4ae010f40fbfc6a4f4dbe4a950aa1a 100644
--- a/src/main/java/org/olat/search/service/indexer/repository/SharedFolderRepositoryIndexer.java
+++ b/src/main/java/org/olat/search/service/indexer/repository/SharedFolderRepositoryIndexer.java
@@ -46,6 +46,8 @@ import org.olat.search.service.indexer.OlatFullIndexer;
  */
 public class SharedFolderRepositoryIndexer extends FolderIndexer implements Indexer {
 	private static final OLog log = Tracing.createLoggerFor(SharedFolderRepositoryIndexer.class);
+	// fxdiff: see LibraryManager
+	private static final String NO_FOLDER_INDEXING_LOCKFILE = ".noFolderIndexing";
 	
 	// Must correspond with LocalString_xx.properties
 	// Do not use '_' because we want to seach for certain documenttype and lucene haev problems with '_' 
@@ -78,8 +80,10 @@ public class SharedFolderRepositoryIndexer extends FolderIndexer implements Inde
 		resourceContext.setParentContextName(repositoryEntry.getDisplayname());
     
 		VFSContainer sfContainer = SharedFolderManager.getInstance().getSharedFolder(repositoryEntry.getOlatResource());
-		doIndexVFSContainer(resourceContext,sfContainer,indexWriter,"", FolderIndexerAccess.FULL_ACCESS);
-
+		// fxdiff: only index if no lockfile found. see OLAT-5724
+		if (sfContainer.resolve(NO_FOLDER_INDEXING_LOCKFILE) == null){
+			doIndexVFSContainer(resourceContext,sfContainer,indexWriter,"", FolderIndexerAccess.FULL_ACCESS);
+		}
 	}
 
 
diff --git a/src/main/java/org/olat/search/service/indexer/repository/course/DialogCourseNodeIndexer.java b/src/main/java/org/olat/search/service/indexer/repository/course/DialogCourseNodeIndexer.java
index a0dcf238a1fec9a79b41f7050b1412bb696f3a98..69cce40eb662bdc5bc297689bada193271f5f5ee 100644
--- a/src/main/java/org/olat/search/service/indexer/repository/course/DialogCourseNodeIndexer.java
+++ b/src/main/java/org/olat/search/service/indexer/repository/course/DialogCourseNodeIndexer.java
@@ -74,8 +74,6 @@ public class DialogCourseNodeIndexer implements CourseNodeIndexer {
 
 	private final static String SUPPORTED_TYPE_NAME = "org.olat.course.nodes.DialogCourseNode";
 	
-	private ForumManager forumMgr;
-
 	private DialogElementsPropertyManager dialogElmsMgr;
 
 	private CourseIndexer courseNodeIndexer;
@@ -83,7 +81,6 @@ public class DialogCourseNodeIndexer implements CourseNodeIndexer {
 
 	
 	public DialogCourseNodeIndexer() {
-		forumMgr = ForumManager.getInstance();
 		dialogElmsMgr = DialogElementsPropertyManager.getInstance();
 		courseNodeIndexer = new CourseIndexer();
 	}
@@ -103,7 +100,7 @@ public class DialogCourseNodeIndexer implements CourseNodeIndexer {
 			DialogElement element = iter.next();
 			element.getAuthor();
 			element.getDate();
-		  Forum forum = forumMgr.loadForum(element.getForumKey());
+		  Forum forum = ForumManager.getInstance().loadForum(element.getForumKey());
 			// do IndexForum
 			doIndexAllMessages(courseNodeResourceContext, forum, indexWriter );
 			// do Index File
@@ -153,7 +150,7 @@ public class DialogCourseNodeIndexer implements CourseNodeIndexer {
 
 	private void doIndexAllMessages(SearchResourceContext parentResourceContext, Forum forum, OlatFullIndexer indexWriter) throws IOException,InterruptedException {
 		// loop over all messages of a forum
-		List<Message> messages = forumMgr.getMessagesByForum(forum);
+		List<Message> messages = ForumManager.getInstance().getMessagesByForum(forum);
 		for(Message message:messages){
 			SearchResourceContext searchResourceContext = new SearchResourceContext(parentResourceContext);
 			searchResourceContext.setBusinessControlFor(message);
diff --git a/src/main/java/org/olat/upgrade/DatabaseUpgrade.java b/src/main/java/org/olat/upgrade/DatabaseUpgrade.java
new file mode 100644
index 0000000000000000000000000000000000000000..9876f1bdb088817297f0c2bc8293287451b7162d
--- /dev/null
+++ b/src/main/java/org/olat/upgrade/DatabaseUpgrade.java
@@ -0,0 +1,26 @@
+package org.olat.upgrade;
+
+public class DatabaseUpgrade extends OLATUpgrade {
+	
+	private final String version;
+	
+	public DatabaseUpgrade(String version) {
+		this.version = version;
+	}
+
+	@Override
+	public String getVersion() {
+		return version;
+	}
+
+	
+	@Override
+	public boolean doPreSystemInitUpgrade(UpgradeManager upgradeManager) {
+		return false;
+	}
+
+	@Override
+	public boolean doPostSystemInitUpgrade(UpgradeManager upgradeManager) {
+		return false;
+	}
+}
diff --git a/src/main/java/org/olat/upgrade/DatabaseUpgradeManager.java b/src/main/java/org/olat/upgrade/DatabaseUpgradeManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..c7ab70765db36956eb94ff3cb56acc366181ac4a
--- /dev/null
+++ b/src/main/java/org/olat/upgrade/DatabaseUpgradeManager.java
@@ -0,0 +1,160 @@
+package org.olat.upgrade;
+
+import java.io.File;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.olat.core.logging.StartupException;
+import org.olat.core.util.WebappHelper;
+import org.olat.core.util.xml.XStreamHelper;
+
+
+/**
+ * 
+ * Description:<br>
+ * Upgrade the database
+ * 
+ * <P>
+ * Initial Date:  8 sept. 2011 <br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class DatabaseUpgradeManager extends UpgradeManagerImpl {
+
+	protected UpgradesDefinitions olatUpgradesDefinitions;
+	
+	public DatabaseUpgradeManager() {
+		INSTALLED_UPGRADES_XML = "installed_database_upgrades.xml";
+	}
+	
+	/**
+	 * [used by Spring]
+	 * @param olatUpgradesDefinitions
+	 */
+	public void setOlatUpgradesDefinitions(UpgradesDefinitions olatUpgradesDefinitions) {
+		this.olatUpgradesDefinitions = olatUpgradesDefinitions;
+	}
+	
+	@Override
+	public void init() {
+		// load upgrades using spring framework 
+		upgrades = upgradesDefinitions.getUpgrades();
+		// load history of previous upgrades using xstream
+		initUpgradesHistories();
+		if (autoUpgradeDatabase) {
+			runAlterDbStatements();
+		} else {
+			logInfo("Auto upgrade of the database is disabled. Make sure you do it manually by applying the " +
+					"alter*.sql scripts and adding an entry to system/installed_upgrades.xml file.");
+		}
+	}
+
+	/**
+	 * @see org.olat.upgrade.UpgradeManager#runAlterDbStatements()
+	 */
+	@Override
+	public void runAlterDbStatements() {
+		String dialect = "";
+		//only run upgrades on mysql or postgresql
+		if (getDbVendor().contains("mysql")) dialect = "mysql";
+		else return;
+			
+		Statement statement = null;
+		try {
+			
+			logAudit("+--------------------------------------------------------------+");
+			logAudit("+... Pure database upgrade: starting alter DB statements ...+");
+			logAudit("+ If it fails, do it manually by applying the content of the alter_X_to_Y.sql files.+");
+			logAudit("+ For each file you upgraded to add an entry like this to the [pathToOlat]/olatdata/system/installed_database_upgrades.xml: +");
+			logAudit("+ <entry><string>Database update</string><boolean>true</boolean></entry>+");
+			logAudit("+--------------------------------------------------------------+");
+			
+			statement  = dataSource.getConnection().createStatement();
+			
+			Iterator<OLATUpgrade> iter = upgrades.iterator();
+			OLATUpgrade upgrade = null;
+			while (iter.hasNext()) {
+				upgrade = iter.next();
+				String alterDbStatementsFilename = upgrade.getAlterDbStatements();
+				if (alterDbStatementsFilename != null) {
+					UpgradeHistoryData uhd = getUpgradesHistory(upgrade.getVersion());
+					if (uhd == null) {
+						// has never been called, initialize
+						uhd = new UpgradeHistoryData();
+					} 
+						
+					if (!uhd.getBooleanDataValue(OLATUpgrade.TASK_DP_UPGRADE)) {
+						loadAndExecuteSqlStatements(statement, alterDbStatementsFilename, dialect);
+						uhd.setBooleanDataValue(OLATUpgrade.TASK_DP_UPGRADE, true);
+						setUpgradesHistory(uhd, upgrade.getVersion());
+						logAudit("Successfully executed alter DB statements for Version::" + upgrade.getVersion());
+					}
+				}
+			}
+			
+		}	catch (SQLException e) {
+			logError("Could not upgrade your database! Please do it manually and add ", e);
+			throw new StartupException("Could not execute alter db statements. Please do it manually.", e);
+			
+		} catch (Throwable e) {
+			logWarn("Error executing alter DB statements::", e);
+			abort(e);
+		} finally {
+			try {
+				if (statement != null) {
+					statement.close();
+				}
+			} catch (SQLException e2){
+				logWarn("Could not close sql statement", e2);
+				throw new StartupException("Could not close sql statements.", e2);
+			}
+		}
+	}
+	
+	@SuppressWarnings("unchecked")
+	protected void initUpgradesHistories() {
+		File upgradesDir = new File(WebappHelper.getUserDataRoot(), SYSTEM_DIR);
+		File upgradesHistoriesFile = new File(upgradesDir, INSTALLED_UPGRADES_XML);
+		if (upgradesHistoriesFile.exists()) {
+			upgradesHistories = (Map<String, UpgradeHistoryData>) XStreamHelper.readObject(upgradesHistoriesFile);
+		}
+		if (upgradesHistories == null) {
+			upgradesHistories = new HashMap<String, UpgradeHistoryData>();
+		}
+		transferToDBUpgrade(upgradesDir, upgradesHistories);
+	}
+	
+	private void transferToDBUpgrade(File upgradesDir, Map<String, UpgradeHistoryData> dbUpgradeHistory) {
+		File stdUpgradesHistoriesFile = new File(upgradesDir, "installed_upgrades.xml");
+		if (stdUpgradesHistoriesFile.exists()) {
+			Set<String> versions = new HashSet<String>();
+			for(OLATUpgrade upgrade:upgradesDefinitions.getUpgrades()) {
+				versions.add(upgrade.getVersion());
+			}
+
+			Map<String, UpgradeHistoryData> stdUpgradesHistories = (Map<String, UpgradeHistoryData>) XStreamHelper.readObject(stdUpgradesHistoriesFile);
+			for(Map.Entry<String, UpgradeHistoryData> entry: stdUpgradesHistories.entrySet()) {
+				String version = entry.getKey();
+				UpgradeHistoryData data = entry.getValue();
+				boolean updated = data.getBooleanDataValue("Database update");
+				if(versions.contains(version) && updated && !dbUpgradeHistory.containsKey(version)) {
+					dbUpgradeHistory.put(version, data);
+				}
+			}
+		}
+	}
+
+	@Override
+	public void doPreSystemInitUpgrades() {
+		//
+	}
+
+	@Override
+	public void doPostSystemInitUpgrades() {
+		//
+	}
+}
diff --git a/src/main/java/org/olat/upgrade/OLATUpgrade_5_0_0.java b/src/main/java/org/olat/upgrade/OLATUpgrade_5_0_0.java
index ffd88806dbe91144aeaa2b7a790756cd449bf1bd..653a3cb9cc6e88972d2ac56f74fbedd8b33f3d5e 100644
--- a/src/main/java/org/olat/upgrade/OLATUpgrade_5_0_0.java
+++ b/src/main/java/org/olat/upgrade/OLATUpgrade_5_0_0.java
@@ -117,7 +117,8 @@ public class OLATUpgrade_5_0_0 extends OLATUpgrade {
 	
 				// get all repository entries
 				Roles roles = new Roles(true, true, true, true, false, true, false);
-				List inDatabase = RepositoryManager.getInstance().genericANDQueryWithRolesRestriction(null, null, null, null, roles, null);
+				//fxdiff VCRP-1,2: access control of resources
+				List inDatabase = RepositoryManager.getInstance().genericANDQueryWithRolesRestriction(null, null, null, null, null, roles, null);
 	
 				Set inDatabaseIDs = new HashSet(inDatabase.size());
 				for (Iterator iter = inDatabase.iterator(); iter.hasNext();) {
diff --git a/src/main/java/org/olat/upgrade/OLATUpgrade_7_0_1.java b/src/main/java/org/olat/upgrade/OLATUpgrade_7_0_1.java
new file mode 100644
index 0000000000000000000000000000000000000000..d359ea6a3acbd159ae28215647da74bb4e8f214e
--- /dev/null
+++ b/src/main/java/org/olat/upgrade/OLATUpgrade_7_0_1.java
@@ -0,0 +1,126 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
+* University of Zurich, Switzerland.
+* <p>
+*/
+package org.olat.upgrade;
+
+import java.util.List;
+
+import org.hibernate.ObjectDeletedException;
+import org.olat.core.commons.persistence.DBFactory;
+import org.olat.core.util.StringHelper;
+import org.olat.core.util.notifications.NotificationsManager;
+import org.olat.core.util.notifications.Publisher;
+
+public class OLATUpgrade_7_0_1 extends OLATUpgrade {
+	
+	private static final String TASK_CHECK_NOTIFICATIONS = "Check notifications publishers";
+	
+	private static final String VERSION = "OLAT_7.0.1";
+
+	/**
+	 * @see org.olat.upgrade.OLATUpgrade#doPostSystemInitUpgrade(org.olat.upgrade.UpgradeManager)
+	 */
+	@Override
+	public boolean doPostSystemInitUpgrade(UpgradeManager upgradeManager) {
+		UpgradeHistoryData uhd = upgradeManager.getUpgradesHistory(VERSION);
+		if (uhd == null) {
+			// has never been called, initialize
+			uhd = new UpgradeHistoryData();
+		} else {
+			if (uhd.isInstallationComplete()) return false;
+		}
+		
+		migrateNotificationPublishers(upgradeManager, uhd);
+			
+		uhd.setInstallationComplete(true);
+		upgradeManager.setUpgradesHistory(uhd, VERSION);
+		log.audit("Finished OLATUpgrade_7_0_1 successfully!" );
+		return true;
+	}
+	
+
+
+	/**
+	 * @see org.olat.upgrade.OLATUpgrade#doPreSystemInitUpgrade(org.olat.upgrade.UpgradeManager)
+	 */
+	@Override
+	public boolean doPreSystemInitUpgrade(UpgradeManager upgradeManager) {
+		return false;
+	}
+	
+	private void migrateNotificationPublishers(UpgradeManager upgradeManager, UpgradeHistoryData uhd) {
+		if (!uhd.getBooleanDataValue(TASK_CHECK_NOTIFICATIONS)) {
+			log.audit("+-----------------------------------------------------------------------------+");
+			log.audit("+... Check the businesspath for the publishers (notifications)             ...+");
+			log.audit("+-----------------------------------------------------------------------------+");
+
+			int counter = 0;
+			NotificationsManager notificationMgr = NotificationsManager.getInstance();
+			List<Publisher> allPublishers = notificationMgr.getAllPublisher();
+			if (log.isDebug()) log.info("Found " + allPublishers.size() + " publishers to check.");
+
+			for(Publisher publisher:allPublishers) {
+				if(publisher != null && StringHelper.containsNonWhitespace(publisher.getBusinessPath())
+						&& (publisher.getBusinessPath().startsWith("[Identity") || publisher.getBusinessPath().startsWith("ROOT[Identity"))) {
+					try {
+						String businessPath = publisher.getBusinessPath();
+						int startIndex = businessPath.indexOf("[Identity");
+						int stopIndex = businessPath.indexOf("]", startIndex);
+						int wide = stopIndex - startIndex;
+						if(wide > 30) {
+							//Identity:326394598 cannot be too wide
+							continue;
+						} else if (stopIndex + 1 >= businessPath.length()) {
+							//only identity
+							continue;
+						}
+						
+						String correctPath = businessPath.substring(stopIndex + 1);
+						publisher.setBusinessPath(correctPath);
+						DBFactory.getInstance().updateObject(publisher);
+					} catch (ObjectDeletedException e) {
+						log.warn("Publisher was already deleted, no update possible! Publisher key: "+publisher.getKey() );
+					} catch (Exception e) {
+						log.warn("Publisher was already deleted, no update possible! Publisher key: "+publisher.getKey() );
+					}
+					counter++;
+				}
+				if (counter > 0 && counter % 100 == 0) {
+					log.audit("Another 100 publishers done");
+					DBFactory.getInstance().intermediateCommit();
+				}
+			}
+
+			DBFactory.getInstance().intermediateCommit();
+			log.audit("**** Checked " + counter + " publishers. ****");
+
+			uhd.setBooleanDataValue(TASK_CHECK_NOTIFICATIONS, true);
+			upgradeManager.setUpgradesHistory(uhd, VERSION);
+		}
+	}
+
+	/**
+	 * @see org.olat.upgrade.OLATUpgrade#getVersion()
+	 */
+	@Override
+	public String getVersion() {
+		return VERSION;
+	}
+}
diff --git a/src/main/java/org/olat/upgrade/UpgradeManager.java b/src/main/java/org/olat/upgrade/UpgradeManager.java
index 6be10992574e877c6b7269068d5db144443b2ce0..5f6e6220f97303af268fc2f5ff2947038e4cd77b 100644
--- a/src/main/java/org/olat/upgrade/UpgradeManager.java
+++ b/src/main/java/org/olat/upgrade/UpgradeManager.java
@@ -34,15 +34,15 @@ import org.olat.core.util.xml.XStreamHelper;
 
 public abstract class UpgradeManager extends BasicManager implements Initializable, GenericEventListener {
 	
-	static final String INSTALLED_UPGRADES_XML = "installed_upgrades.xml";
+	protected String INSTALLED_UPGRADES_XML = "installed_upgrades.xml";
 	static final String SYSTEM_DIR = "system";
 	
 	List<OLATUpgrade> upgrades;
 	Map<String, UpgradeHistoryData> upgradesHistories;
-	private UpgradesDefinitions upgradesDefinitions;
+	protected UpgradesDefinitions upgradesDefinitions;
 	protected DataSource dataSource;
-	private boolean needsUpgrade = true;
-	private boolean autoUpgradeDatabase = true;
+	protected boolean needsUpgrade = true;
+	protected boolean autoUpgradeDatabase = true;
 	
 	/**
    * [used by spring]
diff --git a/src/main/java/org/olat/upgrade/UpgradeManagerImpl.java b/src/main/java/org/olat/upgrade/UpgradeManagerImpl.java
index 00393310c9cf5a1a83a15c0fb126f8752eb75fbf..52c7d49e83f86ceb4cc6e0dd061bac2fdf6e20f3 100644
--- a/src/main/java/org/olat/upgrade/UpgradeManagerImpl.java
+++ b/src/main/java/org/olat/upgrade/UpgradeManagerImpl.java
@@ -50,10 +50,14 @@ public class UpgradeManagerImpl extends UpgradeManager {
 	/**
 	 * used by spring
 	 */
-	private UpgradeManagerImpl() {
+	public UpgradeManagerImpl() {
 		//
 	}
 	
+	public String getDbVendor() {
+		return dbVendor;
+	}
+	
 	/**
 	 * [user by Spring]
 	 * @param dbVendor
@@ -176,7 +180,7 @@ public class UpgradeManagerImpl extends UpgradeManager {
 	 * @param statements
 	 * @param alterDbStatements
 	 */
-	private void loadAndExecuteSqlStatements(Statement statement, String alterDbStatements, String dialect) {
+	protected void loadAndExecuteSqlStatements(Statement statement, String alterDbStatements, String dialect) {
 		try {
 			Resource setupDatabaseFile = new ClassPathResource("/database/"+dialect+"/"+alterDbStatements);
 			if (!setupDatabaseFile.exists()) {
diff --git a/src/main/java/org/olat/upgrade/_spring/databaseUpgradeContext.xml b/src/main/java/org/olat/upgrade/_spring/databaseUpgradeContext.xml
new file mode 100644
index 0000000000000000000000000000000000000000..dae9d48c2b947d9f3d34fc4e8940aa79d03675a5
--- /dev/null
+++ b/src/main/java/org/olat/upgrade/_spring/databaseUpgradeContext.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xmlns:context="http://www.springframework.org/schema/context" 
+	xsi:schemaLocation="
+  http://www.springframework.org/schema/beans 
+  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
+  http://www.springframework.org/schema/context 
+  http://www.springframework.org/schema/context/spring-context-3.0.xsd">
+  
+ 	<bean id="databaseUpgrader" class="org.olat.upgrade.DatabaseUpgradeManager" init-method="init"
+ 		depends-on="org.olat.core.util.WebappHelper">
+ 		<property name="dbVendor" value="${db.vendor}"/>
+		<property name="upgradesDefinitions" ref="databaseUpgrades"/>
+		<property name="dataSource" ref="${db.vendor}DataSource"/>
+		<property name="autoUpgradeDatabase" value="${auto.upgrade.database}" />
+	</bean>
+
+	<bean id="databaseUpgrades" class="org.olat.upgrade.UpgradesDefinitions">
+		<property name="upgrades">
+			<list>
+				<bean id="database_upgrade_7_1_0" class="org.olat.upgrade.DatabaseUpgrade">
+					<constructor-arg index="0" value="OLAT_7.1.0" />
+					<property name="alterDbStatements" value="alter_7_0_x_to_7_1_0.sql" />
+				</bean>
+				<bean id="database_upgrade_7_1_1" class="org.olat.upgrade.DatabaseUpgrade">
+					<constructor-arg index="0" value="OLAT_7.1.1" />
+					<property name="alterDbStatements" value="alter_7_1_x_to_7_1_1.sql" />
+				</bean>
+				<bean id="database_upgrade_8_0" class="org.olat.upgrade.DatabaseUpgrade">
+					<constructor-arg index="0" value="OLAT_8.0.0" />
+					<property name="alterDbStatements" value="alter_7_1_x_to_8_0_0.sql" />
+				</bean>
+			</list>
+		</property>
+	</bean>
+
+</beans>
\ No newline at end of file
diff --git a/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml b/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml
index 404ca62156d5742ee39f5204fdb2662d4926004d..ef0612fd97bf81dbf4fd3650435c000f7f4b2701 100644
--- a/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml
+++ b/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml
@@ -8,8 +8,6 @@
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">
   
-<context:property-placeholder location="classpath:serviceconfig/olat.properties, classpath:olat.local.properties" />
-  
 <context:annotation-config />
 <context:component-scan base-package="org.olat.upgrade" />
 
@@ -59,6 +57,7 @@
 				<bean id="upgrade_7_0_0" class="org.olat.upgrade.OLATUpgrade_7_0_0" >
 					<property name="alterDbStatements" value="alter_6_3_x_to_7_0_0.sql"/>
 				</bean>
+				<bean id="upgrade_7_0_1" class="org.olat.upgrade.OLATUpgrade_7_0_1"/>			
 				<bean id="upgrade_7_1_0" class="org.olat.upgrade.OLATUpgrade_7_1_0">
 					<property name="portletRepositoryStudentEnabled" value="${portlet.repository.student.enabled}"/>
 					<property name="portletRepositoryTeacherEnabled" value="${portlet.repository.teacher.enabled}"/>
diff --git a/src/main/java/org/olat/user/IdentityContextEntryControllerCreator.java b/src/main/java/org/olat/user/IdentityContextEntryControllerCreator.java
index 8c0ddcc5301fd089b80564cdc82f6ed7fab44115..1466620e6a62058a3dd276fa4a92c0a21da1757b 100644
--- a/src/main/java/org/olat/user/IdentityContextEntryControllerCreator.java
+++ b/src/main/java/org/olat/user/IdentityContextEntryControllerCreator.java
@@ -27,10 +27,12 @@ import org.olat.core.gui.control.WindowControl;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.id.context.ContextEntry;
-import org.olat.core.id.context.ContextEntryControllerCreator;
+import org.olat.core.id.context.ContextEntryControllerCreator2;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 
+import org.olat.home.HomeSite;
+
 /**
  * <h3>Description:</h3>
  * <p>
@@ -41,7 +43,7 @@ import org.olat.core.logging.Tracing;
  * 
  * @author gnaegi, gnaegi@frentix.com, www.frentix.com
  */
-public class IdentityContextEntryControllerCreator implements ContextEntryControllerCreator {
+public class IdentityContextEntryControllerCreator implements ContextEntryControllerCreator2 {
 	private static final OLog log = Tracing.createLoggerFor(IdentityContextEntryControllerCreator.class);
 
 	/**
@@ -64,6 +66,16 @@ public class IdentityContextEntryControllerCreator implements ContextEntryContro
 		return null;
 	}
 
+	@Override
+	//fxdiff BAKS-7 Resume function
+	public String getSiteClassName(UserRequest ureq, ContextEntry ce) {
+		Long resId = ce.getOLATResourceable().getResourceableId();
+		if(resId != null && resId.equals(ureq.getIdentity().getKey())) {
+			return HomeSite.class.getName();
+		}
+		return null;
+	}
+
 	/**
 	 * @see org.olat.core.id.context.ContextEntryControllerCreator#getTabName(org.olat.core.id.context.ContextEntry)
 	 */
diff --git a/src/main/resources/database/mysql/alter_7_1_x_to_8_0_0.sql b/src/main/resources/database/mysql/alter_7_1_x_to_8_0_0.sql
new file mode 100644
index 0000000000000000000000000000000000000000..d6d8ede75fa2f82cabcce9a450c2aa42075fba57
--- /dev/null
+++ b/src/main/resources/database/mysql/alter_7_1_x_to_8_0_0.sql
@@ -0,0 +1,192 @@
+-- mail preferences
+alter table o_user add column receiverealmail varchar(16);
+
+-- mail system
+create table if not exists o_mail (
+  mail_id bigint NOT NULL,
+  meta_mail_id varchar(64),
+  creationdate datetime,
+	lastmodified datetime,
+	resname varchar(50),
+  resid bigint,
+  ressubpath varchar(2048),
+  businesspath varchar(2048),
+  subject varchar(512),
+  body longtext,
+  fk_from_id bigint,
+  primary key (mail_id)
+);
+
+-- mail recipient
+create table if not exists o_mail_to_recipient (
+  pos mediumint NOT NULL default 0,
+  fk_mail_id bigint,
+  fk_recipient_id bigint
+);
+
+create table if not exists o_mail_recipient (
+  recipient_id bigint NOT NULL,
+  recipientvisible bit,
+  deleted bit,
+  mailread bit,
+  mailmarked bit,
+  email varchar(255),
+  recipientgroup varchar(255),
+  creationdate datetime,
+  fk_recipient_id bigint,
+  primary key (recipient_id)
+);
+
+-- mail attachments
+create table o_mail_attachment (
+	attachment_id bigint NOT NULL,
+  creationdate datetime,
+	datas mediumblob,
+	datas_size bigint,
+	datas_name varchar(255),
+	mimetype varchar(255),
+  fk_att_mail_id bigint,
+	primary key (attachment_id)
+);
+
+-- access control
+create table  if not exists o_ac_offer (
+	offer_id bigint NOT NULL,
+  creationdate datetime,
+	lastmodified datetime,
+	is_valid bit default 1,
+	validfrom datetime,
+	validto datetime,
+  version mediumint unsigned not null,
+  resourceid bigint,
+  resourcetypename varchar(255),
+  resourcedisplayname varchar(255),
+  token varchar(255),
+  price_amount DECIMAL(12,4),
+	price_currency_code VARCHAR(3),
+	offer_desc VARCHAR(2000),
+  fk_resource_id bigint,
+	primary key (offer_id)
+);
+
+create table if not exists o_ac_method (
+	method_id bigint NOT NULL,
+	access_method varchar(32),
+  version mediumint unsigned not null,
+  creationdate datetime,
+	lastmodified datetime,
+	is_valid bit default 1,
+	is_enabled bit default 1,
+	validfrom datetime,
+	validto datetime,
+	primary key (method_id)
+);
+
+create table if not exists o_ac_offer_access (
+	offer_method_id bigint NOT NULL,
+  version mediumint unsigned not null,
+  creationdate datetime,
+	is_valid bit default 1,
+	validfrom datetime,
+	validto datetime,
+  fk_offer_id bigint,
+  fk_method_id bigint,
+	primary key (offer_method_id)
+);
+
+-- access cart
+create table if not exists o_ac_order (
+	order_id bigint NOT NULL,
+  version mediumint unsigned not null,
+  creationdate datetime,
+	lastmodified datetime,
+	is_valid bit default 1,
+	total_lines_amount DECIMAL(12,4),
+	total_lines_currency_code VARCHAR(3),
+	total_amount DECIMAL(12,4),
+	total_currency_code VARCHAR(3),
+	discount_amount DECIMAL(12,4),
+	discount_currency_code VARCHAR(3),
+	order_status VARCHAR(32) default 'NEW',
+  fk_delivery_id bigint,
+	primary key (order_id)
+);
+
+create table if not exists o_ac_order_part (
+	order_part_id bigint NOT NULL,
+  version mediumint unsigned not null,
+  pos mediumint unsigned,
+  creationdate datetime,
+  total_lines_amount DECIMAL(12,4),
+  total_lines_currency_code VARCHAR(3),
+  total_amount DECIMAL(12,4),
+  total_currency_code VARCHAR(3),
+  fk_order_id bigint,
+	primary key (order_part_id)
+);
+
+create table if not exists o_ac_order_line (
+	order_item_id bigint NOT NULL,
+  version mediumint unsigned not null,
+  pos mediumint unsigned,
+  creationdate datetime,
+	unit_price_amount DECIMAL(12,4),
+	unit_price_currency_code VARCHAR(3),
+	total_amount DECIMAL(12,4),
+	total_currency_code VARCHAR(3),
+  fk_order_part_id bigint,
+  fk_offer_id bigint,
+	primary key (order_item_id)
+);
+
+create table if not exists o_ac_transaction (
+	transaction_id bigint NOT NULL,
+  version mediumint unsigned not null,
+  creationdate datetime,
+  trx_status VARCHAR(32) default 'NEW',
+  amount_amount DECIMAL(12,4),
+  amount_currency_code VARCHAR(3),
+  fk_order_part_id bigint,
+  fk_order_id bigint,
+  fk_method_id bigint,
+	primary key (transaction_id)
+);
+
+-- access control
+alter table o_repositoryentry add column fk_tutorgroup bigint;
+alter table o_repositoryentry add column fk_participantgroup bigint;
+alter table o_repositoryentry add column membersonly bit default 0;
+create index repo_members_only_idx on o_repositoryentry (membersonly);
+alter table o_repositoryentry add constraint repo_tutor_sec_group_ctx foreign key (fk_tutorgroup) references o_bs_secgroup (id);
+alter table o_repositoryentry add constraint repo_parti_sec_group_ctx foreign key (fk_participantgroup) references o_bs_secgroup (id);
+
+create index name_idx on o_olatresource (resname);
+
+alter table o_mail ENGINE = InnoDB;
+alter table o_mail_to_recipient ENGINE = InnoDB;
+alter table o_mail_recipient ENGINE = InnoDB;
+alter table o_mail_attachment ENGINE = InnoDB;
+alter table o_ac_offer ENGINE = InnoDB;
+alter table o_ac_method ENGINE = InnoDB;
+alter table o_ac_offer_access ENGINE = InnoDB;
+alter table o_ac_order ENGINE = InnoDB;
+alter table o_ac_order_part ENGINE = InnoDB;
+alter table o_ac_order_line ENGINE = InnoDB;
+alter table o_ac_transaction ENGINE = InnoDB;
+
+alter table o_mail_to_recipient add constraint FKF86663165A4FA5DE foreign key (fk_mail_id) references o_mail (mail_id);
+alter table o_mail_recipient add constraint FKF86663165A4FA5DG foreign key (fk_recipient_id) references o_bs_identity (id);
+alter table o_mail add constraint FKF86663165A4FA5DC foreign key (fk_from_id) references o_mail_recipient (recipient_id);
+alter table o_mail_to_recipient add constraint FKF86663165A4FA5DD foreign key (fk_recipient_id) references o_mail_recipient (recipient_id);
+alter table o_mail_attachment add constraint FKF86663165A4FA5DF foreign key (fk_att_mail_id) references o_mail (mail_id);
+
+create index ac_offer_to_resource_idx on o_ac_offer (fk_resource_id);
+alter table o_ac_offer_access add constraint off_to_meth_meth_ctx foreign key (fk_method_id) references o_ac_method (method_id);
+alter table o_ac_offer_access add constraint off_to_meth_off_ctx foreign key (fk_offer_id) references o_ac_offer (offer_id);
+create index ac_order_to_delivery_idx on o_ac_order (fk_delivery_id);
+alter table o_ac_order_part add constraint ord_part_ord_ctx foreign key (fk_order_id) references o_ac_order (order_id);
+alter table o_ac_order_line add constraint ord_item_ord_part_ctx foreign key (fk_order_part_id) references o_ac_order_part (order_part_id);
+alter table o_ac_order_line add constraint ord_item_offer_ctx foreign key (fk_offer_id) references o_ac_offer (offer_id);
+alter table o_ac_transaction add constraint trans_ord_ctx foreign key (fk_order_id) references o_ac_order (order_id);
+alter table o_ac_transaction add constraint trans_ord_part_ctx foreign key (fk_order_part_id) references o_ac_order_part (order_part_id);
+alter table o_ac_transaction add constraint trans_method_ctx foreign key (fk_method_id) references o_ac_method (method_id);
\ No newline at end of file
diff --git a/src/main/resources/database/mysql/setupDatabase.sql b/src/main/resources/database/mysql/setupDatabase.sql
index 0d54d9c684bf77bede8f1f838062c6a2ad38e231..ab6f5cf167ecc6483653bee7c1722534e19ffa10 100644
--- a/src/main/resources/database/mysql/setupDatabase.sql
+++ b/src/main/resources/database/mysql/setupDatabase.sql
@@ -290,9 +290,12 @@ create table if not exists o_repositoryentry (
    resourcename varchar(100) not null,
    fk_olatresource bigint unique,
    fk_ownergroup bigint unique,
+   fk_tutorgroup bigint,
+	 fk_participantgroup bigint,
    description longtext,
    initialauthor varchar(128) not null,
    accesscode integer not null default 0,
+   membersonly bit default 0,
    statuscode integer,
    canlaunch bit not null,
    candownload bit not null,
@@ -750,6 +753,157 @@ create table if not exists o_ep_struct_artefact_link (
   primary key (link_id)
 );
 
+-- mail system
+
+create table if not exists o_mail (
+  mail_id bigint NOT NULL,
+  meta_mail_id varchar(64),
+  creationdate datetime,
+	lastmodified datetime,
+	resname varchar(50),
+  resid bigint,
+  ressubpath varchar(2048),
+  businesspath varchar(2048),
+  subject varchar(512),
+  body longtext,
+  fk_from_id bigint,
+  primary key (mail_id)
+);
+
+-- mail recipient
+create table if not exists o_mail_to_recipient (
+  pos mediumint NOT NULL default 0,
+  fk_mail_id bigint,
+  fk_recipient_id bigint
+);
+
+create table if not exists o_mail_recipient (
+  recipient_id bigint NOT NULL,
+  recipientvisible bit,
+  deleted bit,
+  mailread bit,
+  mailmarked bit,
+  email varchar(255),
+  recipientgroup varchar(255),
+  creationdate datetime,
+  fk_recipient_id bigint,
+  primary key (recipient_id)
+);
+
+-- mail attachments
+create table o_mail_attachment (
+	attachment_id bigint NOT NULL,
+  creationdate datetime,
+	datas mediumblob,
+	datas_size bigint,
+	datas_name varchar(255),
+	mimetype varchar(255),
+  fk_att_mail_id bigint,
+	primary key (attachment_id)
+);
+
+-- access control
+create table  if not exists o_ac_offer (
+	offer_id bigint NOT NULL,
+  creationdate datetime,
+	lastmodified datetime,
+	is_valid bit default 1,
+	validfrom datetime,
+	validto datetime,
+  version mediumint unsigned not null,
+  resourceid bigint,
+  resourcetypename varchar(255),
+  resourcedisplayname varchar(255),
+  token varchar(255),
+  price_amount DECIMAL(12,4),
+	price_currency_code VARCHAR(3),
+	offer_desc VARCHAR(2000),
+  fk_resource_id bigint,
+	primary key (offer_id)
+);
+
+create table if not exists o_ac_method (
+	method_id bigint NOT NULL,
+	access_method varchar(32),
+  version mediumint unsigned not null,
+  creationdate datetime,
+	lastmodified datetime,
+	is_valid bit default 1,
+	is_enabled bit default 1,
+	validfrom datetime,
+	validto datetime,
+	primary key (method_id)
+);
+
+create table if not exists o_ac_offer_access (
+	offer_method_id bigint NOT NULL,
+  version mediumint unsigned not null,
+  creationdate datetime,
+	is_valid bit default 1,
+	validfrom datetime,
+	validto datetime,
+  fk_offer_id bigint,
+  fk_method_id bigint,
+	primary key (offer_method_id)
+);
+
+-- access cart
+create table if not exists o_ac_order (
+	order_id bigint NOT NULL,
+  version mediumint unsigned not null,
+  creationdate datetime,
+	lastmodified datetime,
+	is_valid bit default 1,
+	total_lines_amount DECIMAL(12,4),
+	total_lines_currency_code VARCHAR(3),
+	total_amount DECIMAL(12,4),
+	total_currency_code VARCHAR(3),
+	discount_amount DECIMAL(12,4),
+	discount_currency_code VARCHAR(3),
+	order_status VARCHAR(32) default 'NEW',
+  fk_delivery_id bigint,
+	primary key (order_id)
+);
+
+create table if not exists o_ac_order_part (
+	order_part_id bigint NOT NULL,
+  version mediumint unsigned not null,
+  pos mediumint unsigned,
+  creationdate datetime,
+  total_lines_amount DECIMAL(12,4),
+  total_lines_currency_code VARCHAR(3),
+  total_amount DECIMAL(12,4),
+  total_currency_code VARCHAR(3),
+  fk_order_id bigint,
+	primary key (order_part_id)
+);
+
+create table if not exists o_ac_order_line (
+	order_item_id bigint NOT NULL,
+  version mediumint unsigned not null,
+  pos mediumint unsigned,
+  creationdate datetime,
+	unit_price_amount DECIMAL(12,4),
+	unit_price_currency_code VARCHAR(3),
+	total_amount DECIMAL(12,4),
+	total_currency_code VARCHAR(3),
+  fk_order_part_id bigint,
+  fk_offer_id bigint,
+	primary key (order_item_id)
+);
+
+create table if not exists o_ac_transaction (
+	transaction_id bigint NOT NULL,
+  version mediumint unsigned not null,
+  creationdate datetime,
+  trx_status VARCHAR(32) default 'NEW',
+  amount_amount DECIMAL(12,4),
+  amount_currency_code VARCHAR(3),
+  fk_order_part_id bigint,
+  fk_order_id bigint,
+  fk_method_id bigint,
+	primary key (transaction_id)
+);
 
 create index  ocl_asset_idx on oc_lock (asset);
 alter table oc_lock add index FK9E30F4B66115906D (identity_fk), add constraint FK9E30F4B66115906D foreign key (identity_fk) references o_bs_identity (id);
@@ -804,6 +958,18 @@ alter table o_ep_collect_restriction ENGINE = InnoDB;
 alter table o_ep_struct_el ENGINE = InnoDB;
 alter table o_ep_struct_struct_link ENGINE = InnoDB;
 alter table o_ep_struct_artefact_link ENGINE = InnoDB;
+alter table o_co_db_entry ENGINE = InnoDB;
+alter table o_mail ENGINE = InnoDB;
+alter table o_mail_to_recipient ENGINE = InnoDB;
+alter table o_mail_recipient ENGINE = InnoDB;
+alter table o_mail_attachment ENGINE = InnoDB;
+alter table o_ac_offer ENGINE = InnoDB;
+alter table o_ac_method ENGINE = InnoDB;
+alter table o_ac_offer_access ENGINE = InnoDB;
+alter table o_ac_order ENGINE = InnoDB;
+alter table o_ac_order_part ENGINE = InnoDB;
+alter table o_ac_order_line ENGINE = InnoDB;
+alter table o_ac_transaction ENGINE = InnoDB;
 
 
 create index  resid_idx on o_property (resourcetypeid);
@@ -874,6 +1040,8 @@ create index  displayname_idx on o_repositoryentry (displayname);
 create index  softkey_idx on o_repositoryentry (softkey);
 alter table o_repositoryentry add index FK2F9C439888C31018 (fk_olatresource), add constraint FK2F9C439888C31018 foreign key (fk_olatresource) references o_olatresource (resource_id);
 alter table o_repositoryentry add index FK2F9C4398A1FAC766 (fk_ownergroup), add constraint FK2F9C4398A1FAC766 foreign key (fk_ownergroup) references o_bs_secgroup (id);
+alter table o_repositoryentry add constraint repo_tutor_sec_group_ctx foreign key (fk_tutorgroup) references o_bs_secgroup (id);
+alter table o_repositoryentry add constraint repo_parti_sec_group_ctx foreign key (fk_participantgroup) references o_bs_secgroup (id);
 alter table o_bookmark add index FK68C4E30663219E27 (owner_id), add constraint FK68C4E30663219E27 foreign key (owner_id) references o_bs_identity (id);
 alter table o_bs_membership add index FK7B6288B45259603C (identity_id), add constraint FK7B6288B45259603C foreign key (identity_id) references o_bs_identity (id);
 alter table o_bs_membership add index FK7B6288B4B85B522C (secgroup_id), add constraint FK7B6288B4B85B522C foreign key (secgroup_id) references o_bs_secgroup (id);
@@ -931,6 +1099,24 @@ alter table o_ep_struct_artefact_link add constraint FKF26C8375236F24X foreign k
 alter table o_ep_struct_artefact_link add constraint FKF26C8375236F25X foreign key (fk_artefact_id) references o_ep_artefact (artefact_id);
 alter table o_ep_struct_artefact_link add constraint FKF26C8375236F26Y foreign key (fk_auth_id) references o_bs_identity (id);
 
+alter table o_mail_to_recipient add constraint FKF86663165A4FA5DE foreign key (fk_mail_id) references o_mail (mail_id);
+alter table o_mail_recipient add constraint FKF86663165A4FA5DG foreign key (fk_recipient_id) references o_bs_identity (id);
+alter table o_mail add constraint FKF86663165A4FA5DC foreign key (fk_from_id) references o_mail_recipient (recipient_id);
+alter table o_mail_to_recipient add constraint FKF86663165A4FA5DD foreign key (fk_recipient_id) references o_mail_recipient (recipient_id);
+alter table o_mail_attachment add constraint FKF86663165A4FA5DF foreign key (fk_att_mail_id) references o_mail (mail_id);
+
+create index ac_offer_to_resource_idx on o_ac_offer (fk_resource_id);
+alter table o_ac_offer_access add constraint off_to_meth_meth_ctx foreign key (fk_method_id) references o_ac_method (method_id);
+alter table o_ac_offer_access add constraint off_to_meth_off_ctx foreign key (fk_offer_id) references o_ac_offer (offer_id);
+create index ac_order_to_delivery_idx on o_ac_order (fk_delivery_id);
+alter table o_ac_order_part add constraint ord_part_ord_ctx foreign key (fk_order_id) references o_ac_order (order_id);
+alter table o_ac_order_line add constraint ord_item_ord_part_ctx foreign key (fk_order_part_id) references o_ac_order_part (order_part_id);
+alter table o_ac_order_line add constraint ord_item_offer_ctx foreign key (fk_offer_id) references o_ac_offer (offer_id);
+alter table o_ac_transaction add constraint trans_ord_ctx foreign key (fk_order_id) references o_ac_order (order_id);
+alter table o_ac_transaction add constraint trans_ord_part_ctx foreign key (fk_order_part_id) references o_ac_order_part (order_part_id);
+alter table o_ac_transaction add constraint trans_method_ctx foreign key (fk_method_id) references o_ac_method (method_id);
+
+
 alter table o_tag add constraint FK6491FCA5A4FA5DC foreign key (fk_author_id) references o_bs_identity (id);
 
 alter table o_bs_invitation add constraint FKF26C8375236F27X foreign key (fk_secgroup) references o_bs_secgroup (id);
diff --git a/src/main/resources/serviceconfig/olat.properties b/src/main/resources/serviceconfig/olat.properties
index 4e54d112a2ba68a502a6bcfa63315f8c20c0c31b..4b56b98c384e6d35cb62897dcba78bf1739fa908 100644
--- a/src/main/resources/serviceconfig/olat.properties
+++ b/src/main/resources/serviceconfig/olat.properties
@@ -246,6 +246,7 @@ portlet.institution.enabled=false
 portlet.repository.student.enabled=false
 portlet.repository.teacher.enabled=false
 portlet.system.events.enabled=false
+portlet.institution.enabled=false
 # sysinfo portlet settings (files are editable if hosted on local server) (system.events)
 portlet.sysinfo.url=../../raw/${build.version}/events.html
 portlet.sysinfo.filepath=pathToYourEventsFile/static/events.html
@@ -329,7 +330,7 @@ db.url.options.mysql=?useUnicode=true&characterEncoding=UTF-8
 db.show_sql=false
 # validate, update, create, create-drop are valid entries. Default is update for use as developer setup with embedded hsqldb.
 # set to validate or disable with empty value to not validate against your database.
-db.hibernate.ddl.auto=update
+db.hibernate.ddl.auto=
 # configure the c3p0 pool with hibernate
 db.hibernate.c3p0.minsize=20
 db.hibernate.c3p0.maxsize=50
@@ -561,6 +562,17 @@ log.anonymous=false
 
 
 
+########################################
+# Access control
+########################################
+#module on/off
+resource.accesscontrol.enabled=true
+#The user has a menu item in home to see the list of access
+resource.accesscontrol.home.overview=true
+#access methods available
+method.token.enabled=true
+method.free.enabled=true
+
 ########################################
 # Course building blocks, every course building block can be disabled by adding a property here and reference it in
 # appropriate spring config file (by default are course bb are enabled)
diff --git a/src/test/java/org/olat/repository/RepositoryManagerQueryTest.java b/src/test/java/org/olat/repository/RepositoryManagerQueryTest.java
index 8c75dceb223055cca6b1db9783b82afa218ce878..5871e67424b877dfb6af727de10900dd19adc751 100644
--- a/src/test/java/org/olat/repository/RepositoryManagerQueryTest.java
+++ b/src/test/java/org/olat/repository/RepositoryManagerQueryTest.java
@@ -5,7 +5,6 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -14,7 +13,6 @@ import java.util.Set;
 import org.junit.Before;
 import org.junit.Test;
 import org.olat.basesecurity.BaseSecurity;
-import org.olat.basesecurity.BaseSecurityManager;
 import org.olat.basesecurity.Constants;
 import org.olat.basesecurity.SecurityGroup;
 import org.olat.core.commons.persistence.DB;
@@ -49,6 +47,8 @@ public class RepositoryManagerQueryTest extends OlatTestCase {
 	@Autowired
 	private UserManager userManager;
 	
+	private static Identity admin;
+	
 	private static final String author = "RepositoryManagerQueryAuthor";
 	private static boolean initialized = false;
 	
@@ -62,6 +62,8 @@ public class RepositoryManagerQueryTest extends OlatTestCase {
 		
 		DB db = DBFactory.getInstance();
 		
+		admin = JunitTestHelper.createAndPersistIdentityAsAdmin("administrator");
+		
 		Identity id1 = JunitTestHelper.createAndPersistIdentityAsAuthor(author + "1");
 		id1.getUser().setProperty(UserConstants.FIRSTNAME, author + "1");
 		id1.getUser().setProperty(UserConstants.LASTNAME, author + "1");
@@ -130,7 +132,7 @@ public class RepositoryManagerQueryTest extends OlatTestCase {
 	public void testTwoShootQuery() {
 		List<String> types = Collections.singletonList(TEST_RES_NAME);
 		Roles role1 = new Roles(false, false, false, true, false, false, false);
-		List<RepositoryEntry> resultTwoShoot = rm.genericANDQueryWithRolesRestriction(null, null, null, types, role1, null);
+		List<RepositoryEntry> resultTwoShoot = rm.genericANDQueryWithRolesRestriction(null, null, null, types, null, role1, null);
 		assertNotNull(resultTwoShoot);
 		assertFalse(resultTwoShoot.isEmpty());
 	}
@@ -141,13 +143,13 @@ public class RepositoryManagerQueryTest extends OlatTestCase {
 		
 		//roles: author + institution manager
 		Roles role2 = new Roles(false, false, false, true, false, true, false);
-		List<RepositoryEntry> resultTwoShootInstitut = rm.genericANDQueryWithRolesRestriction(null, null, null, types, role2, "Volks");
+		List<RepositoryEntry> resultTwoShootInstitut = rm.genericANDQueryWithRolesRestriction(null, null, null, types, null, role2, "Volks");
 		Set<RepositoryEntry> resultTwoShootInstitutSet = new HashSet<RepositoryEntry>(resultTwoShootInstitut);
 		assertNotNull(resultTwoShootInstitut);
 		assertFalse(resultTwoShootInstitut.isEmpty());
 		assertEquals(resultTwoShootInstitutSet.size(), resultTwoShootInstitut.size());
 		
-		List<RepositoryEntry> resultOneShootInstitut = rm.genericANDQueryWithRolesRestriction(null, null, null, types, role2, "Volks", 0, -1, true);
+		List<RepositoryEntry> resultOneShootInstitut = rm.genericANDQueryWithRolesRestriction(null, null, null, types, admin, role2, "Volks", 0, -1, true);
 		assertNotNull(resultOneShootInstitut);
 		assertFalse(resultOneShootInstitut.isEmpty());
 
@@ -160,11 +162,11 @@ public class RepositoryManagerQueryTest extends OlatTestCase {
 		
 		//roles: author + institution manager
 		Roles role2 = new Roles(false, false, false, true, false, false, false);
-		List<RepositoryEntry> resultTwoShoot = rm.genericANDQueryWithRolesRestriction(null, null, null, types, role2, null);
+		List<RepositoryEntry> resultTwoShoot = rm.genericANDQueryWithRolesRestriction(null, null, null, types, null, role2, null);
 		assertNotNull(resultTwoShoot);
 		assertFalse(resultTwoShoot.isEmpty());
 		
-		List<RepositoryEntry> resultOneShoot = rm.genericANDQueryWithRolesRestriction(null, null, null, types, role2, null, 0, -1, true);
+		List<RepositoryEntry> resultOneShoot = rm.genericANDQueryWithRolesRestriction(null, null, null, types, null, role2, null, 0, -1, true);
 		assertNotNull(resultOneShoot);
 		assertFalse(resultOneShoot.isEmpty());
 
@@ -177,11 +179,11 @@ public class RepositoryManagerQueryTest extends OlatTestCase {
 		
 		//roles: institution manager
 		Roles role3 = new Roles(false, false, false, true, false, true, false);
-		List<RepositoryEntry> resultTwoShootInstitut3 = rm.genericANDQueryWithRolesRestriction(null, null, null, types, role3, "Volks");
+		List<RepositoryEntry> resultTwoShootInstitut3 = rm.genericANDQueryWithRolesRestriction(null, null, null, types, null, role3, "Volks");
 		assertNotNull(resultTwoShootInstitut3);
 		assertFalse(resultTwoShootInstitut3.isEmpty());
 		
-		List<RepositoryEntry> resultOneShootInstitut3 = rm.genericANDQueryWithRolesRestriction(null, null, null, types, role3, "Volks", 0, -1, true);
+		List<RepositoryEntry> resultOneShootInstitut3 = rm.genericANDQueryWithRolesRestriction(null, null, null, types, null, role3, "Volks", 0, -1, true);
 		assertNotNull(resultOneShootInstitut3);
 		assertFalse(resultOneShootInstitut3.isEmpty());
 		//check
@@ -194,12 +196,12 @@ public class RepositoryManagerQueryTest extends OlatTestCase {
 		
 		//roles: institution manager search: authorname
 		Roles role4 = new Roles(false, false, false, false, false, true, false);
-		List<RepositoryEntry> resultTwoShootInstitut4 = rm.genericANDQueryWithRolesRestriction(null, "kan", null, types, role4, "Volks");
+		List<RepositoryEntry> resultTwoShootInstitut4 = rm.genericANDQueryWithRolesRestriction(null, "kan", null, types, null, role4, "Volks");
 		assertNotNull(resultTwoShootInstitut4);
 		assertFalse(resultTwoShootInstitut4.isEmpty());
 		
 
-		List<RepositoryEntry> resultOneShootInstitut4 = rm.genericANDQueryWithRolesRestriction(null, "kan", null, types, role4, "Volks", 0, -1, true);
+		List<RepositoryEntry> resultOneShootInstitut4 = rm.genericANDQueryWithRolesRestriction(null, "kan", null, types, null, role4, "Volks", 0, -1, true);
 		assertNotNull(resultOneShootInstitut4);
 		assertFalse(resultOneShootInstitut4.isEmpty());
 		//check
@@ -212,13 +214,13 @@ public class RepositoryManagerQueryTest extends OlatTestCase {
 		
 		//roles: institution manager search: authorname
 		Roles role4 = new Roles(false, false, false, false, false, true, false);
-		List<RepositoryEntry> resultTwoShootInstitut4 = rm.genericANDQueryWithRolesRestriction(null, "kan", null, types, role4, "Volks");
+		List<RepositoryEntry> resultTwoShootInstitut4 = rm.genericANDQueryWithRolesRestriction(null, "kan", null, types, null, role4, "Volks");
 		assertNotNull(resultTwoShootInstitut4);
 		assertFalse(resultTwoShootInstitut4.isEmpty());
 		
 		//test paging
-		List<RepositoryEntry> resultOneShootInstitut6 = rm.genericANDQueryWithRolesRestriction(null, "kan", null, types, role4, "Volks", 0, 50, true);
-		int resultOneShootInstitutTotal6 = rm.countGenericANDQueryWithRolesRestriction(null, "kan", null, types, role4, "Volks", true);
+		List<RepositoryEntry> resultOneShootInstitut6 = rm.genericANDQueryWithRolesRestriction(null, "kan", null, types, null, role4, "Volks", 0, 50, true);
+		int resultOneShootInstitutTotal6 = rm.countGenericANDQueryWithRolesRestriction(null, "kan", null, types, null, role4, "Volks", true);
 		assertNotNull(resultOneShootInstitut6);
 		assertEquals(50, resultOneShootInstitut6.size());
 		//check
diff --git a/src/test/java/org/olat/repository/RepositoryManagerTest.java b/src/test/java/org/olat/repository/RepositoryManagerTest.java
index 4876b6a682dfd1339d51f8a0a3a708a9a44e2769..e44b547a1cdb11bbb570e14c09bb973888c52c21 100644
--- a/src/test/java/org/olat/repository/RepositoryManagerTest.java
+++ b/src/test/java/org/olat/repository/RepositoryManagerTest.java
@@ -87,14 +87,9 @@ public class RepositoryManagerTest extends OlatTestCase {
 	@Before public void setup() {
 		try {
 			// Setup for code-points
-
-			System.out.println("Tschagaaa, start RepositoryManagerTest!");
 			JMSCodePointServerJunitHelper.startServer(CODEPOINT_SERVER_ID);
 		} catch (Exception e) {
 			log.error("Error while setting up activeMq or Codepointserver", e);
-		} catch(Error err) {
-			System.out.println("Tschagaaa, ERROR starting RepositoryManagerTest!");
-			throw err;
 		}
 	}
 	
@@ -116,9 +111,6 @@ public class RepositoryManagerTest extends OlatTestCase {
 	@Test
 	public void testRawRepositoryEntryCreate() {
 		try {
-
-			System.out.println("Tschagaaa, start testRawRepositoryEntryCreate!");
-			
 			DB db = DBFactory.getInstance();
 			OLATResourceManager rm = OLATResourceManager.getInstance();
 			// create course and persist as OLATResourceImpl
@@ -367,14 +359,16 @@ public class RepositoryManagerTest extends OlatTestCase {
 						if (i % 20 == 0 ) {
 							int ACCESS_VALUE = 4;
 							System.out.println("RepositoryManagerTest: call setAccess i=" + i);
-							RepositoryManager.getInstance().setAccess(repositoryEntryT1, ACCESS_VALUE);
+							//fxdiff VCRP-1,2: access control of resources
+							RepositoryManager.getInstance().setAccess(repositoryEntryT1, ACCESS_VALUE, false);
 							DBFactory.getInstance().closeSession();
 							RepositoryEntry repositoryEntryT1Reloaded = RepositoryManager.getInstance().lookupRepositoryEntry(keyRepo);
 							assertEquals("Wrong access value",ACCESS_VALUE,repositoryEntryT1Reloaded.getAccess());
 						} else if (i % 10 == 0 ) {
 							int ACCESS_VALUE = 1;
 							System.out.println("RepositoryManagerTest: call setAccess i=" + i);
-							RepositoryManager.getInstance().setAccess(repositoryEntryT1, ACCESS_VALUE);
+							//fxdiff VCRP-1,2: access control of resources
+							RepositoryManager.getInstance().setAccess(repositoryEntryT1, ACCESS_VALUE, false);
 							DBFactory.getInstance().closeSession();
 							RepositoryEntry repositoryEntryT1Reloaded = RepositoryManager.getInstance().lookupRepositoryEntry(keyRepo);
 							assertEquals("Wrong access value",ACCESS_VALUE,repositoryEntryT1Reloaded.getAccess());
diff --git a/src/test/java/org/olat/restapi/CourseTest.java b/src/test/java/org/olat/restapi/CourseTest.java
index d465e0c016dbf8e1553cbee1925ee5109b756ea5..6da76d87e7599825c242ec3ec2c85de1c5e69d79 100644
--- a/src/test/java/org/olat/restapi/CourseTest.java
+++ b/src/test/java/org/olat/restapi/CourseTest.java
@@ -140,7 +140,8 @@ public class CourseTest extends OlatJerseyTestCase {
 		List<String> courseType = new ArrayList<String>();
 		courseType.add(CourseModule.getCourseTypeName());
 		Roles roles = new Roles(true, true, true, true, false, true, false);
-		List<RepositoryEntry> repoEntries = RepositoryManager.getInstance().genericANDQueryWithRolesRestriction("*", "*", "*", courseType, roles, "");
+		//fxdiff VCRP-1,2: access control of resources
+		List<RepositoryEntry> repoEntries = RepositoryManager.getInstance().genericANDQueryWithRolesRestriction("*", "*", "*", courseType, null, roles, "");
 		assertNotNull(repoEntries);
 		
 		for(RepositoryEntry entry:repoEntries) {
diff --git a/src/test/java/org/olat/search/service/document/file/FileDocumentFactoryTest.java b/src/test/java/org/olat/search/service/document/file/FileDocumentFactoryTest.java
index 101af83bd5d5d2022ea525ef2aa84b5c4ae32080..b4fe6abec33af505ac628a4a3585b65e376b3934 100644
--- a/src/test/java/org/olat/search/service/document/file/FileDocumentFactoryTest.java
+++ b/src/test/java/org/olat/search/service/document/file/FileDocumentFactoryTest.java
@@ -25,9 +25,10 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
 
 import org.apache.log4j.Logger;
 import org.apache.lucene.document.Document;
@@ -91,8 +92,8 @@ public class FileDocumentFactoryTest extends OlatTestCase {
 		assertTrue("pdf must be supported", fileDocumentFactory.isFileSupported(new LocalFileImpl(new File("test.pdf"))));
 		assertTrue("PDF must be supported", fileDocumentFactory.isFileSupported(new LocalFileImpl(new File("test.PDF"))));
 
-		assertTrue("DOC must be supported", fileDocumentFactory.isFileSupported(new LocalFileImpl(new File("test.DOC"))));
-		assertTrue("doc must be supported", fileDocumentFactory.isFileSupported(new LocalFileImpl(new File("test.doc"))));
+		assertTrue("DOC must be supported", fileDocumentFactory.isFileSupported(getVFSFile("test2.DOC")));
+		assertTrue("doc must be supported", fileDocumentFactory.isFileSupported(getVFSFile("test.doc")));
 
 		assertTrue("TXT must be supported", fileDocumentFactory.isFileSupported(new LocalFileImpl(new File("test.TXT"))));
 		assertTrue("txt must be supported", fileDocumentFactory.isFileSupported(new LocalFileImpl(new File("test.txt"))));
@@ -103,6 +104,17 @@ public class FileDocumentFactoryTest extends OlatTestCase {
 		assertTrue("XML must be supported", fileDocumentFactory.isFileSupported(new LocalFileImpl(new File("test.XML"))));
 		assertTrue("xml must be supported", fileDocumentFactory.isFileSupported(new LocalFileImpl(new File("test.xml"))));
 	}
+	
+	private VFSLeaf getVFSFile(String name) {
+		try {
+			URL url = FileDocumentFactoryTest.class.getResource(name);
+			File file = new File(url.toURI());
+			return new LocalFileImpl(file);
+		} catch (URISyntaxException e) {
+			e.printStackTrace();
+			return null;
+		}
+	}
 
 	@Test public void testCreateHtmlDocument() {
 		String filePath = "SearchTestFolder";
diff --git a/src/test/java/org/olat/test/OlatJerseyTestCase.java b/src/test/java/org/olat/test/OlatJerseyTestCase.java
index 95a4c6f148373e1a149db6c5ee67b4bc77b45808..baaa3344caa3d4cf025d2b3330bcb06b80fc2d3d 100644
--- a/src/test/java/org/olat/test/OlatJerseyTestCase.java
+++ b/src/test/java/org/olat/test/OlatJerseyTestCase.java
@@ -285,7 +285,16 @@ public abstract class OlatJerseyTestCase extends OlatTestCase {
 		return createPut(requestURI, accept, cookie);
 	}
 	
+	public PutMethod createPut(String requestStr, String accept, String langage, boolean cookie) {
+		URI requestURI = UriBuilder.fromUri(getContextURI()).path(requestStr).build();
+		return createPut(requestURI, accept, langage, cookie);
+	}
+	
 	public PutMethod createPut(URI requestURI, String accept, boolean cookie) {
+		return createPut(requestURI, accept, "en", cookie);
+	}
+	
+	public PutMethod createPut(URI requestURI, String accept, String langage, boolean cookie) {
 		PutMethod method = new PutMethod(requestURI.toString());
 		if(cookie) {
 			method.getParams().setCookiePolicy(CookiePolicy.RFC_2109);
@@ -293,7 +302,7 @@ public abstract class OlatJerseyTestCase extends OlatTestCase {
 		if(StringHelper.containsNonWhitespace(accept)) {
 			method.addRequestHeader("Accept", accept);
 		}
-		method.addRequestHeader("Accept-Language", "en");
+		method.addRequestHeader("Accept-Language", langage);
 		return method;
 	}
 	
diff --git a/src/test/java/org/olat/user/UserTest.java b/src/test/java/org/olat/user/UserTest.java
index 1c4330795ef7c4cc78c8295c7438ee699f2565cb..6762845a1dc4e09b0acec0957b3424bfab04afd4 100644
--- a/src/test/java/org/olat/user/UserTest.java
+++ b/src/test/java/org/olat/user/UserTest.java
@@ -381,7 +381,8 @@ public class UserTest extends OlatTestCase {
 		assertEquals(0, result.size());
 		// find identity 2-3 via first, last and instuser id (non-deletable fields)
 		result = BaseSecurityManager.getInstance().getIdentitiesByPowerSearch(null, searchValue, false, null, null, null, null, null, null, null, null);
-		assertEquals(2, result.size());
+		//fxdiff
+		assertEquals(3, result.size());
 		
 		// check using other methods
 		Identity identity = um.findIdentityByEmail("instjudihui@id.uzh.ch");