Author: stillalex Date: Thu Apr 4 08:02:23 2019 New Revision: 1856908 URL: http://svn.apache.org/viewvc?rev=1856908&view=rev Log: OAK-8055 Add conflict handler for rep:lastSynced property on external groups
Added: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityConflictHandler.java (with props) Modified: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalPrincipalConfiguration.java jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandlerTest.java Added: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityConflictHandler.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityConflictHandler.java?rev=1856908&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityConflictHandler.java (added) +++ jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityConflictHandler.java Thu Apr 4 08:02:23 2019 @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.jackrabbit.oak.spi.security.authentication.external.impl.principal; + +import static org.apache.jackrabbit.util.ISO8601.parse; + +import java.util.Calendar; + +import org.apache.jackrabbit.oak.api.PropertyState; +import org.apache.jackrabbit.oak.api.Type; +import org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler; +import org.apache.jackrabbit.oak.spi.security.authentication.external.impl.ExternalIdentityConstants; +import org.apache.jackrabbit.oak.spi.state.NodeBuilder; +import org.apache.jackrabbit.oak.spi.state.NodeState; +import org.jetbrains.annotations.NotNull; + +/** + * Conflict handler that merges concurrent updates to external entities on the + * {@code ExternalIdentityConstants.REP_LAST_SYNCED} property by picking the + * older of the 2 conflicting dates. + */ +class ExternalIdentityConflictHandler implements ThreeWayConflictHandler { + + @NotNull + @Override + public Resolution addExistingProperty(NodeBuilder parent, PropertyState ours, PropertyState theirs) { + if (ExternalIdentityConstants.REP_LAST_SYNCED.equals(ours.getName())) { + merge(parent, ours, theirs); + return Resolution.MERGED; + } + return Resolution.IGNORED; + } + + @NotNull + @Override + public Resolution changeChangedProperty(NodeBuilder parent, PropertyState ours, PropertyState theirs, + PropertyState base) { + if (ExternalIdentityConstants.REP_LAST_SYNCED.equals(ours.getName())) { + merge(parent, ours, theirs); + return Resolution.MERGED; + } + return Resolution.IGNORED; + } + + private static void merge(NodeBuilder parent, PropertyState ours, PropertyState theirs) { + Calendar o = parse(ours.getValue(Type.DATE)); + Calendar t = parse(theirs.getValue(Type.DATE)); + Calendar v = o.before(t) ? t : o; + parent.setProperty(ours.getName(), v); + } + + @Override + @NotNull + public Resolution changeDeletedProperty(@NotNull NodeBuilder parent, @NotNull PropertyState ours, + @NotNull PropertyState base) { + return Resolution.IGNORED; + } + + @Override + @NotNull + public Resolution deleteDeletedProperty(@NotNull NodeBuilder parent, @NotNull PropertyState base) { + return Resolution.IGNORED; + } + + @Override + @NotNull + public Resolution deleteChangedProperty(@NotNull NodeBuilder parent, @NotNull PropertyState theirs, + @NotNull PropertyState base) { + return Resolution.IGNORED; + } + + @Override + @NotNull + public Resolution addExistingNode(@NotNull NodeBuilder parent, @NotNull String name, @NotNull NodeState ours, + @NotNull NodeState theirs) { + return Resolution.IGNORED; + } + + @Override + @NotNull + public Resolution changeDeletedNode(@NotNull NodeBuilder parent, @NotNull String name, @NotNull NodeState ours, + @NotNull NodeState base) { + return Resolution.IGNORED; + } + + @Override + @NotNull + public Resolution deleteChangedNode(@NotNull NodeBuilder parent, @NotNull String name, @NotNull NodeState theirs, + @NotNull NodeState base) { + return Resolution.IGNORED; + } + + @Override + @NotNull + public Resolution deleteDeletedNode(@NotNull NodeBuilder parent, @NotNull String name, @NotNull NodeState base) { + return Resolution.IGNORED; + } +} Propchange: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityConflictHandler.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalPrincipalConfiguration.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalPrincipalConfiguration.java?rev=1856908&r1=1856907&r2=1856908&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalPrincipalConfiguration.java (original) +++ jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalPrincipalConfiguration.java Thu Apr 4 08:02:23 2019 @@ -20,6 +20,7 @@ import static org.apache.jackrabbit.oak. import java.security.Principal; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -27,7 +28,6 @@ import java.util.Map; import java.util.Set; import com.google.common.base.Function; import com.google.common.base.Predicates; -import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.collect.ObjectArrays; import org.apache.felix.scr.annotations.Activate; @@ -41,6 +41,7 @@ import org.apache.jackrabbit.oak.api.Roo import org.apache.jackrabbit.oak.commons.PropertiesUtil; import org.apache.jackrabbit.oak.namepath.NamePathMapper; import org.apache.jackrabbit.oak.spi.commit.MoveTracker; +import org.apache.jackrabbit.oak.spi.commit.ThreeWayConflictHandler; import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider; import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer; import org.apache.jackrabbit.oak.spi.security.ConfigurationBase; @@ -141,13 +142,19 @@ public class ExternalPrincipalConfigurat @NotNull @Override public List<? extends ValidatorProvider> getValidators(@NotNull String workspaceName, @NotNull Set<Principal> principals, @NotNull MoveTracker moveTracker) { - return ImmutableList.of(new ExternalIdentityValidatorProvider(principals, protectedExternalIds())); + return Collections.singletonList(new ExternalIdentityValidatorProvider(principals, protectedExternalIds())); } @NotNull @Override public List<ProtectedItemImporter> getProtectedItemImporters() { - return ImmutableList.<ProtectedItemImporter>of(new ExternalIdentityImporter()); + return Collections.singletonList(new ExternalIdentityImporter()); + } + + @NotNull + @Override + public List<ThreeWayConflictHandler> getConflictHandlers() { + return Collections.singletonList(new ExternalIdentityConflictHandler()); } //----------------------------------------------------< SCR integration >--- Modified: jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandlerTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandlerTest.java?rev=1856908&r1=1856907&r2=1856908&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandlerTest.java (original) +++ jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandlerTest.java Thu Apr 4 08:02:23 2019 @@ -265,4 +265,25 @@ public class DefaultSyncHandlerTest exte assertNotNull(ref.getProviderName()); } } + + @Test + public void testLastSynced() throws Exception { + sync(USER_ID, false); + + // force sync on next update + Authorizable a = userManager.getAuthorizable(USER_ID); + a.removeProperty(DefaultSyncContext.REP_LAST_SYNCED); + root.commit(); + + // start sync + SyncContext ctx = syncHandler.createContext(idp, userManager, getValueFactory()); + SyncResult res = ctx.sync(USER_ID); + assertSame(SyncResult.Status.UPDATE, res.getStatus()); + + // concurrent login + login(new SimpleCredentials(USER_ID, new char[0])).close(); + + // the conflict handler needs to fix overlapping update + root.commit(); + } }