You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openmeetings.apache.org by so...@apache.org on 2018/11/04 04:04:40 UTC

[openmeetings] branch 4.0.x updated: OPENMEETINGS-1636 Upgrade Caldav4j to 1.0.0-rc.1 (#12)

This is an automated email from the ASF dual-hosted git repository.

solomax pushed a commit to branch 4.0.x
in repository https://gitbox.apache.org/repos/asf/openmeetings.git


The following commit(s) were added to refs/heads/4.0.x by this push:
     new bc31afe  OPENMEETINGS-1636 Upgrade Caldav4j to 1.0.0-rc.1 (#12)
bc31afe is described below

commit bc31afe2d36abe18613b2c742afd7b911e26bc82
Author: Ankush Mishra <an...@gmail.com>
AuthorDate: Sun Nov 4 09:20:21 2018 +0530

    OPENMEETINGS-1636 Upgrade Caldav4j to 1.0.0-rc.1 (#12)
    
    *  * Updated CalDAV4j to 1.0-SNAPSHOT
     * Converted all code from HttpClient 3.x to 4.x
     * Added documentation where ever it was needed.
     * Now credentials are stored in HttpClientContext objects per CalendarPanel. This is necessary as HttpClient objects, no more contain states, and context objects contain states.
    
    * Fixed issues which arose during testing.
    
     - TimeZone caching for iCal4j is set to MapTimeZonecache
     - Fixed iCalUtils to parse MeetingMembers correctly.
     - Changed listToMap to only require Appointment Objects.
     - Fixed handling of Appointment paths in various places.
     - Removed the need for MultiGetHandler, except for fetching ETags
     - Also, fixed a DAO update issue.
    
    * Fixed a minor issue with parsing VEVENT CHAIR from iCal
    
    * Fixes based on the PR review
---
 .../calendar/caldav/AppointmentManager.java        | 180 ++++++++++-----------
 .../service/calendar/caldav/IcalUtils.java         |  34 ++--
 .../caldav/handler/AbstractCalendarHandler.java    |  44 +++--
 .../calendar/caldav/handler/CtagHandler.java       |  35 ++--
 .../calendar/caldav/handler/EtagsHandler.java      | 151 +++++++++--------
 .../calendar/caldav/handler/MultigetHandler.java   |  56 ++++---
 .../calendar/caldav/handler/WebDAVSyncHandler.java |  80 +++++----
 .../calendar/caldav/methods/SyncMethod.java        |  72 +++++----
 .../web/user/calendar/AppointmentDialog.java       |   3 +-
 .../web/user/calendar/CalendarDialog.java          |  52 +++---
 .../web/user/calendar/CalendarPanel.java           |  22 ++-
 pom.xml                                            |   2 +-
 12 files changed, 430 insertions(+), 301 deletions(-)

diff --git a/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/AppointmentManager.java b/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/AppointmentManager.java
index a47b435..ad5bebf 100644
--- a/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/AppointmentManager.java
+++ b/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/AppointmentManager.java
@@ -26,19 +26,21 @@ import java.io.IOException;
 import java.net.URI;
 import java.util.Collection;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 import javax.annotation.PreDestroy;
 
-import org.apache.commons.httpclient.Credentials;
-import org.apache.commons.httpclient.HttpClient;
-import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
-import org.apache.commons.httpclient.auth.AuthScope;
-import org.apache.commons.httpclient.methods.OptionsMethod;
-import org.apache.commons.httpclient.params.HttpClientParams;
-import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
+import org.apache.http.HttpResponse;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.Credentials;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpOptions;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
 import org.apache.jackrabbit.webdav.DavConstants;
 import org.apache.jackrabbit.webdav.MultiStatusResponse;
-import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
+import org.apache.jackrabbit.webdav.client.methods.HttpPropfind;
 import org.apache.jackrabbit.webdav.property.DavProperty;
 import org.apache.jackrabbit.webdav.property.DavPropertyName;
 import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
@@ -54,28 +56,36 @@ import org.apache.openmeetings.service.calendar.caldav.handler.CtagHandler;
 import org.apache.openmeetings.service.calendar.caldav.handler.EtagsHandler;
 import org.apache.openmeetings.service.calendar.caldav.handler.WebDAVSyncHandler;
 import org.apache.wicket.util.string.Strings;
-import org.osaf.caldav4j.CalDAVConstants;
 import org.red5.logging.Red5LoggerFactory;
 import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 import org.w3c.dom.Element;
 
+import com.github.caldav4j.CalDAVConstants;
+
+import net.fortuna.ical4j.util.MapTimeZoneCache;
+
 /**
  * Class which does syncing and provides respective API's required for performing CalDAV Operations.
- * @author Ankush Mishra
+ * @author Ankush Mishra <an...@gmail.com>
  */
 @Component
 public class AppointmentManager {
 	private static final Logger log = Red5LoggerFactory.getLogger(AppointmentManager.class, getWebAppRootKey());
 
 	//HttpClient and ConnectionManager Params
-	private static final int IDLE_CONNECTION_TIMEOUT = 30000; // 30 seconds
+	private static final int IDLE_CONNECTION_TIMEOUT = 30; // 30 seconds
 	private static final int MAX_HOST_CONNECTIONS = 6; // Number of simultaneous connections to one host
 	private static final int MAX_TOTAL_CONNECTIONS = 10; // Max Connections, at one time in memory.
 	private static final int CONNECTION_MANAGER_TIMEOUT = 1000; // Waits for 1 sec if no empty connection exists
 
-	private MultiThreadedHttpConnectionManager connmanager = null;
+	private PoolingHttpClientConnectionManager connmanager = null;
+
+	static {
+		// Disable TimeZone caching through JCache
+		System.setProperty("net.fortuna.ical4j.timezone.cache.impl", MapTimeZoneCache.class.getName());
+	}
 
 	@Autowired
 	private OmCalendarDao calendarDao;
@@ -91,29 +101,14 @@ public class AppointmentManager {
 	 */
 	public HttpClient createHttpClient() {
 		if (connmanager == null) {
-			connmanager = new MultiThreadedHttpConnectionManager();
-			HttpConnectionManagerParams params = new HttpConnectionManagerParams();
-			params.setDefaultMaxConnectionsPerHost(MAX_HOST_CONNECTIONS);
-			params.setMaxTotalConnections(MAX_TOTAL_CONNECTIONS);
-			connmanager.setParams(params);
+			connmanager = new PoolingHttpClientConnectionManager();
+			connmanager.setDefaultMaxPerRoute(MAX_HOST_CONNECTIONS);
+			connmanager.setMaxTotal(MAX_TOTAL_CONNECTIONS);
 		}
 
-		HttpClientParams clientParams = new HttpClientParams();
-		clientParams.setConnectionManagerTimeout(CONNECTION_MANAGER_TIMEOUT);
-		return new HttpClient(connmanager);
-	}
-
-	/**
-	 * Returns the Path from the Calendar.
-	 *
-	 * @param client   Client which makes the connection.
-	 * @param calendar Calendar who's URL is used to get the path from.
-	 * @return Path component of the URL.
-	 */
-	public String getPathfromCalendar(HttpClient client, OmCalendar calendar) {
-		URI temp = URI.create(calendar.getHref());
-		client.getHostConfiguration().setHost(temp.getHost(), temp.getPort(), temp.getScheme());
-		return temp.getPath();
+		return HttpClients.custom()
+				.setConnectionManager(connmanager)
+				.build();
 	}
 
 	/**
@@ -129,15 +124,15 @@ public class AppointmentManager {
 	/**
 	 * Adds the Credentials provided to the given client on the Calendar's URL.
 	 *
-	 * @param client      Client which makes the connection.
+	 * @param context     Context of the Client which makes the connection.
 	 * @param calendar    Calendar whose Host the Credentials are for.
 	 * @param credentials Credentials to add
 	 */
-	public void provideCredentials(HttpClient client, OmCalendar calendar, Credentials credentials) {
+	public void provideCredentials(HttpClientContext context, OmCalendar calendar, Credentials credentials) {
+		// Done through creating a new Local context
 		if (!Strings.isEmpty(calendar.getHref()) && credentials != null) {
 			URI temp = URI.create(calendar.getHref());
-			client.getHostConfiguration().setHost(temp.getHost(), temp.getPort(), temp.getScheme());
-			client.getState().setCredentials(new AuthScope(temp.getHost(), temp.getPort()), credentials);
+			context.getCredentialsProvider().setCredentials(new AuthScope(temp.getHost(), temp.getPort()), credentials);
 		}
 	}
 
@@ -148,16 +143,16 @@ public class AppointmentManager {
 	 * @param calendar Calendar whose URL is to be accessed.
 	 * @return Returns true for HTTP Status 200, or 204, else false.
 	 */
-	public boolean testConnection(HttpClient client, OmCalendar calendar) {
+	public boolean testConnection(HttpClient client, HttpClientContext context, OmCalendar calendar) {
 		cleanupIdleConnections();
 
-		OptionsMethod optionsMethod = null;
+		HttpOptions optionsMethod = null;
 		try {
-			String path = getPathfromCalendar(client, calendar);
-			optionsMethod = new OptionsMethod(path);
-			optionsMethod.setRequestHeader("Accept", "*/*");
-			client.executeMethod(optionsMethod);
-			int status = optionsMethod.getStatusCode();
+			String path = calendar.getHref();
+			optionsMethod = new HttpOptions(path);
+			optionsMethod.setHeader("Accept", "*/*");
+			HttpResponse response = client.execute(optionsMethod, context);
+			int status = response.getStatusLine().getStatusCode();
 			if (status == SC_OK || status == SC_NO_CONTENT) {
 				return true;
 			}
@@ -168,7 +163,7 @@ public class AppointmentManager {
 			log.error("Severe Error in executing OptionsMethod during testConnection.", e);
 		} finally {
 			if (optionsMethod != null) {
-				optionsMethod.releaseConnection();
+				optionsMethod.reset();
 			}
 		}
 		return false;
@@ -181,9 +176,9 @@ public class AppointmentManager {
 	 * @param calendar - calendar to be created
 	 * @return <code>true</code> if calendar was created/updated
 	 */
-	public boolean createCalendar(HttpClient client, OmCalendar calendar) {
+	public boolean createCalendar(HttpClient client, HttpClientContext context, OmCalendar calendar) {
 		if (calendar.getId() == null && calendar.getSyncType() != SyncType.GOOGLE_CALENDAR) {
-			return discoverCalendars(client, calendar);
+			return discoverCalendars(client, context, calendar);
 		}
 		calendarDao.update(calendar);
 		return true;
@@ -230,23 +225,23 @@ public class AppointmentManager {
 	 * @param client - {@link HttpClient} to discover calendar
 	 * @param calendar Calendar who's sync has to take place
 	 */
-	public void syncItem(HttpClient client, OmCalendar calendar) {
+	public void syncItem(HttpClient client, HttpClientContext context, OmCalendar calendar) {
 		cleanupIdleConnections();
 
 		if (calendar.getSyncType() != SyncType.NONE) {
 			CalendarHandler calendarHandler;
-			String path = getPathfromCalendar(client, calendar);
+			String path = calendar.getHref();
 
 			switch (calendar.getSyncType()) {
 				case WEBDAV_SYNC:
-					calendarHandler = new WebDAVSyncHandler(path, calendar, client, appointmentDao, utils);
+					calendarHandler = new WebDAVSyncHandler(path, calendar, client, context, appointmentDao, utils);
 					break;
 				case CTAG:
-					calendarHandler = new CtagHandler(path, calendar, client, appointmentDao, utils);
+					calendarHandler = new CtagHandler(path, calendar, client, context, appointmentDao, utils);
 					break;
 				case ETAG:
 				default: //Default is the EtagsHandler.
-					calendarHandler = new EtagsHandler(path, calendar, client, appointmentDao, utils);
+					calendarHandler = new EtagsHandler(path, calendar, client, context, appointmentDao, utils);
 					break;
 			}
 
@@ -261,10 +256,10 @@ public class AppointmentManager {
 	 * @param client - {@link HttpClient} to discover calendar
 	 * @param userId - id of the user
 	 */
-	public void syncItems(HttpClient client, Long userId) {
+	public void syncItems(HttpClient client, HttpClientContext context, Long userId) {
 		List<OmCalendar> calendars = getCalendars(userId);
 		for (OmCalendar calendar : calendars) {
-			syncItem(client, calendar);
+			syncItem(client, context, calendar);
 		}
 	}
 
@@ -275,11 +270,11 @@ public class AppointmentManager {
 	 * @param calendar - calendar to get principal URL from
 	 * @return - <code>true</code> in case calendar was discovered successfully
 	 */
-	private boolean discoverCalendars(HttpClient client, OmCalendar calendar) {
+	private boolean discoverCalendars(HttpClient client, HttpClientContext context, OmCalendar calendar) {
 		cleanupIdleConnections();
 
 		if (calendar.getSyncType() == SyncType.NONE) {
-			PropFindMethod propFindMethod = null;
+			HttpPropfind propFindMethod = null;
 			String userPath = null, homepath = null;
 
 			DavPropertyName curUserPrincipal = DavPropertyName.create("current-user-principal"),
@@ -288,25 +283,25 @@ public class AppointmentManager {
 
 			//Find out whether it's a calendar or if we can find the calendar-home or current-user url
 			try {
-				String path = getPathfromCalendar(client, calendar);
+				String path = calendar.getHref();
 
 				DavPropertyNameSet properties = new DavPropertyNameSet();
 				properties.add(curUserPrincipal);
 				properties.add(calHomeSet);
 				properties.add(DavPropertyName.RESOURCETYPE);
 
-				propFindMethod = new PropFindMethod(path, properties, CalDAVConstants.DEPTH_0);
-				client.executeMethod(propFindMethod);
+				propFindMethod = new HttpPropfind(path, properties, CalDAVConstants.DEPTH_0);
+				HttpResponse httpResponse = client.execute(propFindMethod, context);
 
-				if (propFindMethod.succeeded()) {
-					for (MultiStatusResponse response : propFindMethod.getResponseBodyAsMultiStatus().getResponses()) {
+				if (propFindMethod.succeeded(httpResponse)) {
+					for (MultiStatusResponse response : propFindMethod.getResponseBodyAsMultiStatus(httpResponse).getResponses()) {
 						DavPropertySet set = response.getProperties(SC_OK);
 						DavProperty<?> calhome = set.get(calHomeSet), curPrinci = set.get(curUserPrincipal),
 								resourcetype = set.get(DavPropertyName.RESOURCETYPE);
 
 						if (checkCalendarResourceType(resourcetype)) {
 							//This is a calendar and thus initialize and return
-							return initCalendar(client, calendar);
+							return initCalendar(client, context, calendar);
 						}
 
 						//Else find all the calendars on the Principal and return.
@@ -328,11 +323,11 @@ public class AppointmentManager {
 					//If calendar home path wasn't set, then we get it
 					DavPropertyNameSet props = new DavPropertyNameSet();
 					props.add(calHomeSet);
-					propFindMethod = new PropFindMethod(userPath, props, DavConstants.DEPTH_0);
-					client.executeMethod(propFindMethod);
+					propFindMethod = new HttpPropfind(userPath, props, DavConstants.DEPTH_0);
+					httpResponse = client.execute(propFindMethod, context);
 
-					if (propFindMethod.succeeded()) {
-						for (MultiStatusResponse response : propFindMethod.getResponseBodyAsMultiStatus().getResponses()) {
+					if (propFindMethod.succeeded(httpResponse)) {
+						for (MultiStatusResponse response : propFindMethod.getResponseBodyAsMultiStatus(httpResponse).getResponses()) {
 							DavPropertySet set = response.getProperties(SC_OK);
 							DavProperty<?> calhome = set.get(calHomeSet);
 
@@ -352,13 +347,16 @@ public class AppointmentManager {
 					props.add(suppCalCompSet);
 					props.add(DavPropertyName.DISPLAYNAME);
 
-					propFindMethod = new PropFindMethod(homepath, props, DavConstants.DEPTH_1);
+					propFindMethod = new HttpPropfind(homepath, props, DavConstants.DEPTH_1);
 
-					client.executeMethod(propFindMethod);
+					httpResponse = client.execute(propFindMethod, context);
 
-					if (propFindMethod.succeeded()) {
+					if (propFindMethod.succeeded(httpResponse)) {
 						boolean success = false;
-						for (MultiStatusResponse response : propFindMethod.getResponseBodyAsMultiStatus().getResponses()) {
+
+						URI resourceUri = propFindMethod.getURI();
+						String host = resourceUri.getScheme() + "://" + resourceUri.getHost() + ((resourceUri.getPort() != -1)? ":" + resourceUri.getPort() : "");
+						for (MultiStatusResponse response : propFindMethod.getResponseBodyAsMultiStatus(httpResponse).getResponses()) {
 							boolean isVevent = false, isCalendar;
 
 							DavPropertySet set = response.getProperties(SC_OK);
@@ -389,13 +387,13 @@ public class AppointmentManager {
 									tempCalendar.setTitle(displayname.getValue().toString());
 								}
 
-								tempCalendar.setHref(client.getHostConfiguration().getHostURL() + response.getHref());
+								tempCalendar.setHref(host + response.getHref());
 
 								tempCalendar.setDeleted(false);
 								tempCalendar.setOwner(calendar.getOwner());
 
 								calendarDao.update(tempCalendar);
-								initCalendar(client, tempCalendar);
+								initCalendar(client, context, tempCalendar);
 							}
 						}
 						return success;
@@ -408,7 +406,7 @@ public class AppointmentManager {
 				log.error("Severe Error in executing PROPFIND Method, during testConnection.", e);
 			} finally {
 				if (propFindMethod != null) {
-					propFindMethod.releaseConnection();
+					propFindMethod.reset();
 				}
 			}
 		}
@@ -462,15 +460,15 @@ public class AppointmentManager {
 	 * @param calendar - calendar to be inited
 	 * @return <code>true</code> in case calendar was inited
 	 */
-	private boolean initCalendar(HttpClient client, OmCalendar calendar) {
+	private boolean initCalendar(HttpClient client, HttpClientContext context, OmCalendar calendar) {
 
 		if (calendar.getToken() == null || calendar.getSyncType() == SyncType.NONE) {
 			calendarDao.update(calendar);
 
-			PropFindMethod propFindMethod = null;
+			HttpPropfind propFindMethod = null;
 
 			try {
-				String path = getPathfromCalendar(client, calendar);
+				String path = calendar.getHref();
 
 				DavPropertyNameSet properties = new DavPropertyNameSet();
 				properties.add(DavPropertyName.RESOURCETYPE);
@@ -478,12 +476,12 @@ public class AppointmentManager {
 				properties.add(CtagHandler.DNAME_GETCTAG);
 				properties.add(WebDAVSyncHandler.DNAME_SYNCTOKEN);
 
-				propFindMethod = new PropFindMethod(path, properties, CalDAVConstants.DEPTH_0);
-				client.executeMethod(propFindMethod);
+				propFindMethod = new HttpPropfind(path, properties, CalDAVConstants.DEPTH_0);
+				HttpResponse httpResponse = client.execute(propFindMethod, context);
 
-				if (propFindMethod.succeeded()) {
+				if (propFindMethod.succeeded(httpResponse)) {
 
-					for (MultiStatusResponse response : propFindMethod.getResponseBodyAsMultiStatus().getResponses()) {
+					for (MultiStatusResponse response : propFindMethod.getResponseBodyAsMultiStatus(httpResponse).getResponses()) {
 						DavPropertySet set = response.getProperties(SC_OK);
 
 						if (calendar.getTitle() == null) {
@@ -502,10 +500,10 @@ public class AppointmentManager {
 						}
 					}
 
-					syncItem(client, calendar);
+					syncItem(client, context, calendar);
 					return true;
 				} else {
-					log.error("Error executing PROPFIND Method, with status Code: {}", propFindMethod.getStatusCode());
+					log.error("Error executing PROPFIND Method, with status Code: {}", httpResponse.getStatusLine().getStatusCode());
 					calendar.setSyncType(SyncType.NONE);
 				}
 
@@ -515,7 +513,7 @@ public class AppointmentManager {
 				log.error("Severe Error in executing OptionsMethod during testConnection.", e);
 			} finally {
 				if (propFindMethod != null) {
-					propFindMethod.releaseConnection();
+					propFindMethod.reset();
 				}
 			}
 		}
@@ -531,20 +529,20 @@ public class AppointmentManager {
 	 * @param appointment Appointment to create/update.
 	 * @return <code>true</code> in case item was updated
 	 */
-	public boolean updateItem(HttpClient client, Appointment appointment) {
+	public boolean updateItem(HttpClient client, HttpClientContext context, Appointment appointment) {
 		cleanupIdleConnections();
 
 		OmCalendar calendar = appointment.getCalendar();
 		SyncType type = calendar.getSyncType();
 		if (type != SyncType.NONE && type != SyncType.GOOGLE_CALENDAR) {
 			CalendarHandler calendarHandler;
-			String path = ensureTrailingSlash(getPathfromCalendar(client, calendar));
+			String path = ensureTrailingSlash(calendar.getHref());
 
 			switch (type) {
 				case WEBDAV_SYNC:
 				case CTAG:
 				case ETAG:
-					calendarHandler = new EtagsHandler(path, calendar, client, appointmentDao, utils);
+					calendarHandler = new EtagsHandler(path, calendar, client, context, appointmentDao, utils);
 					break;
 				default:
 					return false;
@@ -563,7 +561,7 @@ public class AppointmentManager {
 	 * @param appointment Appointment to Delete
 	 * @return <code>true</code> in case item was deleted
 	 */
-	public boolean deleteItem(HttpClient client, Appointment appointment) {
+	public boolean deleteItem(HttpClient client, HttpClientContext context, Appointment appointment) {
 		cleanupIdleConnections();
 
 		OmCalendar calendar = appointment.getCalendar();
@@ -571,13 +569,13 @@ public class AppointmentManager {
 
 		if (type != SyncType.NONE && type != SyncType.GOOGLE_CALENDAR) {
 			CalendarHandler calendarHandler;
-			String path = getPathfromCalendar(client, calendar);
+			String path = calendar.getHref();
 
 			switch (type) {
 				case WEBDAV_SYNC:
 				case CTAG:
 				case ETAG:
-					calendarHandler = new EtagsHandler(path, calendar, client, appointmentDao, utils);
+					calendarHandler = new EtagsHandler(path, calendar, client, context, appointmentDao, utils);
 					break;
 				default:
 					return false;
@@ -603,7 +601,7 @@ public class AppointmentManager {
 	 */
 	public void cleanupIdleConnections() {
 		if (connmanager != null) {
-			connmanager.closeIdleConnections(IDLE_CONNECTION_TIMEOUT);
+			connmanager.closeIdleConnections(IDLE_CONNECTION_TIMEOUT, TimeUnit.SECONDS);
 		}
 	}
 
@@ -612,7 +610,7 @@ public class AppointmentManager {
 	 */
 	@PreDestroy
 	public void destroy() {
-		MultiThreadedHttpConnectionManager.shutdownAll();
+		connmanager.shutdown();
 		connmanager = null;
 	}
 }
diff --git a/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/IcalUtils.java b/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/IcalUtils.java
index 25935f1..74d3ade 100644
--- a/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/IcalUtils.java
+++ b/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/IcalUtils.java
@@ -25,9 +25,11 @@ import java.net.URI;
 import java.text.ParsePosition;
 import java.util.ArrayList;
 import java.util.Date;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.NoSuchElementException;
+import java.util.Set;
 import java.util.TimeZone;
 import java.util.UUID;
 
@@ -217,7 +219,9 @@ public class IcalUtils {
 			}
 		}
 
-		List<MeetingMember> attList = a.getMeetingMembers() == null ? new ArrayList<>() : a.getMeetingMembers();
+		Set<MeetingMember> attList = a.getMeetingMembers() == null ? new HashSet<>()
+				: new HashSet<>(a.getMeetingMembers());
+		String organizerEmail = null;
 
 		//Note this value can be repeated in attendees as well.
 		if (organizer != null) {
@@ -226,13 +230,17 @@ public class IcalUtils {
 			//If the value of the organizer is an email
 			if ("mailto".equals(uri.getScheme())) {
 				String email = uri.getSchemeSpecificPart();
-				//Contact or exist and owner
-				User org = userDao.getByEmail(email);
-				if (org == null) {
-					org = userDao.getContact(email, a.getOwner());
-					attList.add(createMeetingMember(a, org));
-				} else if (!org.getId().equals(a.getOwner().getId())) {
-					attList.add(createMeetingMember(a, org));
+
+				organizerEmail = email;
+				if (!email.equals(a.getOwner().getAddress().getEmail())) {
+					//Contact or exist and owner
+					User org = userDao.getByEmail(email);
+					if (org == null) {
+						org = userDao.getContact(email, a.getOwner());
+						attList.add(createMeetingMember(a, org));
+					} else if (!org.getId().equals(a.getOwner().getId())) {
+						attList.add(createMeetingMember(a, org));
+					}
 				}
 			}
 		}
@@ -242,16 +250,24 @@ public class IcalUtils {
 				URI uri = URI.create(attendee.getValue());
 				if ("mailto".equals(uri.getScheme())) {
 					String email = uri.getSchemeSpecificPart();
+
+					Role role = attendee.getParameter(Role.CHAIR.getName());
+					if (role != null && role.getValue().equals(Role.CHAIR.getValue())
+							&& email.equals(organizerEmail)) {
+						continue;
+					}
+
 					User u = userDao.getByEmail(email);
 					if (u == null) {
 						u = userDao.getContact(email, a.getOwner());
 					}
 					attList.add(createMeetingMember(a, u));
+
 				}
 			}
 		}
 
-		a.setMeetingMembers(attList.isEmpty() ? null : attList);
+		a.setMeetingMembers(attList.isEmpty() ? null : new ArrayList<>(attList));
 
 		return a;
 	}
diff --git a/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/handler/AbstractCalendarHandler.java b/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/handler/AbstractCalendarHandler.java
index b459628..893f815 100644
--- a/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/handler/AbstractCalendarHandler.java
+++ b/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/handler/AbstractCalendarHandler.java
@@ -25,9 +25,11 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.commons.httpclient.HttpClient;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.client.protocol.HttpClientContext;
 import org.apache.jackrabbit.webdav.DavException;
-import org.apache.jackrabbit.webdav.client.methods.DavMethodBase;
+import org.apache.jackrabbit.webdav.client.methods.BaseDavRequest;
 import org.apache.openmeetings.db.dao.calendar.AppointmentDao;
 import org.apache.openmeetings.db.entity.calendar.Appointment;
 import org.apache.openmeetings.db.entity.calendar.OmCalendar;
@@ -42,6 +44,7 @@ public abstract class AbstractCalendarHandler implements CalendarHandler {
 	private static final Logger log = Red5LoggerFactory.getLogger(AbstractCalendarHandler.class, getWebAppRootKey());
 
 	protected HttpClient client;
+	protected HttpClientContext context;
 	protected OmCalendar calendar;
 	protected String path;
 	protected IcalUtils utils;
@@ -49,26 +52,36 @@ public abstract class AbstractCalendarHandler implements CalendarHandler {
 	protected AppointmentDao appointmentDao;
 
 	public AbstractCalendarHandler(String path, OmCalendar calendar, HttpClient client,
-			AppointmentDao appointmentDao, IcalUtils utils)
+	                               HttpClientContext context, AppointmentDao appointmentDao,
+	                               IcalUtils utils)
 	{
 		this.path = path;
 		this.calendar = calendar;
 		this.client = client;
+		this.context = context;
 		this.appointmentDao = appointmentDao;
 		this.utils = utils;
 	}
 
-	public static Map<String, Appointment> listToMap(List<String> keys, List<Appointment> values) {
+	/**
+	 * Converts a list of appointments to a {@link HashMap} with the Href as the key
+	 * @param appointments Appointments to map
+	 * @return Map of Hrefs to Appointments
+	 */
+	static Map<String, Appointment> listToMap(List<Appointment> appointments) {
 		Map<String, Appointment> map = new HashMap<>();
-		for (int i = 0; i < keys.size(); ++i) {
-			map.put(keys.get(i), values.get(i));
+		for(Appointment a : appointments) {
+			map.put(a.getHref(), a);
 		}
 		return map;
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	@Override
 	public OmCalendar syncItems() {
-		DavMethodBase method = null;
+		BaseDavRequest method = null;
 		try {
 			method = internalSyncItems();
 		} catch (IOException | DavException e) {
@@ -81,11 +94,22 @@ public abstract class AbstractCalendarHandler implements CalendarHandler {
 		return calendar;
 	}
 
-	void releaseConnection(DavMethodBase method) {
+	/**
+	 * Resets the Method for reusablility.
+	 * @param method Method to reset.
+	 */
+	void releaseConnection(HttpRequestBase method) {
 		if (method != null) {
-			method.releaseConnection();
+			method.reset();
 		}
 	}
 
-	abstract DavMethodBase internalSyncItems() throws IOException, DavException;
+	/**
+	 * Abstract method for syncing, this is implemented by subclasses to
+	 * perform the actual syncing.
+	 * @return Method which performed the execution.
+	 * @throws IOException on error
+	 * @throws DavException on error
+	 */
+	abstract BaseDavRequest internalSyncItems() throws IOException, DavException;
 }
diff --git a/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/handler/CtagHandler.java b/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/handler/CtagHandler.java
index fd3dfbb..e74f5ef 100644
--- a/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/handler/CtagHandler.java
+++ b/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/handler/CtagHandler.java
@@ -23,10 +23,12 @@ import static org.apache.openmeetings.util.OpenmeetingsVariables.getWebAppRootKe
 
 import java.io.IOException;
 
-import org.apache.commons.httpclient.HttpClient;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.protocol.HttpClientContext;
 import org.apache.jackrabbit.webdav.DavException;
 import org.apache.jackrabbit.webdav.MultiStatusResponse;
-import org.apache.jackrabbit.webdav.client.methods.DavMethodBase;
+import org.apache.jackrabbit.webdav.client.methods.BaseDavRequest;
 import org.apache.jackrabbit.webdav.property.DavPropertyName;
 import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
 import org.apache.jackrabbit.webdav.property.DavPropertySet;
@@ -36,11 +38,12 @@ import org.apache.openmeetings.db.entity.calendar.Appointment;
 import org.apache.openmeetings.db.entity.calendar.OmCalendar;
 import org.apache.openmeetings.service.calendar.caldav.AppointmentManager;
 import org.apache.openmeetings.service.calendar.caldav.IcalUtils;
-import org.osaf.caldav4j.CalDAVConstants;
-import org.osaf.caldav4j.methods.PropFindMethod;
 import org.red5.logging.Red5LoggerFactory;
 import org.slf4j.Logger;
 
+import com.github.caldav4j.CalDAVConstants;
+import com.github.caldav4j.methods.HttpPropFindMethod;
+
 /**
  * Class for Syncing through the help of Ctags.
  * It checks if the Ctag of the Calendar has changed.
@@ -54,46 +57,48 @@ public class CtagHandler extends AbstractCalendarHandler {
 	public static final Namespace NAMESPACE_CALSERVER = Namespace.getNamespace("cs", "http://calendarserver.org/ns/");
 	public static final DavPropertyName DNAME_GETCTAG = DavPropertyName.create("getctag", NAMESPACE_CALSERVER);
 
-	public CtagHandler(String path, OmCalendar calendar, HttpClient client, AppointmentDao appointmentDao, IcalUtils utils) {
-		super(path, calendar, client, appointmentDao, utils);
+	public CtagHandler(String path, OmCalendar calendar, HttpClient client,
+	                   HttpClientContext context, AppointmentDao appointmentDao,
+	                   IcalUtils utils) {
+		super(path, calendar, client, context, appointmentDao, utils);
 	}
 
 	@Override
-	DavMethodBase internalSyncItems() throws IOException, DavException {
+	BaseDavRequest internalSyncItems() throws IOException, DavException {
 		//Calendar already inited.
 
 		DavPropertyNameSet properties = new DavPropertyNameSet();
 		properties.add(DNAME_GETCTAG);
 
-		PropFindMethod method = new PropFindMethod(path, properties, CalDAVConstants.DEPTH_0);
-		client.executeMethod(method);
+		HttpPropFindMethod method = new HttpPropFindMethod(path, properties, CalDAVConstants.DEPTH_0);
+		HttpResponse httpResponse = client.execute(method, context);
 
-		if (method.succeeded()) {
-			for (MultiStatusResponse response : method.getResponseBodyAsMultiStatus().getResponses()) {
+		if (method.succeeded(httpResponse)) {
+			for (MultiStatusResponse response : method.getResponseBodyAsMultiStatus(httpResponse).getResponses()) {
 				DavPropertySet set = response.getProperties(SC_OK);
 				String ctag = AppointmentManager.getTokenFromProperty(set.get(DNAME_GETCTAG));
 
 				if (ctag != null && !ctag.equals(calendar.getToken())) {
-					EtagsHandler etagsHandler = new EtagsHandler(path, calendar, client, appointmentDao, utils);
+					EtagsHandler etagsHandler = new EtagsHandler(path, calendar, client, context, appointmentDao, utils);
 					etagsHandler.syncItems();
 					calendar.setToken(ctag);
 				}
 			}
 		} else {
-			log.error("Error executing PROPFIND Method, with status Code: {}", method.getStatusCode());
+			log.error("Error executing PROPFIND Method, with status Code: {}", httpResponse.getStatusLine().getStatusCode());
 		}
 		return method;
 	}
 
 	@Override
 	public boolean updateItem(Appointment appointment) {
-		EtagsHandler etagsHandler = new EtagsHandler(path, calendar, client, appointmentDao, utils);
+		EtagsHandler etagsHandler = new EtagsHandler(path, calendar, client, context, appointmentDao, utils);
 		return etagsHandler.updateItem(appointment);
 	}
 
 	@Override
 	public boolean deleteItem(Appointment appointment) {
-		EtagsHandler etagsHandler = new EtagsHandler(path, calendar, client, appointmentDao, utils);
+		EtagsHandler etagsHandler = new EtagsHandler(path, calendar, client, context, appointmentDao, utils);
 		return etagsHandler.deleteItem(appointment);
 	}
 }
diff --git a/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/handler/EtagsHandler.java b/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/handler/EtagsHandler.java
index 8142551..fbf0739 100644
--- a/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/handler/EtagsHandler.java
+++ b/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/handler/EtagsHandler.java
@@ -18,23 +18,24 @@
  */
 package org.apache.openmeetings.service.calendar.caldav.handler;
 
-import static javax.servlet.http.HttpServletResponse.SC_CREATED;
 import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
 import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
 import static javax.servlet.http.HttpServletResponse.SC_OK;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.getWebAppRootKey;
 
 import java.io.IOException;
-import java.util.ArrayList;
+import java.net.URI;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.commons.httpclient.Header;
-import org.apache.commons.httpclient.HttpClient;
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.protocol.HttpClientContext;
 import org.apache.jackrabbit.webdav.DavException;
 import org.apache.jackrabbit.webdav.MultiStatusResponse;
-import org.apache.jackrabbit.webdav.client.methods.DavMethodBase;
+import org.apache.jackrabbit.webdav.client.methods.BaseDavRequest;
 import org.apache.jackrabbit.webdav.property.DavPropertyName;
 import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
 import org.apache.openmeetings.db.dao.calendar.AppointmentDao;
@@ -43,18 +44,20 @@ import org.apache.openmeetings.db.entity.calendar.OmCalendar;
 import org.apache.openmeetings.db.entity.calendar.OmCalendar.SyncType;
 import org.apache.openmeetings.service.calendar.caldav.IcalUtils;
 import org.apache.wicket.util.string.Strings;
-import org.osaf.caldav4j.CalDAVConstants;
-import org.osaf.caldav4j.methods.CalDAVReportMethod;
-import org.osaf.caldav4j.methods.DeleteMethod;
-import org.osaf.caldav4j.methods.PutMethod;
-import org.osaf.caldav4j.model.request.CalendarData;
-import org.osaf.caldav4j.model.request.CalendarQuery;
-import org.osaf.caldav4j.model.request.CompFilter;
-import org.osaf.caldav4j.model.response.CalendarDataProperty;
-import org.osaf.caldav4j.util.UrlUtils;
 import org.red5.logging.Red5LoggerFactory;
 import org.slf4j.Logger;
 
+import com.github.caldav4j.CalDAVConstants;
+import com.github.caldav4j.methods.HttpCalDAVReportMethod;
+import com.github.caldav4j.methods.HttpDeleteMethod;
+import com.github.caldav4j.methods.HttpPutMethod;
+import com.github.caldav4j.model.request.CalendarData;
+import com.github.caldav4j.model.request.CalendarQuery;
+import com.github.caldav4j.model.request.CalendarRequest;
+import com.github.caldav4j.model.request.CompFilter;
+import com.github.caldav4j.model.response.CalendarDataProperty;
+import com.github.caldav4j.util.UrlUtils;
+
 import net.fortuna.ical4j.data.CalendarOutputter;
 import net.fortuna.ical4j.model.Calendar;
 import net.fortuna.ical4j.model.Component;
@@ -74,15 +77,27 @@ import net.fortuna.ical4j.model.Component;
 public class EtagsHandler extends AbstractCalendarHandler {
 	private static final Logger log = Red5LoggerFactory.getLogger(EtagsHandler.class, getWebAppRootKey());
 
-	public EtagsHandler(String path, OmCalendar calendar, HttpClient client, AppointmentDao appointmentDao, IcalUtils utils) {
-		super(path, calendar, client, appointmentDao, utils);
+	/**
+	 * @param uri URI to provide the host and scheme
+	 * @param path Path to append to host
+	 * @return Returns the full path, based on the URI as host and the path provided
+	 */
+	private static String getFullPath(URI uri, String path) {
+		return uri.getScheme() + "://" + uri.getAuthority() + path;
+	}
+
+	public EtagsHandler(String path, OmCalendar calendar, HttpClient client,
+	                    HttpClientContext context, AppointmentDao appointmentDao, IcalUtils utils) {
+		super(path, calendar, client, context, appointmentDao, utils);
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	@Override
-	DavMethodBase internalSyncItems() throws IOException, DavException {
+	BaseDavRequest internalSyncItems() throws IOException, DavException {
 		Long ownerId = this.calendar.getOwner().getId();
-		Map<String, Appointment> map = listToMap(appointmentDao.getHrefsbyCalendar(calendar.getId()),
-				appointmentDao.getbyCalendar(calendar.getId()));
+		Map<String, Appointment> map = listToMap(appointmentDao.getbyCalendar(calendar.getId()));
 
 		DavPropertyNameSet properties = new DavPropertyNameSet();
 		properties.add(DavPropertyName.GETETAG);
@@ -90,11 +105,11 @@ public class EtagsHandler extends AbstractCalendarHandler {
 		CompFilter vcalendar = new CompFilter(Calendar.VCALENDAR);
 		vcalendar.addCompFilter(new CompFilter(Component.VEVENT));
 
-		CalendarQuery query = new CalendarQuery(properties, vcalendar, map.isEmpty() ? new CalendarData() : null, false, false);
-		CalDAVReportMethod method = new CalDAVReportMethod(path, query, CalDAVConstants.DEPTH_1);
-		client.executeMethod(method);
-		if (method.succeeded()) {
-			MultiStatusResponse[] multiStatusResponses = method.getResponseBodyAsMultiStatus().getResponses();
+		CalendarQuery query = new CalendarQuery(properties, vcalendar, new CalendarData(), false, false);
+		HttpCalDAVReportMethod method = new HttpCalDAVReportMethod(path, query, CalDAVConstants.DEPTH_1);
+		HttpResponse httpResponse = client.execute(method, context);
+		if (method.succeeded(httpResponse)) {
+			MultiStatusResponse[] multiStatusResponses = method.getResponseBodyAsMultiStatus(httpResponse).getResponses();
 			if (map.isEmpty()) {
 				//Initializing the Calendar for the first time.
 
@@ -111,7 +126,6 @@ public class EtagsHandler extends AbstractCalendarHandler {
 				}
 			} else {
 				//Calendar has been inited before
-				List<String> currenthrefs = new ArrayList<>();
 
 				for (MultiStatusResponse response : multiStatusResponses) {
 					if (response.getStatus()[0].getStatusCode() == SC_OK) {
@@ -124,12 +138,19 @@ public class EtagsHandler extends AbstractCalendarHandler {
 
 							//If etag is modified
 							if (!currentetag.equals(origetag)) {
-								currenthrefs.add(appointment.getHref());
+								Calendar calendar = CalendarDataProperty.getCalendarfromResponse(response);
+								appointment = utils.parseCalendartoAppointment(appointment, calendar, currentetag);
+								appointmentDao.update(appointment, ownerId);
 							}
 							map.remove(response.getHref());
 						} else {
 							// The orig list of events doesn't contain this event.
-							currenthrefs.add(response.getHref());
+							String etag = CalendarDataProperty.getEtagfromResponse(response);
+							Calendar ical = CalendarDataProperty.getCalendarfromResponse(response);
+							Appointment appointments = utils.parseCalendartoAppointment(
+									ical, response.getHref(), etag, calendar);
+
+							appointmentDao.update(appointments, ownerId);
 						}
 					}
 				}
@@ -138,19 +159,16 @@ public class EtagsHandler extends AbstractCalendarHandler {
 				for (Map.Entry<String, Appointment> entry : map.entrySet()) {
 					appointmentDao.delete(entry.getValue(), ownerId);
 				}
-
-				//Get the rest of the events through a Multiget Handler.
-				MultigetHandler multigetHandler = new MultigetHandler(currenthrefs, path,
-						calendar, client, appointmentDao, utils);
-				releaseConnection(method);
-				return multigetHandler.internalSyncItems();
 			}
 		} else {
-			log.error("Report Method return Status: {} for calId {} ", method.getStatusCode(), calendar.getId());
+			log.error("Report Method return Status: {} for calId {} ", httpResponse.getStatusLine().getStatusCode(), calendar.getId());
 		}
 		return method;
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
 	@Override
 	public boolean updateItem(Appointment appointment) {
 		OmCalendar calendar = appointment.getCalendar();
@@ -159,38 +177,36 @@ public class EtagsHandler extends AbstractCalendarHandler {
 		if (calendar != null && calendar.getSyncType() != SyncType.NONE) {
 
 			//Store new Appointment on the server
-			PutMethod putMethod = null;
+			HttpPutMethod putMethod = null;
 			try {
 				List<String> hrefs = null;
 				CalendarOutputter calendarOutputter = new CalendarOutputter();
 
+				String temp = null;
 				Calendar ical = utils.parseAppointmenttoCalendar(appointment);
-
-				putMethod = new PutMethod();
-				putMethod.setRequestBody(ical);
-				putMethod.setCalendarOutputter(calendarOutputter);
+				CalendarRequest cr = new CalendarRequest(ical);
 
 				if (Strings.isEmpty(appointment.getHref())) {
-					String temp = path + appointment.getIcalId() + ".ics";
+					temp = this.path + appointment.getIcalId() + ".ics";
 					temp = UrlUtils.removeDoubleSlashes(temp);
-					putMethod.setPath(temp);
-					putMethod.setIfNoneMatch(true);
-					putMethod.setAllEtags(true);
+					cr.setIfNoneMatch(true);
+					cr.setAllEtags(true);
 				} else {
-					putMethod.setPath(appointment.getHref());
-					putMethod.setIfMatch(true);
-					putMethod.addEtag(appointment.getEtag());
+					temp = getFullPath(URI.create(this.path), appointment.getHref());
+					cr.setIfMatch(true);
+					cr.addEtag(appointment.getEtag());
 				}
 
-				client.executeMethod(putMethod);
+				putMethod = new HttpPutMethod(temp, cr, calendarOutputter);
+
+				HttpResponse httpResponse =  client.execute(putMethod, context);
 
-				if (putMethod.getStatusCode() == SC_CREATED ||
-						putMethod.getStatusCode() == SC_NO_CONTENT) {
-					href = putMethod.getPath();
+				if (putMethod.succeeded(httpResponse)) {
+					href = putMethod.getURI().getPath(); // Set the href as the path
 					appointment.setHref(href);
 
 					//Check if the ETag header was returned.
-					Header etagh = putMethod.getResponseHeader("ETag");
+					Header etagh = putMethod.getFirstHeader("ETag");
 					if (etagh == null)
 						hrefs = Collections.singletonList(appointment.getHref());
 					else {
@@ -204,7 +220,7 @@ public class EtagsHandler extends AbstractCalendarHandler {
 
 				//Get new etags for the ones which didn't return an ETag header
 				MultigetHandler multigetHandler = new MultigetHandler(hrefs, true, path,
-						calendar, client, appointmentDao, utils);
+						calendar, client, context, appointmentDao, utils);
 				multigetHandler.syncItems();
 				return true;
 			} catch (IOException e) {
@@ -212,9 +228,7 @@ public class EtagsHandler extends AbstractCalendarHandler {
 			} catch (Exception e) {
 				log.error("Severe Error in executing OptionsMethod during testConnection.", e);
 			} finally {
-				if (putMethod != null) {
-					putMethod.releaseConnection();
-				}
+				releaseConnection(putMethod);
 			}
 		}
 
@@ -222,21 +236,30 @@ public class EtagsHandler extends AbstractCalendarHandler {
 	}
 
 	/**
-	 * @see CalendarHandler#deleteItem(Appointment)
+	 * {@inheritDoc}
 	 */
 	@Override
 	public boolean deleteItem(Appointment appointment) {
 
-		if (calendar != null && calendar.getSyncType() != SyncType.NONE && !Strings.isEmpty(appointment.getHref())) {
-			DeleteMethod deleteMethod = null;
+		if (calendar != null && calendar.getSyncType() != SyncType.NONE) {
+			HttpDeleteMethod deleteMethod = null;
 			try {
-				deleteMethod = new DeleteMethod(appointment.getHref(), appointment.getEtag());
 
-				log.info("Deleting at location: {} with ETag: {}", appointment.getHref(), appointment.getEtag());
+				String fullPath;
+				if (Strings.isEmpty(appointment.getHref())) {
+					// Make sure to set HREF just in case, if calendar exists but no href does.
+					fullPath = this.path + appointment.getIcalId() + ".ics";
+				} else {
+					fullPath = getFullPath(URI.create(this.path), appointment.getHref());
+				}
+
+				deleteMethod = new HttpDeleteMethod(fullPath, appointment.getEtag());
 
-				client.executeMethod(deleteMethod);
+				log.info("Deleting at location: {} with ETag: {}", fullPath, appointment.getEtag());
 
-				int status = deleteMethod.getStatusCode();
+				HttpResponse response = client.execute(deleteMethod, context);
+
+				int status = response.getStatusLine().getStatusCode();
 				if (status == SC_NO_CONTENT || status == SC_OK || status == SC_NOT_FOUND) {
 					log.info("Successfully deleted appointment with id: " + appointment.getId());
 					return true;
@@ -248,9 +271,7 @@ public class EtagsHandler extends AbstractCalendarHandler {
 			} catch (Exception e) {
 				log.error("Severe Error in executing OptionsMethod during testConnection.", e);
 			} finally {
-				if (deleteMethod != null) {
-					deleteMethod.releaseConnection();
-				}
+				releaseConnection(deleteMethod);
 			}
 		}
 		return false;
diff --git a/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/handler/MultigetHandler.java b/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/handler/MultigetHandler.java
index 99e3ce3..8997faa 100644
--- a/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/handler/MultigetHandler.java
+++ b/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/handler/MultigetHandler.java
@@ -25,10 +25,12 @@ import java.io.IOException;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.commons.httpclient.HttpClient;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.protocol.HttpClientContext;
 import org.apache.jackrabbit.webdav.DavException;
 import org.apache.jackrabbit.webdav.MultiStatusResponse;
-import org.apache.jackrabbit.webdav.client.methods.DavMethodBase;
+import org.apache.jackrabbit.webdav.client.methods.BaseDavRequest;
 import org.apache.jackrabbit.webdav.property.DavPropertyName;
 import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
 import org.apache.openmeetings.db.dao.calendar.AppointmentDao;
@@ -36,22 +38,24 @@ import org.apache.openmeetings.db.entity.calendar.Appointment;
 import org.apache.openmeetings.db.entity.calendar.OmCalendar;
 import org.apache.openmeetings.db.entity.calendar.OmCalendar.SyncType;
 import org.apache.openmeetings.service.calendar.caldav.IcalUtils;
-import org.osaf.caldav4j.CalDAVConstants;
-import org.osaf.caldav4j.methods.CalDAVReportMethod;
-import org.osaf.caldav4j.model.request.CalendarData;
-import org.osaf.caldav4j.model.request.CalendarMultiget;
-import org.osaf.caldav4j.model.request.CompFilter;
-import org.osaf.caldav4j.model.response.CalendarDataProperty;
 import org.red5.logging.Red5LoggerFactory;
 import org.slf4j.Logger;
 
+import com.github.caldav4j.CalDAVConstants;
+import com.github.caldav4j.methods.HttpCalDAVReportMethod;
+import com.github.caldav4j.model.request.CalendarData;
+import com.github.caldav4j.model.request.CalendarMultiget;
+import com.github.caldav4j.model.request.CompFilter;
+import com.github.caldav4j.model.response.CalendarDataProperty;
+
 import net.fortuna.ical4j.model.Calendar;
 import net.fortuna.ical4j.model.Component;
 
 /**
- * Class used to sync a given list of hrefs and update or add new Appointments, whenever feasible.
- * This class cannot be used to update or delete Appointments, which are handled seperately.
- * We use the Calendar-Multiget Report Method to handle this type of query.
+ * Class used to sync a given list of hrefs and update or add new Appointments,
+ * whenever feasible. This class cannot be used to update or delete Appointments,
+ * which are handled seperately. We use the Calendar-Multiget Report Method to
+ * handle this type of query.
  *
  * @see CalendarHandler
  */
@@ -61,9 +65,11 @@ public class MultigetHandler extends AbstractCalendarHandler {
 	private CalendarMultiget query;
 	private boolean isMultigetDisabled = false, onlyEtag = false;
 
-	public MultigetHandler(List<String> hrefs, boolean onlyEtag, String path, OmCalendar calendar, HttpClient client,
-			AppointmentDao appointmentDao, IcalUtils utils) {
-		super(path, calendar, client, appointmentDao, utils);
+	public MultigetHandler(List<String> hrefs, boolean onlyEtag, String path,
+	                       OmCalendar calendar, HttpClient client,
+	                       HttpClientContext context, AppointmentDao appointmentDao,
+	                       IcalUtils utils) {
+		super(path, calendar, client, context, appointmentDao, utils);
 		this.onlyEtag = onlyEtag;
 
 		if (hrefs == null || hrefs.isEmpty() || calendar.getSyncType() == SyncType.NONE) {
@@ -83,25 +89,25 @@ public class MultigetHandler extends AbstractCalendarHandler {
 		}
 	}
 
-	public MultigetHandler(List<String> hrefs, String path, OmCalendar calendar, HttpClient client,
-			AppointmentDao appointmentDao, IcalUtils utils)
+	public MultigetHandler(List<String> hrefs, String path, OmCalendar calendar,
+	                       HttpClient client, HttpClientContext context,
+	                       AppointmentDao appointmentDao, IcalUtils utils)
 	{
-		this(hrefs, false, path, calendar, client, appointmentDao, utils);
+		this(hrefs, false, path, calendar, client, context, appointmentDao, utils);
 	}
 
 	@Override
-	DavMethodBase internalSyncItems() throws IOException, DavException {
+	BaseDavRequest internalSyncItems() throws IOException, DavException {
 		Long ownerId = this.calendar.getOwner().getId();
 		if (!isMultigetDisabled) {
-			CalDAVReportMethod method = new CalDAVReportMethod(path, query, CalDAVConstants.DEPTH_1);
+			HttpCalDAVReportMethod method = new HttpCalDAVReportMethod(path, query, CalDAVConstants.DEPTH_1);
 
-			client.executeMethod(method);
-			if (method.succeeded()) {
+			HttpResponse httpResponse = client.execute(method, context);
+			if (method.succeeded(httpResponse)) {
 				//Map for each Href as key and Appointment as Value.
-				Map<String, Appointment> map = listToMap(appointmentDao.getHrefsbyCalendar(calendar.getId()),
-						appointmentDao.getbyCalendar(calendar.getId()));
+				Map<String, Appointment> map = listToMap(appointmentDao.getbyCalendar(calendar.getId()));
 
-				for (MultiStatusResponse response : method.getResponseBodyAsMultiStatus().getResponses()) {
+				for (MultiStatusResponse response : method.getResponseBodyAsMultiStatus(httpResponse).getResponses()) {
 					if (response.getStatus()[0].getStatusCode() == SC_OK) {
 						Appointment a = map.get(response.getHref());
 
@@ -133,7 +139,7 @@ public class MultigetHandler extends AbstractCalendarHandler {
 					}
 				}
 			} else {
-				log.error("Report Method return Status: {} for calId {}", method.getStatusCode(), calendar.getId());
+				log.error("Report Method return Status: {} for calId {}", httpResponse.getStatusLine().getStatusCode(), calendar.getId());
 			}
 			return method;
 		}
diff --git a/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/handler/WebDAVSyncHandler.java b/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/handler/WebDAVSyncHandler.java
index 3dde420..ba27e90 100644
--- a/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/handler/WebDAVSyncHandler.java
+++ b/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/handler/WebDAVSyncHandler.java
@@ -27,14 +27,14 @@ import static org.apache.jackrabbit.webdav.DavServletResponse.SC_INSUFFICIENT_SP
 import static org.apache.openmeetings.util.OpenmeetingsVariables.getWebAppRootKey;
 
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Map;
 
-import org.apache.commons.httpclient.HttpClient;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.protocol.HttpClientContext;
 import org.apache.jackrabbit.webdav.DavException;
 import org.apache.jackrabbit.webdav.MultiStatusResponse;
-import org.apache.jackrabbit.webdav.client.methods.DavMethodBase;
+import org.apache.jackrabbit.webdav.client.methods.BaseDavRequest;
 import org.apache.jackrabbit.webdav.property.DavPropertyName;
 import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
 import org.apache.openmeetings.db.dao.calendar.AppointmentDao;
@@ -43,10 +43,14 @@ import org.apache.openmeetings.db.entity.calendar.OmCalendar;
 import org.apache.openmeetings.service.calendar.caldav.IcalUtils;
 import org.apache.openmeetings.service.calendar.caldav.methods.SyncMethod;
 import org.apache.openmeetings.service.calendar.caldav.methods.SyncReportInfo;
-import org.osaf.caldav4j.model.response.CalendarDataProperty;
 import org.red5.logging.Red5LoggerFactory;
 import org.slf4j.Logger;
 
+import com.github.caldav4j.CalDAVConstants;
+import com.github.caldav4j.model.response.CalendarDataProperty;
+
+import net.fortuna.ical4j.model.Calendar;
+
 /**
  * Class used to sync events using WebDAV-Sync defined in RFC 6578.
  * This handles the additional HTTP Status Code 507, which specifies for further sync required.
@@ -59,30 +63,37 @@ public class WebDAVSyncHandler extends AbstractCalendarHandler {
 	public static final DavPropertyName DNAME_SYNCTOKEN = DavPropertyName.create(SyncReportInfo.XML_SYNC_TOKEN,
 			SyncReportInfo.NAMESPACE);
 
-	public WebDAVSyncHandler(String path, OmCalendar calendar, HttpClient client, AppointmentDao appointmentDao, IcalUtils utils) {
-		super(path, calendar, client, appointmentDao, utils);
+	public WebDAVSyncHandler(String path, OmCalendar calendar, HttpClient client,
+	                         HttpClientContext context, AppointmentDao appointmentDao,
+	                         IcalUtils utils) {
+		super(path, calendar, client, context, appointmentDao, utils);
 	}
 
+	/**
+	 * Sync using WebDAV-Sync.
+	 * @throws IOException on error
+	 * @throws DavException on error
+	 */
 	@Override
-	DavMethodBase internalSyncItems() throws IOException, DavException {
+	BaseDavRequest internalSyncItems() throws IOException, DavException {
+		Long ownerId = this.calendar.getOwner().getId();
 		boolean additionalSyncNeeded = false;
 
 		DavPropertyNameSet properties = new DavPropertyNameSet();
 		properties.add(DavPropertyName.GETETAG);
+		properties.add(CalDAVConstants.DNAME_CALENDAR_DATA); // To return Calendar Data.
 
 		//Create report to get
 		SyncReportInfo reportInfo = new SyncReportInfo(calendar.getToken(), properties, SyncReportInfo.SYNC_LEVEL_1);
 		SyncMethod method = new SyncMethod(path, reportInfo);
-		client.executeMethod(method);
+		HttpResponse httpResponse = client.execute(method, context);
 
-		if (method.succeeded()) {
-			List<String> currenthrefs = new ArrayList<>();
+		if (method.succeeded(httpResponse)) {
 
 			//Map of Href and the Appointments, belonging to it.
-			Map<String, Appointment> map = listToMap(appointmentDao.getHrefsbyCalendar(calendar.getId()),
-					appointmentDao.getbyCalendar(calendar.getId()));
+			Map<String, Appointment> map = listToMap(appointmentDao.getbyCalendar(calendar.getId()));
 
-			for (MultiStatusResponse response : method.getResponseBodyAsMultiStatus().getResponses()) {
+			for (MultiStatusResponse response : method.getResponseBodyAsMultiStatus(httpResponse).getResponses()) {
 				int status = response.getStatus()[0].getStatusCode();
 				if (status == SC_OK) {
 					Appointment a = map.get(response.getHref());
@@ -90,15 +101,22 @@ public class WebDAVSyncHandler extends AbstractCalendarHandler {
 					if (a != null) {
 						//Old Event to get
 						String origetag = a.getEtag(),
-								currentetag = CalendarDataProperty.getEtagfromResponse(response);
+								currentetag = CalendarDataProperty
+										.getEtagfromResponse(response);
 
 						//If event modified, only then get it.
 						if (!currentetag.equals(origetag)) {
-							currenthrefs.add(response.getHref());
+							Calendar calendar = CalendarDataProperty.getCalendarfromResponse(response);
+							a = utils.parseCalendartoAppointment(a, calendar, currentetag);
+							appointmentDao.update(a, ownerId);
 						}
 					} else {
 						//New Event, to get
-						currenthrefs.add(response.getHref());
+						String etag = CalendarDataProperty.getEtagfromResponse(response);
+						Calendar ical = CalendarDataProperty.getCalendarfromResponse(response);
+						Appointment appointments = utils.parseCalendartoAppointment(
+								ical, response.getHref(), etag, calendar);
+						appointmentDao.update(appointments, ownerId);
 					}
 				} else if (status == SC_NOT_FOUND) {
 					//Delete the Appointments not found on the server.
@@ -113,14 +131,10 @@ public class WebDAVSyncHandler extends AbstractCalendarHandler {
 				}
 			}
 
-
-			MultigetHandler multigetHandler = new MultigetHandler(currenthrefs, path,
-					calendar, client, appointmentDao, utils);
-			multigetHandler.syncItems();
-
 			//Set the new token
-			calendar.setToken(method.getResponseSynctoken());
-		} else if (method.getStatusCode() == SC_FORBIDDEN || method.getStatusCode() == SC_PRECONDITION_FAILED) {
+			calendar.setToken(method.getResponseSynctoken(httpResponse));
+		} else if (httpResponse.getStatusLine().getStatusCode() == SC_FORBIDDEN
+				|| httpResponse.getStatusLine().getStatusCode() == SC_PRECONDITION_FAILED) {
 
 			//Specific case where a server might sometimes forget the sync token
 			//Thus requiring a full sync needed to be done.
@@ -128,7 +142,7 @@ public class WebDAVSyncHandler extends AbstractCalendarHandler {
 			calendar.setToken(null);
 			additionalSyncNeeded = true;
 		} else {
-			log.error("Error in Sync Method Response with status code {}", method.getStatusCode());
+			log.error("Error in Sync Method Response with status code {}", httpResponse.getStatusLine().getStatusCode());
 		}
 		if (additionalSyncNeeded) {
 			releaseConnection(method);
@@ -137,15 +151,27 @@ public class WebDAVSyncHandler extends AbstractCalendarHandler {
 		return method;
 	}
 
+	/**
+	 * {@inheritDoc}
+	 * <br><br>
+	 * Note: This Uses EtagsHandler for Updating.
+	 */
 	@Override
 	public boolean updateItem(Appointment appointment) {
-		EtagsHandler etagsHandler = new EtagsHandler(path, calendar, client, appointmentDao, utils);
+		EtagsHandler etagsHandler = new EtagsHandler(path, calendar, client, context,
+				appointmentDao, utils);
 		return etagsHandler.updateItem(appointment);
 	}
 
+	/**
+	 * {@inheritDoc}
+	 * <br><br>
+	 * Note: This Uses EtagsHandler for Deleting.<br>
+	 */
 	@Override
 	public boolean deleteItem(Appointment appointment) {
-		EtagsHandler etagsHandler = new EtagsHandler(path, calendar, client, appointmentDao, utils);
+		EtagsHandler etagsHandler = new EtagsHandler(path, calendar, client, context,
+				appointmentDao, utils);
 		return etagsHandler.deleteItem(appointment);
 	}
 }
diff --git a/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/methods/SyncMethod.java b/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/methods/SyncMethod.java
index 43e1241..c70be85 100644
--- a/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/methods/SyncMethod.java
+++ b/openmeetings-service/src/main/java/org/apache/openmeetings/service/calendar/caldav/methods/SyncMethod.java
@@ -21,16 +21,16 @@ package org.apache.openmeetings.service.calendar.caldav.methods;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.getWebAppRootKey;
 
 import java.io.IOException;
+import java.net.URI;
 
-import org.apache.commons.httpclient.HttpConnection;
-import org.apache.commons.httpclient.HttpState;
+import org.apache.http.HttpResponse;
 import org.apache.jackrabbit.webdav.DavConstants;
 import org.apache.jackrabbit.webdav.DavException;
 import org.apache.jackrabbit.webdav.DavMethods;
 import org.apache.jackrabbit.webdav.DavServletResponse;
 import org.apache.jackrabbit.webdav.MultiStatus;
-import org.apache.jackrabbit.webdav.client.methods.DavMethodBase;
-import org.apache.jackrabbit.webdav.client.methods.ReportMethod;
+import org.apache.jackrabbit.webdav.client.methods.BaseDavRequest;
+import org.apache.jackrabbit.webdav.client.methods.XmlEntity;
 import org.apache.jackrabbit.webdav.header.DepthHeader;
 import org.apache.jackrabbit.webdav.xml.DomUtil;
 import org.red5.logging.Red5LoggerFactory;
@@ -42,15 +42,16 @@ import org.w3c.dom.Document;
  *
  * @see SyncReportInfo for Request Report to be given as argument
  */
-public class SyncMethod extends DavMethodBase {
-	private static final Logger log = Red5LoggerFactory.getLogger(ReportMethod.class, getWebAppRootKey());
+public class SyncMethod extends BaseDavRequest {
+	private static final Logger log = Red5LoggerFactory.getLogger(SyncMethod.class, getWebAppRootKey());
 
 	private MultiStatus multiStatus = null;
 	private String synctoken = null;
+	private boolean processedResponse = false;
 
-	public SyncMethod(String uri, SyncReportInfo reportInfo) throws IOException {
+	public SyncMethod(URI uri, SyncReportInfo reportInfo) throws IOException {
 		super(uri);
-		setRequestBody(reportInfo);
+		setEntity(XmlEntity.create(reportInfo));
 
 		if (reportInfo.getDepth() >= 0) {
 			parseDepth(reportInfo.getDepth());
@@ -59,6 +60,10 @@ public class SyncMethod extends DavMethodBase {
 		log.info("Using the WEBDAV-SYNC method for syncing.");
 	}
 
+	public SyncMethod(String uri, SyncReportInfo reportInfo) throws IOException {
+		this(URI.create(uri), reportInfo);
+	}
+
 	/**
 	 * Used to add request header for Depth.
 	 *
@@ -66,7 +71,8 @@ public class SyncMethod extends DavMethodBase {
 	 *            Depth of the Request
 	 */
 	private void parseDepth(int depth) {
-		addRequestHeader(new DepthHeader(depth));
+		DepthHeader dh = new DepthHeader(depth);
+		setHeader(dh.getHeaderName(), dh.getHeaderValue());
 	}
 
 	/**
@@ -83,21 +89,22 @@ public class SyncMethod extends DavMethodBase {
 	 * Implements the Report Method.
 	 */
 	@Override
-	public String getName() {
+	public String getMethod() {
 		return DavMethods.METHOD_REPORT;
 	}
 
 	/**
-	 * @see DavMethodBase#isSuccess
+	 * @see BaseDavRequest#succeeded(HttpResponse)
 	 * @return Return true only when when Response is Multistatus.
 	 */
 	@Override
-	protected boolean isSuccess(int statusCode) {
-		return statusCode == DavServletResponse.SC_MULTI_STATUS;
+	public boolean succeeded(HttpResponse response) {
+		return response.getStatusLine().getStatusCode() == DavServletResponse.SC_MULTI_STATUS;
 	}
 
-	public String getResponseSynctoken() {
-		checkUsed();
+	public String getResponseSynctoken(HttpResponse response) {
+		if (!processedResponse)
+			processResponseBody(response);
 		return synctoken;
 	}
 
@@ -105,45 +112,48 @@ public class SyncMethod extends DavMethodBase {
 	 * Adapted from DavMethodBase to handle MultiStatus responses.
 	 *
 	 * @return MultiStatus response
-	 * @throws IOException if the response body could not be parsed
-	 * @throws DavException in case of error
+	 * @throws DavException if the response body could not be parsed
 	 */
 	@Override
-	public MultiStatus getResponseBodyAsMultiStatus() throws IOException, DavException {
-		checkUsed();
+	public MultiStatus getResponseBodyAsMultiStatus(HttpResponse response) throws DavException {
+		if (!processedResponse)
+			processResponseBody(response);
+
 		if (multiStatus != null) {
 			return multiStatus;
 		} else {
-			DavException dx = getResponseException();
+			DavException dx = getResponseException(response);
 			if (dx != null) {
 				throw dx;
 			} else {
-				throw new DavException(getStatusCode(), getName() + " resulted with unexpected status: " + getStatusLine());
+				throw new DavException(response.getStatusLine().getStatusCode(), getMethod() + " resulted with unexpected status: " + response.getStatusLine());
 			}
 		}
 	}
 
 	/**
-	 * Overridden to process the sync-token. Adapted from DavMethodBase.
-	 *
-	 * @see DavMethodBase#processResponseBody(HttpState, HttpConnection)
+	 * Process the sync-token, from the response.
 	 */
-	@Override
-	protected void processResponseBody(HttpState httpState, HttpConnection httpConnection) {
-		if (getStatusCode() == DavServletResponse.SC_MULTI_STATUS) {
+	protected void processResponseBody(HttpResponse response) {
+		if (!processedResponse && succeeded(response)) {
 			try {
-				Document document = getResponseBodyAsDocument();
+				Document document = getResponseBodyAsDocument(response.getEntity());
 				if (document != null) {
 					synctoken = DomUtil.getChildText(document.getDocumentElement(), SyncReportInfo.XML_SYNC_TOKEN, DavConstants.NAMESPACE);
 					log.info("Sync-Token for REPORT: " + synctoken);
-
 					multiStatus = MultiStatus.createFromXml(document.getDocumentElement());
-					processMultiStatusBody(multiStatus, httpState, httpConnection);
 				}
 			} catch (IOException e) {
 				log.error("Error while parsing sync-token.", e);
-				setSuccess(false);
 			}
+
+			processedResponse = true;
 		}
 	}
+
+	@Override
+	public void reset() {
+		super.reset();
+		processedResponse = false;
+	}
 }
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/calendar/AppointmentDialog.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/calendar/AppointmentDialog.java
index 2f8b03d..d32343e 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/calendar/AppointmentDialog.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/calendar/AppointmentDialog.java
@@ -280,10 +280,11 @@ public class AppointmentDialog extends AbstractFormDialog<Appointment> {
 		a.setStart(getDate(form.start.getModelObject()));
 		a.setEnd(getDate(form.end.getModelObject()));
 		a.setCalendar(form.cals.getModelObject());
-		getBean(AppointmentDao.class).update(a, getUserId());
 		if (a.getCalendar() != null) {
+			// Updates on the remote server and sets the href. Should be before dao update
 			calendarPanel.updatedeleteAppointment(target, CalendarDialog.DIALOG_TYPE.UPDATE_APPOINTMENT, a);
 		}
+		getBean(AppointmentDao.class).update(a, getUserId());
 		target.add(feedback);
 		calendarPanel.refresh(target);
 	}
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/calendar/CalendarDialog.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/calendar/CalendarDialog.java
index f9b3b1d..58a4a16 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/calendar/CalendarDialog.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/calendar/CalendarDialog.java
@@ -24,8 +24,9 @@ import static org.apache.openmeetings.web.app.WebSession.getUserId;
 import java.util.Arrays;
 import java.util.List;
 
-import org.apache.commons.httpclient.HttpClient;
-import org.apache.commons.httpclient.UsernamePasswordCredentials;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.protocol.HttpClientContext;
 import org.apache.openmeetings.db.dao.calendar.AppointmentDao;
 import org.apache.openmeetings.db.entity.calendar.Appointment;
 import org.apache.openmeetings.db.entity.calendar.OmCalendar;
@@ -208,9 +209,10 @@ public class CalendarDialog extends AbstractFormDialog<OmCalendar> {
 		switch (type) {
 			case UPDATE_CALENDAR:
 				OmCalendar c = form.getModelObject();
-				AppointmentManager appointmentManager = calendarPanel.getAppointmentManager();
+				AppointmentManager apptManager = calendarPanel.getAppointmentManager();
 				c.setHref(form.url.getModelObject());
 				HttpClient client = calendarPanel.getHttpClient();
+				HttpClientContext context = calendarPanel.getHttpClientContext();
 
 				if (form.gcal.getModelObject()) {
 					c.setSyncType(OmCalendar.SyncType.GOOGLE_CALENDAR);
@@ -219,11 +221,11 @@ public class CalendarDialog extends AbstractFormDialog<OmCalendar> {
 						calendarPanel.populateGoogleCalendar(c, target);
 					}
 				} else if (c.getId() == null && form.username.getModelObject() != null) {
-					appointmentManager.provideCredentials(client, c, new UsernamePasswordCredentials(form.username.getModelObject(),
+					apptManager.provideCredentials(context, c, new UsernamePasswordCredentials(form.username.getModelObject(),
 							form.pass.getModelObject()));
 				}
 
-				appointmentManager.createCalendar(client, c);
+				apptManager.createCalendar(client, context, c);
 				calendarPanel.refreshCalendars(target);
 				calendarPanel.refresh(target);
 				break;
@@ -255,13 +257,14 @@ public class CalendarDialog extends AbstractFormDialog<OmCalendar> {
 	 * @param handler Handler used to update the CalendarPanel
 	 */
 	private void syncCalendar(OmCalendar c, IPartialPageRequestHandler handler) {
-		AppointmentManager appointmentManager = calendarPanel.getAppointmentManager();
+		AppointmentManager apptManager = calendarPanel.getAppointmentManager();
 		HttpClient client = calendarPanel.getHttpClient();
+		HttpClientContext context = calendarPanel.getHttpClientContext();
 		if (form.username.getModelObject() != null) {
-			appointmentManager.provideCredentials(client, c, new UsernamePasswordCredentials(form.username.getModelObject(),
+			apptManager.provideCredentials(context, c, new UsernamePasswordCredentials(form.username.getModelObject(),
 					form.pass.getModelObject()));
 		}
-		appointmentManager.syncItem(client, c);
+		apptManager.syncItem(client, context, c);
 		calendarPanel.refresh(handler);
 		log.trace("Calendar " + c.getTitle() + " Successfully synced.");
 	}
@@ -272,8 +275,8 @@ public class CalendarDialog extends AbstractFormDialog<OmCalendar> {
 	 * @param a Appointment to delete
 	 */
 	private void deleteAppointment(Appointment a) {
-		AppointmentManager appointmentManager = calendarPanel.getAppointmentManager();
-		appointmentManager.deleteItem(calendarPanel.getHttpClient(), a);
+		AppointmentManager apptManager = calendarPanel.getAppointmentManager();
+		apptManager.deleteItem(calendarPanel.getHttpClient(), calendarPanel.getHttpClientContext(), a);
 		appointment = null;
 	}
 
@@ -283,8 +286,8 @@ public class CalendarDialog extends AbstractFormDialog<OmCalendar> {
 	 * @param a Appointment to update
 	 */
 	private void updateAppointment(Appointment a) {
-		AppointmentManager appointmentManager = calendarPanel.getAppointmentManager();
-		appointmentManager.updateItem(calendarPanel.getHttpClient(), a);
+		AppointmentManager apptManager = calendarPanel.getAppointmentManager();
+		apptManager.updateItem(calendarPanel.getHttpClient(), calendarPanel.getHttpClientContext(), a);
 		appointment = null;
 	}
 
@@ -306,9 +309,9 @@ public class CalendarDialog extends AbstractFormDialog<OmCalendar> {
 	 */
 	private boolean setCalendarList(IPartialPageRequestHandler target) {
 		type = DIALOG_TYPE.SYNC_CALENDAR;
-		AppointmentManager appointmentManager = calendarPanel.getAppointmentManager();
-		cals = appointmentManager.getCalendars(getUserId());
-		appointmentManager.createHttpClient();
+		AppointmentManager apptManager = calendarPanel.getAppointmentManager();
+		cals = apptManager.getCalendars(getUserId());
+		calendarPanel.getHttpClient();
 		calIndex = 0;
 		setButtons(target);
 		return setFormModelObject();
@@ -316,17 +319,18 @@ public class CalendarDialog extends AbstractFormDialog<OmCalendar> {
 
 	// Sets the form object when in need of syncing. Returns true if model is set
 	private boolean setFormModelObject() {
-		AppointmentManager appointmentManager = calendarPanel.getAppointmentManager();
+		AppointmentManager apptManager = calendarPanel.getAppointmentManager();
 
 		if (cals != null && !cals.isEmpty() && calIndex < cals.size()) {
 			OmCalendar calendar = cals.get(calIndex++);
 			HttpClient client = calendarPanel.getHttpClient();
-			if (!appointmentManager.testConnection(client, calendar)) {
+			HttpClientContext context = calendarPanel.getHttpClientContext();
+			if (!apptManager.testConnection(client, context, calendar)) {
 				form.setModelObject(calendar);
 				form.url.setModelObject(calendar.getHref());
 				return true;
 			} else {
-				appointmentManager.syncItem(client, calendar);
+				apptManager.syncItem(client, context, calendar);
 				return setFormModelObject();
 			}
 		}
@@ -338,7 +342,7 @@ public class CalendarDialog extends AbstractFormDialog<OmCalendar> {
 	// Sets the form model object if the calendar cannot be reached. Returns true if model is set
 	private boolean setFormModelObject(Appointment a, IPartialPageRequestHandler target) {
 		OmCalendar c = a.getCalendar();
-		if (calendarPanel.getAppointmentManager().testConnection(calendarPanel.getHttpClient(), c)) {
+		if (calendarPanel.getAppointmentManager().testConnection(calendarPanel.getHttpClient(), calendarPanel.getHttpClientContext(), c)) {
 			return false;
 		}
 
@@ -576,20 +580,22 @@ public class CalendarDialog extends AbstractFormDialog<OmCalendar> {
 					case UPDATE_APPOINTMENT:
 					case DELETE_APPOINTMENT:
 					case SYNC_CALENDAR:
-						AppointmentManager appointmentManager = calendarPanel.getAppointmentManager();
+						AppointmentManager apptManager = calendarPanel.getAppointmentManager();
 						try {
 							OmCalendar calendar = getModelObject();
 							if (url.isEnabled()) {
 								calendar.setHref(url.getInput());
 							}
 							HttpClient client = calendarPanel.getHttpClient();
-							appointmentManager.provideCredentials(client, calendar,
+							HttpClientContext context = calendarPanel.getHttpClientContext();
+
+							apptManager.provideCredentials(context, calendar,
 									new UsernamePasswordCredentials(username.getInput(), pass.getInput()));
-							if (appointmentManager.testConnection(client, calendar)) {
+							if (apptManager.testConnection(client, context, calendar)) {
 								return;
 							}
 						} catch (Exception e) {
-							log.error("Error executing the TestConnection");
+							log.error("Error executing the TestConnection", e);
 						}
 
 						error(getString("calendar.error"));
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/calendar/CalendarPanel.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/calendar/CalendarPanel.java
index 178dd05..1482d19 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/calendar/CalendarPanel.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/calendar/CalendarPanel.java
@@ -32,8 +32,10 @@ import java.util.Date;
 import java.util.List;
 import java.util.Optional;
 
-import org.apache.commons.httpclient.HttpClient;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.impl.client.BasicCredentialsProvider;
 import org.apache.openmeetings.db.dao.calendar.AppointmentDao;
 import org.apache.openmeetings.db.dao.user.UserDao;
 import org.apache.openmeetings.db.entity.calendar.Appointment;
@@ -92,7 +94,12 @@ public class CalendarPanel extends UserBasePanel {
 	private CalendarDialog calendarDialog;
 	private AppointmentDialog dialog;
 	private final WebMarkupContainer calendarListContainer = new WebMarkupContainer("calendarListContainer");
-	private transient HttpClient client = null; // Non-Serializable HttpClient.
+
+	// Non-Serializable HttpClient.
+	private transient HttpClient client = null;
+
+	// Context for the HttpClient. Mainly used for credentials.
+	private transient HttpClientContext context = null;
 
 	public CalendarPanel(String id) {
 		super(id);
@@ -311,7 +318,7 @@ public class CalendarPanel extends UserBasePanel {
 		syncTimer.stop(handler);
 		if (client != null) {
 			getAppointmentManager().cleanupIdleConnections();
-			client.getState().clear();
+			context.getCredentialsProvider().clear();
 		}
 	}
 
@@ -355,6 +362,15 @@ public class CalendarPanel extends UserBasePanel {
 		return client;
 	}
 
+	public HttpClientContext getHttpClientContext() {
+		if (context == null) {
+			context = HttpClientContext.create();
+			context.setCredentialsProvider(new BasicCredentialsProvider());
+		}
+
+		return context;
+	}
+
 	//Adds a new Event Source to the Calendar
 	public void populateGoogleCalendar(OmCalendar gcal, IPartialPageRequestHandler target) {
 		calendar.addSource(new GoogleCalendar(gcal.getHref(), gcal.getToken()));
diff --git a/pom.xml b/pom.xml
index c562acc..55e5e5f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -106,7 +106,7 @@
 		<commons-collections4.version>4.2</commons-collections4.version>
 		<xstream.version>1.4.11.1</xstream.version>
 		<api-all.version>2.0.0.AM2</api-all.version>
-		<caldav4j.version>0.9.1</caldav4j.version>
+		<caldav4j.version>1.0.0-rc.1</caldav4j.version>
 		<tika-parsers.version>1.19.1</tika-parsers.version>
 		<commons-text.version>1.6</commons-text.version>
 		<license.excludedScopes>test</license.excludedScopes>