//
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is part of dcm4che, an implementation of DICOM(TM) in
* Java(TM), hosted at https://github.com/gunterze/dcm4che.
*
* The Initial Developer of the Original Code is
* Agfa Healthcare.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* See @authors listed below
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.dcm4chee.hooks;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.inject.Inject;
import org.dcm4chee.hooks.HooksConfig.HookTypeConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ApplicationScoped
public class HooksManager {
private static final Logger LOG = LoggerFactory.getLogger(HooksManager.class);
@Inject
@ProducedHooksConfig
private HooksConfig hooksConfig;
private final ConcurrentMap<Type, Collection<Bean<?>>> activeHookBeansMap = new ConcurrentHashMap<>();
/**
*
* @param injectionPoint
* @param beanManager
* @return Returns an ordered list of active hook (bean) instances that are suitable (in CDI terms) for the
* given injection point.
*/
public Collection<Object> getOrderedActiveHooks(InjectionPoint injectionPoint, BeanManager beanManager) {
return resolveHooks(injectionPoint, beanManager);
}
private Collection<Object> resolveHooks(InjectionPoint injectionPoint, BeanManager beanManager) {
ParameterizedType type = (ParameterizedType) injectionPoint.getType();
Type hookType = type.getActualTypeArguments()[0];
Collection<Bean<?>> orderedHookBeans = activeHookBeansMap.get(hookType);
if(orderedHookBeans == null) {
orderedHookBeans = getOrderedHookBeansFromConfig(hookType, beanManager);
activeHookBeansMap.putIfAbsent(hookType, orderedHookBeans);
}
List<Object> beanInstances = new ArrayList<>();
for(Bean<?> hookBean : orderedHookBeans) {
Object hook = getBeanInstance(hookBean, hookType, beanManager);
beanInstances.add(hook);
}
return beanInstances;
}
private Collection<Bean<?>> getOrderedHookBeansFromConfig(Type hookType, BeanManager beanManager) {
TreeMap<Double,Bean<?>> resolvedHooks = new TreeMap<>();
Class<?> hookTypeClass = (Class<?>)hookType;
for (Bean<?> hookBean : beanManager.getBeans(hookType)) {
Class<?> hookBeanClass = hookBean.getBeanClass();
Double priority = getHookPriority(hookTypeClass, hookBeanClass);
if(priority != null) {
resolvedHooks.put(priority, hookBean);
LOG.debug("Configuring the hook implementation {} for hook type {} with priority {}.", hookBeanClass.getName(), hookTypeClass.getName(), priority);
} else {
LOG.debug("Not configuring the hook implementation {} for hook type {} because it is not in the configuration.", hookBeanClass.getName(), hookTypeClass.getName());
}
}
return resolvedHooks.values();
}
private Double getHookPriority(Class<?> hookTypeClass, Class<?> hookBeanClass) {
String hookTypeClassName = hookTypeClass.getName();
HookTypeConfig hookTypeConfig = hooksConfig.getHooks().get(hookTypeClassName);
if (hookTypeConfig == null) {
LOG.warn("Hook type {} not defined in the hooks configuration.", hookTypeClassName);
return null;
}
String hookBeanClassName = hookBeanClass.getName();
Map<String, Double> hookBean2PriorityMap = hookTypeConfig.getPrioritiesMap();
// to handle proxies like org.abc.MyDecorator$_$$WeldProxy
for (Entry<String,Double> entry : hookBean2PriorityMap.entrySet()) {
if (hookBeanClassName.startsWith(entry.getKey())) {
return entry.getValue();
}
}
return null;
}
private static Object getBeanInstance(Bean<?> bean, Type beanType, BeanManager beanManager) {
CreationalContext<?> dependentScopeCreationalContext = beanManager.createCreationalContext(null);
Object beanInstance = beanManager.getReference(bean, beanType, dependentScopeCreationalContext);
return beanInstance;
}
}