package org.osaf.caldav4j; /** * TODO tutti gli attributi, tutti i metodi non specializzati * * @author rpolli * */ import net.fortuna.ical4j.model.Calendar; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HostConfiguration; import org.osaf.caldav4j.cache.CalDAVResourceCache; import org.osaf.caldav4j.cache.EhCacheResourceCache; import org.osaf.caldav4j.cache.NoOpResourceCache; import org.osaf.caldav4j.exceptions.BadStatusException; import org.osaf.caldav4j.exceptions.CacheException; import org.osaf.caldav4j.exceptions.CalDAV4JException; import org.osaf.caldav4j.exceptions.ResourceOutOfDateException; import org.osaf.caldav4j.methods.CalDAV4JMethodFactory; import org.osaf.caldav4j.methods.HttpClient; import org.osaf.caldav4j.methods.OptionsMethod; import org.osaf.caldav4j.methods.PutMethod; import org.osaf.caldav4j.util.CaldavStatus; import org.osaf.caldav4j.util.UrlUtils; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.regex.Pattern; public abstract class CalDAVCalendarCollectionBase implements CalDAVConstants { CalDAV4JMethodFactory methodFactory = null; private String calendarCollectionRoot = null; HostConfiguration hostConfiguration = null; String prodId = null; Random random = new Random(); protected CalDAVResourceCache cache = NoOpResourceCache.SINGLETON; //Configuration Methods public HostConfiguration getHostConfiguration() { return hostConfiguration; } public void setHostConfiguration(HostConfiguration hostConfiguration) { this.hostConfiguration = hostConfiguration; } public CalDAV4JMethodFactory getMethodFactory() { return methodFactory; } public void setMethodFactory(CalDAV4JMethodFactory methodFactory) { this.methodFactory = methodFactory; } /** * remove double slashes * @return String */ public String getCalendarCollectionRoot() { return UrlUtils.removeDoubleSlashes(calendarCollectionRoot); } /** * set base path, appending trailing "/" and removing unneeded "/" * @param path */ public void setCalendarCollectionRoot(String path) { this.calendarCollectionRoot = UrlUtils.removeDoubleSlashes(path.concat("/")); } public CalDAVResourceCache getCache() { return cache; } public void setCache(CalDAVResourceCache cache) { this.cache = cache; } /** * Check if a cache is set * @return true if cache is not NoOpResourceCache */ public boolean isCacheEnabled() { boolean p = (this.cache instanceof NoOpResourceCache); return !p; } /** * Returns the path relative to the calendars path given an href * * @param href * @return */ protected String getRelativePath(String href){ int start = href.indexOf(calendarCollectionRoot); return href.substring(start + calendarCollectionRoot.length() + 1); } /** * Create a PUT method setting If-None-Match: * * this tag causes PUT fails if a given event exist * @param resourceName * @param calendar * @return a PutMethod for creating events */ PutMethod createPutMethodForNewResource(String resourceName, Calendar calendar) { PutMethod putMethod = methodFactory.createPutMethod(); putMethod.setPath(calendarCollectionRoot + "/" + resourceName); putMethod.setAllEtags(true); putMethod.setIfNoneMatch(true); putMethod.setRequestBody(calendar); return putMethod; } /** * TODO check hostConfiguration.getUri() * @param path * @return the URI of the path resource * * XXX maybe it will be faster to write down the whole url including port... */ String getHref(String path){ int port = hostConfiguration.getPort(); String scheme = hostConfiguration.getProtocol().getScheme(); String portString = ""; if ( (port != 80 && "http".equals(scheme)) || (port != 443 && "https".equals(scheme)) ) { portString = ":" + port; } return UrlUtils.removeDoubleSlashes( String.format("%s://%s%s/%s", scheme, hostConfiguration.getHost(), portString, path ) ); } /** * create cache resources: UID_TO_HREF, HREF_TO_RESOURCE * XXX create test method */ public void enableSimpleCache() throws CalDAV4JException { EhCacheResourceCache cache = null; if (!isCacheEnabled()) { try { cache = EhCacheResourceCache.createSimpleCache(); } catch (CacheException e) { // avoid error if cache doesn't exist e.printStackTrace(); } this.setCache(cache); } } /** * set cache to NoOpResourceCache * XXX test it */ public void disableSimpleCache() { EhCacheResourceCache.removeSimpleCache(); this.setCache(NoOpResourceCache.SINGLETON); } private boolean tolerantParsing = false; public boolean isTolerantParsing() { return tolerantParsing; } public void setTolerantParsing(boolean tolerantParsing) { this.tolerantParsing = tolerantParsing; } /** * TODO manage status codes with an helper * TODO I should throw an exception when server doesn't set etag * * @param httpClient * @param calendar * @param path * @param etag * @throws CalDAV4JException */ void put(HttpClient httpClient, Calendar calendar, String path, String etag) throws CalDAV4JException { PutMethod putMethod = methodFactory.createPutMethod(); putMethod.addEtag(etag); putMethod.setPath(path); putMethod.setIfMatch(true); putMethod.setRequestBody(calendar); try { httpClient.executeMethod(hostConfiguration, putMethod); int statusCode = putMethod.getStatusCode(); switch(statusCode) { case CaldavStatus.SC_NO_CONTENT: case CaldavStatus.SC_CREATED: break; case CaldavStatus.SC_PRECONDITION_FAILED: throw new ResourceOutOfDateException("Etag was not matched: "+ etag); default: throw new BadStatusException(statusCode, putMethod.getName(), path); } } catch (Exception e){ throw new CalDAV4JException("Problem executing put method",e); } Header h = putMethod.getResponseHeader("ETag"); if (h != null) { String newEtag = h.getValue(); cache.putResource(new CalDAVResource(calendar, newEtag, getHref(putMethod.getPath()))); } } /** * get OPTIONS for calendarCollectionRoot * @param httpClient * @return * @throws CalDAV4JException */ public List<Header> getOptions(HttpClient httpClient) throws CalDAV4JException { List<Header> hList = new ArrayList<Header>(); OptionsMethod optMethod = new OptionsMethod(); optMethod.setPath(this.calendarCollectionRoot); optMethod.setRequestHeader(new Header("Host", hostConfiguration.getHost())); try { httpClient.executeMethod(this.hostConfiguration, optMethod); } catch (Exception e) { throw new CalDAV4JException("Trouble executing OPTIONS", e); } int status = optMethod.getStatusCode(); switch (status) { case CaldavStatus.SC_OK: break; default: throw new BadStatusException(status, optMethod.getName(), getCalendarCollectionRoot()); } for (Header h: optMethod.getResponseHeaders()) { hList.add(h); } return hList; } /** * check whether server Allows the given action * XXX we should implement it as allowed props should be an attribute of this class, * set each time the base-path is changed * @param action * @return * @throws CalDAV4JException */ public boolean allows(HttpClient httpClient, String action, List<Header> hList) throws CalDAV4JException { for (Header h : hList) { if ("Allow".equals(h.getName()) && (h.getValue() != null) && Pattern.compile("\\b"+action+"\\b").matcher(h.getValue()).find()) { return true; } } return false; } }