This is an automated email from the ASF dual-hosted git repository. ilgrosso pushed a commit to branch SYNCOPE-1448_alternative-fix in repository https://gitbox.apache.org/repos/asf/syncope.git
commit 44bf731faea371d0439286386b453d38b80c6832 Author: Francesco Chicchiriccò <[email protected]> AuthorDate: Mon Mar 18 08:03:40 2019 +0100 [SYNCOPE-1448] Relying on Spring's concurrency checks --- .../syncope/core/spring/ImplementationManager.java | 60 ++++++++---- .../core/spring/ImplementationManagerTest.java | 106 +++++++++++++++++++++ 2 files changed, 146 insertions(+), 20 deletions(-) diff --git a/core/spring/src/main/java/org/apache/syncope/core/spring/ImplementationManager.java b/core/spring/src/main/java/org/apache/syncope/core/spring/ImplementationManager.java index b3e050a..85a7662 100644 --- a/core/spring/src/main/java/org/apache/syncope/core/spring/ImplementationManager.java +++ b/core/spring/src/main/java/org/apache/syncope/core/spring/ImplementationManager.java @@ -70,10 +70,14 @@ public final class ImplementationManager { reportlet = (Reportlet) ApplicationContextProvider.getBeanFactory(). getSingleton(reportletClass.getName()); } else { - reportlet = (Reportlet) ApplicationContextProvider.getBeanFactory(). - createBean(reportletClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false); - ApplicationContextProvider.getBeanFactory(). - registerSingleton(reportletClass.getName(), reportlet); + try { + reportlet = (Reportlet) ApplicationContextProvider.getBeanFactory(). + createBean(reportletClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false); + ApplicationContextProvider.getBeanFactory(). + registerSingleton(reportletClass.getName(), reportlet); + } catch (IllegalStateException e) { + LOG.warn("While attempting to register {}", reportletClass.getName(), e); + } } reportlet.setConf(reportletConf); } @@ -104,10 +108,14 @@ public final class ImplementationManager { rule = (AccountRule) ApplicationContextProvider.getBeanFactory(). getSingleton(ruleClass.getName()); } else { - rule = (AccountRule) ApplicationContextProvider.getBeanFactory(). - createBean(ruleClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false); - ApplicationContextProvider.getBeanFactory(). - registerSingleton(ruleClass.getName(), rule); + try { + rule = (AccountRule) ApplicationContextProvider.getBeanFactory(). + createBean(ruleClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false); + ApplicationContextProvider.getBeanFactory(). + registerSingleton(ruleClass.getName(), rule); + } catch (IllegalStateException e) { + LOG.warn("While attempting to register {}", ruleClass.getName(), e); + } } rule.setConf(ruleConf); } @@ -138,10 +146,14 @@ public final class ImplementationManager { rule = (PasswordRule) ApplicationContextProvider.getBeanFactory(). getSingleton(ruleClass.getName()); } else { - rule = (PasswordRule) ApplicationContextProvider.getBeanFactory(). - createBean(ruleClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false); - ApplicationContextProvider.getBeanFactory(). - registerSingleton(ruleClass.getName(), rule); + try { + rule = (PasswordRule) ApplicationContextProvider.getBeanFactory(). + createBean(ruleClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false); + ApplicationContextProvider.getBeanFactory(). + registerSingleton(ruleClass.getName(), rule); + } catch (IllegalStateException e) { + LOG.warn("While attempting to register {}", ruleClass.getName(), e); + } } rule.setConf(ruleConf); } @@ -173,10 +185,14 @@ public final class ImplementationManager { rule = (PullCorrelationRule) ApplicationContextProvider.getBeanFactory(). getSingleton(ruleClass.getName()); } else { - rule = (PullCorrelationRule) ApplicationContextProvider.getBeanFactory(). - createBean(ruleClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false); - ApplicationContextProvider.getBeanFactory(). - registerSingleton(ruleClass.getName(), rule); + try { + rule = (PullCorrelationRule) ApplicationContextProvider.getBeanFactory(). + createBean(ruleClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false); + ApplicationContextProvider.getBeanFactory(). + registerSingleton(ruleClass.getName(), rule); + } catch (IllegalStateException e) { + LOG.warn("While attempting to register {}", ruleClass.getName(), e); + } } rule.setConf(ruleConf); } @@ -208,10 +224,14 @@ public final class ImplementationManager { rule = (PushCorrelationRule) ApplicationContextProvider.getBeanFactory(). getSingleton(ruleClass.getName()); } else { - rule = (PushCorrelationRule) ApplicationContextProvider.getBeanFactory(). - createBean(ruleClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false); - ApplicationContextProvider.getBeanFactory(). - registerSingleton(ruleClass.getName(), rule); + try { + rule = (PushCorrelationRule) ApplicationContextProvider.getBeanFactory(). + createBean(ruleClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false); + ApplicationContextProvider.getBeanFactory(). + registerSingleton(ruleClass.getName(), rule); + } catch (IllegalStateException e) { + LOG.warn("While attempting to register {}", ruleClass.getName(), e); + } } rule.setConf(ruleConf); } diff --git a/core/spring/src/test/java/org/apache/syncope/core/spring/ImplementationManagerTest.java b/core/spring/src/test/java/org/apache/syncope/core/spring/ImplementationManagerTest.java new file mode 100644 index 0000000..359d484 --- /dev/null +++ b/core/spring/src/test/java/org/apache/syncope/core/spring/ImplementationManagerTest.java @@ -0,0 +1,106 @@ +/* + * 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.syncope.core.spring; + +import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.apache.syncope.common.lib.policy.DefaultPasswordRuleConf; +import org.apache.syncope.core.persistence.api.dao.PasswordRule; +import org.apache.syncope.core.provisioning.api.serialization.POJOHelper; +import org.apache.syncope.core.spring.security.TestImplementation; +import org.junit.jupiter.api.Test; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; +import java.time.Duration; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.Collectors; + +@SpringJUnitConfig(locations = { "classpath:springTest.xml" }) +class ImplementationManagerTest { + + private DefaultPasswordRuleConf createBaseDefaultPasswordRuleConf() { + DefaultPasswordRuleConf baseDefaultPasswordRuleConf = new DefaultPasswordRuleConf(); + baseDefaultPasswordRuleConf.setAlphanumericRequired(false); + baseDefaultPasswordRuleConf.setDigitRequired(false); + baseDefaultPasswordRuleConf.setLowercaseRequired(false); + baseDefaultPasswordRuleConf.setMaxLength(1000); + baseDefaultPasswordRuleConf.setMinLength(8); + baseDefaultPasswordRuleConf.setMustEndWithAlpha(false); + baseDefaultPasswordRuleConf.setMustEndWithDigit(false); + baseDefaultPasswordRuleConf.setMustEndWithNonAlpha(false); + baseDefaultPasswordRuleConf.setMustStartWithAlpha(false); + baseDefaultPasswordRuleConf.setMustStartWithDigit(false); + baseDefaultPasswordRuleConf.setMustStartWithNonAlpha(false); + baseDefaultPasswordRuleConf.setMustntEndWithAlpha(false); + baseDefaultPasswordRuleConf.setMustntEndWithDigit(false); + baseDefaultPasswordRuleConf.setMustntEndWithNonAlpha(false); + baseDefaultPasswordRuleConf.setMustntStartWithAlpha(false); + baseDefaultPasswordRuleConf.setMustntStartWithDigit(false); + baseDefaultPasswordRuleConf.setMustntStartWithNonAlpha(false); + baseDefaultPasswordRuleConf.setNonAlphanumericRequired(false); + baseDefaultPasswordRuleConf.setUppercaseRequired(false); + return baseDefaultPasswordRuleConf; + } + + @Test + public void concurrentPasswordRuleBuilding() { + assertTimeoutPreemptively(Duration.ofSeconds(30), () -> { + TestImplementation implementation = new TestImplementation(); + implementation.setBody(POJOHelper.serialize(createBaseDefaultPasswordRuleConf())); + ReentrantLock lock = new ReentrantLock(); + lock.lock(); + AtomicInteger runningThreads = new AtomicInteger(0); + AtomicInteger errorCount = new AtomicInteger(0); + List<String> errorMessages = Collections.synchronizedList(new LinkedList<>()); + for (int i = 0; i < 10; i++) { + runningThreads.incrementAndGet(); + new Thread(() -> { + try { + while (lock.isLocked()) { + Thread.yield(); + } + Optional<PasswordRule> passwordRule; + try { + passwordRule = ImplementationManager.buildPasswordRule(implementation); + passwordRule.orElseThrow(); + } catch (Exception e) { + errorMessages.add(e.getLocalizedMessage()); + errorCount.incrementAndGet(); + } + } finally { + runningThreads.decrementAndGet(); + } + }).start(); + } + lock.unlock(); + while (runningThreads.get() > 0) { + Thread.yield(); + } + + assertTrue( + errorMessages.isEmpty(), + errorMessages.stream().collect(Collectors.joining(System.lineSeparator()))); + }); + } +}
