Hello,
We're trying to build a POC on SCIM APIs on top of Syncope.Problem is when 
we're using some basic SCIM APIs to update the groups membership of a given 
user, we got a OptimisticLockException.
This is due to the fact that SCIM group membership can be updated only from the 
Group endpoint (not from the User endpoint).From 
https://tools.ietf.org/html/rfc7643#page-24 
groups
A list of groups to which the user belongs,...
Since this attribute has a mutability of "readOnly", group membership changes 
MUST be applied via the
"Group" Resource (Section 4.2).  This attribute has a mutability of "readOnly".
So, we have the following scenario : * we have a user1 member of 2 groups 
(group1 and group2). * we want to remove the user1 from both groups from a UI 
console. * the UI then needs to send 2 HTTP PUT on SCIM /Groups endpoint (one 
for each group).
    /PUT Groups/group1
    /PUT Groups/group2
 * we get a OptimisticLockException since both calls are made for a relation on 
the same user - because on the SCIM side for the Group endpoint, we must call   
userService.update(userTO) to update a user <-> group relation.
i.e.         MembershipTO membershipTO =
                new MembershipTO.Builder().group(userTO.getKey(), 
"USER").group(groupTO.getKey(), groupTO.getName()).build();
        userTO.getMemberships().add(membershipTO);
        try {
            userService.update(userTO);
        } catch (SyncopeClientException e) {
            throw new SCIMException(String.format("User %s was not added to the 
group %s", userId, groupTO.getName()), e);
        }

Is there an API to update user or group membership without testing @Version 
field ? (i.e like a syncope REST API on top of a jpql update ?) 
Perhaps we're not using the good API here (is there an API to handle membership 
from the group's side ?
Do you see another possible solution (besides updating membership from the 
Group side/screen) ?
Thanks,Adrian

Sample stacktrace on client side :2016-09-27 09:31:46.065 DEBUG 1 --- 
[tp1754926770-22] o.s.web.client.RestTemplate              : PUT request for 
"http://scim:7777/Groups/2564b3a7-0f5d-424d-a4b3-a70f5d624d80"; resulted in 500 
(Server Error); invoking error handler
     at 
org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
 [jetty-server-9.2.14.v20151106.jar!/:9.2.14.v20151106]
     at 
org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) 
[jetty-server-9.2.14.v20151106.jar!/:9.2.14.v20151106]
     at 
org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97) 
[jetty-server-9.2.14.v20151106.jar!/:9.2.14.v20151106]
     at org.eclipse.jetty.server.Server.handle(Server.java:499) 
[jetty-server-9.2.14.v20151106.jar!/:9.2.14.v20151106]
     at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311) 
[jetty-server-9.2.14.v20151106.jar!/:9.2.14.v20151106]
     at 
org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257) 
[jetty-server-9.2.14.v20151106.jar!/:9.2.14.v20151106]
     at 
org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544) 
[jetty-io-9.2.14.v20151106.jar!/:9.2.14.v20151106]
     at 
org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
 [jetty-util-9.2.14.v20151106.jar!/:9.2.14.v20151106]
     at 
org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555) 
[jetty-util-9.2.14.v20151106.jar!/:9.2.14.v20151106]
     at java.lang.Thread.run(Thread.java:745) [na:1.8.0_92-internal]
 Caused by: org.apache.syncope.common.lib.SyncopeClientException: 
GenericPersistence [OptimisticLockException: An optimistic lock violation was 
detected when flushing object instance 
"org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttrValue-62f5f8bf-b390-4354-b5f8-bfb390a354e8"
 to the data store.  This indicates that the object was concurrently modified 
in another transaction.]
     at 
org.apache.syncope.common.lib.SyncopeClientException.build(SyncopeClientException.java:37)
 ~[syncope-common-lib-2.0.0-SNAPSHOT.jar!/:2.0.0-SNAPSHOT]
     at 
org.apache.syncope.client.lib.RestClientExceptionMapper.checkSyncopeClientCompositeException(RestClientExceptionMapper.java:147)
 ~[syncope-client-lib-2.0.0-SNAPSHOT.jar!/:2.0.0-SNAPSHOT]
     at 
org.apache.syncope.client.lib.RestClientExceptionMapper.fromResponse(RestClientExceptionMapper.java:58)
 ~[syncope-client-lib-2.0.0-SNAPSHOT.jar!/:2.0.0-SNAPSHOT]
     at 
