
org.jboss.weld.bootstrap.enablement.GlobalEnablementBuilder Maven / Gradle / Ivy
/*
* JBoss, Home of Professional Open Source
* Copyright 2013, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed 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.jboss.weld.bootstrap.enablement;
import static org.jboss.weld.util.reflection.Reflections.cast;
import java.lang.annotation.Annotation;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import jakarta.enterprise.inject.spi.Extension;
import org.jboss.weld.bootstrap.BeanDeployment;
import org.jboss.weld.bootstrap.api.helpers.AbstractBootstrapService;
import org.jboss.weld.bootstrap.spi.BeansXml;
import org.jboss.weld.bootstrap.spi.Metadata;
import org.jboss.weld.exceptions.DeploymentException;
import org.jboss.weld.logging.BootstrapLogger;
import org.jboss.weld.logging.LogMessageCallback;
import org.jboss.weld.logging.MessageCallback;
import org.jboss.weld.logging.ValidatorLogger;
import org.jboss.weld.resources.spi.ResourceLoader;
import org.jboss.weld.resources.spi.ResourceLoadingException;
import org.jboss.weld.util.collections.ImmutableList;
import org.jboss.weld.util.collections.ImmutableMap;
import org.jboss.weld.util.collections.ImmutableSet;
/**
* This service gathers globally enabled interceptors, decorators and alternatives and builds a list of each.
*
* @author Jozef Hartinger
*
*/
public class GlobalEnablementBuilder extends AbstractBootstrapService {
private final List- alternatives = Collections.synchronizedList(new ArrayList
- ());
private final List
- interceptors = Collections.synchronizedList(new ArrayList
- ());
private final List
- decorators = Collections.synchronizedList(new ArrayList
- ());
private volatile Map
, Integer> cachedAlternativeMap;
private volatile boolean sorted;
private volatile boolean dirty;
private void addItem(List- list, Class> javaClass, int priority) {
sorted = false;
dirty = true;
synchronized (list) {
int originalPriority = priority;
if (!list.isEmpty()) {
int scaling = list.get(0).getNumberOfScaling();
if (scaling > 0) {
// We have to scale the priority if necessary
priority *= new BigInteger("" + Item.ITEM_PRIORITY_SCALE_POWER).pow(scaling).intValue();
}
}
list.add(new Item(javaClass, originalPriority, priority));
}
}
public void addAlternative(Class> javaClass, int priority) {
addItem(alternatives, javaClass, priority);
}
public void addInterceptor(Class> javaClass, int priority) {
addItem(interceptors, javaClass, priority);
}
public void addDecorator(Class> javaClass, int priority) {
addItem(decorators, javaClass, priority);
}
public List
> getAlternativeList(final Extension extension) {
initialize();
return new EnablementListView() {
@Override
protected Extension getExtension() {
return extension;
}
@Override
protected ViewType getViewType() {
return ViewType.ALTERNATIVES;
}
@Override
protected List- getDelegate() {
return alternatives;
}
};
}
public List
> getInterceptorList(final Extension extension) {
initialize();
return new EnablementListView() {
@Override
protected Extension getExtension() {
return extension;
}
@Override
protected ViewType getViewType() {
return ViewType.INTERCEPTORS;
}
@Override
protected List- getDelegate() {
return interceptors;
}
};
}
public List
> getDecoratorList(final Extension extension) {
initialize();
return new EnablementListView() {
@Override
protected Extension getExtension() {
return extension;
}
@Override
protected ViewType getViewType() {
return ViewType.DECORATORS;
}
@Override
protected List- getDelegate() {
return decorators;
}
};
}
/**
*
* @return
true
if a new item was added and the up-to-date enablements were not built yet, false
* otherwise
*/
public boolean isDirty() {
return dirty;
}
/*
* cachedAlternativeMap is accessed from a single thread only and the result is safely propagated. Therefore, there is no
* need to synchronize access to
* cachedAlternativeMap.
*/
private Map, Integer> getGlobalAlternativeMap() {
if (cachedAlternativeMap == null || dirty) {
Map, Integer> map = new HashMap, Integer>();
for (Item item : alternatives) {
map.put(item.getJavaClass(), item.getPriority());
}
cachedAlternativeMap = ImmutableMap.copyOf(map);
}
return cachedAlternativeMap;
}
private void initialize() {
if (!sorted) {
Collections.sort(alternatives);
Collections.sort(interceptors);
Collections.sort(decorators);
sorted = true;
}
}
public ModuleEnablement createModuleEnablement(BeanDeployment deployment) {
ClassLoader loader = new ClassLoader(deployment.getBeanManager().getServices().get(ResourceLoader.class));
BeansXml beansXml = deployment.getBeanDeploymentArchive().getBeansXml();
Set> alternativeClasses = null;
Set> alternativeStereotypes = null;
List> globallyEnabledInterceptors = getInterceptorList(null);
List> globallyEnabledDecorators = getDecoratorList(null);
ImmutableList.Builder> moduleInterceptorsBuilder = ImmutableList.> builder();
moduleInterceptorsBuilder.addAll(globallyEnabledInterceptors);
ImmutableList.Builder> moduleDecoratorsBuilder = ImmutableList.> builder();
moduleDecoratorsBuilder.addAll(globallyEnabledDecorators);
if (beansXml != null) {
checkForDuplicates(beansXml.getEnabledInterceptors(), ValidatorLogger.INTERCEPTOR_SPECIFIED_TWICE);
checkForDuplicates(beansXml.getEnabledDecorators(), ValidatorLogger.DECORATOR_SPECIFIED_TWICE);
checkForDuplicates(beansXml.getEnabledAlternativeClasses(),
ValidatorLogger.ALTERNATIVE_CLASS_SPECIFIED_MULTIPLE_TIMES);
checkForDuplicates(beansXml.getEnabledAlternativeStereotypes(),
ValidatorLogger.ALTERNATIVE_STEREOTYPE_SPECIFIED_MULTIPLE_TIMES);
List> interceptorClasses = beansXml.getEnabledInterceptors().stream().map(loader)
.collect(Collectors.toList());
moduleInterceptorsBuilder.addAll(filter(interceptorClasses, globallyEnabledInterceptors,
ValidatorLogger.INTERCEPTOR_ENABLED_FOR_APP_AND_ARCHIVE,
deployment));
List> decoratorClasses = beansXml.getEnabledDecorators().stream().map(loader).collect(Collectors.toList());
moduleDecoratorsBuilder.addAll(
filter(decoratorClasses, globallyEnabledDecorators, ValidatorLogger.DECORATOR_ENABLED_FOR_APP_AND_ARCHIVE,
deployment));
alternativeClasses = beansXml.getEnabledAlternativeClasses().stream().map(loader).collect(ImmutableSet.collector());
alternativeStereotypes = cast(
beansXml.getEnabledAlternativeStereotypes().stream().map(loader).collect(ImmutableSet.collector()));
} else {
alternativeClasses = Collections.emptySet();
alternativeStereotypes = Collections.emptySet();
}
Map, Integer> globalAlternatives = getGlobalAlternativeMap();
// We suppose that enablements are always created all at once
dirty = false;
return new ModuleEnablement(moduleInterceptorsBuilder.build(), moduleDecoratorsBuilder.build(), globalAlternatives,
alternativeClasses,
alternativeStereotypes);
}
@Override
public void cleanupAfterBoot() {
alternatives.clear();
interceptors.clear();
decorators.clear();
}
@Override
public String toString() {
return "GlobalEnablementBuilder [alternatives=" + alternatives + ", interceptors=" + interceptors + ", decorators="
+ decorators + "]";
}
private void checkForDuplicates(List> list, MessageCallback messageCallback) {
Map> map = new HashMap>();
for (Metadata item : list) {
Metadata previousOccurrence = map.put(item.getValue(), item);
if (previousOccurrence != null) {
throw messageCallback.construct(item.getValue(), item, previousOccurrence);
}
}
}
/**
* Filter out interceptors and decorators which are also enabled globally.
*
* @param enabledClasses
* @param globallyEnabledClasses
* @param logMessageCallback
* @param deployment
* @return the filtered list
*/
private List> filter(List> enabledClasses, List> globallyEnabledClasses,
LogMessageCallback logMessageCallback,
BeanDeployment deployment) {
for (Iterator> iterator = enabledClasses.iterator(); iterator.hasNext();) {
Class> enabledClass = iterator.next();
if (globallyEnabledClasses.contains(enabledClass)) {
logMessageCallback.log(enabledClass, deployment.getBeanDeploymentArchive().getId());
iterator.remove();
}
}
return enabledClasses;
}
private static class ClassLoader implements Function, Class>> {
private final ResourceLoader resourceLoader;
public ClassLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
@Override
public Class> apply(Metadata from) {
try {
return resourceLoader.classForName(from.getValue());
} catch (ResourceLoadingException e) {
throw BootstrapLogger.LOG.errorLoadingBeansXmlEntry(from.getValue(), from.getLocation(), e.getCause());
} catch (Exception e) {
throw BootstrapLogger.LOG.errorLoadingBeansXmlEntry(from.getValue(), from.getLocation(), e);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy