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