diff --git a/src/main/java/org/olat/collaboration/CollaborationManager.java b/src/main/java/org/olat/collaboration/CollaborationManager.java
index 3a41b69d59cf3b27042ec5ecf2d4911aaf2a02b1..8702403350bf4d370bd13b97cf7d5d31f48f9003 100644
--- a/src/main/java/org/olat/collaboration/CollaborationManager.java
+++ b/src/main/java/org/olat/collaboration/CollaborationManager.java
@@ -19,6 +19,9 @@
  */
 package org.olat.collaboration;
 
+import java.util.List;
+import java.util.Map;
+
 import org.olat.commons.calendar.ui.components.KalendarRenderWrapper;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.id.OLATResourceable;
@@ -34,6 +37,8 @@ public interface CollaborationManager {
 	
 	public Long lookupFolderAccess(OLATResourceable ores);
 	
+	public Map<Long,Long> lookupCalendarAccess(List<BusinessGroup> groups);
+	
 	public KalendarRenderWrapper getCalendar(BusinessGroup group, UserRequest ureq, boolean isAdmin);
 
 }
diff --git a/src/main/java/org/olat/collaboration/CollaborationManagerImpl.java b/src/main/java/org/olat/collaboration/CollaborationManagerImpl.java
index 28ca29d6bf62bc4532dfe4768b0b5dea784e70ee..6ec567167f296141b9cf465915a6bf189015f858 100644
--- a/src/main/java/org/olat/collaboration/CollaborationManagerImpl.java
+++ b/src/main/java/org/olat/collaboration/CollaborationManagerImpl.java
@@ -19,23 +19,31 @@
  */
 package org.olat.collaboration;
 
+import static org.olat.collaboration.CollaborationTools.KEY_CALENDAR_ACCESS;
 import static org.olat.collaboration.CollaborationTools.KEY_FOLDER_ACCESS;
 import static org.olat.collaboration.CollaborationTools.PROP_CAT_BG_COLLABTOOLS;
 
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+
+import javax.persistence.TypedQuery;
 
 import org.olat.basesecurity.BaseSecurityManager;
 import org.olat.commons.calendar.CalendarManager;
 import org.olat.commons.calendar.CalendarManagerFactory;
 import org.olat.commons.calendar.model.KalendarConfig;
 import org.olat.commons.calendar.ui.components.KalendarRenderWrapper;
+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.commons.persistence.PersistenceHelper;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.manager.BasicManager;
 import org.olat.group.BusinessGroup;
 import org.olat.properties.Property;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
@@ -43,6 +51,8 @@ import org.olat.properties.Property;
  */
 public class CollaborationManagerImpl extends BasicManager implements CollaborationManager {
 	
+	@Autowired
+	private DB dbInstance;
 	
 	public String getFolderRelPath(OLATResourceable ores) {
 		return "/cts/folders/" + ores.getResourceableTypeName() + "/" + ores.getResourceableId();
@@ -69,6 +79,42 @@ public class CollaborationManagerImpl extends BasicManager implements Collaborat
 			return props.get(0);
 		}
 	}