org.apache.syncope.client.lib.RestClientExceptionMapper.fromResponse(RestClientExceptionMapper.java:42)
 ~[syncope-client-lib-2.0.0-SNAPSHOT.jar!/:2.0.0-SNAPSHOT]
     at 
org.apache.cxf.jaxrs.client.ClientProxyImpl.checkResponse(ClientProxyImpl.java:306)
 ~[cxf-rt-rs-client-3.1.7.jar!/:3.1.7]
2016-09-27 09:31:46.068 DEBUG 1 --- [tp1754926770-22] 
.m.m.a.ExceptionHandlerExceptionResolver : Resolving exception from handler 
[public void 
org.mycompany.iam.server.controller.GroupController.updateGroup(java.lang.String,org.mycompany.iam.common.model.Group)
 throws org.mycompany.iam.server.exception.IamServerException]: 
org.mycompany.iam.server.exception.IamServerException: Can't update group
     at 
org.apache.cxf.jaxrs.client.ClientProxyImpl.handleResponse(ClientProxyImpl.java:838)
 ~[cxf-rt-rs-client-3.1.7.jar!/:3.1.7]
2016-09-27 09:31:46.071 DEBUG 1 --- [tp1754926770-22] 
.m.m.a.ExceptionHandlerExceptionResolver : Invoking @ExceptionHandler method: 
public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, 
java.lang.Object>> 
org.mycompany.iam.server.exception.IamServerExceptionHandler.handleIamException(org.mycompany.iam.server.exception.IamServerException)
     at 
org.apache.cxf.jaxrs.client.ClientProxyImpl.doChainedInvocation(ClientProxyImpl.java:752)
 ~[cxf-rt-rs-client-3.1.7.jar!/:3.1.7]
     at 
org.apache.cxf.jaxrs.client.ClientProxyImpl.invoke(ClientProxyImpl.java:231) 
~[cxf-rt-rs-client-3.1.7.jar!/:3.1.7]
     at com.sun.proxy.$Proxy131.update(Unknown Source) ~[na:na]
     at 
org.mycompany.iam.scim.provisioning.SCIMGroupProvisioning.addUserToGroup(SCIMGroupProvisioning.java:201)
 ~[iam-scim_tpsvc-1011-update-group-in-user-1-20160927092425-g1ca9982.jar!/:na]
     ... 57 common frames omitted

Sample stacktrace on Syncope side :09:31:45.914 ERROR 
org.apache.syncope.core.rest.cxf.RestServiceExceptionMapper - Exception thrown
org.apache.openjpa.persistence.OptimisticLockException: Optimistic locking 
errors were detected when flushing to the data store.  The following objects 
may have been concurrently modified in another transaction: 
[org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttrValue-62f5f8bf-b390-4354-b5f8-bfb390a354e8,
 
org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttrValue-314a1e53-0235-41ff-8a1e-53023571ff42,
 
org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttrValue-c4c32ec3-0312-4f00-832e-c30312af0045,
 
org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttrValue-9ce613a2-5b42-4bce-a613-a25b425bce86,
 
org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttrValue-32fb4c5b-995f-45f2-bb4c-5b995f05f255,
 
org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttrValue-7117ce5e-4f87-43da-97ce-5e4f8773da92]
    at 
org.apache.openjpa.kernel.BrokerImpl.newFlushException(BrokerImpl.java:2357) 
~[openjpa-kernel-2.4.1.jar:2.4.1]
enjpa-kernel-2.4.1.jar:2.4.1].kernel.BrokerImpl.flush(BrokerImpl.java:2205) 
~[op--More--
    at org.apache.openjpa.kernel.BrokerImpl.flushSafe(BrokerImpl.java:2103) 
~[openjpa-kernel-2.4.1.jar:2.4.1]
    at org.apache.openjpa.kernel.BrokerImpl.flush(BrokerImpl.java:1874) 
~[openjpa-kernel-2.4.1.jar:2.4.1]
    at 
org.apache.openjpa.kernel.DelegatingBroker.flush(DelegatingBroker.java:1044) 
~[openjpa-kernel-2.4.1.jar:2.4.1]
    at 
org.apache.openjpa.persistence.EntityManagerImpl.flush(EntityManagerImpl.java:664)
 ~[openjpa-persistence-2.4.1.jar:2.4.1]
    at 
org.apache.syncope.core.persistence.jpa.dao.JPAUserDAO.save(JPAUserDAO.java:399)
 ~[syncope-core-persistence-jpa-2.0.0-SNAPSHOT.jar:2.0.0-SNAPSHOT]
    at 
org.apache.syncope.core.persistence.jpa.dao.JPAUserDAO.save(JPAUserDAO.java:83) 
~[syncope-core-persistence-jpa-2.0.0-SNAPSHOT.jar:2.0.0-SNAPSHOT]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_91]
    at 
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
~[?:1.8.0_91]
    at 
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 ~[?:1.8.0_91]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_91]
    at 
