1 /*
2  * Copyright 2002-2008 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package org.springframework.transaction.support;
18 
19 import java.util.Date;
20 
21 import org.springframework.transaction.TransactionTimedOutException;
22 
23 /**
24  * Convenient base class for resource holders.
25  *
26  * <p>Features rollback-only support for nested transactions.
27  * Can expire after a certain number of seconds or milliseconds,
28  * to determine transactional timeouts.
29  *
30  * @author Juergen Hoeller
31  * @since 02.02.2004
32  * @see org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin
33  * @see org.springframework.jdbc.datasource.DataSourceUtils#applyTransactionTimeout
34  */
35 public abstract class ResourceHolderSupport implements ResourceHolder {
36 
37 	private boolean synchronizedWithTransaction = false;
38 
39 	private boolean rollbackOnly = false;
40 
41 	private Date deadline;
42 
43 	private int referenceCount = 0;
44 
45 	private boolean isVoid = false;
46 
47 
48 	/**
49 	 * Mark the resource as synchronized with a transaction.
50 	 */
setSynchronizedWithTransaction(boolean synchronizedWithTransaction)51 	public void setSynchronizedWithTransaction(boolean synchronizedWithTransaction) {
52 		this.synchronizedWithTransaction = synchronizedWithTransaction;
53 	}
54 
55 	/**
56 	 * Return whether the resource is synchronized with a transaction.
57 	 */
isSynchronizedWithTransaction()58 	public boolean isSynchronizedWithTransaction() {
59 		return this.synchronizedWithTransaction;
60 	}
61 
62 	/**
63 	 * Mark the resource transaction as rollback-only.
64 	 */
setRollbackOnly()65 	public void setRollbackOnly() {
66 		this.rollbackOnly = true;
67 	}
68 
69 	/**
70 	 * Return whether the resource transaction is marked as rollback-only.
71 	 */
isRollbackOnly()72 	public boolean isRollbackOnly() {
73 		return this.rollbackOnly;
74 	}
75 
76 	/**
77 	 * Set the timeout for this object in seconds.
78 	 * @param seconds number of seconds until expiration
79 	 */
setTimeoutInSeconds(int seconds)80 	public void setTimeoutInSeconds(int seconds) {
81 		setTimeoutInMillis(seconds * 1000);
82 	}
83 
84 	/**
85 	 * Set the timeout for this object in milliseconds.
86 	 * @param millis number of milliseconds until expiration
87 	 */
setTimeoutInMillis(long millis)88 	public void setTimeoutInMillis(long millis) {
89 		this.deadline = new Date(System.currentTimeMillis() + millis);
90 	}
91 
92 	/**
93 	 * Return whether this object has an associated timeout.
94 	 */
hasTimeout()95 	public boolean hasTimeout() {
96 		return (this.deadline != null);
97 	}
98 
99 	/**
100 	 * Return the expiration deadline of this object.
101 	 * @return the deadline as Date object
102 	 */
getDeadline()103 	public Date getDeadline() {
104 		return this.deadline;
105 	}
106 
107 	/**
108 	 * Return the time to live for this object in seconds.
109 	 * Rounds up eagerly, e.g. 9.00001 still to 10.
110 	 * @return number of seconds until expiration
111 	 * @throws TransactionTimedOutException if the deadline has already been reached
112 	 */
getTimeToLiveInSeconds()113 	public int getTimeToLiveInSeconds() {
114 		double diff = ((double) getTimeToLiveInMillis()) / 1000;
115 		int secs = (int) Math.ceil(diff);
116 		checkTransactionTimeout(secs <= 0);
117 		return secs;
118 	}
119 
120 	/**
121 	 * Return the time to live for this object in milliseconds.
122 	 * @return number of millseconds until expiration
123 	 * @throws TransactionTimedOutException if the deadline has already been reached
124 	 */
getTimeToLiveInMillis()125 	public long getTimeToLiveInMillis() throws TransactionTimedOutException{
126 		if (this.deadline == null) {
127 			throw new IllegalStateException("No timeout specified for this resource holder");
128 		}
129 		long timeToLive = this.deadline.getTime() - System.currentTimeMillis();
130 		checkTransactionTimeout(timeToLive <= 0);
131 		return timeToLive;
132 	}
133 
134 	/**
135 	 * Set the transaction rollback-only if the deadline has been reached,
136 	 * and throw a TransactionTimedOutException.
137 	 */
checkTransactionTimeout(boolean deadlineReached)138 	private void checkTransactionTimeout(boolean deadlineReached) throws TransactionTimedOutException {
139 		if (deadlineReached) {
140 			setRollbackOnly();
141 			throw new TransactionTimedOutException("Transaction timed out: deadline was " + this.deadline);
142 		}
143 	}
144 
145 	/**
146 	 * Increase the reference count by one because the holder has been requested
147 	 * (i.e. someone requested the resource held by it).
148 	 */
requested()149 	public void requested() {
150 		this.referenceCount++;
151 	}
152 
153 	/**
154 	 * Decrease the reference count by one because the holder has been released
155 	 * (i.e. someone released the resource held by it).
156 	 */
released()157 	public void released() {
158 		this.referenceCount--;
159 	}
160 
161 	/**
162 	 * Return whether there are still open references to this holder.
163 	 */
isOpen()164 	public boolean isOpen() {
165 		return (this.referenceCount > 0);
166 	}
167 
168 	/**
169 	 * Clear the transactional state of this resource holder.
170 	 */
clear()171 	public void clear() {
172 		this.synchronizedWithTransaction = false;
173 		this.rollbackOnly = false;
174 		this.deadline = null;
175 	}
176 
177 	/**
178 	 * Reset this resource holder - transactional state as well as reference count.
179 	 */
reset()180 	public void reset() {
181 		clear();
182 		this.referenceCount = 0;
183 	}
184 
unbound()185 	public void unbound() {
186 		this.isVoid = true;
187 	}
188 
isVoid()189 	public boolean isVoid() {
190 		return this.isVoid;
191 	}
192 
193 }
194