001/* 002 * Copyright 2002-2019 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 * https://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 017package org.springframework.transaction.interceptor; 018 019import java.beans.PropertyEditorSupport; 020 021import org.springframework.util.StringUtils; 022 023/** 024 * PropertyEditor for {@link TransactionAttribute} objects. Accepts a String of form 025 * <p>{@code PROPAGATION_NAME, ISOLATION_NAME, readOnly, timeout_NNNN,+Exception1,-Exception2} 026 * <p>where only propagation code is required. For example: 027 * <p>{@code PROPAGATION_MANDATORY, ISOLATION_DEFAULT} 028 * 029 * <p>The tokens can be in <strong>any</strong> order. Propagation and isolation codes 030 * must use the names of the constants in the TransactionDefinition class. Timeout values 031 * are in seconds. If no timeout is specified, the transaction manager will apply a default 032 * timeout specific to the particular transaction manager. 033 * 034 * <p>A "+" before an exception name substring indicates that transactions should commit 035 * even if this exception is thrown; a "-" that they should roll back. 036 * 037 * @author Rod Johnson 038 * @author Juergen Hoeller 039 * @since 24.04.2003 040 * @see org.springframework.transaction.TransactionDefinition 041 * @see org.springframework.core.Constants 042 */ 043public class TransactionAttributeEditor extends PropertyEditorSupport { 044 045 /** 046 * Format is PROPAGATION_NAME,ISOLATION_NAME,readOnly,timeout_NNNN,+Exception1,-Exception2. 047 * Null or the empty string means that the method is non transactional. 048 */ 049 @Override 050 public void setAsText(String text) throws IllegalArgumentException { 051 if (StringUtils.hasLength(text)) { 052 // tokenize it with "," 053 String[] tokens = StringUtils.commaDelimitedListToStringArray(text); 054 RuleBasedTransactionAttribute attr = new RuleBasedTransactionAttribute(); 055 for (String token : tokens) { 056 // Trim leading and trailing whitespace. 057 String trimmedToken = StringUtils.trimWhitespace(token.trim()); 058 // Check whether token contains illegal whitespace within text. 059 if (StringUtils.containsWhitespace(trimmedToken)) { 060 throw new IllegalArgumentException( 061 "Transaction attribute token contains illegal whitespace: [" + trimmedToken + "]"); 062 } 063 // Check token type. 064 if (trimmedToken.startsWith(RuleBasedTransactionAttribute.PREFIX_PROPAGATION)) { 065 attr.setPropagationBehaviorName(trimmedToken); 066 } 067 else if (trimmedToken.startsWith(RuleBasedTransactionAttribute.PREFIX_ISOLATION)) { 068 attr.setIsolationLevelName(trimmedToken); 069 } 070 else if (trimmedToken.startsWith(RuleBasedTransactionAttribute.PREFIX_TIMEOUT)) { 071 String value = trimmedToken.substring(DefaultTransactionAttribute.PREFIX_TIMEOUT.length()); 072 attr.setTimeout(Integer.parseInt(value)); 073 } 074 else if (trimmedToken.equals(RuleBasedTransactionAttribute.READ_ONLY_MARKER)) { 075 attr.setReadOnly(true); 076 } 077 else if (trimmedToken.startsWith(RuleBasedTransactionAttribute.PREFIX_COMMIT_RULE)) { 078 attr.getRollbackRules().add(new NoRollbackRuleAttribute(trimmedToken.substring(1))); 079 } 080 else if (trimmedToken.startsWith(RuleBasedTransactionAttribute.PREFIX_ROLLBACK_RULE)) { 081 attr.getRollbackRules().add(new RollbackRuleAttribute(trimmedToken.substring(1))); 082 } 083 else { 084 throw new IllegalArgumentException("Invalid transaction attribute token: [" + trimmedToken + "]"); 085 } 086 } 087 setValue(attr); 088 } 089 else { 090 setValue(null); 091 } 092 } 093 094}