+	
+	@Override
+	public Map<Long,Long> lookupCalendarAccess(List<BusinessGroup> groups) {
+		if(groups == null || groups.isEmpty()) {
+			return new HashMap<Long,Long>();
+		}
+		
+		StringBuilder query = new StringBuilder();
+		query.append("select prop from ").append(Property.class.getName()).append(" as prop where ")
+		     .append(" prop.category='").append(PROP_CAT_BG_COLLABTOOLS).append("'")
+		     .append(" and prop.resourceTypeName='BusinessGroup'")
+		     .append(" and prop.resourceTypeId in (:groupKeys)")
+		     .append(" and prop.name='").append(KEY_CALENDAR_ACCESS).append("'")
+		     .append(" and prop.identity is null and prop.grp is null");
+		
+		TypedQuery<Property> dbquery = dbInstance.getCurrentEntityManager().createQuery(query.toString(), Property.class);
+		Map<Long,Long> groupKeyToAccess = new HashMap<Long,Long>();
+
+		int count = 0;
+		int batch = 200;
+		do {
+			int toIndex = Math.min(count + batch, groups.size());
+			List<BusinessGroup> toLoad = groups.subList(count, toIndex);
+			List<Long> groupKeys = PersistenceHelper.toKeys(toLoad);
+
+			List<Property> props = dbquery.setFirstResult(count)
+				.setMaxResults(batch)
+				.setParameter("groupKeys", groupKeys)
+				.getResultList();
+			for(Property prop:props) {
+				groupKeyToAccess.put(prop.getResourceTypeId(), prop.getLongValue());
+			}
+			count += batch;
+		} while(count < groups.size());
+		return groupKeyToAccess;
+	}
 
 	@Override
 	public KalendarRenderWrapper getCalendar(BusinessGroup businessGroup, UserRequest ureq, boolean isAdmin) {
diff --git a/src/main/java/org/olat/collaboration/CollaborationTools.java b/src/main/java/org/olat/collaboration/CollaborationTools.java
index 20e772bc6cc5214085e5dcfbc8e50fbd1a3c53bb..069ed53bb323311d76b937f91e30645b07602890 100644
--- a/src/main/java/org/olat/collaboration/CollaborationTools.java
+++ b/src/main/java/org/olat/collaboration/CollaborationTools.java
@@ -218,7 +218,7 @@ public class CollaborationTools implements Serializable {
 	 * cache for Boolean Objects representing the State
 	 */
 	private final static String KEY_NEWS = "news";
-	private final static String KEY_CALENDAR_ACCESS = "cal";
+	public final static String KEY_CALENDAR_ACCESS = "cal";
 	//fxdiff VCRP-8: collaboration tools folder access control
 	public final static String KEY_FOLDER_ACCESS = "folder";
 
diff --git a/src/main/java/org/olat/commons/calendar/ICalFileCalendarManager.java b/src/main/java/org/olat/commons/calendar/ICalFileCalendarManager.java
index e445656577391aaf179a7b1a67efcaae37a19ed7..4f967f2cf2bcb02a0ec276a50aebcc3fb9cd911e 100644
--- a/src/main/java/org/olat/commons/calendar/ICalFileCalendarManager.java
+++ b/src/main/java/org/olat/commons/calendar/ICalFileCalendarManager.java
@@ -63,7 +63,6 @@ import net.fortuna.ical4j.model.property.CalScale;
 import net.fortuna.ical4j.model.property.Clazz;
 import net.fortuna.ical4j.model.property.Contact;
 import net.fortuna.ical4j.model.property.Created;
-import net.fortuna.ical4j.model.property.DtEnd;
 import net.fortuna.ical4j.model.property.Duration;
 import net.fortuna.ical4j.model.property.ExDate;
 import net.fortuna.ical4j.model.property.LastModified;
@@ -108,7 +107,7 @@ public class ICalFileCalendarManager extends BasicManager implements CalendarMan
 
 	private File fStorageBase;
 	// o_clusterOK by:cg 
-	private CacheWrapper calendarCache;
+	private CacheWrapper<String, Kalendar> calendarCache;
 
 	private static final Clazz ICAL_CLASS_PRIVATE = new Clazz("PRIVATE");
 	private static final Clazz ICAL_CLASS_PUBLIC = new Clazz("PUBLIC");
@@ -162,27 +161,30 @@ public class ICalFileCalendarManager extends BasicManager implements CalendarMan
 		return new Kalendar(calendarID, type);
 	}
 
-	public Kalendar getCalendar(String type, String calendarID) {
-		//o_clusterOK by:cg
-		OLATResourceable calOres = OresHelper.createOLATResourceableType(getKeyFor(type,calendarID));
-		final String callType = type;
-		final String callCalendarID = calendarID;
-		Kalendar cal = CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync( calOres, new SyncerCallback<Kalendar>() {
-			public Kalendar execute() {
-				return getCalendarFromCache(callType, callCalendarID);
-			}
-		});
+	@Override
+	public Kalendar getCalendar(final String type, final String calendarID) {
+		String key = getKeyFor(type, calendarID);
+		Kalendar cal = calendarCache.get(key);
+		if(cal == null) {
+			//o_clusterOK by:cg
+			OLATResourceable calOres = OresHelper.createOLATResourceableType(getKeyFor(type,calendarID));
+			cal = CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync( calOres, new SyncerCallback<Kalendar>() {
+				public Kalendar execute() {
+					return getCalendarFromCache(type, calendarID);
+				}
+			});
+		}
 		return cal;
 	}
 
-	protected Kalendar getCalendarFromCache(final String callType, final String callCalendarID) {
-		OLATResourceable calOres = OresHelper.createOLATResourceableType(getKeyFor(callType,callCalendarID));		
+	private Kalendar getCalendarFromCache(final String callType, final String callCalendarID) {
+		String calKey = getKeyFor(callType,callCalendarID);
+		OLATResourceable calOres = OresHelper.createOLATResourceableType(calKey);		
 		CoordinatorManager.getInstance().getCoordinator().getSyncer().assertAlreadyDoInSyncFor(calOres);
-		String key = getKeyFor(callType,callCalendarID);
-		Kalendar cal = (Kalendar)calendarCache.get(key);
+		Kalendar cal = calendarCache.get(calKey);
 		if (cal == null) {
 			cal = loadOrCreateCalendar(callType, callCalendarID);
-			calendarCache.put(key, cal);
+			calendarCache.put(calKey, cal);
 		}
 		return cal;
 	}
@@ -400,10 +402,10 @@ public class ICalFileCalendarManager extends BasicManager implements CalendarMan
 		}
 		
 		// event links
-		List kalendarEventLinks = kEvent.getKalendarEventLinks();
+		List<KalendarEventLink> kalendarEventLinks = kEvent.getKalendarEventLinks();
 		if ((kalendarEventLinks != null) && !kalendarEventLinks.isEmpty()) {
-			for (Iterator iter = kalendarEventLinks.iterator(); iter.hasNext();) {
-				KalendarEventLink link = (KalendarEventLink) iter.next();
+			for (Iterator<KalendarEventLink> iter = kalendarEventLinks.iterator(); iter.hasNext();) {
+				KalendarEventLink link = iter.next();
 				StringBuilder linkEncoded = new StringBuilder(200);
 				linkEncoded.append(link.getProvider());
 				linkEncoded.append("§");
@@ -547,7 +549,7 @@ public class ICalFileCalendarManager extends BasicManager implements CalendarMan
 		
 		// links if any
 		List linkProperties = event.getProperties(ICAL_X_OLAT_LINK);
-		List kalendarEventLinks = new ArrayList();
+		List<KalendarEventLink> kalendarEventLinks = new ArrayList<KalendarEventLink>();
 		for (Iterator iter = linkProperties.iterator(); iter.hasNext();) {
 			XProperty linkProperty = (XProperty) iter.next();
 			if (linkProperty != null) {
diff --git a/src/main/java/org/olat/commons/calendar/model/Kalendar.java b/src/main/java/org/olat/commons/calendar/model/Kalendar.java
index 003e65a024b56411accdc2878610af39a214ca07..e96d85fe927ca5d303d61568e321e6bce30a3c3a 100644
--- a/src/main/java/org/olat/commons/calendar/model/Kalendar.java
+++ b/src/main/java/org/olat/commons/calendar/model/Kalendar.java
@@ -32,6 +32,8 @@ import java.util.Map;
 
 public class Kalendar implements Serializable {
 
+	private static final long serialVersionUID = -2179014489859413340L;
+	
 	private String calendarID;
 	private String type;
 	private Map<String, KalendarEvent> events;
diff --git a/src/main/java/org/olat/home/HomeCalendarController.java b/src/main/java/org/olat/home/HomeCalendarController.java
index c6ef0dd6685e899249710754cc8abfedae3e4e84..15b2532a675abdec2f1673fd5f902ade6fbcf3d6 100644
--- a/src/main/java/org/olat/home/HomeCalendarController.java
+++ b/src/main/java/org/olat/home/HomeCalendarController.java
@@ -29,9 +29,10 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
+import org.olat.collaboration.CollaborationManager;
 import org.olat.collaboration.CollaborationTools;
-import org.olat.collaboration.CollaborationToolsFactory;
 import org.olat.commons.calendar.CalendarManager;
 import org.olat.commons.calendar.CalendarManagerFactory;
 import org.olat.commons.calendar.ImportCalendarManager;
@@ -197,18 +198,25 @@ public class HomeCalendarController extends BasicController implements Activatea
 		return ImportCalendarManager.getImportedCalendarsForIdentity(ureq);
 	}
 	
+	/**
+	 * Append the calendars of a list of groups. The groups must have their calendar tool
+	 * enabled, this routine doesn't check it.
+	 * @param ureq
+	 * @param groups
+	 * @param isOwner
+	 * @param calendars
+	 */
 	private static void addCalendars(UserRequest ureq, List<BusinessGroup> groups, boolean isOwner, List<KalendarRenderWrapper> calendars) {
-		CollaborationToolsFactory collabFactory = CollaborationToolsFactory.getInstance();
 		CalendarManager calendarManager = CalendarManagerFactory.getInstance().getCalendarManager();
-		for (Iterator<BusinessGroup> iter = groups.iterator(); iter.hasNext();) {
-			BusinessGroup bGroup = iter.next();
-			CollaborationTools collabTools = collabFactory.getOrCreateCollaborationTools(bGroup);
-			if (!collabTools.isToolEnabled(CollaborationTools.TOOL_CALENDAR)) continue;
+		Map<Long,Long> groupKeyToAccess = CoreSpringFactory.getImpl(CollaborationManager.class).lookupCalendarAccess(groups);
+		for (BusinessGroup bGroup:groups) {
 			KalendarRenderWrapper groupCalendarWrapper = calendarManager.getGroupCalendar(bGroup);
 			// set calendar access
 			int iCalAccess = CollaborationTools.CALENDAR_ACCESS_OWNERS;
-			Long lCalAccess = collabTools.lookupCalendarAccess();
-			if (lCalAccess != null) iCalAccess = lCalAccess.intValue();
+			Long lCalAccess = groupKeyToAccess.get(bGroup.getKey());
+			if (lCalAccess != null) {
+				iCalAccess = lCalAccess.intValue();
+			}
 			if (iCalAccess == CollaborationTools.CALENDAR_ACCESS_OWNERS && !isOwner) {
 				groupCalendarWrapper.setAccess(KalendarRenderWrapper.ACCESS_READ_ONLY);
 			} else {
diff --git a/src/main/resources/infinispan-config.xml b/src/main/resources/infinispan-config.xml
index 9df5dcb7a95ff169981c3600dab717cba5758636..37a50c8a2c995d373c3cc159978f4dbebf9821bd 100644
--- a/src/main/resources/infinispan-config.xml
+++ b/src/main/resources/infinispan-config.xml
@@ -29,6 +29,12 @@
 		<transaction transactionMode="TRANSACTIONAL" />
 	</namedCache>
 	
+	<namedCache name="CalendarManager@calendar">
+		<eviction maxEntries="500" strategy="LRU"/>
+		<expiration maxIdle="900000" wakeUpInterval="5000"/>
+		<transaction transactionMode="NON_TRANSACTIONAL" />
+	</namedCache>
+	
 	<!-- 
 	Hibernate cache
 	 -->