001: /*******************************************************************************
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: *******************************************************************************/package org.ofbiz.entity.transaction;
019:
020: import java.sql.Connection;
021: import java.sql.SQLException;
022: import java.util.HashMap;
023: import java.util.Map;
024:
025: import javax.naming.InitialContext;
026: import javax.naming.NamingException;
027: import javax.sql.DataSource;
028: import javax.sql.XAConnection;
029: import javax.sql.XADataSource;
030: import javax.transaction.TransactionManager;
031: import javax.transaction.UserTransaction;
032:
033: import org.ofbiz.base.config.GenericConfigException;
034: import org.ofbiz.base.util.Debug;
035: import org.ofbiz.base.util.GeneralException;
036: import org.ofbiz.base.util.JNDIContextFactory;
037: import org.ofbiz.entity.GenericEntityException;
038: import org.ofbiz.entity.config.DatasourceInfo;
039: import org.ofbiz.entity.config.EntityConfigUtil;
040: import org.ofbiz.entity.jdbc.ConnectionFactory;
041: import org.w3c.dom.Element;
042:
043: /**
044: * Central source for Tyrex JTA objects from JNDI
045: */
046: public class JNDIFactory implements TransactionFactoryInterface {
047:
048: // Debug module name
049: public static final String module = JNDIFactory.class.getName();
050:
051: static TransactionManager transactionManager = null;
052: static UserTransaction userTransaction = null;
053:
054: // protected static UtilCache dsCache = new UtilCache("entity.JndiDataSources", 0, 0);
055: protected static Map dsCache = new HashMap();
056:
057: public TransactionManager getTransactionManager() {
058: if (transactionManager == null) {
059: synchronized (JNDIFactory.class) {
060: // try again inside the synch just in case someone when through while we were waiting
061: if (transactionManager == null) {
062: try {
063: String jndiName = EntityConfigUtil
064: .getTxFactoryTxMgrJndiName();
065: String jndiServerName = EntityConfigUtil
066: .getTxFactoryTxMgrJndiServerName();
067:
068: if (jndiName != null && jndiName.length() > 0) {
069: // if (Debug.verboseOn()) Debug.logVerbose("[JNDIFactory.getTransactionManager] Trying JNDI name " + jndiName, module);
070:
071: try {
072: InitialContext ic = JNDIContextFactory
073: .getInitialContext(jndiServerName);
074:
075: if (ic != null) {
076: transactionManager = (TransactionManager) ic
077: .lookup(jndiName);
078: }
079: } catch (NamingException ne) {
080: Debug.logWarning(ne,
081: "NamingException while finding TransactionManager named "
082: + jndiName
083: + " in JNDI.", module);
084: transactionManager = null;
085: }
086: if (transactionManager == null) {
087: Debug.logWarning(
088: "[JNDIFactory.getTransactionManager] Failed to find TransactionManager named "
089: + jndiName
090: + " in JNDI.", module);
091: }
092: }
093: } catch (GeneralException e) {
094: Debug.logError(e, module);
095: transactionManager = null;
096: }
097: }
098: }
099: }
100: return transactionManager;
101: }
102:
103: public UserTransaction getUserTransaction() {
104: if (userTransaction == null) {
105: synchronized (JNDIFactory.class) {
106: // try again inside the synch just in case someone when through while we were waiting
107: if (userTransaction == null) {
108: try {
109: String jndiName = EntityConfigUtil
110: .getTxFactoryUserTxJndiName();
111: String jndiServerName = EntityConfigUtil
112: .getTxFactoryUserTxJndiServerName();
113:
114: if (jndiName != null && jndiName.length() > 0) {
115: // if (Debug.verboseOn()) Debug.logVerbose("[JNDIFactory.getTransactionManager] Trying JNDI name " + jndiName, module);
116:
117: try {
118: InitialContext ic = JNDIContextFactory
119: .getInitialContext(jndiServerName);
120:
121: if (ic != null) {
122: userTransaction = (UserTransaction) ic
123: .lookup(jndiName);
124: }
125: } catch (NamingException ne) {
126: Debug.logWarning(ne,
127: "NamingException while finding UserTransaction named "
128: + jndiName
129: + " in JNDI.", module);
130: userTransaction = null;
131: }
132: if (userTransaction == null) {
133: Debug.logWarning(
134: "[JNDIFactory.getUserTransaction] Failed to find UserTransaction named "
135: + jndiName
136: + " in JNDI.", module);
137: }
138: }
139: } catch (GeneralException e) {
140: Debug.logError(e, module);
141: transactionManager = null;
142: }
143: }
144: }
145: }
146: return userTransaction;
147: }
148:
149: public String getTxMgrName() {
150: return "jndi";
151: }
152:
153: public Connection getConnection(String helperName)
154: throws SQLException, GenericEntityException {
155: DatasourceInfo datasourceInfo = EntityConfigUtil
156: .getDatasourceInfo(helperName);
157:
158: if (datasourceInfo.jndiJdbcElement != null) {
159: Element jndiJdbcElement = datasourceInfo.jndiJdbcElement;
160: String jndiName = jndiJdbcElement.getAttribute("jndi-name");
161: String jndiServerName = jndiJdbcElement
162: .getAttribute("jndi-server-name");
163: Connection con = getJndiConnection(jndiName, jndiServerName);
164: if (con != null)
165: return TransactionFactory.getCursorConnection(
166: helperName, con);
167: } else {
168: // Debug.logError("JNDI loaded is the configured transaction manager but no jndi-jdbc element was specified in the " + helperName + " datasource. Please check your configuration.", module);
169: }
170:
171: if (datasourceInfo.inlineJdbcElement != null) {
172: Connection otherCon = ConnectionFactory
173: .tryGenericConnectionSources(helperName,
174: datasourceInfo.inlineJdbcElement);
175: return TransactionFactory.getCursorConnection(helperName,
176: otherCon);
177: } else {
178: //no real need to print an error here
179: return null;
180: }
181: }
182:
183: public static Connection getJndiConnection(String jndiName,
184: String jndiServerName) throws SQLException,
185: GenericEntityException {
186: // if (Debug.verboseOn()) Debug.logVerbose("Trying JNDI name " + jndiName, module);
187: Object ds;
188:
189: ds = dsCache.get(jndiName);
190: if (ds != null) {
191: if (ds instanceof XADataSource) {
192: XADataSource xads = (XADataSource) ds;
193:
194: return TransactionUtil.enlistConnection(xads
195: .getXAConnection());
196: } else {
197: DataSource nds = (DataSource) ds;
198:
199: return nds.getConnection();
200: }
201: }
202:
203: synchronized (ConnectionFactory.class) {
204: // try again inside the synch just in case someone when through while we were waiting
205: ds = dsCache.get(jndiName);
206: if (ds != null) {
207: if (ds instanceof XADataSource) {
208: XADataSource xads = (XADataSource) ds;
209:
210: return TransactionUtil.enlistConnection(xads
211: .getXAConnection());
212: } else {
213: DataSource nds = (DataSource) ds;
214:
215: return nds.getConnection();
216: }
217: }
218:
219: try {
220: if (Debug.infoOn())
221: Debug.logInfo("Doing JNDI lookup for name "
222: + jndiName, module);
223: InitialContext ic = JNDIContextFactory
224: .getInitialContext(jndiServerName);
225:
226: if (ic != null) {
227: ds = ic.lookup(jndiName);
228: } else {
229: Debug.logWarning(
230: "Initial Context returned was NULL for server name "
231: + jndiServerName, module);
232: }
233:
234: if (ds != null) {
235: if (Debug.verboseOn())
236: Debug.logVerbose("Got a Datasource object.",
237: module);
238: dsCache.put(jndiName, ds);
239: Connection con = null;
240:
241: if (ds instanceof XADataSource) {
242: if (Debug.infoOn())
243: Debug.logInfo("Got XADataSource for name "
244: + jndiName, module);
245: XADataSource xads = (XADataSource) ds;
246: XAConnection xac = xads.getXAConnection();
247:
248: con = TransactionUtil.enlistConnection(xac);
249: } else {
250: if (Debug.infoOn())
251: Debug.logInfo("Got DataSource for name "
252: + jndiName, module);
253: DataSource nds = (DataSource) ds;
254:
255: con = nds.getConnection();
256: }
257:
258: /* NOTE: This code causes problems because settting the transaction isolation level after a transaction has started is a no-no
259: * The question is: how should we do this?
260: String isolationLevel = jndiJdbcElement.getAttribute("isolation-level");
261: if (con != null && isolationLevel != null && isolationLevel.length() > 0) {
262: if ("Serializable".equals(isolationLevel)) {
263: con.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
264: } else if ("RepeatableRead".equals(isolationLevel)) {
265: con.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
266: } else if ("ReadUncommitted".equals(isolationLevel)) {
267: con.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
268: } else if ("ReadCommitted".equals(isolationLevel)) {
269: con.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
270: } else if ("None".equals(isolationLevel)) {
271: con.setTransactionIsolation(Connection.TRANSACTION_NONE);
272: }
273: }
274: */
275:
276: // if (con != null) if (Debug.infoOn()) Debug.logInfo("[ConnectionFactory.getConnection] Got JNDI connection with catalog: " + con.getCatalog(), module);
277: return con;
278: } else {
279: Debug.logError("Datasource returned was NULL.",
280: module);
281: }
282: } catch (NamingException ne) {
283: Debug.logWarning(ne,
284: "[ConnectionFactory.getConnection] Failed to find DataSource named "
285: + jndiName
286: + " in JNDI server with name "
287: + jndiServerName
288: + ". Trying normal database.", module);
289: } catch (GenericConfigException gce) {
290: throw new GenericEntityException(
291: "Problems with the JNDI configuration.", gce
292: .getNested());
293: }
294: }
295: return null;
296: }
297:
298: public void shutdown() {
299: }
300: }
|