001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.resource.adapter.jdbc.xa;
023:
024: import org.jboss.resource.adapter.jdbc.BaseWrapperManagedConnectionFactory;
025: import java.lang.reflect.InvocationTargetException;
026: import java.lang.reflect.Method;
027: import java.beans.PropertyEditorManager;
028: import java.beans.PropertyEditor;
029: import javax.sql.XADataSource;
030: import javax.sql.XAConnection;
031: import java.io.ByteArrayInputStream;
032: import java.io.IOException;
033: import java.io.InputStream;
034: import java.sql.SQLException;
035: import java.util.Iterator;
036: import java.util.Properties;
037: import java.util.Set;
038: import javax.resource.ResourceException;
039: import javax.resource.spi.ConnectionRequestInfo;
040: import javax.resource.spi.ManagedConnection;
041: import javax.security.auth.Subject;
042: import org.jboss.resource.JBossResourceException;
043:
044: /**
045: * XAManagedConnectionFactory
046: *
047: * @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
048: * @author <a href="mailto:adrian@jboss.com">Adrian Brock</a>
049: * @author <a href="weston.price@jboss.com">Weston Price</a>
050: *
051: * @version $Revision: 60398 $
052: */
053: public class XAManagedConnectionFactory extends
054: BaseWrapperManagedConnectionFactory {
055: private static final long serialVersionUID = 1647927657609573729L;
056:
057: private String xaDataSourceClass;
058:
059: private String xaDataSourceProperties;
060:
061: protected final Properties xaProps = new Properties();
062:
063: private Boolean isSameRMOverrideValue;
064:
065: private XADataSource xads;
066:
067: public XAManagedConnectionFactory() {
068: }
069:
070: /**
071: * Get the XaDataSourceClass value.
072: *
073: * @return the XaDataSourceClass value.
074: */
075: public String getXADataSourceClass() {
076: return xaDataSourceClass;
077: }
078:
079: /**
080: * Set the XaDataSourceClass value.
081: *
082: * @param xaDataSourceClass The new XaDataSourceClass value.
083: */
084: public void setXADataSourceClass(String xaDataSourceClass) {
085: this .xaDataSourceClass = xaDataSourceClass;
086: }
087:
088: /**
089: * Get the XADataSourceProperties value.
090: *
091: * @return the XADataSourceProperties value.
092: */
093: public String getXADataSourceProperties() {
094: return xaDataSourceProperties;
095: }
096:
097: /**
098: * Set the XADataSourceProperties value.
099: *
100: * @param xaDataSourceProperties The new XADataSourceProperties value.
101: */
102: public void setXADataSourceProperties(String xaDataSourceProperties)
103: throws ResourceException {
104: this .xaDataSourceProperties = xaDataSourceProperties;
105: xaProps.clear();
106: if (xaDataSourceProperties != null) {
107: // Map any \ to \\
108: xaDataSourceProperties = xaDataSourceProperties.replaceAll(
109: "\\\\", "\\\\\\\\");
110:
111: InputStream is = new ByteArrayInputStream(
112: xaDataSourceProperties.getBytes());
113: try {
114: xaProps.load(is);
115: } catch (IOException ioe) {
116: throw new JBossResourceException(
117: "Could not load connection properties", ioe);
118: }
119: }
120: }
121:
122: public ManagedConnection createManagedConnection(Subject subject,
123: ConnectionRequestInfo cri)
124: throws javax.resource.ResourceException {
125: Properties props = getConnectionProperties(subject, cri);
126: try {
127: final String user = props.getProperty("user");
128: final String password = props.getProperty("password");
129:
130: XAConnection xaConnection = (user != null) ? getXADataSource()
131: .getXAConnection(user, password)
132: : getXADataSource().getXAConnection();
133:
134: return newXAManagedConnection(props, xaConnection);
135: } catch (Exception e) {
136: throw new JBossResourceException(
137: "Could not create connection", e);
138: }
139: }
140:
141: /**
142: * This method can be overwritten by sublcasses to provide rm specific
143: * implementation of XAManagedConnection
144: */
145: protected ManagedConnection newXAManagedConnection(
146: Properties props, XAConnection xaConnection)
147: throws SQLException {
148: return new XAManagedConnection(this , xaConnection, props,
149: transactionIsolation, preparedStatementCacheSize);
150: }
151:
152: public ManagedConnection matchManagedConnections(Set mcs,
153: Subject subject, ConnectionRequestInfo cri)
154: throws ResourceException {
155: Properties newProps = getConnectionProperties(subject, cri);
156: for (Iterator i = mcs.iterator(); i.hasNext();) {
157: Object o = i.next();
158: if (o instanceof XAManagedConnection) {
159: XAManagedConnection mc = (XAManagedConnection) o;
160:
161: if (mc.getProps().equals(newProps)) {
162: //Next check to see if we are validating on matchManagedConnections
163: if ((getValidateOnMatch() && mc.checkValid())
164: || !getValidateOnMatch()) {
165:
166: return mc;
167:
168: }
169:
170: }
171:
172: }
173: }
174: return null;
175: }
176:
177: public int hashCode() {
178: int result = 17;
179: result = result
180: * 37
181: + ((xaDataSourceClass == null) ? 0 : xaDataSourceClass
182: .hashCode());
183: result = result * 37 + xaProps.hashCode();
184: result = result * 37
185: + ((userName == null) ? 0 : userName.hashCode());
186: result = result * 37
187: + ((password == null) ? 0 : password.hashCode());
188: result = result * 37 + transactionIsolation;
189: return result;
190: }
191:
192: public boolean equals(Object other) {
193: if (this == other)
194: return true;
195: if (getClass() != other.getClass())
196: return false;
197: XAManagedConnectionFactory otherMcf = (XAManagedConnectionFactory) other;
198: return this .xaDataSourceClass
199: .equals(otherMcf.xaDataSourceClass)
200: && this .xaProps.equals(otherMcf.xaProps)
201: && ((this .userName == null) ? otherMcf.userName == null
202: : this .userName.equals(otherMcf.userName))
203: && ((this .password == null) ? otherMcf.password == null
204: : this .password.equals(otherMcf.password))
205: && this .transactionIsolation == otherMcf.transactionIsolation;
206:
207: }
208:
209: protected synchronized XADataSource getXADataSource()
210: throws ResourceException {
211: if (xads == null) {
212: if (xaDataSourceClass == null)
213: throw new JBossResourceException(
214: "No XADataSourceClass supplied!");
215: try {
216: Class clazz = Thread.currentThread()
217: .getContextClassLoader().loadClass(
218: xaDataSourceClass);
219: xads = (XADataSource) clazz.newInstance();
220: Class[] NOCLASSES = new Class[] {};
221: for (Iterator i = xaProps.keySet().iterator(); i
222: .hasNext();) {
223: String name = (String) i.next();
224: String value = xaProps.getProperty(name);
225: //This is a bad solution. On the other hand the only known example
226: // of a setter with no getter is for Oracle with password.
227: //Anyway, each xadatasource implementation should get its
228: //own subclass of this that explicitly sets the
229: //properties individually.
230: Class type = null;
231: try {
232: Method getter = clazz.getMethod("get" + name,
233: NOCLASSES);
234: type = getter.getReturnType();
235: } catch (NoSuchMethodException e) {
236: type = String.class;
237:
238: try {
239: //HACK for now until we can rethink the XADataSourceProperties variable and pass type information
240: Method getter = clazz.getMethod(
241: "is" + name, NOCLASSES);
242: type = getter.getReturnType();
243:
244: } catch (NoSuchMethodException nsme) {
245: type = String.class;
246:
247: }
248:
249: }
250:
251: Method setter = clazz.getMethod("set" + name,
252: new Class[] { type });
253: PropertyEditor editor = PropertyEditorManager
254: .findEditor(type);
255: if (editor == null)
256: throw new JBossResourceException(
257: "No property editor found for type: "
258: + type);
259: editor.setAsText(value);
260: setter.invoke(xads, new Object[] { editor
261: .getValue() });
262: }
263: } catch (ClassNotFoundException cnfe) {
264: throw new JBossResourceException(
265: "Class not found for XADataSource "
266: + xaDataSourceClass, cnfe);
267: } catch (InstantiationException ie) {
268: throw new JBossResourceException(
269: "Could not create an XADataSource: ", ie);
270: } catch (IllegalAccessException iae) {
271: throw new JBossResourceException(
272: "Could not set a property: ", iae);
273: } catch (IllegalArgumentException iae) {
274: throw new JBossResourceException(
275: "Could not set a property: ", iae);
276: } catch (InvocationTargetException ite) {
277: throw new JBossResourceException(
278: "Could not invoke setter on XADataSource: ",
279: ite);
280: } catch (NoSuchMethodException nsme) {
281: throw new JBossResourceException(
282: "Could not find accessor on XADataSource: ",
283: nsme);
284: }
285: }
286: return xads;
287: }
288:
289: protected Properties getXaProps() {
290: return xaProps;
291: }
292: }
|