001: /*
002: * $Id: JNDIFactory.java,v 1.3 2003/12/01 20:46:49 ajzeneski Exp $
003: *
004: * Copyright (c) 2001, 2002 The Open For Business Project - www.ofbiz.org
005: *
006: * Permission is hereby granted, free of charge, to any person obtaining a
007: * copy of this software and associated documentation files (the "Software"),
008: * to deal in the Software without restriction, including without limitation
009: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
010: * and/or sell copies of the Software, and to permit persons to whom the
011: * Software is furnished to do so, subject to the following conditions:
012: *
013: * The above copyright notice and this permission notice shall be included
014: * in all copies or substantial portions of the Software.
015: *
016: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
017: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
018: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
019: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
020: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
021: * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
022: * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
023: */
024:
025: package org.ofbiz.entity.transaction;
026:
027: import java.sql.Connection;
028: import java.sql.SQLException;
029: import java.util.HashMap;
030: import java.util.Map;
031:
032: import javax.naming.InitialContext;
033: import javax.naming.NamingException;
034: import javax.sql.DataSource;
035: import javax.sql.XAConnection;
036: import javax.sql.XADataSource;
037: import javax.transaction.TransactionManager;
038: import javax.transaction.UserTransaction;
039:
040: import org.ofbiz.base.config.GenericConfigException;
041: import org.ofbiz.base.util.Debug;
042: import org.ofbiz.base.util.GeneralException;
043: import org.ofbiz.base.util.JNDIContextFactory;
044: import org.ofbiz.entity.GenericEntityException;
045: import org.ofbiz.entity.config.EntityConfigUtil;
046: import org.ofbiz.entity.jdbc.ConnectionFactory;
047: import org.w3c.dom.Element;
048:
049: /**
050: * Central source for Tyrex JTA objects from JNDI
051: *
052: * @author <a href="mailto:jonesde@ofbiz.org">David E. Jones</a>
053: * @version $Revision: 1.3 $
054: * @since 2.0
055: */
056: public class JNDIFactory implements TransactionFactoryInterface {
057:
058: // Debug module name
059: public static final String module = JNDIFactory.class.getName();
060:
061: static TransactionManager transactionManager = null;
062: static UserTransaction userTransaction = null;
063:
064: // protected static UtilCache dsCache = new UtilCache("entity.JndiDataSources", 0, 0);
065: protected static Map dsCache = new HashMap();
066:
067: public TransactionManager getTransactionManager() {
068: if (transactionManager == null) {
069: synchronized (JNDIFactory.class) {
070: // try again inside the synch just in case someone when through while we were waiting
071: if (transactionManager == null) {
072: try {
073: String jndiName = EntityConfigUtil
074: .getTxFactoryTxMgrJndiName();
075: String jndiServerName = EntityConfigUtil
076: .getTxFactoryTxMgrJndiServerName();
077:
078: if (jndiName != null && jndiName.length() > 0) {
079: // if (Debug.verboseOn()) Debug.logVerbose("[JNDIFactory.getTransactionManager] Trying JNDI name " + jndiName, module);
080:
081: try {
082: InitialContext ic = JNDIContextFactory
083: .getInitialContext(jndiServerName);
084:
085: if (ic != null) {
086: transactionManager = (TransactionManager) ic
087: .lookup(jndiName);
088: }
089: } catch (NamingException ne) {
090: Debug.logWarning(ne,
091: "NamingException while finding TransactionManager named "
092: + jndiName
093: + " in JNDI.", module);
094: transactionManager = null;
095: }
096: if (transactionManager == null) {
097: Debug.logWarning(
098: "[JNDIFactory.getTransactionManager] Failed to find TransactionManager named "
099: + jndiName
100: + " in JNDI.", module);
101: }
102: }
103: } catch (GeneralException e) {
104: Debug.logError(e, module);
105: transactionManager = null;
106: }
107: }
108: }
109: }
110: return transactionManager;
111: }
112:
113: public UserTransaction getUserTransaction() {
114: if (userTransaction == null) {
115: synchronized (JNDIFactory.class) {
116: // try again inside the synch just in case someone when through while we were waiting
117: if (userTransaction == null) {
118: try {
119: String jndiName = EntityConfigUtil
120: .getTxFactoryUserTxJndiName();
121: String jndiServerName = EntityConfigUtil
122: .getTxFactoryUserTxJndiServerName();
123:
124: if (jndiName != null && jndiName.length() > 0) {
125: // if (Debug.verboseOn()) Debug.logVerbose("[JNDIFactory.getTransactionManager] Trying JNDI name " + jndiName, module);
126:
127: try {
128: InitialContext ic = JNDIContextFactory
129: .getInitialContext(jndiServerName);
130:
131: if (ic != null) {
132: userTransaction = (UserTransaction) ic
133: .lookup(jndiName);
134: }
135: } catch (NamingException ne) {
136: Debug.logWarning(ne,
137: "NamingException while finding UserTransaction named "
138: + jndiName
139: + " in JNDI.", module);
140: userTransaction = null;
141: }
142: if (userTransaction == null) {
143: Debug.logWarning(
144: "[JNDIFactory.getUserTransaction] Failed to find UserTransaction named "
145: + jndiName
146: + " in JNDI.", module);
147: }
148: }
149: } catch (GeneralException e) {
150: Debug.logError(e, module);
151: transactionManager = null;
152: }
153: }
154: }
155: }
156: return userTransaction;
157: }
158:
159: public String getTxMgrName() {
160: return "jndi";
161: }
162:
163: public Connection getConnection(String helperName)
164: throws SQLException, GenericEntityException {
165: EntityConfigUtil.DatasourceInfo datasourceInfo = EntityConfigUtil
166: .getDatasourceInfo(helperName);
167:
168: if (datasourceInfo.jndiJdbcElement != null) {
169: Element jndiJdbcElement = datasourceInfo.jndiJdbcElement;
170: String jndiName = jndiJdbcElement.getAttribute("jndi-name");
171: String jndiServerName = jndiJdbcElement
172: .getAttribute("jndi-server-name");
173: Connection con = getJndiConnection(jndiName, jndiServerName);
174: if (con != null)
175: return con;
176: } else {
177: // Debug.logError("JNDI loaded is the configured transaction manager but no jndi-jdbc element was specified in the " + helperName + " datasource. Please check your configuration; will try other sources", module);
178: }
179:
180: if (datasourceInfo.inlineJdbcElement != null) {
181: Connection otherCon = ConnectionFactory
182: .tryGenericConnectionSources(helperName,
183: datasourceInfo.inlineJdbcElement);
184: return otherCon;
185: } else {
186: //no real need to print an error here
187: return null;
188: }
189: }
190:
191: public static Connection getJndiConnection(String jndiName,
192: String jndiServerName) throws SQLException,
193: GenericEntityException {
194: // if (Debug.verboseOn()) Debug.logVerbose("Trying JNDI name " + jndiName, module);
195: Object ds;
196:
197: ds = dsCache.get(jndiName);
198: if (ds != null) {
199: if (ds instanceof XADataSource) {
200: XADataSource xads = (XADataSource) ds;
201:
202: return TransactionUtil.enlistConnection(xads
203: .getXAConnection());
204: } else {
205: DataSource nds = (DataSource) ds;
206:
207: return nds.getConnection();
208: }
209: }
210:
211: synchronized (ConnectionFactory.class) {
212: // try again inside the synch just in case someone when through while we were waiting
213: ds = dsCache.get(jndiName);
214: if (ds != null) {
215: if (ds instanceof XADataSource) {
216: XADataSource xads = (XADataSource) ds;
217:
218: return TransactionUtil.enlistConnection(xads
219: .getXAConnection());
220: } else {
221: DataSource nds = (DataSource) ds;
222:
223: return nds.getConnection();
224: }
225: }
226:
227: try {
228: if (Debug.infoOn())
229: Debug.logInfo("Doing JNDI lookup for name "
230: + jndiName, module);
231: InitialContext ic = JNDIContextFactory
232: .getInitialContext(jndiServerName);
233:
234: if (ic != null) {
235: ds = ic.lookup(jndiName);
236: } else {
237: Debug.logWarning(
238: "Initial Context returned was NULL for server name "
239: + jndiServerName, module);
240: }
241:
242: if (ds != null) {
243: if (Debug.verboseOn())
244: Debug.logVerbose("Got a Datasource object.",
245: module);
246: dsCache.put(jndiName, ds);
247: Connection con = null;
248:
249: if (ds instanceof XADataSource) {
250: if (Debug.infoOn())
251: Debug.logInfo("Got XADataSource for name "
252: + jndiName, module);
253: XADataSource xads = (XADataSource) ds;
254: XAConnection xac = xads.getXAConnection();
255:
256: con = TransactionUtil.enlistConnection(xac);
257: } else {
258: if (Debug.infoOn())
259: Debug.logInfo("Got DataSource for name "
260: + jndiName, module);
261: DataSource nds = (DataSource) ds;
262:
263: con = nds.getConnection();
264: }
265:
266: /* NOTE: This code causes problems because settting the transaction isolation level after a transaction has started is a no-no
267: * The question is: how should we do this?
268: String isolationLevel = jndiJdbcElement.getAttribute("isolation-level");
269: if (con != null && isolationLevel != null && isolationLevel.length() > 0) {
270: if ("Serializable".equals(isolationLevel)) {
271: con.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
272: } else if ("RepeatableRead".equals(isolationLevel)) {
273: con.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
274: } else if ("ReadUncommitted".equals(isolationLevel)) {
275: con.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
276: } else if ("ReadCommitted".equals(isolationLevel)) {
277: con.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
278: } else if ("None".equals(isolationLevel)) {
279: con.setTransactionIsolation(Connection.TRANSACTION_NONE);
280: }
281: }
282: */
283:
284: // if (con != null) if (Debug.infoOn()) Debug.logInfo("[ConnectionFactory.getConnection] Got JNDI connection with catalog: " + con.getCatalog(), module);
285: return con;
286: } else {
287: Debug.logError("Datasource returned was NULL.",
288: module);
289: }
290: } catch (NamingException ne) {
291: Debug.logWarning(ne,
292: "[ConnectionFactory.getConnection] Failed to find DataSource named "
293: + jndiName
294: + " in JNDI server with name "
295: + jndiServerName
296: + ". Trying normal database.", module);
297: } catch (GenericConfigException gce) {
298: throw new GenericEntityException(
299: "Problems with the JNDI configuration.", gce
300: .getNested());
301: }
302: }
303: return null;
304: }
305:
306: public void shutdown() {
307: }
308: }
|