diff --git a/src/main/java/org/olat/commons/calendar/restapi/CalWebService.java b/src/main/java/org/olat/commons/calendar/restapi/CalWebService.java
new file mode 100644
index 0000000000000000000000000000000000000000..cf34a4f0553152f91ebe358746ce4f81a3ef1a7e
--- /dev/null
+++ b/src/main/java/org/olat/commons/calendar/restapi/CalWebService.java
@@ -0,0 +1,180 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <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 the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <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>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.commons.calendar.restapi;
+
+import static org.olat.restapi.security.RestSecurityHelper.getUserRequest;
+import static org.olat.commons.calendar.restapi.CalendarWSHelper.*;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.UUID;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Request;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.olat.commons.calendar.CalendarManager;
+import org.olat.commons.calendar.CalendarManagerFactory;
+import org.olat.commons.calendar.model.KalendarEvent;
+import org.olat.commons.calendar.ui.components.KalendarRenderWrapper;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.util.StringHelper;
+
+public class CalWebService {
+	
+	private final KalendarRenderWrapper calendar;
+	
+	public CalWebService(KalendarRenderWrapper calendar) {
+		this.calendar = calendar;
+	}
+	
+	@GET
+	@Path("events")
+	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
+	public Response getEventsByCalendar(@PathParam("calendarId") String calendarId,
+			@PathParam("identityKey") Long identityKey, @QueryParam("start") @DefaultValue("0") Integer start,
+			@QueryParam("limit") @DefaultValue("25") Integer limit,
+			@QueryParam("onlyFuture") @DefaultValue("false") Boolean onlyFuture,
+			@Context HttpServletRequest httpRequest, @Context Request request) {
+		
+		UserRequest ureq = getUserRequest(httpRequest);
+		if(!ureq.getUserSession().isAuthenticated()) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+		
+		if(calendar == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		} else if (!hasReadAccess(calendar)) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+		
+		List<EventVO> events = new ArrayList<EventVO>();
+		Collection<KalendarEvent> kalEvents = calendar.getKalendar().getEvents();
+		for(KalendarEvent kalEvent:kalEvents) {
+			EventVO eventVo = new EventVO(kalEvent);
+			events.add(eventVo);
+		}
+
+		return processEvents(events, onlyFuture, start, limit, httpRequest, request);
+	}
+	
+	@DELETE
+	@Path("events/{eventId}")
+	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
+	@Consumes({MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
+	public Response deleteEventByCalendar(@PathParam("calendarId") String calendarId,
+			@PathParam("eventId") String eventId, @PathParam("identityKey") Long identityKey,
+			@Context HttpServletRequest httpRequest) {
+		
+		UserRequest ureq = getUserRequest(httpRequest);
+		if(!ureq.getUserSession().isAuthenticated()) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+		
+		if(calendar == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		} else if(!hasWriteAccess(calendar)) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+
+		CalendarManager calendarManager = CalendarManagerFactory.getInstance().getCalendarManager();
+		if(eventId == null) {
+			return Response.ok().status(Status.NOT_FOUND).build();
+		} else {
+			KalendarEvent kalEvent = calendar.getKalendar().getEvent(eventId);
+			if(kalEvent == null) {
+				return Response.ok().status(Status.NOT_FOUND).build();
+			} else {
+				calendarManager.removeEventFrom(calendar.getKalendar(), kalEvent);
+			}
+		}
+
+		return Response.ok().build();
+	}
+	
+	@PUT
+	@Path("events")
+	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
+	@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
+	public Response putEventByCalendar(@PathParam("calendarId") String calendarId,
+			EventVO event, @Context HttpServletRequest httpRequest) {
+		return addEventByCalendar(calendarId, event, httpRequest);
+	}
+	
+	@POST
+	@Path("events")
+	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
+	@Consumes({MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
+	public Response postEventByCalendar(@PathParam("calendarId") String calendarId,
+			EventVO event, @Context HttpServletRequest httpRequest) {
+		return addEventByCalendar(calendarId, event, httpRequest);
+	}
+	
+	private Response addEventByCalendar(String calendarId, EventVO event, HttpServletRequest httpRequest) {
+		UserRequest ureq = getUserRequest(httpRequest);
+		if(!ureq.getUserSession().isAuthenticated()) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+		
+		if(calendar == null) {
+			return Response.serverError().status(Status.NOT_FOUND).build();
+		} else if(!hasWriteAccess(calendar)) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+		
+		KalendarEvent kalEvent;
+		CalendarManager calendarManager = CalendarManagerFactory.getInstance().getCalendarManager();
+		if(!StringHelper.containsNonWhitespace(event.getId())) {
+			String id = UUID.randomUUID().toString();
+			kalEvent = new KalendarEvent(id, event.getSubject(), event.getBegin(), event.getEnd());
+			transfer(event, kalEvent);
+			calendarManager.addEventTo(calendar.getKalendar(), kalEvent);
+		} else {
+			kalEvent = calendar.getKalendar().getEvent(event.getId());
+			if(kalEvent == null) {
+				kalEvent = new KalendarEvent(event.getId(), event.getSubject(), event.getBegin(), event.getEnd());
+				transfer(event, kalEvent);
+				calendarManager.addEventTo(calendar.getKalendar(), kalEvent);
+			} else {
+				kalEvent.setBegin(event.getBegin());
+				kalEvent.setEnd(event.getEnd());
+				kalEvent.setSubject(event.getSubject());
+				transfer(event, kalEvent);
+			}
+		}
+		
+		EventVO vo = new EventVO(kalEvent);
+		return Response.ok(vo).build();
+	}
+}
diff --git a/src/main/java/org/olat/commons/calendar/restapi/CalendarWSHelper.java b/src/main/java/org/olat/commons/calendar/restapi/CalendarWSHelper.java
new file mode 100644
index 0000000000000000000000000000000000000000..6a66d2a1e37165cb8a2a580e08b8518974d2db13
--- /dev/null
+++ b/src/main/java/org/olat/commons/calendar/restapi/CalendarWSHelper.java
@@ -0,0 +1,134 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <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 the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <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>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.commons.calendar.restapi;
+
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.Request;
+import javax.ws.rs.core.Response;
+
+import org.olat.commons.calendar.CalendarUtils;
+import org.olat.commons.calendar.model.KalendarEvent;
+import org.olat.commons.calendar.ui.components.KalendarRenderWrapper;
+import org.olat.core.util.i18n.I18nManager;
+import org.olat.restapi.support.MediaTypeVariants;
+
+/**
+ * 
+ * Initial date: 08.08.2013<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class CalendarWSHelper {
+	
+	protected static void transfer(EventVO event, KalendarEvent kalEvent) {
+		kalEvent.setDescription(event.getDescription());
+		kalEvent.setLocation(event.getLocation());
+		kalEvent.setAllDayEvent(event.isAllDayEvent());
+	}
+	
+	protected static boolean hasReadAccess(KalendarRenderWrapper wrapper) {
+		if(wrapper.getAccess() == KalendarRenderWrapper.ACCESS_READ_ONLY) {
+			return true;
+		}
+		if(wrapper.getAccess() == KalendarRenderWrapper.ACCESS_READ_WRITE) {
+			return true;
+		}
+		return false;
+	}
+	
+	protected static boolean hasWriteAccess(KalendarRenderWrapper wrapper) {
+		if(wrapper.getAccess() == KalendarRenderWrapper.ACCESS_READ_WRITE) {
+			return true;
+		}
+		return false;
+	}
+	
+	protected static Response processEvents(List<EventVO> events, Boolean onlyFuture, int firstResult, int maxReturns,
+			HttpServletRequest httpRequest, Request request) {
+		
+		if(onlyFuture != null && onlyFuture.booleanValue()) {
+			Locale locale = I18nManager.getInstance().getCurrentThreadLocale();
+			Calendar cal = CalendarUtils.getStartOfDayCalendar(locale);
+			Date today = cal.getTime();
+			
+			for(Iterator<EventVO> eventIt=events.iterator(); eventIt.hasNext(); ) {
+				EventVO event = eventIt.next();
+				Date end = event.getEnd();
+				if(end.before(today)) {
+					eventIt.remove();
+				}
+			}
+		}
+		
+		Collections.sort(events, new EventComparator());
+		
+		if(MediaTypeVariants.isPaged(httpRequest, request)) {
+			int totalCount = events.size();
+			if(maxReturns > 0 && firstResult >= 0) {
+				if(firstResult >= events.size()) {
+					events.clear();
+				} else {	
+					int lastResult = Math.min(events.size(), firstResult + maxReturns);
+					events = events.subList(firstResult, lastResult); 
+				}
+			}
+			
+			EventVO[] voes = new EventVO[events.size()];
+			voes = events.toArray(voes);
+			EventVOes vos = new EventVOes();
+			vos.setEvents(voes);
+			vos.setTotalCount(totalCount);
+			return Response.ok(vos).build();
+		} else {
+			EventVO[] voes = new EventVO[events.size()];
+			voes = events.toArray(voes);
+			return Response.ok(voes).build();
+		}
+	}
+	
+	private static class EventComparator implements Comparator<EventVO> {
+		@Override
+		public int compare(EventVO e1, EventVO e2) {
+			if(e1 == null) {
+				if(e2 == null) return 0;
+				return -1;
+			}
+			if(e2 == null) return 1;
+			
+			Date d1 = e1.getBegin();
+			Date d2 = e2.getBegin();
+			if(d1 == null) {
+				if(d2 == null) return 0;
+				return -1;
+			}
+			if(d2 == null) return 1;
+			return d1.compareTo(d2);
+		}
+	}
+
+}
diff --git a/src/main/java/org/olat/commons/calendar/restapi/CalendarWebService.java b/src/main/java/org/olat/commons/calendar/restapi/UserCalendarWebService.java
similarity index 56%
rename from src/main/java/org/olat/commons/calendar/restapi/CalendarWebService.java
rename to src/main/java/org/olat/commons/calendar/restapi/UserCalendarWebService.java
index 5ec001c7720c9ee878d929e4ba9e612a96c4b912..fd8675405e3a016d47a427919e284e6c5aa7cdb1 100644
--- a/src/main/java/org/olat/commons/calendar/restapi/CalendarWebService.java
+++ b/src/main/java/org/olat/commons/calendar/restapi/UserCalendarWebService.java
@@ -19,30 +19,24 @@
  */
 package org.olat.commons.calendar.restapi;
 
+import static org.olat.commons.calendar.restapi.CalendarWSHelper.hasReadAccess;
+import static org.olat.commons.calendar.restapi.CalendarWSHelper.hasWriteAccess;
+import static org.olat.commons.calendar.restapi.CalendarWSHelper.processEvents;
 import static org.olat.restapi.security.RestSecurityHelper.getUserRequest;
 
 import java.util.ArrayList;
-import java.util.Calendar;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.Iterator;
 import java.util.List;
-import java.util.Locale;
-import java.util.UUID;
 
 import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
 import javax.ws.rs.DefaultValue;
 import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Request;
@@ -55,7 +49,6 @@ import org.olat.collaboration.CollaborationManager;
 import org.olat.collaboration.CollaborationTools;
 import org.olat.commons.calendar.CalendarManager;
 import org.olat.commons.calendar.CalendarManagerFactory;
-import org.olat.commons.calendar.CalendarUtils;
 import org.olat.commons.calendar.model.KalendarConfig;
 import org.olat.commons.calendar.model.KalendarEvent;
 import org.olat.commons.calendar.ui.components.KalendarRenderWrapper;
@@ -66,8 +59,6 @@ import org.olat.core.id.IdentityEnvironment;
 import org.olat.core.id.Roles;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
-import org.olat.core.util.StringHelper;
-import org.olat.core.util.i18n.I18nManager;
 import org.olat.core.util.nodes.INode;
 import org.olat.core.util.tree.Visitor;
 import org.olat.course.CourseFactory;
@@ -84,16 +75,15 @@ import org.olat.repository.RepositoryManager;
 import org.olat.repository.SearchRepositoryEntryParameters;
 import org.olat.resource.accesscontrol.ACService;
 import org.olat.resource.accesscontrol.AccessResult;
-import org.olat.restapi.support.MediaTypeVariants;
 
 /**
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
 @Path("users/{identityKey}/calendars")
-public class CalendarWebService {
+public class UserCalendarWebService {
 	
-	private static final OLog log = Tracing.createLoggerFor(CalendarWebService.class);
+	private static final OLog log = Tracing.createLoggerFor(UserCalendarWebService.class);
 	
 	
 	@GET
@@ -118,140 +108,27 @@ public class CalendarWebService {
 		return Response.ok(voes).build();
 	}
 	
-	@GET
-	@Path("{calendarId}/events")
-	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
-	public Response getEventsByCalendar(@PathParam("calendarId") String calendarId,
-			@PathParam("identityKey") Long identityKey, @QueryParam("start") @DefaultValue("0") Integer start,
-			@QueryParam("limit") @DefaultValue("25") Integer limit,
-			@QueryParam("onlyFuture") @DefaultValue("false") Boolean onlyFuture,
-			@Context HttpServletRequest httpRequest, @Context Request request) {
+	@Path("{calendarId}")
+	public CalWebService getCalendarWebService(@PathParam("calendarId") String calendarId,
+			@PathParam("identityKey") Long identityKey, @Context HttpServletRequest httpRequest) {
 		
 		UserRequest ureq = getUserRequest(httpRequest);
 		if(!ureq.getUserSession().isAuthenticated()) {
-			return Response.serverError().status(Status.UNAUTHORIZED).build();
+			throw new WebApplicationException(Response.serverError().status(Status.UNAUTHORIZED).build());
 		} else if (ureq.getIdentity() == null || !ureq.getIdentity().getKey().equals(identityKey)) {
-			return Response.serverError().status(Status.UNAUTHORIZED).build();
+			throw new WebApplicationException(Response.serverError().status(Status.UNAUTHORIZED).build());
 		}
 		
 		KalendarRenderWrapper calendar = getCalendar(ureq, calendarId);
 		if(calendar == null) {
-			return Response.serverError().status(Status.NOT_FOUND).build();
+			throw new WebApplicationException(Response.serverError().status(Status.NOT_FOUND).build());
 		} else if (!hasReadAccess(calendar)) {
-			return Response.serverError().status(Status.UNAUTHORIZED).build();
+			throw new WebApplicationException(Response.serverError().status(Status.UNAUTHORIZED).build());
 		}
 		
-		List<EventVO> events = new ArrayList<EventVO>();
-		Collection<KalendarEvent> kalEvents = calendar.getKalendar().getEvents();
-		for(KalendarEvent kalEvent:kalEvents) {
-			EventVO eventVo = new EventVO(kalEvent);
-			events.add(eventVo);
-		}
-
-		return processEvents(events, onlyFuture, start, limit, httpRequest, request);
+		return new CalWebService(calendar);
 	}
-	
-	@DELETE
-	@Path("{calendarId}/events/{eventId}")
-	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
-	@Consumes({MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
-	public Response deleteEventByCalendar(@PathParam("calendarId") String calendarId,
-			@PathParam("eventId") String eventId, @PathParam("identityKey") Long identityKey,
-			@Context HttpServletRequest httpRequest) {
-		
-		UserRequest ureq = getUserRequest(httpRequest);
-		if(!ureq.getUserSession().isAuthenticated()) {
-			return Response.serverError().status(Status.UNAUTHORIZED).build();
-		} else if (ureq.getIdentity() == null || !ureq.getIdentity().getKey().equals(identityKey)) {
-			return Response.serverError().status(Status.UNAUTHORIZED).build();
-		}
-		
-		KalendarRenderWrapper calendar = getCalendar(ureq, calendarId);
-		if(calendar == null) {
-			return Response.serverError().status(Status.NOT_FOUND).build();
-		} else if(!hasWriteAccess(calendar)) {
-			return Response.serverError().status(Status.UNAUTHORIZED).build();
-		}
 
-		CalendarManager calendarManager = CalendarManagerFactory.getInstance().getCalendarManager();
-		if(eventId == null) {
-			return Response.ok().status(Status.NOT_FOUND).build();
-		} else {
-			KalendarEvent kalEvent = calendar.getKalendar().getEvent(eventId);
-			if(kalEvent == null) {
-				return Response.ok().status(Status.NOT_FOUND).build();
-			} else {
-				calendarManager.removeEventFrom(calendar.getKalendar(), kalEvent);
-			}
-		}
-
-		return Response.ok().build();
-	}
-	
-	@PUT
-	@Path("{calendarId}/events")
-	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
-	@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
-	public Response putEventByCalendar(@PathParam("calendarId") String calendarId,
-			@PathParam("identityKey") Long identityKey, EventVO event, @Context HttpServletRequest httpRequest) {
-		return addEventByCalendar(calendarId, identityKey, event, httpRequest);
-	}
-	
-	@POST
-	@Path("{calendarId}/events")
-	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
-	@Consumes({MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
-	public Response postEventByCalendar(@PathParam("calendarId") String calendarId,
-			@PathParam("identityKey") Long identityKey, EventVO event, @Context HttpServletRequest httpRequest) {
-		return addEventByCalendar(calendarId, identityKey, event, httpRequest);
-	}
-	
-	private Response addEventByCalendar(String calendarId, Long identityKey, EventVO event, HttpServletRequest httpRequest) {
-		UserRequest ureq = getUserRequest(httpRequest);
-		if(!ureq.getUserSession().isAuthenticated()) {
-			return Response.serverError().status(Status.UNAUTHORIZED).build();
-		} else if (ureq.getIdentity() == null || !ureq.getIdentity().getKey().equals(identityKey)) {
-			return Response.serverError().status(Status.UNAUTHORIZED).build();
-		}
-		
-		KalendarRenderWrapper calendar = getCalendar(ureq, calendarId);
-		if(calendar == null) {
-			return Response.serverError().status(Status.NOT_FOUND).build();
-		} else if(!hasWriteAccess(calendar)) {
-			return Response.serverError().status(Status.UNAUTHORIZED).build();
-		}
-		
-		KalendarEvent kalEvent;
-		CalendarManager calendarManager = CalendarManagerFactory.getInstance().getCalendarManager();
-		if(!StringHelper.containsNonWhitespace(event.getId())) {
-			String id = UUID.randomUUID().toString();
-			kalEvent = new KalendarEvent(id, event.getSubject(), event.getBegin(), event.getEnd());
-			transfer(event, kalEvent);
-			calendarManager.addEventTo(calendar.getKalendar(), kalEvent);
-		} else {
-			kalEvent = calendar.getKalendar().getEvent(event.getId());
-			if(kalEvent == null) {
-				kalEvent = new KalendarEvent(event.getId(), event.getSubject(), event.getBegin(), event.getEnd());
-				transfer(event, kalEvent);
-				calendarManager.addEventTo(calendar.getKalendar(), kalEvent);
-			} else {
-				kalEvent.setBegin(event.getBegin());
-				kalEvent.setEnd(event.getEnd());
-				kalEvent.setSubject(event.getSubject());
-				transfer(event, kalEvent);
-			}
-		}
-		
-		EventVO vo = new EventVO(kalEvent);
-		return Response.ok(vo).build();
-	}
-	
-	private void transfer(EventVO event, KalendarEvent kalEvent) {
-		kalEvent.setDescription(event.getDescription());
-		kalEvent.setLocation(event.getLocation());
-		kalEvent.setAllDayEvent(event.isAllDayEvent());
-	}
-	
 	@GET
 	@Path("events")
 	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@@ -283,66 +160,6 @@ public class CalendarWebService {
 		return processEvents(events, onlyFuture, start, limit, httpRequest, request);
 	}
 	
-	private Response processEvents(List<EventVO> events, Boolean onlyFuture, int firstResult, int maxReturns,
-			HttpServletRequest httpRequest, Request request) {
-		
-		if(onlyFuture != null && onlyFuture.booleanValue()) {
-			Locale locale = I18nManager.getInstance().getCurrentThreadLocale();
-			Calendar cal = CalendarUtils.getStartOfDayCalendar(locale);
-			Date today = cal.getTime();
-			
-			for(Iterator<EventVO> eventIt=events.iterator(); eventIt.hasNext(); ) {
-				EventVO event = eventIt.next();
-				Date end = event.getEnd();
-				if(end.before(today)) {
-					eventIt.remove();
-				}
-			}
-		}
-		
-		Collections.sort(events, new EventComparator());
-		
-		if(MediaTypeVariants.isPaged(httpRequest, request)) {
-			int totalCount = events.size();
-			if(maxReturns > 0 && firstResult >= 0) {
-				if(firstResult >= events.size()) {
-					events.clear();
-				} else {	
-					int lastResult = Math.min(events.size(), firstResult + maxReturns);
-					events = events.subList(firstResult, lastResult); 
-				}
-			}
-			
-			EventVO[] voes = new EventVO[events.size()];
-			voes = events.toArray(voes);
-			EventVOes vos = new EventVOes();
-			vos.setEvents(voes);
-			vos.setTotalCount(totalCount);
-			return Response.ok(vos).build();
-		} else {
-			EventVO[] voes = new EventVO[events.size()];
-			voes = events.toArray(voes);
-			return Response.ok(voes).build();
-		}
-	}
-	
-	private boolean hasReadAccess(KalendarRenderWrapper wrapper) {
-		if(wrapper.getAccess() == KalendarRenderWrapper.ACCESS_READ_ONLY) {
-			return true;
-		}
-		if(wrapper.getAccess() == KalendarRenderWrapper.ACCESS_READ_WRITE) {
-			return true;
-		}
-		return false;
-	}
-	
-	private boolean hasWriteAccess(KalendarRenderWrapper wrapper) {
-		if(wrapper.getAccess() == KalendarRenderWrapper.ACCESS_READ_WRITE) {
-			return true;
-		}
-		return false;
-	}
-	
 	private KalendarRenderWrapper getCalendar(UserRequest ureq, String calendarId) {
 		int typeIndex = calendarId.indexOf('_');
 		if(typeIndex <= 0 || (typeIndex + 1 >= calendarId.length())) {
@@ -438,26 +255,6 @@ public class CalendarWebService {
 		}
 	}
 	
-	private static class EventComparator implements Comparator<EventVO> {
-		@Override
-		public int compare(EventVO e1, EventVO e2) {
-			if(e1 == null) {
-				if(e2 == null) return 0;
-				return -1;
-			}
-			if(e2 == null) return 1;
-			
-			Date d1 = e1.getBegin();
-			Date d2 = e2.getBegin();
-			if(d1 == null) {
-				if(d2 == null) return 0;
-				return -1;
-			}
-			if(d2 == null) return 1;
-			return d1.compareTo(d2);
-		}
-	}
-	
 	private static interface CalendarVisitor {
 		public void visit(KalendarRenderWrapper wrapper);
 	}
diff --git a/src/main/java/org/olat/core/gui/render/velocity/VelocityRenderDecorator.java b/src/main/java/org/olat/core/gui/render/velocity/VelocityRenderDecorator.java
index 8ddb6204b65d785f8fe2b06081a3e82249a83f06..3a6e68071afcd7805535b49dec1a307f7b323ce6 100644
--- a/src/main/java/org/olat/core/gui/render/velocity/VelocityRenderDecorator.java
+++ b/src/main/java/org/olat/core/gui/render/velocity/VelocityRenderDecorator.java
@@ -492,10 +492,16 @@ public class VelocityRenderDecorator {
 	 * @return
 	 */
 	public String escapeHtml(String str) throws IOException {
+		if(str == null) {
+			return "";
+		}
 		return StringEscapeUtils.escapeHtml(str);
 	}
 	
 	public String xssScan(String str) {
+		if(str == null) {
+			return "";
+		}
 		OWASPAntiSamyXSSFilter filter = new OWASPAntiSamyXSSFilter();
 		return filter.filter(str);
 	}
diff --git a/src/main/java/org/olat/restapi/_spring/restApiContext.xml b/src/main/java/org/olat/restapi/_spring/restApiContext.xml
index 471bd36de1b618bf918b1f996114670f6b595e20..25331c039244e85e372b647f465b2c5699a256be 100644
--- a/src/main/java/org/olat/restapi/_spring/restApiContext.xml
+++ b/src/main/java/org/olat/restapi/_spring/restApiContext.xml
@@ -51,7 +51,7 @@
 				<value>org.olat.catalog.restapi.CatalogWebService</value>
 				<value>org.olat.notifications.restapi.NotificationsWebService</value>
 				<value>org.olat.registration.restapi.RegistrationWebService</value>
-				<value>org.olat.commons.calendar.restapi.CalendarWebService</value>
+				<value>org.olat.commons.calendar.restapi.UserCalendarWebService</value>
 				<value>org.olat.restapi.system.LogWebService</value>
 				<value>org.olat.restapi.system.SystemWebService</value>
 			</list>
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 893c5780cee90639d814a3e79cff8271ae1ff9bf..8d8c60d392d2ce75f02abfba4071865220163064 100644
--- a/src/main/java/org/olat/restapi/repository/course/CourseWebService.java
+++ b/src/main/java/org/olat/restapi/repository/course/CourseWebService.java
@@ -40,6 +40,7 @@ import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.CacheControl;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
@@ -52,6 +53,8 @@ import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.BaseSecurityManager;
 import org.olat.basesecurity.Constants;
 import org.olat.basesecurity.SecurityGroup;
+import org.olat.commons.calendar.restapi.CalWebService;
+import org.olat.commons.calendar.ui.components.KalendarRenderWrapper;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.media.MediaResource;
@@ -70,6 +73,7 @@ import org.olat.course.CourseFactory;
 import org.olat.course.CourseModule;
 import org.olat.course.ICourse;
 import org.olat.course.config.CourseConfig;
+import org.olat.course.nodes.cal.CourseCalendars;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryManager;
 import org.olat.repository.handlers.RepositoryHandler;
@@ -128,8 +132,24 @@ public class CourseWebService {
 	@Path("groups")
 	public CourseGroupWebService getCourseGroupWebService(@PathParam("courseId") Long courseId) {
 		OLATResource ores = getCourseOLATResource(courseId);
-		if(ores != null) {
-			return new CourseGroupWebService(ores);
+		if(ores == null) {
+			throw new WebApplicationException(Response.serverError().status(Status.NOT_FOUND).build());
+		}
+		return new CourseGroupWebService(ores);
+	}
+	
+	@Path("calendar")
+	public CalWebService getCourseCalendarWebService(@PathParam("courseId") Long courseId,
+			@Context HttpServletRequest request) {
+		ICourse course = loadCourse(courseId);
+		if(course == null) {
+			throw new WebApplicationException(Response.serverError().status(Status.NOT_FOUND).build());
+		}
+		if(course.getCourseConfig().isCalendarEnabled()) {
+			OLATResource ores = getCourseOLATResource(courseId);
+			UserRequest ureq = getUserRequest(request);
+			KalendarRenderWrapper wrapper = CourseCalendars.getCourseCalendarWrapper(ureq, ores, null);
+			return new CalWebService(wrapper);
 		}
 		return null;
 	}
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 af2ca899e9a512e1d3234fe3d8b105af32e66229..e9d3379b5d8d21bf6ead14fbb253f9e8dae0d420 100644
--- a/src/main/java/org/olat/restapi/repository/course/CoursesWebService.java
+++ b/src/main/java/org/olat/restapi/repository/course/CoursesWebService.java
@@ -209,8 +209,9 @@ public class CoursesWebService {
 	 */
 	@PUT
 	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
-	public Response createEmptyCourse(@QueryParam("shortTitle") String shortTitle,
-			@QueryParam("title") String title,
+	public Response createEmptyCourse(@QueryParam("shortTitle") String shortTitle, @QueryParam("title") String title,
+			@QueryParam("softKey") String softKey, @QueryParam("externalId") String externalId,
+			@QueryParam("externalRef") String externalRef, @QueryParam("managedFlags") String managedFlags,
 			@QueryParam("sharedFolderSoftKey") String sharedFolderSoftKey,
 			@QueryParam("copyFrom") Long copyFrom,
 			@Context HttpServletRequest request) {
@@ -223,14 +224,43 @@ public class CoursesWebService {
 		ICourse course;
 		UserRequest ureq = getUserRequest(request);
 		if(copyFrom != null) {
-			course = copyCourse(copyFrom, ureq, shortTitle, title, configVO);
+			course = copyCourse(copyFrom, ureq, shortTitle, title, softKey, externalId, externalRef, managedFlags, configVO);
 		} else {
-			course = createEmptyCourse(ureq.getIdentity(), shortTitle, title, null, null, null, null, configVO);
+			course = createEmptyCourse(ureq.getIdentity(), shortTitle, title, softKey, externalId, externalRef, managedFlags, configVO);
 		}
 		CourseVO vo = ObjectFactory.get(course);
 		return Response.ok(vo).build();
 	}
 	
+	/**
+	 * Creates an empty course
+	 * @response.representation.200.qname {http://www.example.com}courseVO
+   * @response.representation.200.mediaType application/xml, application/json
+   * @response.representation.200.doc The metadatas of the created course
+   * @response.representation.200.example {@link org.olat.restapi.support.vo.Examples#SAMPLE_COURSEVO}
+	 * @response.representation.401.doc The roles of the authenticated user are not sufficient
+   * @param courseVo The course
+   * @param request The HTTP request
+	 * @return It returns the newly created course
+	 */
+	@PUT
+	@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
+	@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
+	public Response createEmptyCourse(CourseVO courseVo, @Context HttpServletRequest request) {
+		if(!isAuthor(request)) {
+			return Response.serverError().status(Status.UNAUTHORIZED).build();
+		}
+
+		UserRequest ureq = getUserRequest(request);
+
+		CourseConfigVO configVO = new CourseConfigVO();
+		ICourse course = createEmptyCourse(ureq.getIdentity(), courseVo.getTitle(),
+				courseVo.getTitle(), courseVo.getSoftKey(), courseVo.getExternalId(),
+				courseVo.getExternalRef(), courseVo.getManagedFlags(), configVO);
+		CourseVO vo = ObjectFactory.get(course);
+		return Response.ok(vo).build();
+	}
+	
 	/**
 	 * 
 	 * 
@@ -387,7 +417,8 @@ public class CoursesWebService {
 		}
 	}
 	
-	public static ICourse copyCourse(Long copyFrom, UserRequest ureq, String name, String longTitle, CourseConfigVO courseConfigVO) {
+	public static ICourse copyCourse(Long copyFrom, UserRequest ureq, String name, String longTitle,
+			String softKey, String externalId, String externalRef, String managedFlags, CourseConfigVO courseConfigVO) {
 		String shortTitle = name;
 		//String learningObjectives = name + " (Example of creating a new course)";
 		
@@ -410,6 +441,19 @@ public class CoursesWebService {
 				preparedEntry.setDisplayname("Copy of " + src.getDisplayname());
 			}
 			preparedEntry.setDescription(src.getDescription());
+			
+			if(StringHelper.containsNonWhitespace(softKey)) {
+				preparedEntry.setSoftkey(softKey);
+			}
+			if(StringHelper.containsNonWhitespace(externalId)) {
+				preparedEntry.setExternalId(externalId);
+			}
+			if(StringHelper.containsNonWhitespace(externalRef)) {
+				preparedEntry.setExternalRef(externalRef);
+			}
+			if(StringHelper.containsNonWhitespace(managedFlags)) {
+				preparedEntry.setManagedFlagsString(managedFlags);
+			}
 
 			String resName = src.getResourcename();
 			if (resName == null) {
diff --git a/src/main/java/org/olat/restapi/security/RestApiLoginFilter.java b/src/main/java/org/olat/restapi/security/RestApiLoginFilter.java
index af3d3e53de028130a852da8729a3ee924923447c..77b562c1caaacadaea2bad00293dd828f03c857a 100644
--- a/src/main/java/org/olat/restapi/security/RestApiLoginFilter.java
+++ b/src/main/java/org/olat/restapi/security/RestApiLoginFilter.java
@@ -107,7 +107,7 @@ public class RestApiLoginFilter implements Filter {
 				
 				String requestURI = httpRequest.getRequestURI();
 				RestModule restModule = (RestModule)CoreSpringFactory.getBean("restModule");
-				if(!restModule.isEnabled() && !isRequestURIAlwaysEnabled(requestURI)) {
+				if(restModule == null || !restModule.isEnabled() && !isRequestURIAlwaysEnabled(requestURI)) {
 					httpResponse.sendError(403);
 					return;
 				}
@@ -122,7 +122,7 @@ public class RestApiLoginFilter implements Filter {
 					//use the available session
 					followSession(httpRequest, httpResponse, chain);
 				} else {
-					if(requestURI.startsWith(getLoginUrl())) {
+					if(isRequestURIInLoginSpace(requestURI)) {
 						followForAuthentication(requestURI, uress, httpRequest, httpResponse, chain);
 					} else if(isRequestURIInOpenSpace(requestURI)) {
 						followWithoutAuthentication(httpRequest, httpResponse, chain);
@@ -210,8 +210,18 @@ public class RestApiLoginFilter implements Filter {
 		return securityBean.isTokenRegistrated(token, request.getSession(true));
 	}
 	
+	private boolean isRequestURIInLoginSpace(String requestURI) {
+		String loginUrl = getLoginUrl();
+		if(loginUrl != null && requestURI.startsWith(loginUrl)) {
+			return true;
+		}
+		return false;
+	}
+	
 	private boolean isRequestURIInOpenSpace(String requestURI) {
-		for(String openURI : getOpenURIs()) {
+		List<String> uris = getOpenURIs();
+		if(uris == null) return false;
+		for(String openURI : uris) {
 			if(requestURI.startsWith(openURI)) {
 				return true;
 			}
@@ -220,7 +230,9 @@ public class RestApiLoginFilter implements Filter {
 	}
 	
 	private boolean isRequestURIInIPProtectedSpace(String requestURI, HttpServletRequest httpRequest, RestModule restModule) {
-		for(String openURI : getIPProtectedURIs()) {
+		List<String> uris = getIPProtectedURIs();
+		if(uris == null) return false;
+		for(String openURI : uris) {
 			if(requestURI.startsWith(openURI)) {
 				String remoteAddr = httpRequest.getRemoteAddr();
 				if(StringHelper.containsNonWhitespace(remoteAddr)) {
@@ -232,7 +244,9 @@ public class RestApiLoginFilter implements Filter {
 	}
 	
 	private boolean isRequestURIAlwaysEnabled(String requestURI) {
-		for(String openURI : getAlwaysEnabledURIs()) {
+		List<String> uris = getAlwaysEnabledURIs();
+		if(uris == null) return false;
+		for(String openURI : uris) {
 			if(requestURI.startsWith(openURI)) {
 				return true;
 			}
@@ -386,8 +400,15 @@ public class RestApiLoginFilter implements Filter {
 		}
 	}
 	
+	private boolean isWebappHelperInitiated() {
+		if(Settings.isJUnitTest()) {
+			return true;
+		}
+		return StringHelper.containsNonWhitespace(WebappHelper.getServletContextPath());
+	}
+	
 	private String getLoginUrl() {
-		if(LOGIN_URL == null) {
+		if(LOGIN_URL == null && isWebappHelperInitiated()) {
 			String context = (Settings.isJUnitTest() ? "/olat" : WebappHelper.getServletContextPath() + RestSecurityHelper.SUB_CONTEXT);
 			LOGIN_URL = context + "/auth";
 		}
@@ -395,39 +416,42 @@ public class RestApiLoginFilter implements Filter {
 	}
 	
 	private List<String> getAlwaysEnabledURIs() {
-		if(alwaysEnabledUrls == null) {
+		if(alwaysEnabledUrls == null && isWebappHelperInitiated() ) {
 			String context = (Settings.isJUnitTest() ? "/olat" : WebappHelper.getServletContextPath() + RestSecurityHelper.SUB_CONTEXT);
-			alwaysEnabledUrls = new ArrayList<String>();
-			alwaysEnabledUrls.add(context + "/i18n");
-			alwaysEnabledUrls.add(context + "/api");
-			alwaysEnabledUrls.add(context + "/ping");
-			alwaysEnabledUrls.add(context + "/openmeetings");
-			alwaysEnabledUrls.add(context + "/system");
+			List<String > urls = new ArrayList<String>();
+			urls.add(context + "/i18n");
+			urls.add(context + "/api");
+			urls.add(context + "/ping");
+			urls.add(context + "/openmeetings");
+			urls.add(context + "/system");
+			alwaysEnabledUrls = urls;
 		}
 		return alwaysEnabledUrls;
 	}
 	
 	private List<String> getOpenURIs() {
-		if(openUrls == null) {
+		if(openUrls == null && isWebappHelperInitiated()) {
 			String context = (Settings.isJUnitTest() ? "/olat" : WebappHelper.getServletContextPath() + RestSecurityHelper.SUB_CONTEXT);
-			openUrls = new ArrayList<String>();
-			openUrls.add(context + "/i18n");
-			openUrls.add(context + "/api");
-			openUrls.add(context + "/ping");
-			openUrls.add(context + "/application.wadl");
-			openUrls.add(context + "/application.html");
-			openUrls.add(context + "/wadl");
-			openUrls.add(context + "/registration");
-			openUrls.add(context + "/openmeetings");
+			List<String > urls = new ArrayList<String>();
+			urls.add(context + "/i18n");
+			urls.add(context + "/api");
+			urls.add(context + "/ping");
+			urls.add(context + "/application.wadl");
+			urls.add(context + "/application.html");
+			urls.add(context + "/wadl");
+			urls.add(context + "/registration");
+			urls.add(context + "/openmeetings");
+			openUrls = urls;
 		}
 		return openUrls;
 	}
 	
 	private List<String> getIPProtectedURIs() {
-		if(ipProtectedUrls == null) {
+		if(ipProtectedUrls == null && isWebappHelperInitiated()) {
 			String context = (Settings.isJUnitTest() ? "/olat" : WebappHelper.getServletContextPath() + RestSecurityHelper.SUB_CONTEXT);
-			ipProtectedUrls = new ArrayList<String>();
-			ipProtectedUrls.add(context + "/system");
+			List<String > urls  = new ArrayList<String>();
+			urls.add(context + "/system");
+			ipProtectedUrls = urls;
 		}
 		return ipProtectedUrls;
 	}
diff --git a/src/test/java/org/olat/restapi/CourseCalendarTest.java b/src/test/java/org/olat/restapi/CourseCalendarTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e4837cfb0bd2f861aa31780b16a17b17ffb07122
--- /dev/null
+++ b/src/test/java/org/olat/restapi/CourseCalendarTest.java
@@ -0,0 +1,244 @@
+/**
+* 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.
+* <hr>
+* <a href="http://www.openolat.org">
+* OpenOLAT - Online Learning and Training</a><br>
+* This file has been modified by the OpenOLAT community. Changes are licensed
+* under the Apache 2.0 license as the original file.  
+* <p>
+*/
+
+
+package org.olat.restapi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.UriBuilder;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.util.EntityUtils;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.type.TypeReference;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.olat.commons.calendar.CalendarManager;
+import org.olat.commons.calendar.CalendarManagerFactory;
+import org.olat.commons.calendar.model.KalendarEvent;
+import org.olat.commons.calendar.restapi.EventVO;
+import org.olat.commons.calendar.ui.components.KalendarRenderWrapper;
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.id.Identity;
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
+import org.olat.course.CourseFactory;
+import org.olat.course.ICourse;
+import org.olat.course.config.CourseConfig;
+import org.olat.restapi.repository.course.CoursesWebService;
+import org.olat.test.JunitTestHelper;
+import org.olat.test.OlatJerseyTestCase;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 08.08.2013<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class CourseCalendarTest extends OlatJerseyTestCase {
+	
+	private static final OLog log = Tracing.createLoggerFor(CourseCalendarTest.class);
+	
+	private Identity auth1;
+	private ICourse course1;
+
+	@Autowired
+	private DB dbInstance;
+	
+	/**
+	 * SetUp is called before each test.
+	 */
+	@Before
+	public void setUp() throws Exception {
+		super.setUp();
+		try {
+			// create course and persist as OLATResourceImpl
+			auth1 = JunitTestHelper.createAndPersistIdentityAsUser("rest-course-cal-one");
+			course1 = CoursesWebService.createEmptyCourse(auth1, "course calendar", "course with calendar for REST API testing", null);
+			
+			dbInstance.commit();
+			ICourse course = CourseFactory.openCourseEditSession(course1.getResourceableId());
+			CourseConfig courseConfig = course.getCourseEnvironment().getCourseConfig();
+			courseConfig.setCalendarEnabled(true);
+			CourseFactory.setCourseConfig(course.getResourceableId(), courseConfig);
+			CourseFactory.closeCourseEditSession(course.getResourceableId(),true);
+
+			dbInstance.commit();
+			
+			CalendarManager calendarManager = CalendarManagerFactory.getInstance().getCalendarManager();
+			KalendarRenderWrapper calendarWrapper = calendarManager.getCourseCalendar(course);
+			
+			Calendar cal = Calendar.getInstance();
+			for(int i=0; i<2; i++) {
+				Date begin = cal.getTime();
+				cal.add(Calendar.HOUR_OF_DAY, 1);
+				Date end = cal.getTime();
+				KalendarEvent event = new KalendarEvent(UUID.randomUUID().toString(), "Unit test " + i, begin, end);
+				calendarManager.addEventTo(calendarWrapper.getKalendar(), event);
+				cal.add(Calendar.DATE, 1);
+			}
+			
+		} catch (Exception e) {
+			log.error("Exception in setUp(): " + e);
+		}
+	}
+	
+	@Test
+	public void testGetCalendarEvents()
+	throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		assertTrue(conn.login(auth1.getName(), "A6B7C8"));
+		
+		URI uri = UriBuilder.fromUri(getContextURI()).path("repo").path("courses")
+				.path(course1.getResourceableId().toString()).path("calendar").path("events").build();
+		HttpGet method = conn.createGet(uri, MediaType.APPLICATION_JSON, true);
+		HttpResponse response = conn.execute(method);
+		assertEquals(200, response.getStatusLine().getStatusCode());
+		List<EventVO> vos = parseEventArray(response.getEntity().getContent());
+		assertNotNull(vos);
+		assertTrue(2 <= vos.size());
+		
+		conn.shutdown();
+	}
+	
+	@Test
+	public void testPutCalendarEvent() throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		assertTrue(conn.login(auth1.getName(), "A6B7C8"));
+
+		//create an event
+		EventVO event = new EventVO();
+		Calendar cal = Calendar.getInstance();
+		event.setBegin(cal.getTime());
+		cal.add(Calendar.HOUR_OF_DAY, 1);
+		event.setEnd(cal.getTime());
+		String subject = UUID.randomUUID().toString();
+		event.setSubject(subject);
+
+		URI eventUri = UriBuilder.fromUri(getContextURI()).path("repo").path("courses")
+				.path(course1.getResourceableId().toString()).path("calendar").path("events").build();
+		HttpPut putEventMethod = conn.createPut(eventUri, MediaType.APPLICATION_JSON, true);
+		conn.addJsonEntity(putEventMethod, event);
+		HttpResponse putEventResponse = conn.execute(putEventMethod);
+		assertEquals(200, putEventResponse.getStatusLine().getStatusCode());
+		EntityUtils.consume(putEventResponse.getEntity());
+		
+		//check if the event is saved
+		CalendarManager calendarManager = CalendarManagerFactory.getInstance().getCalendarManager();
+		KalendarRenderWrapper calendarWrapper = calendarManager.getCourseCalendar(course1);
+		Collection<KalendarEvent> savedEvents = calendarWrapper.getKalendar().getEvents();
+		
+		boolean found = false;
+		for(KalendarEvent savedEvent:savedEvents) {
+			if(subject.equals(savedEvent.getSubject())) {
+				found = true;
+			}
+		}
+		Assert.assertTrue(found);
+
+		conn.shutdown();
+	}
+	
+	@Test
+	public void testDeleteCalendarEvent() throws IOException, URISyntaxException {
+		RestConnection conn = new RestConnection();
+		assertTrue(conn.login(auth1.getName(), "A6B7C8"));
+		
+		//create an event if the event is saved
+		CalendarManager calendarManager = CalendarManagerFactory.getInstance().getCalendarManager();
+		KalendarRenderWrapper calendarWrapper = calendarManager.getCourseCalendar(course1);
+		
+		Calendar cal = Calendar.getInstance();
+		Date begin = cal.getTime();
+		cal.add(Calendar.HOUR_OF_DAY, 1);
+		String id = UUID.randomUUID().toString();
+		KalendarEvent kalEvent = new KalendarEvent(id, "Subject " + UUID.randomUUID().toString(), begin, cal.getTime());
+		calendarManager.addEventTo(calendarWrapper.getKalendar(), kalEvent);
+
+		//check if the event exists
+		URI uri = UriBuilder.fromUri(getContextURI()).path("repo").path("courses")
+				.path(course1.getResourceableId().toString()).path("calendar").path("events").build();
+		HttpGet method = conn.createGet(uri, MediaType.APPLICATION_JSON, true);
+		HttpResponse response = conn.execute(method);
+		assertEquals(200, response.getStatusLine().getStatusCode());
+		List<EventVO> vos = parseEventArray(response.getEntity().getContent());
+		assertNotNull(vos);
+		boolean found = false;
+		for(EventVO vo:vos) {
+			if(id.equals(vo.getId())) {
+				found = true;
+			}
+		}
+		assertTrue(found);
+		
+		//delete the event
+		URI eventUri = UriBuilder.fromUri(getContextURI()).path("repo").path("courses")
+				.path(course1.getResourceableId().toString()).path("calendar").path("events")
+				.path(kalEvent.getID()).build();
+		HttpDelete delEventMethod = conn.createDelete(eventUri, MediaType.APPLICATION_JSON, true);
+		HttpResponse delEventResponse = conn.execute(delEventMethod);
+		assertEquals(200, delEventResponse.getStatusLine().getStatusCode());
+		EntityUtils.consume(delEventResponse.getEntity());
+
+		conn.shutdown();
+		
+		//check if the event is really deleted
+		KalendarRenderWrapper reloadedCalendarWrapper = calendarManager.getCourseCalendar(course1);
+		Collection<KalendarEvent> savedEvents = reloadedCalendarWrapper.getKalendar().getEvents();
+		for(KalendarEvent savedEvent:savedEvents) {
+			Assert.assertFalse(savedEvent.getID().equals(kalEvent.getID()));
+		}
+	}
+	
+	protected List<EventVO> parseEventArray(InputStream body) {
+		try {
+			ObjectMapper mapper = new ObjectMapper(jsonFactory); 
+			return mapper.readValue(body, new TypeReference<List<EventVO>>(){/* */});
+		} catch (Exception e) {
+			e.printStackTrace();
+			return null;
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java
index d8521dfa5207f2da38148c2e098f8feefc25adcf..60d6c56584d776f748c74d5b43db0030a99ce36d 100644
--- a/src/test/java/org/olat/test/AllTestsJunit4.java
+++ b/src/test/java/org/olat/test/AllTestsJunit4.java
@@ -168,6 +168,7 @@ import org.junit.runners.Suite;
 	org.olat.restapi.CatalogTest.class,
 	org.olat.restapi.CalendarTest.class,
 	org.olat.restapi.CourseGroupMgmtTest.class,
+	org.olat.restapi.CourseCalendarTest.class,
 	org.olat.restapi.CoursesContactElementTest.class,
 	org.olat.restapi.CourseSecurityTest.class,
 	org.olat.restapi.CoursesElementsTest.class,
diff --git a/src/test/java/org/olat/util/xss/XssInjectionIndex.java b/src/test/java/org/olat/util/xss/XssInjectionIndex.java
index 612100f174e27c7b2d5f44619d7aa1570cbe62e8..12ff8b439b943856d4313222b51d89c17dcb92c9 100644
--- a/src/test/java/org/olat/util/xss/XssInjectionIndex.java
+++ b/src/test/java/org/olat/util/xss/XssInjectionIndex.java
@@ -1,3 +1,22 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <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 the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <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>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
 package org.olat.util.xss;
 
 public @interface XssInjectionIndex {