001: /*--
002:
003: Copyright (C) 2002-2005 Adrian Price.
004: All rights reserved.
005:
006: Redistribution and use in source and binary forms, with or without
007: modification, are permitted provided that the following conditions
008: are met:
009:
010: 1. Redistributions of source code must retain the above copyright
011: notice, this list of conditions, and the following disclaimer.
012:
013: 2. Redistributions in binary form must reproduce the above copyright
014: notice, this list of conditions, and the disclaimer that follows
015: these conditions in the documentation and/or other materials
016: provided with the distribution.
017:
018: 3. The names "OBE" and "Open Business Engine" must not be used to
019: endorse or promote products derived from this software without prior
020: written permission. For written permission, please contact
021: adrianprice@sourceforge.net.
022:
023: 4. Products derived from this software may not be called "OBE" or
024: "Open Business Engine", nor may "OBE" or "Open Business Engine"
025: appear in their name, without prior written permission from
026: Adrian Price (adrianprice@users.sourceforge.net).
027:
028: THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
029: WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
030: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
031: DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
032: INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
033: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
034: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
035: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
036: STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
037: IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
038: POSSIBILITY OF SUCH DAMAGE.
039:
040: For more information on OBE, please see
041: <http://obe.sourceforge.net/>.
042:
043: */
044:
045: package org.obe.server.j2ee.ejb;
046:
047: import org.apache.commons.logging.Log;
048: import org.apache.commons.logging.LogFactory;
049: import org.obe.server.j2ee.repository.TransactionUtil;
050:
051: import javax.ejb.CreateException;
052: import javax.ejb.SessionSynchronization;
053: import java.util.HashMap;
054: import java.util.Map;
055:
056: /**
057: * Tracks the transaction lifecycle. Enables OBE to know when to use read-write
058: * entity beans instead of read-only beans (if the read-write version for a
059: * particular entity class has already been used within the current
060: * transaction).
061: *
062: * @author Adrian Price.
063: * @ejb:bean type="Stateful"
064: * name="TxHelper"
065: * display-name="OBE Transaction Helper"
066: * local-jndi-name="org/obe/ejb/TxHelperLocal"
067: * transaction-type="Container"
068: * view-type="local"
069: * @ejb:home extends="javax.ejb.EJBHome"
070: * local-extends="javax.ejb.EJBLocalHome"
071: * local-package="org.obe.server.j2ee"
072: * @ejb:interface local-extends="javax.ejb.EJBLocalObject"
073: * local-package="org.obe.server.j2ee"
074: * @ejb:permission unchecked="true"
075: * @ejb:transaction type="Supports"
076: * @weblogic:transaction-isolation ${transaction.isolation}
077: * @ejb:resource-ref res-name="jdbc/TxDataSource"
078: * res-type="javax.sql.DataSource"
079: * res-auth="Container"
080: * @jboss:resource-manager res-man-class="javax.sql.DataSource"
081: * res-man-name="jdbc/TxDataSource"
082: * res-man-jndi-name="java:/${xdoclet.DataSource}"
083: * @weblogic:resource-description res-ref-name="jdbc/TxDataSource"
084: * jndi-name="${xdoclet.DataSource}"
085: * @weblogic:pool max-beans-in-free-pool="50"
086: * initial-beans-in-free-pool="0"
087: * @weblogic:cache idle-timeout-seconds="0"
088: */
089: public class TxHelperEJB extends AbstractSessionEJB implements
090: SessionSynchronization {
091:
092: private static final long serialVersionUID = 1284341740343653371L;
093: private static final Log _logger = LogFactory
094: .getLog(TxHelperEJB.class);
095: private String _threadId;
096: private transient Map _modifiedEntities;
097:
098: protected Log getLogger() {
099: return _logger;
100: }
101:
102: public void afterBegin() {
103: if (_logger.isDebugEnabled())
104: _logger.debug("afterBegin()");
105: }
106:
107: public void afterCompletion(boolean committed) {
108: if (_logger.isDebugEnabled())
109: _logger.debug("afterCompletion(" + committed + ')');
110: }
111:
112: public void beforeCompletion() {
113: if (_logger.isDebugEnabled())
114: _logger.debug("beforeCompletion()");
115:
116: _modifiedEntities.clear();
117: }
118:
119: public void ejbActivate() {
120: if (getLogger().isDebugEnabled())
121: getLogger().debug("ejbActivate(), threadId=" + _threadId);
122: _modifiedEntities = new HashMap();
123: }
124:
125: /**
126: * Creates a new TxHelper bean.
127: *
128: * @param threadId The ID of the thread from which the bean is being created.
129: * @throws CreateException
130: * @ejb:create-method
131: */
132: public void ejbCreate(String threadId) throws CreateException {
133: if (_logger.isDebugEnabled())
134: _logger.debug("ejbCreate(" + threadId + ')');
135: _threadId = threadId;
136: _modifiedEntities = new HashMap();
137: }
138:
139: public void ejbPassivate() {
140: if (getLogger().isDebugEnabled())
141: getLogger().debug("ejbPassivate(), threadId=" + _threadId);
142:
143: // The EJB spec. states that when a container removes a SFSB if the bean
144: // times out after passivation, it is not required to call ejbRemove().
145: // We can't call our own remove() during passivation, so instead we
146: // inform TransactionUtil of our passivation so that it can clean up.
147: TransactionUtil.cleanup(_threadId);
148: _modifiedEntities = null;
149: }
150:
151: public void ejbRemove() {
152: if (getLogger().isDebugEnabled())
153: getLogger().debug("ejbRemove(), threadId=" + _threadId);
154:
155: // Inform TransactionUtil of our demise so that it can clean up.
156: TransactionUtil.cleanup(_threadId);
157: _modifiedEntities = null;
158: }
159:
160: /**
161: * Checks whether the bean is still alive. (Stateful session beans can time
162: * out or be removed by a runtime exception).
163: *
164: * @ejb:interface-method
165: */
166: public void ping() {
167: }
168:
169: /**
170: * Marks the specified entity class as having been accessed in read-write
171: * mode.
172: *
173: * @param entityTag A unique tag representing the entity class.
174: * @ejb:interface-method
175: */
176: public void markReadWrite(String entityTag) {
177: if (_logger.isDebugEnabled()) {
178: _logger.debug("Marking txn entity tag '" + entityTag
179: + "' read/write");
180: }
181: _modifiedEntities.put(entityTag, entityTag);
182: }
183:
184: /**
185: * Checks whether the specified entity class has been accessed in read-write
186: * mode in the current transaction.
187: *
188: * @param entityTag A unique tag representing the entity class.
189: * @return <code>true</code> if the entity class has been accessed in
190: * read-write mode, otherwise <code>false</code>.
191: * @ejb:interface-method
192: */
193: public boolean isReadWrite(String entityTag) {
194: boolean isReadWrite = _modifiedEntities.containsKey(entityTag);
195: if (_logger.isDebugEnabled()) {
196: _logger.debug("Checking txn entity tag '" + entityTag
197: + "' for read/write access. Returning: "
198: + isReadWrite);
199: }
200: return isReadWrite;
201: }
202: }
|