You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2019/03/25 13:44:04 UTC
[syncope] branch master updated: [SYNCOPE-1448] Relying on Spring's
concurrency checks
This is an automated email from the ASF dual-hosted git repository.
ilgrosso pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git
The following commit(s) were added to refs/heads/master by this push:
new 50469a1 [SYNCOPE-1448] Relying on Spring's concurrency checks
50469a1 is described below
commit 50469a15b51b99e6b1e52a05626f96e0b9ce6cdd
Author: Francesco Chicchiriccò <il...@apache.org>
AuthorDate: Mon Mar 18 08:03:40 2019 +0100
[SYNCOPE-1448] Relying on Spring's concurrency checks
---
.../syncope/core/spring/ImplementationManager.java | 105 ++++++++-------------
.../core/spring/ImplementationManagerTest.java | 104 ++++++++++++++++++++
2 files changed, 144 insertions(+), 65 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..f1481b3 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
@@ -57,24 +57,14 @@ public final class ImplementationManager {
case JAVA:
default:
- Reportlet reportlet = null;
-
ReportletConf reportletConf = POJOHelper.deserialize(impl.getBody(), ReportletConf.class);
Class<? extends Reportlet> reportletClass = ApplicationContextProvider.getApplicationContext().
getBean(ImplementationLookup.class).getReportletClass(reportletConf.getClass());
- if (reportletClass == null) {
+
+ Reportlet reportlet = buildJavaWithConf(reportletClass);
+ if (reportlet == null) {
LOG.warn("Could not find matching reportlet for {}", reportletConf.getClass());
} else {
- // fetch (or create) reportlet
- if (ApplicationContextProvider.getBeanFactory().containsSingleton(reportletClass.getName())) {
- 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);
- }
reportlet.setConf(reportletConf);
}
@@ -91,24 +81,14 @@ public final class ImplementationManager {
case JAVA:
default:
- AccountRule rule = null;
-
AccountRuleConf ruleConf = POJOHelper.deserialize(impl.getBody(), AccountRuleConf.class);
Class<? extends AccountRule> ruleClass = ApplicationContextProvider.getApplicationContext().
getBean(ImplementationLookup.class).getAccountRuleClass(ruleConf.getClass());
- if (ruleClass == null) {
+
+ AccountRule rule = buildJavaWithConf(ruleClass);
+ if (rule == null) {
LOG.warn("Could not find matching account rule for {}", impl.getClass());
} else {
- // fetch (or create) rule
- if (ApplicationContextProvider.getBeanFactory().containsSingleton(ruleClass.getName())) {
- 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);
- }
rule.setConf(ruleConf);
}
@@ -125,24 +105,14 @@ public final class ImplementationManager {
case JAVA:
default:
- PasswordRule rule = null;
-
PasswordRuleConf ruleConf = POJOHelper.deserialize(impl.getBody(), PasswordRuleConf.class);
Class<? extends PasswordRule> ruleClass = ApplicationContextProvider.getApplicationContext().
getBean(ImplementationLookup.class).getPasswordRuleClass(ruleConf.getClass());
- if (ruleClass == null) {
+
+ PasswordRule rule = buildJavaWithConf(ruleClass);
+ if (rule == null) {
LOG.warn("Could not find matching password rule for {}", impl.getClass());
} else {
- // fetch (or create) rule
- if (ApplicationContextProvider.getBeanFactory().containsSingleton(ruleClass.getName())) {
- 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);
- }
rule.setConf(ruleConf);
}
@@ -159,25 +129,15 @@ public final class ImplementationManager {
case JAVA:
default:
- PullCorrelationRule rule = null;
-
PullCorrelationRuleConf ruleConf =
POJOHelper.deserialize(impl.getBody(), PullCorrelationRuleConf.class);
Class<? extends PullCorrelationRule> ruleClass = ApplicationContextProvider.getApplicationContext().
getBean(ImplementationLookup.class).getPullCorrelationRuleClass(ruleConf.getClass());
- if (ruleClass == null) {
+
+ PullCorrelationRule rule = buildJavaWithConf(ruleClass);
+ if (rule == null) {
LOG.warn("Could not find matching pull correlation rule for {}", impl.getClass());
} else {
- // fetch (or create) rule
- if (ApplicationContextProvider.getBeanFactory().containsSingleton(ruleClass.getName())) {
- 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);
- }
rule.setConf(ruleConf);
}
@@ -194,25 +154,15 @@ public final class ImplementationManager {
case JAVA:
default:
- PushCorrelationRule rule = null;
-
PushCorrelationRuleConf ruleConf =
POJOHelper.deserialize(impl.getBody(), PushCorrelationRuleConf.class);
Class<? extends PushCorrelationRule> ruleClass = ApplicationContextProvider.getApplicationContext().
getBean(ImplementationLookup.class).getPushCorrelationRuleClass(ruleConf.getClass());
- if (ruleClass == null) {
+
+ PushCorrelationRule rule = buildJavaWithConf(ruleClass);
+ if (rule == null) {
LOG.warn("Could not find matching push correlation rule for {}", impl.getClass());
} else {
- // fetch (or create) rule
- if (ApplicationContextProvider.getBeanFactory().containsSingleton(ruleClass.getName())) {
- 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);
- }
rule.setConf(ruleConf);
}
@@ -265,6 +215,31 @@ public final class ImplementationManager {
createBean(clazz, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
}
+ @SuppressWarnings("unchecked")
+ private static <T> T buildJavaWithConf(final Class<T> clazz) {
+ T bean = null;
+
+ if (clazz != null) {
+ if (ApplicationContextProvider.getBeanFactory().containsSingleton(clazz.getName())) {
+ bean = (T) ApplicationContextProvider.getBeanFactory().getSingleton(clazz.getName());
+ } else {
+ try {
+ bean = (T) ApplicationContextProvider.getBeanFactory().
+ createBean(clazz, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
+ ApplicationContextProvider.getBeanFactory().registerSingleton(clazz.getName(), bean);
+ } catch (IllegalStateException e) {
+ LOG.debug("While attempting to register {}", clazz.getName(), e);
+
+ // if this exception was raised, it means another bean for same name is already registered,
+ // revert to it
+ bean = (T) ApplicationContextProvider.getBeanFactory().getSingleton(clazz.getName());
+ }
+ }
+ }
+
+ return bean;
+ }
+
public static Class<?> purge(final String implementation) {
return CLASS_CACHE.remove(implementation);
}
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..9c62381
--- /dev/null
+++ b/core/spring/src/test/java/org/apache/syncope/core/spring/ImplementationManagerTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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.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.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.stream.Collectors;
+
+@SpringJUnitConfig(locations = { "classpath:springTest.xml" })
+public 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() {
+ String body = POJOHelper.serialize(createBaseDefaultPasswordRuleConf());
+
+ assertTimeoutPreemptively(Duration.ofSeconds(30), () -> {
+ TestImplementation implementation = new TestImplementation();
+ implementation.setBody(body);
+ 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();
+ }
+ try {
+ ImplementationManager.buildPasswordRule(implementation).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())));
+ });
+ }
+}