Syndesis: Google Calendar Connector - 'Update step' not allowing single field update

Created on 12 Oct 2018  路  18Comments  路  Source: syndesisio/syndesis

See also https://issues.jboss.org/browse/ENTESB-11442

This is a...


[ ] Feature request
[ ] Regression (a behavior that used to work and stopped working in a new release)
[x] Bug report  
[ ] Documentation issue or request

Description

Google Calendar connector action 'Update Event' doesn't allow partial update of an event.

This issue applies to a use-case where Update Event is used on its own, not depending on a data input from preceding step, e.g. timer -> 'Update event'.

When user specifies calendar and eventId, and changes only 'location' in the form, I would expect, that only that single field is being attempted to be updated.

Pre-filling values into the form is not a valid solution, as it is valid only design time, not during runtime (event could have been updated meanwhile). Rather we'd need to handle the form input as a selective update, see https://developers.google.com/calendar/v3/reference/events/patch .

To illustrate the issue, what I see is, that event the date/time fields are being attempted to be updated even though I set only 'location' in the form. The error I get:

org.apache.camel.RuntimeCamelException: com.google.api.client.googleapis.json.GoogleJsonResponseException: 400 Bad Request
{
  "code" : 400,
  "errors" : [ {
    "domain" : "global",
    "message" : "Missing end time.",
    "reason" : "required"
  } ],
  "message" : "Missing end time."
}
    at org.apache.camel.component.google.calendar.GoogleCalendarProducer.doInvokeMethod(GoogleCalendarProducer.java:51)
    at org.apache.camel.util.component.AbstractApiProducer$1.run(AbstractApiProducer.java:86)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: com.google.api.client.googleapis.json.GoogleJsonResponseException: 400 Bad Request
{
  "code" : 400,
  "errors" : [ {
    "domain" : "global",
    "message" : "Missing end time.",
    "reason" : "required"
  } ],
  "message" : "Missing end time."
}
    at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:146)
    at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
    at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:321)
    at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1065)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:419)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)
    at org.apache.camel.component.google.calendar.GoogleCalendarProducer.doInvokeMethod(GoogleCalendarProducer.java:49)
    ... 8 more
cabug closemigrated grouconnector prip2 sourcqe statunever-stale targe7.x zenhubacklog

Most helpful comment

Sorry for the confusiob

All 18 comments

The design and implementation decision are not up to QE. You're literally destroying this connector. This starts to become boring.

Technical discussion below:
If the 'Update Event' action follows a 'Get a specific Event' action, then the update is performed fine.

I'd remove the calendar + eventId selection from the 'Update Event' completely and I'd rely on passing the Event instance from the 'Get a specific Event' step. The 'Update Event' would then serve as a definition of changes I want to make.

The important part is leaving out the calendar+event specification from the update event, as that needs to match the info specified in 'Get a specific Event' anyway and imo is redundant.

If we change the behavior by using a POJO like we said here https://github.com/syndesisio/syndesis/issues/3803

The flow will change.

To map the input from get a specific event action to update event, once the PR is merged, you can map the parameter you want from the event you get and add in the form only the parameter you want to change.

@oscerd when I specify only a calendar and event_id and then a single field (let's say only description) directly in the update form, I get following error during runtime:

java.text.ParseException: Unparseable date: "null null"
    at java.text.DateFormat.parse(DateFormat.java:366)
    at io.syndesis.connector.calendar.GoogleCalendarUpdateEventCustomizer.createGoogleEvent(GoogleCalendarUpdateEventCustomizer.java:174)
    at io.syndesis.connector.calendar.GoogleCalendarUpdateEventCustomizer.beforeProducer(GoogleCalendarUpdateEventCustomizer.java:116)
    at org.apache.camel.util.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:61)
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:138)
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:101)
    at io.syndesis.integration.component.proxy.ComponentProxyProducer.process(ComponentProxyProducer.java:44)
    at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:148)
    at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:110)
    at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:548)
    at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:201)
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:138)
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:101)
    at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:110)
    at io.syndesis.integration.runtime.logging.ActivityTrackingInterceptStrategy$EventProcessor.process(ActivityTrackingInterceptStrategy.java:79)
    at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:110)
    at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:548)
    at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:201)
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:138)
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:101)
    at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:201)
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:138)
    at org.apache.camel.processor.Pipeline.process(Pipeline.java:101)
    at org.apache.camel.component.timer.TimerConsumer.sendTimerExchange(TimerConsumer.java:197)
    at org.apache.camel.component.timer.TimerConsumer$1.run(TimerConsumer.java:79)
    at java.util.TimerThread.mainLoop(Timer.java:555)
    at java.util.TimerThread.run(Timer.java:505)

Is that something that could be resolved by #3863 ? As this seems, that it brings another level of null-checks for the input:

  1. both date and time are null
  2. date is set, time is null
  3. neither date nor time are null

This issue hits the 1. option. Whereas the #3863 hits option 2.

I am gonna reopen this one, as the issue still appears, although the error is slightly different.

Did you add a datamapper step before, where you map any field for the incoming event that you're not going to insert in the form? Otherwise this is normal.

You're able to combine datamapper and form actually. since this is possible, I can't make form fields required, otherwise the datamapping step will be always overriden

This will expect that you map everything you're not gonna upgrade

I don't use data mapper in this case.
I don't have any event in the body of the flow (no get by id step or anything).
I am providing just calendar name, event id and one extra field to be updated.
I don't want to update any other field.
What should I do? Add a get by id step before the action, then add a mapper, map all the fields and in the form only specify those I want to override?
So the resulting usage patterns would be only:

  1. map fields of incoming event to input data shape + override fields defined in update event form
  2. fill everything in the update event form and update all fields of event

Is that correct?

I still miss the patch operation support which would be an excellent match in both options above plus supporting what I've reported in this issue. I understand it can be a significant effort, in that case I can start a feature request to be considered in future.

Yes, you have to do a get first. The PATCH method is not implemented, the user story ask for updating an event. We can add an enhancement for this and create the PATCH method.

We can add the PATCH operation easily by the way, but this can be only object of 7.3

Your offered solution works, even the partial update is possible currently by using data mapper, the only (mostly usability) issue is #3887.

This issue has been automatically marked as stale because it has not had any activity since 90 days. It will be closed if no further activity occurs within 7 days. Thank you for your contributions!

@oscerd
What exactly is required for this issue to be completed? Is it here for implementing PATCH?

I have a branch which I'm working on for this. It needs a patch operation.

I forgot to assign this to myself

Sorry for the confusiob

Was this page helpful?
0 / 5 - 0 ratings