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 ffb5f1e commit 63c814b
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 77 deletions.
7 changes: 6 additions & 1 deletion src/etc/release_notes.md
Expand Up @@ -781,7 +781,12 @@ The following interfaces will have some of the methods removed:
- `releaseSavepoint(FirebirdSavepoint savepoint)` replace with
`Connection#releaseSavepoint(Savepoint savepoint)`

If you are still using these interfaces or methods, please change your
Visibility of the following classes will be reduced as they are implementation
artifacts and should not be considered API:

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

If you are still using these interfaces, classes or methods, please change your
code to use the JDBC interface or method instead.

### Handling `(VAR)CHAR CHARACTER SET OCTETS` as `(VAR)BINARY` type
Expand Down
96 changes: 77 additions & 19 deletions src/main/org/firebirdsql/jdbc/AbstractDriver.java
Expand Up @@ -39,7 +39,7 @@
* 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 abstract class AbstractDriver implements FirebirdDriver {

Expand Down Expand Up @@ -91,45 +91,43 @@ public abstract class AbstractDriver implements FirebirdDriver {
* included in the Properties.
*
* @param url the URL of the database to which to connect
* @param originalInfo a list of arbitrary string tag/value pairs as
* @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
*/
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 normalizedInfo = FBDriverPropertyManager.normalize(url, mergedProperties);
try {
if (originalInfo == null)
originalInfo = new Properties();

Map 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 (Iterator iter = normalizedInfo.entrySet().iterator(); iter.hasNext();) {
Map.Entry entry = (Map.Entry) iter.next();
mcf.setNonStandardProperty((String)entry.getKey(), (String)entry.getValue());
for (Object o : normalizedInfo.entrySet()) {
Map.Entry entry = (Map.Entry) o;

mcf.setNonStandardProperty((String) entry.getKey(), (String) entry.getValue());
}

FBConnectionHelper.processTpbMapping(mcf.getGDS(), mcf, originalInfo);
FBConnectionHelper.processTpbMapping(mcf.getGDS(), mcf, mergedProperties);

mcf = mcf.canonicalize();

Expand Down Expand Up @@ -178,9 +176,10 @@ private FBDataSource dataSourceFromCache(final FBConnectionProperties cacheKey)

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

if (type == null)
type = ((AbstractGDS)GDSFactory.getDefaultGDS()).getType();
if (type == null) {
type = GDSFactory.getDefaultGDS().getType();
}

try {
FBManagedConnectionFactory mcf = new FBManagedConnectionFactory(type);

Expand Down Expand Up @@ -285,5 +284,64 @@ public int getMinorVersion() {
public boolean jdbcCompliant() {
return true;
}


/**
* 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, "");
}
}
}
}

84 changes: 27 additions & 57 deletions src/main/org/firebirdsql/jdbc/FBDriverPropertyManager.java
@@ -1,5 +1,5 @@
/*
* Firebird Open Source J2ee connector - jdbc driver
* Firebird Open Source JavaEE Connector - JDBC Driver
*
* Distributable under LGPL license.
* You may obtain a copy of the License at http://www.gnu.org/copyleft/lgpl.html
Expand All @@ -12,27 +12,17 @@
* This file was created by members of the firebird development team.
* All individual contributions remain the Copyright (C) of those
* individuals. Contributors to this file are either listed here or
* can be obtained from a CVS history command.
* can be obtained from a source control history command.
*
* All rights reserved.
*/

package org.firebirdsql.jdbc;

import java.sql.DriverPropertyInfo;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.StringTokenizer;

import org.firebirdsql.encodings.EncodingFactory;

import java.sql.DriverPropertyInfo;
import java.sql.SQLException;
import java.util.*;

/**
* Manager of the DPB properties.
Expand Down Expand Up @@ -61,8 +51,7 @@ private static class PropertyInfo {

private int hashCode;

public PropertyInfo(String alias, String dpbName, Integer dpbKey,
String description) {
public PropertyInfo(String alias, String dpbName, Integer dpbKey, String description) {
this.alias = alias;
this.dpbName = dpbName;
this.dpbKey = dpbKey;
Expand Down Expand Up @@ -155,25 +144,40 @@ public boolean equals(Object obj) {
reversedDpbMap.put(dpbKey, propInfo);
}
}

/**
* Normalize the properties. This method resolves the aliases to their
* original names. Also it restores the short syntax for the DPB parameters.
*
* @param url <b>ignored</b>
* @param props instance of {@link Properties} containing original properties.
*
* @return instance of {@link Map} containing the normalized ones.
*
* @throws SQLException if original properties reference the same DPB
* parameter using both alias and original name.
* @deprecated Use {@link #normalize(Properties)} instead. Method will be removed in Jaybird 3.0
*/
@Deprecated
public static Map<String, String> normalize(String url, Properties props) throws SQLException {
return normalize(props);
}

/**
* Normalize the properties. This method resolves the aliases to their
* original names. Also it restores the short syntax for the DPB parameters.
*
* @param props instance of {@link Properties} containing original properties.
*
* @return instance of {@link Properties} containing the normalized ones.
* @return instance of {@link Map} containing the normalized ones.
*
* @throws SQLException if original properties reference the same DPB
* parameter using both alias and original name.
*/
public static HashMap normalize(String url, Map props) throws SQLException {

public static HashMap normalize(Properties props) throws SQLException {
HashMap tempProps = new HashMap();
tempProps.putAll(props);

convertUrlParams(url, tempProps);


HashMap result = new HashMap();

for (Iterator iter = tempProps.entrySet().iterator(); iter.hasNext();) {
Expand Down Expand Up @@ -240,41 +244,7 @@ public static String getCanonicalName(String propertyName) {

return propInfo.dpbName;
}

/**
* Extract properties specified as URL parameter into the specified list
* of properties.
*
* @param url specified URL.
*
* @param info instance of {@link Properties} into which values should
* be extracted.
*/
private static void convertUrlParams(String url, HashMap 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.put(property,value);
} else {
info.put(propertyString, "");
}
}
}

/**
* Handle character encoding parameters. This method ensures that both
* java encoding an client connection encodings are correctly set.
Expand Down
40 changes: 40 additions & 0 deletions src/test/org/firebirdsql/jdbc/TestFBDriver.java
Expand Up @@ -19,6 +19,8 @@
package org.firebirdsql.jdbc;

import org.firebirdsql.common.FBTestBase;
import org.firebirdsql.gds.ISCConstants;
import org.firebirdsql.gds.TransactionParameterBuffer;

import java.sql.*;
import java.util.Calendar;
Expand Down Expand Up @@ -277,5 +279,43 @@ public void testDummyPacketIntervalConnect() throws Exception {
}
}

public void testTransactionConfigThroughPropertiesObject() throws Exception {
Properties props = getDefaultPropertiesForConnection();
// Note that for proper testing this needs to be different from the mapping in isc_tpb_mapping.properties
props.setProperty("TRANSACTION_READ_COMMITTED",
"isc_tpb_read_committed,isc_tpb_no_rec_version,isc_tpb_write,isc_tpb_nowait");
Connection connection = DriverManager.getConnection(getUrl(), props);
try {
FirebirdConnection fbConnection = connection.unwrap(FirebirdConnection.class);
TransactionParameterBuffer tpb =
fbConnection.getTransactionParameters(Connection.TRANSACTION_READ_COMMITTED);

assertTrue("expected isc_tpb_read_committed", tpb.hasArgument(ISCConstants.isc_tpb_read_committed));
assertTrue("expected isc_tpb_no_rec_version", tpb.hasArgument(ISCConstants.isc_tpb_no_rec_version));
assertTrue("expected isc_tpb_write", tpb.hasArgument(ISCConstants.isc_tpb_write));
assertTrue("expected isc_tpb_nowait", tpb.hasArgument(ISCConstants.isc_tpb_nowait));
} finally {
connection.close();
}
}

public void testTransactionConfigThroughConnectionString() throws Exception {
Properties props = getDefaultPropertiesForConnection();
// Note that for proper testing this needs to be different from the mapping in isc_tpb_mapping.properties
String jdbcUrl = getUrl() + "?TRANSACTION_READ_COMMITTED=isc_tpb_read_committed,isc_tpb_no_rec_version,isc_tpb_write,isc_tpb_nowait";
Connection connection = DriverManager.getConnection(jdbcUrl, props);
try {
FirebirdConnection fbConnection = connection.unwrap(FirebirdConnection.class);
TransactionParameterBuffer tpb =
fbConnection.getTransactionParameters(Connection.TRANSACTION_READ_COMMITTED);

assertTrue("expected isc_tpb_read_committed", tpb.hasArgument(ISCConstants.isc_tpb_read_committed));
assertTrue("expected isc_tpb_no_rec_version", tpb.hasArgument(ISCConstants.isc_tpb_no_rec_version));
assertTrue("expected isc_tpb_write", tpb.hasArgument(ISCConstants.isc_tpb_write));
assertTrue("expected isc_tpb_nowait", tpb.hasArgument(ISCConstants.isc_tpb_nowait));
} finally {
connection.close();
}
}
}

0 comments on commit 63c814b

Please sign in to comment.