| /* |
| * 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 groovy.lang.GroovyClassLoader; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.Optional; |
| import org.apache.syncope.common.lib.policy.AccountRuleConf; |
| import org.apache.syncope.common.lib.policy.PasswordRuleConf; |
| import org.apache.syncope.common.lib.policy.PullCorrelationRuleConf; |
| import org.apache.syncope.common.lib.policy.PushCorrelationRuleConf; |
| import org.apache.syncope.common.lib.report.ReportletConf; |
| import org.apache.syncope.core.persistence.api.ImplementationLookup; |
| import org.apache.syncope.core.persistence.api.dao.AccountRule; |
| import org.apache.syncope.core.persistence.api.dao.PasswordRule; |
| import org.apache.syncope.core.persistence.api.dao.PullCorrelationRule; |
| import org.apache.syncope.core.persistence.api.dao.PushCorrelationRule; |
| import org.apache.syncope.core.persistence.api.dao.Reportlet; |
| import org.apache.syncope.core.persistence.api.entity.Implementation; |
| import org.apache.syncope.core.provisioning.api.serialization.POJOHelper; |
| import org.apache.syncope.core.spring.security.AuthContextUtils; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| import org.springframework.beans.factory.support.AbstractBeanDefinition; |
| import org.springframework.beans.factory.support.DefaultListableBeanFactory; |
| |
| public final class ImplementationManager { |
| |
| private static final Logger LOG = LoggerFactory.getLogger(ImplementationManager.class); |
| |
| private static final GroovyClassLoader GROOVY_CLASSLOADER = new GroovyClassLoader(); |
| |
| private static final Map<String, Class<?>> CLASS_CACHE = Collections.synchronizedMap(new HashMap<>()); |
| |
| public static Optional<Reportlet> buildReportlet(final Implementation impl) |
| throws InstantiationException, IllegalAccessException { |
| |
| switch (impl.getEngine()) { |
| case GROOVY: |
| return Optional.of(ImplementationManager.<Reportlet>buildGroovy(impl)); |
| |
| case JAVA: |
| default: |
| ReportletConf reportletConf = POJOHelper.deserialize(impl.getBody(), ReportletConf.class); |
| Class<? extends Reportlet> reportletClass = ApplicationContextProvider.getApplicationContext(). |
| getBean(ImplementationLookup.class).getReportletClass(reportletConf.getClass()); |
| |
| Reportlet reportlet = buildJavaWithConf(reportletClass); |
| if (reportlet == null) { |
| LOG.warn("Could not find matching reportlet for {}", reportletConf.getClass()); |
| } else { |
| reportlet.setConf(reportletConf); |
| } |
| |
| return Optional.ofNullable(reportlet); |
| } |
| } |
| |
| public static Optional<AccountRule> buildAccountRule(final Implementation impl) |
| throws InstantiationException, IllegalAccessException { |
| |
| switch (impl.getEngine()) { |
| case GROOVY: |
| return Optional.of(ImplementationManager.<AccountRule>buildGroovy(impl)); |
| |
| case JAVA: |
| default: |
| AccountRuleConf ruleConf = POJOHelper.deserialize(impl.getBody(), AccountRuleConf.class); |
| Class<? extends AccountRule> ruleClass = ApplicationContextProvider.getApplicationContext(). |
| getBean(ImplementationLookup.class).getAccountRuleClass(ruleConf.getClass()); |
| |
| AccountRule rule = buildJavaWithConf(ruleClass); |
| if (rule == null) { |
| LOG.warn("Could not find matching account rule for {}", impl.getClass()); |
| } else { |
| rule.setConf(ruleConf); |
| } |
| |
| return Optional.ofNullable(rule); |
| } |
| } |
| |
| public static Optional<PasswordRule> buildPasswordRule(final Implementation impl) |
| throws InstantiationException, IllegalAccessException { |
| |
| switch (impl.getEngine()) { |
| case GROOVY: |
| return Optional.of(ImplementationManager.<PasswordRule>buildGroovy(impl)); |
| |
| case JAVA: |
| default: |
| PasswordRuleConf ruleConf = POJOHelper.deserialize(impl.getBody(), PasswordRuleConf.class); |
| Class<? extends PasswordRule> ruleClass = ApplicationContextProvider.getApplicationContext(). |
| getBean(ImplementationLookup.class).getPasswordRuleClass(ruleConf.getClass()); |
| |
| PasswordRule rule = buildJavaWithConf(ruleClass); |
| if (rule == null) { |
| LOG.warn("Could not find matching password rule for {}", impl.getClass()); |
| } else { |
| rule.setConf(ruleConf); |
| } |
| |
| return Optional.ofNullable(rule); |
| } |
| } |
| |
| public static Optional<PullCorrelationRule> buildPullCorrelationRule(final Implementation impl) |
| throws InstantiationException, IllegalAccessException { |
| |
| switch (impl.getEngine()) { |
| case GROOVY: |
| return Optional.of(ImplementationManager.<PullCorrelationRule>buildGroovy(impl)); |
| |
| case JAVA: |
| default: |
| PullCorrelationRuleConf ruleConf = |
| POJOHelper.deserialize(impl.getBody(), PullCorrelationRuleConf.class); |
| Class<? extends PullCorrelationRule> ruleClass = ApplicationContextProvider.getApplicationContext(). |
| getBean(ImplementationLookup.class).getPullCorrelationRuleClass(ruleConf.getClass()); |
| |
| PullCorrelationRule rule = buildJavaWithConf(ruleClass); |
| if (rule == null) { |
| LOG.warn("Could not find matching pull correlation rule for {}", impl.getClass()); |
| } else { |
| rule.setConf(ruleConf); |
| } |
| |
| return Optional.ofNullable(rule); |
| } |
| } |
| |
| public static Optional<PushCorrelationRule> buildPushCorrelationRule(final Implementation impl) |
| throws InstantiationException, IllegalAccessException { |
| |
| switch (impl.getEngine()) { |
| case GROOVY: |
| return Optional.of(ImplementationManager.<PushCorrelationRule>buildGroovy(impl)); |
| |
| case JAVA: |
| default: |
| PushCorrelationRuleConf ruleConf = |
| POJOHelper.deserialize(impl.getBody(), PushCorrelationRuleConf.class); |
| Class<? extends PushCorrelationRule> ruleClass = ApplicationContextProvider.getApplicationContext(). |
| getBean(ImplementationLookup.class).getPushCorrelationRuleClass(ruleConf.getClass()); |
| |
| PushCorrelationRule rule = buildJavaWithConf(ruleClass); |
| if (rule == null) { |
| LOG.warn("Could not find matching push correlation rule for {}", impl.getClass()); |
| } else { |
| rule.setConf(ruleConf); |
| } |
| |
| return Optional.ofNullable(rule); |
| } |
| } |
| |
| public static <T> T build(final Implementation impl) |
| throws InstantiationException, IllegalAccessException, ClassNotFoundException { |
| |
| switch (impl.getEngine()) { |
| case GROOVY: |
| return ImplementationManager.<T>buildGroovy(impl); |
| |
| case JAVA: |
| default: |
| return ImplementationManager.<T>buildJava(impl); |
| } |
| } |
| |
| @SuppressWarnings("unchecked") |
| private static <T> T buildGroovy(final Implementation impl) |
| throws InstantiationException, IllegalAccessException { |
| |
| Class<?> clazz; |
| if (CLASS_CACHE.containsKey(impl.getKey())) { |
| clazz = CLASS_CACHE.get(impl.getKey()); |
| } else { |
| clazz = GROOVY_CLASSLOADER.parseClass(impl.getBody()); |
| CLASS_CACHE.put(impl.getKey(), clazz); |
| } |
| |
| return (T) ApplicationContextProvider.getBeanFactory(). |
| createBean(clazz, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false); |
| } |
| |
| @SuppressWarnings("unchecked") |
| private static <T> T buildJava(final Implementation impl) |
| throws ClassNotFoundException { |
| |
| Class<?> clazz; |
| if (CLASS_CACHE.containsKey(impl.getKey())) { |
| clazz = CLASS_CACHE.get(impl.getKey()); |
| } else { |
| clazz = Class.forName(impl.getBody()); |
| CLASS_CACHE.put(impl.getKey(), clazz); |
| } |
| |
| return (T) ApplicationContextProvider.getBeanFactory(). |
| createBean(clazz, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false); |
| } |
| |
| @SuppressWarnings("unchecked") |
| private static <T> T buildJavaWithConf(final Class<T> clazz) { |
| if (clazz != null) { |
| String domainableBeanNameWithConf = AuthContextUtils.getDomain() + clazz.getName(); |
| DefaultListableBeanFactory beanFactory = ApplicationContextProvider.getBeanFactory(); |
| |
| if (beanFactory.containsSingleton(domainableBeanNameWithConf)) { |
| return (T) beanFactory.getSingleton(domainableBeanNameWithConf); |
| } |
| |
| synchronized (beanFactory.getSingletonMutex()) { |
| if (beanFactory.containsSingleton(domainableBeanNameWithConf)) { |
| return (T) beanFactory.getSingleton(domainableBeanNameWithConf); |
| } else { |
| T bean = (T) beanFactory.createBean(clazz, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false); |
| beanFactory.registerSingleton(domainableBeanNameWithConf, bean); |
| return bean; |
| } |
| } |
| } |
| return null; |
| } |
| |
| public static Class<?> purge(final String implementation) { |
| return CLASS_CACHE.remove(implementation); |
| } |
| |
| private ImplementationManager() { |
| // private constructor for static utility class |
| } |
| } |