Skip to content

Commit

Permalink
JDBC-421 Transaction mapping cannot be configured through JDBC URL
Browse files Browse the repository at this point in the history
  • Loading branch information
mrotteveel committed Jan 23, 2016
1 parent 61ae58c commit b55089c
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 112 deletions.
7 changes: 7 additions & 0 deletions src/documentation/release_notes.md
Expand Up @@ -443,6 +443,13 @@ the interface duplicated the `java.sql.Savepoint` interface and related methods
in `java.sql.Connection`. The interface itself remains for potential future
Firebird-specific extensions.

### Reducing visibility of implementation ###

The following classes, interfaces and/or methods had their visibility reduced as
they are implementation artifacts, and should not be considered API:

- `org.firebirdsql.jdbc.FBDriverPropertyManager` (to package private)

Breaking changes for Jaybird 3.1
--------------------------------

Expand Down
168 changes: 117 additions & 51 deletions src/main/org/firebirdsql/jdbc/FBDriver.java
Expand Up @@ -32,13 +32,14 @@
import java.sql.*;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;

/**
* The Jaybird JDBC Driver implementation for the Firebird database.
*
* @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
* @version 1.0
* @author <a href="mailto:mrotteveel@users.sourceforge.net">Mark Rotteveel</a>
*/
public class FBDriver implements FirebirdDriver {

Expand Down Expand Up @@ -78,62 +79,64 @@ public class FBDriver implements FirebirdDriver {
* of driver to connect to the given URL. This will be common, as when
* the JDBC driver manager is asked to connect to a given URL it passes
* the URL to each loaded driver in turn.
*
* <P>The driver should raise a SQLException if it is the right
* <p>
* The driver should raise a SQLException if it is the right
* driver to connect to the given URL, but has trouble connecting to
* the database.
*
* <P>The java.util.Properties argument can be used to passed arbitrary
* </p>
* <p>
* The java.util.Properties argument can be used to passed arbitrary
* string tag/value pairs as connection arguments.
* Normally at least "user" and "password" properties should be
* included in the Properties.
* </p>
*
* @param url the URL of the database to which to connect
* @param originalInfo a list of arbitrary string tag/value pairs as
* connection arguments. Normally at least a "user" and
* "password" property should be included.
* @param url
* the URL of the database to which to connect
* @param info
* a list of arbitrary string tag/value pairs as
* connection arguments. Normally at least a "user" and
* "password" property should be included.
* @return a <code>Connection</code> object that represents a
* connection to the URL
* @exception SQLException if a database access error occurs
* connection to the URL
* @throws SQLException
* if a database access error occurs
*/
public Connection connect(String url, Properties originalInfo) throws SQLException {
public Connection connect(String url, final Properties info) throws SQLException {
if (url == null) {
throw new SQLException("url is null");
}

final GDSType type = GDSFactory.getTypeForProtocol(url);

if (type == null)
if (type == null) {
return null;
}

final Properties mergedProperties = mergeProperties(url, info);
final Map<String, String> normalizedInfo = FBDriverPropertyManager.normalize(mergedProperties);
try {
if (originalInfo == null)
originalInfo = new Properties();

Map<String, String> normalizedInfo = FBDriverPropertyManager.normalize(url, originalInfo);

int qMarkIndex = url.indexOf('?');
if (qMarkIndex != -1)
if (qMarkIndex != -1) {
url = url.substring(0, qMarkIndex);
}

FBManagedConnectionFactory mcf = new FBManagedConnectionFactory(type);

String databaseURL = GDSFactory.getDatabasePath(type, url);

mcf.setDatabase(databaseURL);
for (Map.Entry<String, String> entry : normalizedInfo.entrySet()) {
mcf.setNonStandardProperty(entry.getKey(), entry.getValue());
}

FBTpbMapper.processMapping(mcf, originalInfo);
FBTpbMapper.processMapping(mcf, mergedProperties);

mcf = mcf.canonicalize();

FBDataSource dataSource = createDataSource(mcf);

return dataSource.getConnection(mcf.getUserName(), mcf.getPassword());
} catch(ResourceException | GDSException resex) {

} catch (ResourceException | GDSException resex) {
throw new FBSQLException(resex);
}
}
Expand Down Expand Up @@ -168,27 +171,27 @@ private FBDataSource dataSourceFromCache(final FBConnectionProperties cacheKey)
final SoftReference<FBDataSource> dataSourceReference = mcfToDataSourceMap.get(cacheKey);
return dataSourceReference != null ? dataSourceReference.get() : null;
}

public FirebirdConnection connect(FirebirdConnectionProperties properties) throws SQLException {
GDSType type = GDSType.getType(properties.getType());

if (type == null)
type = GDSFactory.getDefaultGDSType();
try {
FBManagedConnectionFactory mcf = new FBManagedConnectionFactory(type);

mcf = mcf.canonicalize();

FBDataSource dataSource = createDataSource(mcf);
return (FirebirdConnection)dataSource.getConnection(mcf.getUserName(), mcf.getPassword());
} catch(ResourceException ex) {

return (FirebirdConnection) dataSource.getConnection(mcf.getUserName(), mcf.getPassword());
} catch (ResourceException ex) {
throw new FBSQLException(ex);
}
}

public FirebirdConnectionProperties newConnectionProperties() {
return new FBConnectionProperties();
return new FBConnectionProperties();
}

/**
Expand All @@ -197,11 +200,13 @@ public FirebirdConnectionProperties newConnectionProperties() {
* understand the subprotocol specified in the URL and false if
* they don't.
*
* @param url the URL of the database
* @param url
* the URL of the database
* @return true if this driver can connect to the given URL
* @exception SQLException if a database access error occurs
* @throws SQLException
* if a database access error occurs
*/
public boolean acceptsURL(String url) throws SQLException {
public boolean acceptsURL(String url) throws SQLException {
if (url == null) {
throw new SQLException("url is null");
}
Expand All @@ -210,7 +215,7 @@ public boolean acceptsURL(String url) throws SQLException {
if (url.startsWith(protocol))
return true;
}

return false;
}

Expand All @@ -223,41 +228,44 @@ public boolean acceptsURL(String url) throws SQLException {
* necessary, so it may be necessary to iterate though several calls
* to getPropertyInfo.
*
* @param url the URL of the database to which to connect
* @param info a proposed list of tag/value pairs that will be sent on
* connect open
* @param url
* the URL of the database to which to connect
* @param info
* a proposed list of tag/value pairs that will be sent on
* connect open
* @return an array of DriverPropertyInfo objects describing possible
* properties. This array may be an empty array if no properties
* are required.
* @exception SQLException if a database access error occurs
* TODO check the correctness of implementation
* TODO convert parameters into constants
* properties. This array may be an empty array if no properties
* are required.
* @throws SQLException
* if a database access error occurs
* TODO check the correctness of implementation
* TODO convert parameters into constants
*/
public DriverPropertyInfo[] getPropertyInfo(String url,
Properties info) throws SQLException {

public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
return FBDriverPropertyManager.getDriverPropertyInfo(info);
}

/**
* Gets the driver's major version number. Initially this should be 1.
* @return this driver's major version number
*
* @return this driver's major version number
*/
public int getMajorVersion() {
return 3;
}

/**
* Gets the driver's minor version number. Initially this should be 0.
* @return this driver's minor version number
*
* @return this driver's minor version number
*/
public int getMinorVersion() {
return 0;
}

/**
* Reports whether this driver is a genuine JDBC
* COMPLIANT<sup><font size=-2>TM</font></sup> driver.
* COMPLIANT<sup><font size=-2>TM</font></sup> driver.
* A driver may only report true here if it passes the JDBC compliance
* tests; otherwise it is required to return false.
*
Expand All @@ -279,5 +287,63 @@ public boolean jdbcCompliant() {
public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException {
throw new FBDriverNotCapableException();
}

/**
* Merges the properties from the JDBC URL and properties object.
* <p>
* If a property is present in both, the property specified in the JDBC url takes precedence.
* </p>
*
* @param jdbcUrl JDBC Url
* @param connectionProperties Properties object
* @return Map with connection properties
*/
private static Properties mergeProperties(String jdbcUrl, Properties connectionProperties) {
Properties mergedProperties = new Properties();
if (connectionProperties != null) {
for (String propertyName : connectionProperties.stringPropertyNames()) {
mergedProperties.setProperty(propertyName, connectionProperties.getProperty(propertyName));
}
}

convertUrlParams(jdbcUrl, mergedProperties);

return mergedProperties;
}

/**
* Extract properties specified as URL parameter into the specified map of properties.
*
* @param url
* specified URL.
* @param info
* instance of {@link Map} into which values should
* be extracted.
*/
private static void convertUrlParams(String url, Properties info) {
if (url == null) {
return;
}

int iQuestionMark = url.indexOf("?");
if (iQuestionMark == -1) {
return;
}

String propString = url.substring(iQuestionMark + 1);

StringTokenizer st = new StringTokenizer(propString, "&;");
while (st.hasMoreTokens()) {
String propertyString = st.nextToken();
int iIs = propertyString.indexOf("=");
if (iIs > -1) {
String property = propertyString.substring(0, iIs);
String value = propertyString.substring(iIs + 1);
info.setProperty(property, value);
} else {
info.setProperty(propertyString, "");
}
}
}
}

0 comments on commit b55089c

Please sign in to comment.