org.apache.aries.transaction.TxComponentMetaDataHelperImpl Maven / Gradle / Ivy
/*
* 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.aries.transaction;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.aries.blueprint.ComponentDefinitionRegistry;
import org.osgi.service.blueprint.reflect.ComponentMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TxComponentMetaDataHelperImpl implements TxComponentMetaDataHelper {
private static final Logger LOGGER =
LoggerFactory.getLogger(TxComponentMetaDataHelperImpl.class);
private static class TranData
{
private final Map map;
private final Map cache;
public TranData() {
map = new ConcurrentHashMap();
cache = new ConcurrentHashMap();
}
public void add(Pattern pattern, String txAttribute) {
map.put(pattern, txAttribute);
}
public String getAttribute(String name)
{
String txAttribute = cache.get(name);
if (txAttribute == null) {
List matches = findMatches(name);
int size = matches.size();
if (size == 0) {
// we should default to no transaction since we cannot find a match
txAttribute = null;
}
else if (size == 1) {
txAttribute = map.get(matches.get(0));
}
else {
matches = selectPatternsWithFewestWildcards(matches);
size = matches.size();
if (size == 1) {
txAttribute = map.get(matches.get(0));
}
else {
matches = selectLongestPatterns(matches);
size = matches.size();
if (size == 1) {
txAttribute = map.get(matches.get(0));
}
else {
throw new IllegalStateException(Constants.MESSAGES.getMessage("unable.to.apply.patterns", matches));
}
}
}
if (txAttribute != null) {
cache.put(name, txAttribute);
}
}
return txAttribute;
}
private List findMatches(String name)
{
List matches = new ArrayList();
for (Pattern p : map.keySet()) {
if (p.matcher(name).matches()) {
matches.add(p);
}
}
return matches;
}
private List selectPatternsWithFewestWildcards(List matches) {
List remainingMatches = new ArrayList();
int minWildcards = Integer.MAX_VALUE;
for (Pattern p : matches) {
String pattern = p.pattern();
Matcher m = Constants.WILDCARD.matcher(pattern);
int count = 0;
while (m.find()) {
count++;
}
if (count < minWildcards) {
remainingMatches.clear();
remainingMatches.add(p);
minWildcards = count;
}
else if (count == minWildcards) {
remainingMatches.add(p);
}
}
return remainingMatches;
}
private List selectLongestPatterns(List matches) {
List remainingMatches = new ArrayList();
int longestLength = 0;
for (Pattern p : matches) {
String pattern = p.pattern();
int length = pattern.length();
if (length > longestLength) {
remainingMatches.clear();
remainingMatches.add(p);
longestLength = length;
}
else if (length == longestLength) {
remainingMatches.add(p);
}
}
return remainingMatches;
}
}
private static final Map data = new ConcurrentHashMap();
// bundle transaction map keeps track of the default transaction behavior for the bundle at the bundle-wide level.
// this is configured via top level tx:transaction element for the blueprint managed bundle
private static final ConcurrentHashMap> bundleTransactionMap = new ConcurrentHashMap>();
// this gives us a reverse lookup when we need to clean up
private static final ConcurrentMap> dataForCDR =
new ConcurrentHashMap>();
public void unregister(ComponentDefinitionRegistry registry) {
Collection components = dataForCDR.remove(registry);
bundleTransactionMap.remove(registry);
if (components != null) {
for (ComponentMetadata meta : components) data.remove(meta);
}
}
public synchronized void setComponentTransactionData(ComponentDefinitionRegistry registry, ComponentMetadata component, String value, String method)
{
TranData td = data.get(component);
if (td == null) {
td = new TranData();
data.put(component, td);
dataForCDR.putIfAbsent(registry, new HashSet());
dataForCDR.get(registry).add(component);
}
if (method == null || method.length() == 0) {
method = "*";
}
if(value == null || value.length() == 0) {
value = "Required";
}
String[] names = method.split("[, \t]");
for (int i = 0; i < names.length; i++) {
Pattern pattern = Pattern.compile(names[i].replaceAll("\\*", ".*"));
td.add(pattern, value);
}
}
public String getComponentMethodTxAttribute(ComponentMetadata component, String methodName)
{
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Getting the txAttribute for the component {0} and method {1}", component.getId(), methodName);
}
TranData td = data.get(component);
String result = null;
if (td != null) {
// bean level transaction always overwrite bundle wide transaction
result = td.getAttribute(methodName);
}
if (result != null) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Return the txAttribute {0} for the component and method", result);
}
return result;
} else {
/* check the bundle wide transaction configuration in the following priority order from (high to low)
* 1. top level tx w/ method + bean
* 2. top level tx w/ bean
* 3. top level tx w/ method
* 4. top level tx w/ no other attribute
*/
//result = calculateBundleWideTransaction(component, methodName);
ComponentDefinitionRegistry cdr = getComponentDefinitionRegistry(component);
if (cdr == null) {
// no bundle wide transaction configuration avail
result = null;
} else {
List bundleData = bundleTransactionMap.get(cdr);
result = BundleWideTxDataUtil.getAttribute(component.getId(), methodName, bundleData);
}
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Return the txAttribute {0} for the component and method", result);
}
return result;
}
public void populateBundleWideTransactionData(ComponentDefinitionRegistry cdr, String value,
String method, String bean) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Start populating bundle wide transaction data value {0} method {1} bean {2} per component definition registry", new Object[]{value, method, bean});
}
BundleWideTxData bundleWideTxData = new BundleWideTxData(value, method, bean);
List bundleData = bundleTransactionMap.get(cdr);
if (bundleData == null) {
bundleData = new ArrayList();
bundleData.add(bundleWideTxData);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Adding component definition registry and bundleData to the bundleTransactionMap", new Object[]{cdr, bundleData});
}
bundleTransactionMap.put(cdr, bundleData);
} else {
bundleData.add(bundleWideTxData);
}
}
private ComponentDefinitionRegistry getComponentDefinitionRegistry(ComponentMetadata metadata) {
Enumeration keys = bundleTransactionMap.keys();
while (keys.hasMoreElements()) {
ComponentDefinitionRegistry cdr = keys.nextElement();
if (cdr.containsComponentDefinition(metadata.getId())
&& metadata.equals(cdr.getComponentDefinition(metadata.getId()))) {
return cdr;
}
}
return null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy