#region License
/*
* Copyright 2002-2007 the original author or authors.
*
* 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.
*/
#endregion
using System;
using System.Collections;
using System.Data;
using System.Xml;
using Spring.Collections;
using Spring.Objects.Factory.Config;
using Spring.Objects.Factory.Support;
using Spring.Objects.Factory.Xml;
using Spring.Transaction.Interceptor;
using Spring.Util;
namespace Spring.Transaction.Config{
/// <summary>
/// The <see cref="IObjectDefinitionParser"/> for the <code><tx:advice></code> tag.
/// </summary>
/// <author>Rob Harrop</author>
/// <author>Juergen Hoeller</author>
/// <author>Adrian Colyer</author>
/// <author>Mark Pollack (.NET)</author>
public class TxAdviceObjectDefinitionParser : AbstractSingleObjectDefinitionParser
{
private static string TIMEOUT = "timeout";
private static string READ_ONLY = "read-only";
private static string NAME_MAP = "nameMap";
private static string PROPAGATION = "propagation";
private static string ISOLATION = "isolation";
private static string ROLLBACK_FOR = "rollback-for";
private static string NO_ROLLBACK_FOR = "no-rollback-for";
protected override Type GetObjectType(XmlElement element)
{
return typeof (TransactionInterceptor);
}
protected override void DoParse(XmlElement element, ParserContext parserContext, ObjectDefinitionBuilder builder)
{
builder.AddPropertyReference(TxNamespaceUtils.TRANSACTION_MANAGER_PROPERTY,
GetAttributeValue(element, TxNamespaceUtils.TRANSACTION_MANAGER_ATTRIBUTE));
XmlNodeList txAttributes = element.SelectNodes("*[local-name()='attributes' and namespace-uri()='" + element.NamespaceURI + "']");
if (txAttributes.Count > 1 )
{
parserContext.ReaderContext.ReportException(element, "tx advice", "Element <attributes> is allowed at most once inside element <advice>");
}
else if (txAttributes.Count == 1)
{
//using xml defined source
XmlElement attributeSourceElement = txAttributes[0] as XmlElement;
AbstractObjectDefinition attributeSourceDefinition =
ParseAttributeSource(attributeSourceElement, parserContext);
builder.AddPropertyValue(TxNamespaceUtils.TRANSACTION_ATTRIBUTE_SOURCE, attributeSourceDefinition);
}
else
{
//Assume attibutes source
ObjectDefinitionBuilder txAttributeSourceBuilder =
parserContext.ParserHelper.CreateRootObjectDefinitionBuilder(typeof (AttributesTransactionAttributeSource));
builder.AddPropertyValue(TxNamespaceUtils.TRANSACTION_ATTRIBUTE_SOURCE,
txAttributeSourceBuilder.ObjectDefinition);
}
}
private AbstractObjectDefinition ParseAttributeSource(XmlElement element, ParserContext parserContext)
{
XmlNodeList methods = element.SelectNodes("*[local-name()='method' and namespace-uri()='" + element.NamespaceURI + "']");
ManagedDictionary transactionAttributeMap = new ManagedDictionary();
foreach (XmlElement methodElement in methods)
{
string name = GetAttributeValue(methodElement, "name");
TypedStringValue nameHolder = new TypedStringValue(name);
RuleBasedTransactionAttribute attribute = new RuleBasedTransactionAttribute();
string propagation = GetAttributeValue(methodElement, PROPAGATION);
string isolation = GetAttributeValue(methodElement, ISOLATION);
string timeout = GetAttributeValue(methodElement, TIMEOUT);
string readOnly = GetAttributeValue(methodElement, READ_ONLY);
if (StringUtils.HasText(propagation))
{
attribute.PropagationBehavior = (TransactionPropagation) Enum.Parse(typeof (TransactionPropagation), propagation, true);
}
if (StringUtils.HasText(isolation))
{
attribute.TransactionIsolationLevel =
(IsolationLevel) Enum.Parse(typeof (IsolationLevel), isolation, true);
}
if (StringUtils.HasText(timeout))
{
try
{
attribute.TransactionTimeout = Int32.Parse(timeout);
}
catch (FormatException ex)
{
parserContext.ReaderContext.ReportException(methodElement,"tx advice","timeout must be an integer value: [" + timeout + "]", ex);
}
}
if (StringUtils.HasText(readOnly))
{
attribute.ReadOnly = Boolean.Parse(GetAttributeValue(methodElement, READ_ONLY));
}
IList rollbackRules = new LinkedList();
if (methodElement.HasAttribute(ROLLBACK_FOR))
{
string rollbackForValue = GetAttributeValue(methodElement, ROLLBACK_FOR);
AddRollbackRuleAttributesTo(rollbackRules, rollbackForValue);
}
if (methodElement.HasAttribute(NO_ROLLBACK_FOR))
{
string noRollbackForValue = GetAttributeValue(methodElement, NO_ROLLBACK_FOR);
AddNoRollbackRuleAttributesTo(rollbackRules, noRollbackForValue);
}
attribute.RollbackRules = rollbackRules;
transactionAttributeMap[nameHolder] = attribute;
}
ObjectDefinitionBuilder builder = parserContext
.ParserHelper
.CreateRootObjectDefinitionBuilder(typeof (NameMatchTransactionAttributeSource));
builder.AddPropertyValue(NAME_MAP, transactionAttributeMap);
return builder.ObjectDefinition;
}
private void AddRollbackRuleAttributesTo(IList rollbackRules, string rollbackForValue)
{
string[] exceptionTypeNames = StringUtils.CommaDelimitedListToStringArray(rollbackForValue);
foreach (string exceptionTypeName in exceptionTypeNames)
{
rollbackRules.Add(new RollbackRuleAttribute(exceptionTypeName.Trim()));
}
}
private void AddNoRollbackRuleAttributesTo(IList rollbackRules, string noRollbackForValue)
{
string[] exceptionTypeNames = StringUtils.CommaDelimitedListToStringArray(noRollbackForValue);
foreach (string exceptionTypeName in exceptionTypeNames)
{
rollbackRules.Add(new NoRollbackRuleAttribute(exceptionTypeName.Trim()));
}
}
}
}
|