org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
 ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at 
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
 ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at com.sun.proxy.$Proxy153.save(Unknown Source) ~[?:?]
    at 
org.apache.syncope.core.workflow.java.DefaultUserWorkflowAdapter.doUpdate(DefaultUserWorkflowAdapter.java:115)
 ~[syncope-core-workflow-java-2.0.0-SNAPSHOT.jar:2.0.0-SNAPSHOT]
    at 
org.apache.syncope.core.workflow.java.AbstractUserWorkflowAdapter.update(AbstractUserWorkflowAdapter.java:78)
 ~[syncope-core-workflow-java-2.0.0-SNAPSHOT.jar:2.0.0-SNAPSHOT]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_91]
    at 
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
~[?:1.8.0_91]
    at 
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 ~[?:1.8.0_91]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_91]
    at 
org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
 ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at 
org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
 ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at 
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
 ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at 
org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
 ~[spring-tx-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at 
org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:280)
 ~[spring-tx-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at 
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
 ~[spring-tx-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at 
org.apache.syncope.core.persistence.jpa.spring.DomainTransactionInterceptor.invoke(DomainTransactionInterceptor.java:64)
 ~[syncope-core-persistence-jpa-2.0.0-SNAPSHOT.jar:2.0.0-SNAPSHOT]
    at 
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
 ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at 
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
 ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at com.sun.proxy.$Proxy164.update(Unknown Source) ~[?:?]
    at 
org.apache.syncope.core.provisioning.java.DefaultUserProvisioningManager.update(DefaultUserProvisioningManager.java:121)
 ~[syncope-core-provisioning-java-2.0.0-SNAPSHOT.jar:2.0.0-SNAPSHOT]
    at 
org.apache.syncope.core.provisioning.java.DefaultUserProvisioningManager.update(DefaultUserProvisioningManager.java:57)
 ~[syncope-core-provisioning-java-2.0.0-SNAPSHOT.jar:2.0.0-SNAPSHOT]
    at org.apache.syncope.core.logic.UserLogic.doUpdate(UserLogic.java:232) 
~[syncope-core-logic-2.0.0-SNAPSHOT.jar:2.0.0-SNAPSHOT]
    at org.apache.syncope.core.logic.UserLogic.update(UserLogic.java:213) 
~[syncope-core-logic-2.0.0-SNAPSHOT.jar:2.0.0-SNAPSHOT]
    at org.apache.syncope.core.logic.UserLogic.update(UserLogic.java:68) 
~[syncope-core-logic-2.0.0-SNAPSHOT.jar:2.0.0-SNAPSHOT]
    at 
org.apache.syncope.core.logic.UserLogic$$FastClassBySpringCGLIB$$67b1988f.invoke(<generated>)
 ~[syncope-core-logic-2.0.0-SNAPSHOT.jar:2.0.0-SNAPSHOT]
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) 
~[spring-core-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at 
org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720)
 ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at 
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
 ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at 
org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85)
 ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at 
org.apache.syncope.core.logic.LogicInvocationHandler.around(LogicInvocationHandler.java:72)
 ~[syncope-core-logic-2.0.0-SNAPSHOT.jar:2.0.0-SNAPSHOT]
    at sun.reflect.GeneratedMethodAccessor130.invoke(Unknown Source) ~[?:?]
    at 
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 ~[?:1.8.0_91]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_91]
    at 
org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:629)
 ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at 
org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:618)
 ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at 
org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
 ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at 
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
 ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
        at 
org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
 ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at 
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
 ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at 
