001: /*
002: * Copyright 2002-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.transaction.interceptor;
018:
019: import java.io.Serializable;
020: import java.util.ArrayList;
021: import java.util.Iterator;
022: import java.util.LinkedList;
023: import java.util.List;
024:
025: import org.apache.commons.logging.Log;
026: import org.apache.commons.logging.LogFactory;
027:
028: /**
029: * TransactionAttribute implementation that works out whether a given exception
030: * should cause transaction rollback by applying a number of rollback rules,
031: * both positive and negative. If no rules are relevant to the exception, it
032: * behaves like DefaultTransactionAttribute (rolling back on runtime exceptions).
033: *
034: * <p>TransactionAttributeEditor creates objects of this class.
035: *
036: * @author Rod Johnson
037: * @author Juergen Hoeller
038: * @since 09.04.2003
039: * @see TransactionAttributeEditor
040: */
041: public class RuleBasedTransactionAttribute extends
042: DefaultTransactionAttribute implements Serializable {
043:
044: /** Prefix for rollback-on-exception rules in description strings */
045: public static final String PREFIX_ROLLBACK_RULE = "-";
046:
047: /** Prefix for commit-on-exception rules in description strings */
048: public static final String PREFIX_COMMIT_RULE = "+";
049:
050: /** Static for optimal serializability */
051: private static final Log logger = LogFactory
052: .getLog(RuleBasedTransactionAttribute.class);
053:
054: private List rollbackRules;
055:
056: /**
057: * Create a new RuleBasedTransactionAttribute, with default settings.
058: * Can be modified through bean property setters.
059: * @see #setPropagationBehavior
060: * @see #setIsolationLevel
061: * @see #setTimeout
062: * @see #setReadOnly
063: * @see #setName
064: * @see #setRollbackRules
065: */
066: public RuleBasedTransactionAttribute() {
067: super ();
068: }
069:
070: /**
071: * Copy constructor. Definition can be modified through bean property setters.
072: * @see #setPropagationBehavior
073: * @see #setIsolationLevel
074: * @see #setTimeout
075: * @see #setReadOnly
076: * @see #setName
077: * @see #setRollbackRules
078: */
079: public RuleBasedTransactionAttribute(
080: RuleBasedTransactionAttribute other) {
081: super (other);
082: this .rollbackRules = new ArrayList(other.rollbackRules);
083: }
084:
085: /**
086: * Create a new DefaultTransactionAttribute with the the given
087: * propagation behavior. Can be modified through bean property setters.
088: * @param propagationBehavior one of the propagation constants in the
089: * TransactionDefinition interface
090: * @param rollbackRules the list of RollbackRuleAttributes to apply
091: * @see #setIsolationLevel
092: * @see #setTimeout
093: * @see #setReadOnly
094: */
095: public RuleBasedTransactionAttribute(int propagationBehavior,
096: List rollbackRules) {
097: super (propagationBehavior);
098: this .rollbackRules = rollbackRules;
099: }
100:
101: /**
102: * Set the list of <code>RollbackRuleAttribute</code> objects
103: * (and/or <code>NoRollbackRuleAttribute</code> objects) to apply.
104: * @see RollbackRuleAttribute
105: * @see NoRollbackRuleAttribute
106: */
107: public void setRollbackRules(List rollbackRules) {
108: this .rollbackRules = rollbackRules;
109: }
110:
111: /**
112: * Return the list of <code>RollbackRuleAttribute</code> objects
113: * (never <code>null</code>).
114: */
115: public List getRollbackRules() {
116: if (this .rollbackRules == null) {
117: this .rollbackRules = new LinkedList();
118: }
119: return this .rollbackRules;
120: }
121:
122: /**
123: * Winning rule is the shallowest rule (that is, the closest in the
124: * inheritance hierarchy to the exception). If no rule applies (-1),
125: * return false.
126: * @see TransactionAttribute#rollbackOn(java.lang.Throwable)
127: */
128: public boolean rollbackOn(Throwable ex) {
129: if (logger.isTraceEnabled()) {
130: logger
131: .trace("Applying rules to determine whether transaction should rollback on "
132: + ex);
133: }
134:
135: RollbackRuleAttribute winner = null;
136: int deepest = Integer.MAX_VALUE;
137:
138: if (this .rollbackRules != null) {
139: for (Iterator it = this .rollbackRules.iterator(); it
140: .hasNext();) {
141: RollbackRuleAttribute rule = (RollbackRuleAttribute) it
142: .next();
143: int depth = rule.getDepth(ex);
144: if (depth >= 0 && depth < deepest) {
145: deepest = depth;
146: winner = rule;
147: }
148: }
149: }
150:
151: if (logger.isTraceEnabled()) {
152: logger.trace("Winning rollback rule is: " + winner);
153: }
154:
155: // User superclass behavior (rollback on unchecked) if no rule matches.
156: if (winner == null) {
157: logger
158: .trace("No relevant rollback rule found: applying default rules");
159: return super .rollbackOn(ex);
160: }
161:
162: return !(winner instanceof NoRollbackRuleAttribute);
163: }
164:
165: public String toString() {
166: StringBuffer result = getDefinitionDescription();
167: if (this .rollbackRules != null) {
168: for (Iterator it = this .rollbackRules.iterator(); it
169: .hasNext();) {
170: RollbackRuleAttribute rule = (RollbackRuleAttribute) it
171: .next();
172: String sign = (rule instanceof NoRollbackRuleAttribute ? PREFIX_COMMIT_RULE
173: : PREFIX_ROLLBACK_RULE);
174: result.append(',').append(sign).append(
175: rule.getExceptionName());
176: }
177: }
178: return result.toString();
179: }
180:
181: }
|