/*
* � Copyright IBM Corp. 2012
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.ibm.domino.services.calendar.resources;
import static com.ibm.domino.calendar.store.ICalendarStore.FLAG_NO_WORKFLOW;
import static com.ibm.domino.calendar.store.ICalendarStore.FLAG_REPLACE_COMPLETELY;
import static com.ibm.domino.calendar.store.ICalendarStore.FLAG_SMART_SEQUENCE;
import static com.ibm.domino.commons.model.IGatekeeperProvider.FEATURE_REST_API_CALENDAR_EVENT;
import static com.ibm.domino.services.calendar.service.CalendarService.CALENDAR_SERVICE_LOGGER;
import static com.ibm.domino.services.calendar.service.CalendarService.EVENT;
import static com.ibm.domino.services.calendar.service.CalendarService.FORMAT_ICALENDAR;
import static com.ibm.domino.services.calendar.service.CalendarService.INSTANCE;
import static com.ibm.domino.services.calendar.service.CalendarService.MEDIA_TYPE_ICALENDAR;
import static com.ibm.domino.services.calendar.service.CalendarService.PATH_PARAM_EVENT;
import static com.ibm.domino.services.calendar.service.CalendarService.PATH_PARAM_INSTANCE;
import static com.ibm.domino.services.calendar.service.CalendarService.PATH_SEGMENT_INSTANCES;
import static com.ibm.domino.services.calendar.service.CalendarService.PATH_SEGMENT_SEPERATOR;
import static com.ibm.domino.services.calendar.service.CalendarService.STAT_DELETE_EVENT;
import static com.ibm.domino.services.calendar.service.CalendarService.STAT_MISC;
import static com.ibm.domino.services.calendar.service.CalendarService.STAT_READ_EVENT;
import static com.ibm.domino.services.calendar.service.CalendarService.STAT_UPDATE_EVENT;
import static com.ibm.domino.services.calendar.service.CalendarService.URL_PARAM_ACTION_TYPE;
import static com.ibm.domino.services.calendar.service.CalendarService.URL_PARAM_FORMAT;
import static com.ibm.domino.services.calendar.service.CalendarService.URL_PARAM_LITERALLY;
import static com.ibm.domino.services.calendar.service.CalendarService.URL_PARAM_RECURRENCERANGE;
import static com.ibm.domino.services.calendar.service.CalendarService.URL_PARAM_STRICT_SEQUENCE;
import static com.ibm.domino.services.calendar.service.CalendarService.URL_PARAM_WORKFLOW;
import static com.ibm.domino.services.calendar.service.CalendarService.URL_PARAM_WORKFLOWCOMMENT;
import static net.fortuna.ical4j.model.Parameter.VALUE;
import static net.fortuna.ical4j.model.Property.EXDATE;
import static net.fortuna.ical4j.model.Property.RDATE;
import static net.fortuna.ical4j.model.Property.RRULE;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.net.URI;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Iterator;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
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.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
import net.fortuna.ical4j.data.CalendarBuilder;
import net.fortuna.ical4j.data.CalendarOutputter;
import net.fortuna.ical4j.data.CalendarParser;
import net.fortuna.ical4j.data.CalendarParserFactory;
import net.fortuna.ical4j.data.ParserException;
import net.fortuna.ical4j.data.UnfoldingReader;
import net.fortuna.ical4j.model.Calendar;
import net.fortuna.ical4j.model.Component;
import net.fortuna.ical4j.model.Date;
import net.fortuna.ical4j.model.DateList;
import net.fortuna.ical4j.model.DateTime;
import net.fortuna.ical4j.model.Period;
import net.fortuna.ical4j.model.PeriodList;
import net.fortuna.ical4j.model.ValidationException;
import net.fortuna.ical4j.model.component.VEvent;
import net.fortuna.ical4j.model.parameter.Value;
import net.fortuna.ical4j.model.property.DtStart;
import net.fortuna.ical4j.model.property.ExDate;
import net.fortuna.ical4j.model.property.RDate;
import net.fortuna.ical4j.model.property.RRule;
import net.fortuna.ical4j.util.CompatibilityHints;
import org.w3c.dom.DOMException;
import com.ibm.commons.util.StringUtil;
import com.ibm.commons.util.io.json.JsonException;
import com.ibm.domino.calendar.store.RecurrenceRange;
import com.ibm.domino.calendar.store.StoreException;
import com.ibm.domino.commons.json.JsonIllegalValueException;
import com.ibm.domino.commons.util.UriHelper;
import com.ibm.domino.das.utils.ErrorHelper;
import com.ibm.domino.services.calendar.json.JsonCalendarGenerator;
import com.ibm.domino.services.calendar.json.JsonCalendarParser;
import com.ibm.domino.services.calendar.json.JsonEventAdapter;
import com.ibm.domino.services.calendar.service.CalendarService;
import com.ibm.domino.services.calendar.store.StoreFactory;
import com.ibm.domino.services.calendar.util.Utils;
@Path("calendar/events/" + PATH_PARAM_EVENT) // $NON-NLS-1$
public class EventResource {
private static final long ONE_YEAR = 365L * 24 * 60 * 60 * 1000;
/**
* Get a single event.
*
* @param uriInfo
* @param id
* @return
*/
@GET
public Response getEvent(@Context UriInfo uriInfo, @PathParam(EVENT) String id,
@QueryParam(URL_PARAM_FORMAT) String format) {
CALENDAR_SERVICE_LOGGER.traceEntry(this, "getEvent"); // $NON-NLS-1$
CalendarService.beforeRequest(FEATURE_REST_API_CALENDAR_EVENT, STAT_READ_EVENT);
CalendarService.verifyDatabaseContext();
// Get the base URL (minus the UID)
// BaseURI/eventUID
URI baseURI;
try{
baseURI = UriHelper.copy(uriInfo.getAbsolutePath(),CalendarService.isUseRelativeUrls());
}catch(IllegalArgumentException e){
throw new WebApplicationException(CalendarService.createErrorResponse(e, Response.Status.BAD_REQUEST));
}
baseURI = UriHelper.trimAtLast(baseURI, PATH_SEGMENT_SEPERATOR + UriHelper.encodePathSegment(id) );
baseURI = CalendarService.adaptUriToScn(baseURI);
// Get the event
Response response = getEventInternal(id, null, baseURI, format);
CALENDAR_SERVICE_LOGGER.traceExit(this, "getEvent", response); // $NON-NLS-1$
return response;
}
@Path("instances") // $NON-NLS-1$
@GET
public Response getEventInstances(@Context UriInfo uriInfo, @PathParam(EVENT) String id) {
String jsonEntity = null;
CALENDAR_SERVICE_LOGGER.traceEntry(this, "getEventInstances"); // $NON-NLS-1$
CalendarService.beforeRequest(FEATURE_REST_API_CALENDAR_EVENT, STAT_MISC);
CalendarService.verifyDatabaseContext();
try {
// Get the base URL (minus the UID)
URI baseURI;
try{
baseURI = UriHelper.copy(uriInfo.getAbsolutePath(),CalendarService.isUseRelativeUrls());
}catch(IllegalArgumentException e){
throw new WebApplicationException(CalendarService.createErrorResponse(e, Response.Status.BAD_REQUEST));
}
baseURI = UriHelper.trimAtLast(baseURI, PATH_SEGMENT_SEPERATOR+ PATH_SEGMENT_INSTANCES);
baseURI = CalendarService.adaptUriToScn(baseURI);
// Get the iCalendar representation for a single event
String eventString = StoreFactory.getEventStore().getEvent(id, null);
// Get the RRULE or RDATE
ArrayList<String> recurIdList= new ArrayList<String>();
RRule rrule = null;
RDate rdate = null;
ExDate exdate = null;
DtStart dtStart = null;
Value value= Value.DATE_TIME;
StringReader reader = new StringReader(eventString);
CalendarBuilder builder = new CalendarBuilder();
Calendar calendar = builder.build(new UnfoldingReader(reader, true));
if ( calendar != null && calendar.getComponents() != null ) {
Iterator<Component> iterator = calendar.getComponents().iterator();
while (iterator.hasNext()) {
Component component = iterator.next();
if ( component instanceof VEvent ) {
VEvent event = (VEvent)component;
rrule = (RRule)event.getProperty(RRULE);
rdate = (RDate)event.getProperty(RDATE);
exdate = (ExDate)event.getProperty(EXDATE);
dtStart = event.getStartDate();
if( dtStart.getParameter(VALUE) != null ){
value = (Value) dtStart.getParameter(VALUE);
}
break;
}
}
}
// get recurDates
DateList recurDates = null;
if ( dtStart != null && rrule != null ) {
// TODO: Get more than a ten year range of instances
Date start = dtStart.getDate();
long endTime = start.getTime() + ONE_YEAR * 10;
Date end = new Date(endTime);
recurDates = rrule.getRecur().getDates(start, end, Value.DATE_TIME);
}
else if ( rdate != null ) {
PeriodList periods = rdate.getPeriods();
if ( periods != null ) {
recurDates = new DateList();
Iterator iterator = periods.iterator();
while (iterator.hasNext()) {
Period period = (Period)iterator.next();
recurDates.add(period.getStart());
}
}
}
if ( recurDates == null ) {
throw new WebApplicationException(CalendarService.createErrorResponse("Event does not recur", Response.Status.BAD_REQUEST)); // $NLX-EventResource.Eventdoesnotrecur-1$
}
else {
// get exDates
DateList exDates = (exdate!=null) ? exdate.getDates(): null;
recurIdList = getRecurrenceIDList(recurDates, exDates, value);
jsonEntity = JsonEventAdapter.getInstances(recurIdList, baseURI);
}
}
catch (StoreException e) {
throw new WebApplicationException(ErrorHelper.createErrorResponse(e, Utils.mapStatus(e), Utils.getExtraProps(e)));
}
catch (IOException e) {
throw new WebApplicationException(CalendarService.createErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
}
catch (ParserException e) {
throw new WebApplicationException(CalendarService.createErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
}
catch (JsonException e) {
throw new WebApplicationException(CalendarService.createErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
}
catch (ParseException e) {
throw new WebApplicationException(CalendarService.createErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
}
// Build the response
ResponseBuilder builder = Response.ok();
if ( jsonEntity != null ) {
builder.type(MediaType.APPLICATION_JSON_TYPE).entity(jsonEntity);
}
Response response = builder.build();
CALENDAR_SERVICE_LOGGER.traceExit(this, "getEventInstances", response); // $NON-NLS-1$
return response;
}
/**
* Get a single instance of a recurring event.
*
* @param uriInfo
* @param id
* @return
*/
@Path(PATH_PARAM_INSTANCE)
@GET
public Response getEventInstance(@Context UriInfo uriInfo, @PathParam(EVENT) String id,
@PathParam(INSTANCE) String instanceId,
@QueryParam(URL_PARAM_FORMAT) String format) {
CALENDAR_SERVICE_LOGGER.traceEntry(this, "getEventInstance"); // $NON-NLS-1$
CalendarService.beforeRequest(FEATURE_REST_API_CALENDAR_EVENT, STAT_READ_EVENT);
CalendarService.verifyDatabaseContext();
// Get the base URL (minus the UID, instanceID)
// BaseURI/eventUID/instanceID
URI baseURI;
try{
baseURI = UriHelper.copy(uriInfo.getAbsolutePath(),CalendarService.isUseRelativeUrls());
}catch(IllegalArgumentException e){
throw new WebApplicationException(CalendarService.createErrorResponse(e, Response.Status.BAD_REQUEST));
}
// instanceId don't have special characters, don't need encode
baseURI = UriHelper.trimAtLast(baseURI, PATH_SEGMENT_SEPERATOR + instanceId);
baseURI = UriHelper.trimAtLast(baseURI, PATH_SEGMENT_SEPERATOR );
baseURI = CalendarService.adaptUriToScn(baseURI);
// Get the event
Response response = getEventInternal(id, instanceId, baseURI, format);
CALENDAR_SERVICE_LOGGER.traceExit(this, "getEventInstance", response); // $NON-NLS-1$
return response;
}
@PUT
@Consumes(MediaType.APPLICATION_JSON)
public Response updateJsonEvent(String requestEntity, @Context UriInfo uriInfo,
@PathParam(EVENT) String id,
@QueryParam(URL_PARAM_WORKFLOWCOMMENT) String comments,
@QueryParam(URL_PARAM_WORKFLOW) String workflow,
@QueryParam(URL_PARAM_LITERALLY) String literally,
@QueryParam(URL_PARAM_STRICT_SEQUENCE) String strictSequence) {
String responseEntity = null;
CALENDAR_SERVICE_LOGGER.traceEntry(this, "updateJsonEvent"); // $NON-NLS-1$
CalendarService.beforeRequest(FEATURE_REST_API_CALENDAR_EVENT, STAT_UPDATE_EVENT);
CalendarService.verifyDatabaseContext();
if ( StringUtil.isEmpty(requestEntity) ) {
throw new WebApplicationException(CalendarService.createErrorResponse("Empty request body.", Status.BAD_REQUEST)); // $NLX-EventResource.Emptyrequestbody-1$
}
int flags = getUpdateFlags(workflow, literally, strictSequence);
URI baseURI;
try{
baseURI = UriHelper.copy(uriInfo.getAbsolutePath(),CalendarService.isUseRelativeUrls());
}catch(IllegalArgumentException e){
throw new WebApplicationException(CalendarService.createErrorResponse(e, Response.Status.BAD_REQUEST));
}
baseURI = UriHelper.trimAtLast(baseURI, PATH_SEGMENT_SEPERATOR + UriHelper.encodePathSegment(id) );
baseURI = CalendarService.adaptUriToScn(baseURI);
responseEntity = updateJsonEventInternal(requestEntity, baseURI, id, null, comments, flags);
ResponseBuilder builder = Response.ok();
builder.type(MediaType.APPLICATION_JSON).entity(responseEntity);
Response response = builder.build();
CALENDAR_SERVICE_LOGGER.traceExit(this, "updateJsonEvent", response); // $NON-NLS-1$
return response;
}
@PUT
@Path(PATH_PARAM_INSTANCE)
@Consumes(MediaType.APPLICATION_JSON)
public Response updateJsonEventInstance(String requestEntity, @Context UriInfo uriInfo,
@PathParam(EVENT) String id, @PathParam(INSTANCE) String instanceId,
@QueryParam(URL_PARAM_WORKFLOWCOMMENT) String comments,
@QueryParam(URL_PARAM_WORKFLOW) String workflow,
@QueryParam(URL_PARAM_LITERALLY) String literally,
@QueryParam(URL_PARAM_STRICT_SEQUENCE) String strictSequence) {
String responseEntity = null;
CALENDAR_SERVICE_LOGGER.traceEntry(this, "updateJsonEventInstance"); // $NON-NLS-1$
CalendarService.beforeRequest(FEATURE_REST_API_CALENDAR_EVENT, STAT_UPDATE_EVENT);
CalendarService.verifyDatabaseContext();
if ( StringUtil.isEmpty(requestEntity) ) {
throw new WebApplicationException(CalendarService.createErrorResponse("Empty request body.", Status.BAD_REQUEST)); // $NLX-EventResource.Emptyrequestbody.1-1$
}
int flags = getUpdateFlags(workflow, literally, strictSequence);
URI baseURI;
try{
baseURI = UriHelper.copy(uriInfo.getAbsolutePath(),CalendarService.isUseRelativeUrls());
}catch(IllegalArgumentException e){
throw new WebApplicationException(CalendarService.createErrorResponse(e, Response.Status.BAD_REQUEST));
}
// instanceId don't have special characters, don't need encode
baseURI = UriHelper.trimAtLast(baseURI, PATH_SEGMENT_SEPERATOR + instanceId);
baseURI = UriHelper.trimAtLast(baseURI, PATH_SEGMENT_SEPERATOR );
baseURI = CalendarService.adaptUriToScn(baseURI);
responseEntity = updateJsonEventInternal(requestEntity, baseURI, id, instanceId, comments, flags);
ResponseBuilder builder = Response.ok();
builder.type(MediaType.APPLICATION_JSON).entity(responseEntity);
Response response = builder.build();
CALENDAR_SERVICE_LOGGER.traceExit(this, "updateJsonEventInstance", response); // $NON-NLS-1$
return response;
}
private String updateJsonEventInternal(String requestEntity, URI baseURI,
String id, String instanceId, String comments, int flags) {
String jsonResponse = null;
try {
// Parse JSON to iCal4j object model
StringReader reader = new StringReader(requestEntity);
JsonCalendarParser parser = new JsonCalendarParser();
Calendar calendar = parser.parse(reader);
// Serialize to iCalendar format
ByteArrayOutputStream baos = new ByteArrayOutputStream();
CalendarOutputter outputter = new CalendarOutputter(false);
outputter.output(calendar, baos);
String icalendar = baos.toString("UTF-8");//$NON-NLS-1$
// Update the event
String output = StoreFactory.getEventStore().updateEvent(icalendar, id, instanceId, comments, flags);
// Convert output to JSON
StringReader sr = new StringReader(output);
StringBuilder sb = new StringBuilder();
CalendarParser cp = CalendarParserFactory.getInstance().createParser();
cp.parse(new UnfoldingReader(sr, true), new JsonCalendarGenerator(sb, baseURI, false));
jsonResponse = sb.toString();
}
catch(JsonIllegalValueException e){
throw new WebApplicationException(CalendarService.createErrorResponse(e, Response.Status.BAD_REQUEST));
}
catch(StoreException e) {
throw new WebApplicationException(ErrorHelper.createErrorResponse(e, Utils.mapStatus(e), Utils.getExtraProps(e)));
} catch (JsonException e) {
throw new WebApplicationException(CalendarService.createErrorResponse(e, Response.Status.BAD_REQUEST));
} catch (IOException e) {
throw new WebApplicationException(CalendarService.createErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} catch (ValidationException e) {
throw new WebApplicationException(CalendarService.createErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
} catch (ParserException e) {
throw new WebApplicationException(CalendarService.createErrorResponse(e, Response.Status.BAD_REQUEST));
}
return jsonResponse;
}
@PUT
@Consumes(MEDIA_TYPE_ICALENDAR)
public Response updateEvent(String requestEntity, @Context UriInfo uriInfo,
@PathParam(EVENT) String id,
@QueryParam(URL_PARAM_WORKFLOWCOMMENT) String comments,
@QueryParam(URL_PARAM_WORKFLOW) String workflow,
@QueryParam(URL_PARAM_LITERALLY) String literally,
@QueryParam(URL_PARAM_STRICT_SEQUENCE) String strictSequence) {
String responseEntity = null;
CALENDAR_SERVICE_LOGGER.traceEntry(this, "updateEvent"); // $NON-NLS-1$
CalendarService.beforeRequest(FEATURE_REST_API_CALENDAR_EVENT, STAT_UPDATE_EVENT);
CalendarService.verifyDatabaseContext();
try {
if ( StringUtil.isEmpty(requestEntity) ) {
throw new WebApplicationException(CalendarService.createErrorResponse("Empty request body.", Status.BAD_REQUEST)); // $NLX-EventResource.Emptyrequestbody.2-1$
}
int flags = getUpdateFlags(workflow, literally, strictSequence);
responseEntity = StoreFactory.getEventStore().updateEvent(requestEntity, id, null, comments, flags);
}
catch(StoreException e) {
throw new WebApplicationException(ErrorHelper.createErrorResponse(e, Utils.mapStatus(e), Utils.getExtraProps(e)));
}
ResponseBuilder builder = Response.ok();
builder.type(MEDIA_TYPE_ICALENDAR).entity(responseEntity);
Response response = builder.build();
CALENDAR_SERVICE_LOGGER.traceExit(this, "updateEvent", response); // $NON-NLS-1$
return response;
}
@PUT
@Path(PATH_PARAM_INSTANCE)
@Consumes(MEDIA_TYPE_ICALENDAR)
public Response updateEventInstance(String requestEntity, @Context UriInfo uriInfo,
@PathParam(EVENT) String id, @PathParam(INSTANCE) String instanceId,
@QueryParam(URL_PARAM_WORKFLOWCOMMENT) String comments,
@QueryParam(URL_PARAM_WORKFLOW) String workflow,
@QueryParam(URL_PARAM_LITERALLY) String literally,
@QueryParam(URL_PARAM_STRICT_SEQUENCE) String strictSequence) {
String responseEntity = null;
CALENDAR_SERVICE_LOGGER.traceEntry(this, "updateEventInstance"); // $NON-NLS-1$
CalendarService.beforeRequest(FEATURE_REST_API_CALENDAR_EVENT, STAT_UPDATE_EVENT);
CalendarService.verifyDatabaseContext();
try {
if ( StringUtil.isEmpty(requestEntity) ) {
throw new WebApplicationException(CalendarService.createErrorResponse("Empty request body.", Status.BAD_REQUEST)); // $NLX-EventResource.Emptyrequestbody.3-1$
}
int flags = getUpdateFlags(workflow, literally, strictSequence);
responseEntity = StoreFactory.getEventStore().updateEvent(requestEntity, id, instanceId, comments, flags);
}
catch(StoreException e) {
throw new WebApplicationException(ErrorHelper.createErrorResponse(e, Utils.mapStatus(e), Utils.getExtraProps(e)));
}
ResponseBuilder builder = Response.ok();
builder.type(MEDIA_TYPE_ICALENDAR).entity(responseEntity);
Response response = builder.build();
CALENDAR_SERVICE_LOGGER.traceExit(this, "updateEventInstance", response); // $NON-NLS-1$
return response;
}
/**
* Deletes an event.
*
* @param id
* @return
*/
@DELETE
public Response deleteEvent(@PathParam(EVENT) String id, @QueryParam(URL_PARAM_WORKFLOW) String workflow) {
CALENDAR_SERVICE_LOGGER.traceEntry(this, "deleteEvent"); // $NON-NLS-1$
CalendarService.beforeRequest(FEATURE_REST_API_CALENDAR_EVENT, STAT_DELETE_EVENT);
CalendarService.verifyDatabaseContext();
try {
int flags = getFlags(workflow);
StoreFactory.getEventStore().deleteEvent(id, null, null, flags);
}
catch(StoreException e) {
throw new WebApplicationException(ErrorHelper.createErrorResponse(e, Utils.mapStatus(e), Utils.getExtraProps(e)));
}
Response response = Response.ok().build();
CALENDAR_SERVICE_LOGGER.traceExit(this, "deleteEvent", response); // $NON-NLS-1$
return response;
}
@DELETE
@Path(PATH_PARAM_INSTANCE)
public Response deleteEventInstance(@PathParam(EVENT) String id,
@PathParam(INSTANCE) String instanceId, @QueryParam(URL_PARAM_RECURRENCERANGE) String range,
@QueryParam(URL_PARAM_WORKFLOW) String workflow) {
CALENDAR_SERVICE_LOGGER.traceEntry(this, "deleteEventInstance"); // $NON-NLS-1$
CalendarService.beforeRequest(FEATURE_REST_API_CALENDAR_EVENT, STAT_DELETE_EVENT);
CalendarService.verifyDatabaseContext();
try {
RecurrenceRange rr = Utils.translateRecurrenceRange(range);
int flags = getFlags(workflow);
StoreFactory.getEventStore().deleteEvent(id, instanceId, rr, flags);
}
catch(StoreException e) {
throw new WebApplicationException(ErrorHelper.createErrorResponse(e, Utils.mapStatus(e), Utils.getExtraProps(e)));
}
Response response = Response.ok().build();
CALENDAR_SERVICE_LOGGER.traceExit(this, "deleteEventInstance", response); // $NON-NLS-1$
return response;
}
@Path("action") // $NON-NLS-1$
@PUT
public Response putEventAction(String requestEntity, @HeaderParam("Content-Type") String contentType, // $NON-NLS-1$
@Context UriInfo uriInfo, @PathParam(EVENT) String id,
@QueryParam(URL_PARAM_ACTION_TYPE) String type) {
CALENDAR_SERVICE_LOGGER.traceEntry(this, "putEventAction"); // $NON-NLS-1$
CalendarService.beforeRequest(FEATURE_REST_API_CALENDAR_EVENT, STAT_MISC);
CalendarService.verifyDatabaseContext();
EventActionResource.putEventActionInternal(requestEntity, contentType, id, null, null, type);
ResponseBuilder builder = Response.ok();
Response response = builder.build();
CALENDAR_SERVICE_LOGGER.traceExit(this, "putEventAction", response); // $NON-NLS-1$
return response;
}
@Path(PATH_PARAM_INSTANCE + "/action") // $NON-NLS-1$
@PUT
public Response putEventInstanceAction(String requestEntity, @HeaderParam("Content-Type") String contentType, // $NON-NLS-1$
@Context UriInfo uriInfo, @PathParam(EVENT) String id,
@PathParam(INSTANCE) String instanceId, @QueryParam(URL_PARAM_RECURRENCERANGE) String range,
@QueryParam(URL_PARAM_ACTION_TYPE) String type) {
CALENDAR_SERVICE_LOGGER.traceEntry(this, "putEventActionInstance"); // $NON-NLS-1$
CalendarService.beforeRequest(FEATURE_REST_API_CALENDAR_EVENT, STAT_MISC);
CalendarService.verifyDatabaseContext();
EventActionResource.putEventActionInternal(requestEntity, contentType, id, instanceId, range, type);
ResponseBuilder builder = Response.ok();
Response response = builder.build();
CALENDAR_SERVICE_LOGGER.traceExit(this, "putEventActionInstance", response); // $NON-NLS-1$
return response;
}
private static int getUpdateFlags(String workflow, String literally, String strictSequence) {
int flags = getFlags(workflow);
if ( "true".equalsIgnoreCase(literally) ) { // $NON-NLS-1$
flags |= FLAG_REPLACE_COMPLETELY;
}
// Subtle behavior here: FLAG_SMART_SEQUENCE is the default for updates.
// Only clear the flag if the URL includes strictsequence=true.
if ( ! "true".equalsIgnoreCase(strictSequence) ) { // $NON-NLS-1$
flags |= FLAG_SMART_SEQUENCE;
}
return flags;
}
public static int getFlags(String workflow) {
int flags = 0;
if ( "false".equalsIgnoreCase(workflow) ) { // $NON-NLS-1$
flags |= FLAG_NO_WORKFLOW;
}
return flags;
}
private Response getEventInternal(String id, String instanceId, URI baseUrl, String format) {
String jsonEntity = null;
String eventString = null;
CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_RELAXED_PARSING, true);
try {
// Get the iCalendar representation for a single event
eventString = StoreFactory.getEventStore().getEvent(id, instanceId);
if ( ! FORMAT_ICALENDAR.equalsIgnoreCase(format) ) {
// Parse the iCalendar into JSON format
StringReader reader = new StringReader(eventString);
StringBuilder sb = new StringBuilder();
CalendarParser parser = CalendarParserFactory.getInstance().createParser();
parser.parse(new UnfoldingReader(reader, true), new JsonCalendarGenerator(sb, baseUrl, false));
jsonEntity = sb.toString();
}
}
catch(StoreException e) {
throw new WebApplicationException(ErrorHelper.createErrorResponse(e, Utils.mapStatus(e), Utils.getExtraProps(e)));
}
catch(ParserException e) {
throw new WebApplicationException(CalendarService.createErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
}
catch(IOException e) {
throw new WebApplicationException(CalendarService.createErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
}
catch (DOMException e) {
throw new WebApplicationException(CalendarService.createErrorResponse(e, Response.Status.INTERNAL_SERVER_ERROR));
}
finally {
CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_RELAXED_PARSING, false);
}
ResponseBuilder builder = Response.ok();
if ( jsonEntity != null ) {
builder.type(MediaType.APPLICATION_JSON_TYPE).entity(jsonEntity);
}
else {
builder.type(MEDIA_TYPE_ICALENDAR).entity(eventString);
}
return builder.build();
}
/**
* Get a List of RECURRENCE-ID by recurrence dates and EXDATEs
*
* @param recurDates
* @param exDates
* @param value decide the format of RECURRENCE-ID
* @return
*/
public ArrayList<String> getRecurrenceIDList(DateList recurDates, DateList exDates, Value value) throws ParseException{
ArrayList<String> recurIdList= new ArrayList<String>();
// Date
if( value == Value.DATE ){
fillRecurIDListbyDate(recurIdList, recurDates);
}
// DateTime
else{
fillRecurIDListbyDateTime(recurIdList, recurDates);
}
// remove the exdates
if( exDates != null ){
if( value == Value.DATE ){
removeRecurIDListbyDate(recurIdList, exDates);
}
else{
removeRecurIDListbyDateTime(recurIdList, exDates);
}
}
return recurIdList;
}
/**
* @param recurIdList
* @param iterator The Data in Iterator should be DateTime
*/
public void fillRecurIDListbyDateTime(ArrayList<String> recurIdList, DateList recurDates) {
String sDateTime;
Iterator iterator = recurDates.iterator();
while (iterator.hasNext()) {
DateTime dateTime = (DateTime)iterator.next();
dateTime.setUtc(true);
sDateTime = dateTime.toString();
recurIdList.add(sDateTime);
}
}
/**
* @param recurIdList
* @param iterator The Data in Iterator should be DateTime
*/
public void fillRecurIDListbyDate(ArrayList<String> recurIdList, DateList recurDates) {
String sDateTime;
Iterator iterator = recurDates.iterator();
while (iterator.hasNext()) {
DateTime dateTime = (DateTime)iterator.next();
sDateTime = dateTime.toString();
int positionT = sDateTime.indexOf("T");
if(positionT>0){
sDateTime = sDateTime.substring(0, positionT);
}
recurIdList.add(sDateTime);
}
}
/**
* @param recurIdList
* @param iterator The Data in Iterator should be DateTime
*/
public void removeRecurIDListbyDateTime(ArrayList<String> recurIdList, DateList exDates) {
String sDateTime;
Iterator iterator = exDates.iterator();
while (iterator.hasNext()) {
DateTime exDate = (DateTime)iterator.next();
exDate.setUtc(true);
// exDates must have same type with value
sDateTime = exDate.toString();
recurIdList.remove(sDateTime);
}
}
/**
* @param recurIdList
* @param iterator The Data in Iterator should be Date or DateTime
*/
public void removeRecurIDListbyDate(ArrayList<String> recurIdList, DateList exDates) {
String sDateTime;
Iterator iterator = exDates.iterator();
while (iterator.hasNext()) {
Date exDate = (Date)iterator.next();
if(exDate instanceof DateTime){
((DateTime) exDate).setUtc(true);
}
// exDates must have same type with value
sDateTime = exDate.toString();
int positionT = sDateTime.indexOf("T");
if(positionT>0){
sDateTime = sDateTime.substring(0, positionT);
}
recurIdList.remove(sDateTime);
}
}
}