org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)
 ~[spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at 
org.apache.syncope.core.logic.UserLogic$$EnhancerBySpringCGLIB$$134f19c3.update(<generated>)
 ~[syncope-core-logic-2.0.0-SNAPSHOT.jar:2.0.0-SNAPSHOT]
    at 
org.apache.syncope.core.rest.cxf.service.AbstractAnyService.update(AbstractAnyService.java:200)
 ~[syncope-core-rest-cxf-2.0.0-SNAPSHOT.jar:2.0.0-SNAPSHOT]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_91]
    at 
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
~[?:1.8.0_91]
    at 
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 ~[?:1.8.0_91]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_91]
    at 
org.apache.cxf.service.invoker.AbstractInvoker.performInvocation(AbstractInvoker.java:180)
 ~[cxf-core-3.1.7.jar:3.1.7]
    at 
org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:96) 
~[cxf-core-3.1.7.jar:3.1.7]
        at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:189) 
~[cxf-rt-frontend-jaxrs-3.1.7.jar:3.1.7]
    at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:99) 
~[cxf-rt-frontend-jaxrs-3.1.7.jar:3.1.7]
Caused by: org.apache.openjpa.persistence.OptimisticLockException: An 
optimistic lock violation was detected when flushing object instance 
"org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttrValue-62f5f8bf-b390-4354-b5f8-bfb390a354e8"
 to the data store.  This indicates that the object was concurrently modified 
in another transaction.
    at 
org.apache.openjpa.jdbc.kernel.PreparedStatementManagerImpl.flushAndUpdate(PreparedStatementManagerImpl.java:124)
 ~[openjpa-jdbc-2.4.1.jar:2.4.1]
    at 
org.apache.openjpa.jdbc.kernel.BatchingPreparedStatementManagerImpl.flushAndUpdate(BatchingPreparedStatementManagerImpl.java:79)
 ~[openjpa-jdbc-2.4.1.jar:2.4.1]
    at 
org.apache.openjpa.jdbc.kernel.PreparedStatementManagerImpl.flushInternal(PreparedStatementManagerImpl.java:100)
 ~[openjpa-jdbc-2.4.1.jar:2.4.1]
    at 
org.apache.openjpa.jdbc.kernel.PreparedStatementManagerImpl.flush(PreparedStatementManagerImpl.java:88)
 ~[openjpa-jdbc-2.4.1.jar:2.4.1]
    at 
org.apache.openjpa.jdbc.kernel.ConstraintUpdateManager.flush(ConstraintUpdateManager.java:550)
 ~[openjpa-jdbc-2.4.1.jar:2.4.1]
    at 
org.apache.openjpa.jdbc.kernel.ConstraintUpdateManager.flush(ConstraintUpdateManager.java:120)
 ~[openjpa-jdbc-2.4.1.jar:2.4.1]
    at 
org.apache.openjpa.jdbc.kernel.BatchingConstraintUpdateManager.flush(BatchingConstraintUpdateManager.java:59)
 ~[openjpa-jdbc-2.4.1.jar:2.4.1]
    at 
org.apache.openjpa.jdbc.kernel.AbstractUpdateManager.flush(AbstractUpdateManager.java:104)
 ~[openjpa-jdbc-2.4.1.jar:2.4.1]
    at 
org.apache.openjpa.jdbc.kernel.AbstractUpdateManager.flush(AbstractUpdateManager.java:77)
 ~[openjpa-jdbc-2.4.1.jar:2.4.1]
    at 
org.apache.openjpa.jdbc.kernel.JDBCStoreManager.flush(JDBCStoreManager.java:731)
 ~[openjpa-jdbc-2.4.1.jar:2.4.1]
    at 
org.apache.openjpa.kernel.DelegatingStoreManager.flush(DelegatingStoreManager.java:131)
 ~[openjpa-kernel-2.4.1.jar:2.4.1]
    at 
org.apache.openjpa.datacache.DataCacheStoreManager.flush(DataCacheStoreManager.java:668)
 ~[openjpa-kernel-2.4.1.jar:2.4.1]
    at 
org.apache.openjpa.kernel.DelegatingStoreManager.flush(DelegatingStoreManager.java:131)
 ~[openjpa-kernel-2.4.1.jar:2.4.1]
    ... 131 more

Reply via email to