mirror of https://github.com/apache/openjpa.git
OPENJPA-656: raise error messages with connection parameters on connect failure
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@676073 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
cc85528f69
commit
026c96d513
|
@ -26,6 +26,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
@ -45,7 +46,6 @@ import org.apache.openjpa.lib.util.Localizer;
|
||||||
import org.apache.openjpa.lib.util.Options;
|
import org.apache.openjpa.lib.util.Options;
|
||||||
import org.apache.openjpa.util.ImplHelper;
|
import org.apache.openjpa.util.ImplHelper;
|
||||||
import org.apache.openjpa.util.OpenJPAException;
|
import org.apache.openjpa.util.OpenJPAException;
|
||||||
import org.apache.openjpa.util.StoreException;
|
|
||||||
import org.apache.openjpa.util.UserException;
|
import org.apache.openjpa.util.UserException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -120,7 +120,7 @@ public class DataSourceFactory {
|
||||||
catch (OpenJPAException ke) {
|
catch (OpenJPAException ke) {
|
||||||
throw ke;
|
throw ke;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new StoreException(e).setFatal(true);
|
throw newConnectException(conf, factory2, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// not a driver or a data source; die
|
// not a driver or a data source; die
|
||||||
|
@ -175,7 +175,7 @@ public class DataSourceFactory {
|
||||||
} catch (OpenJPAException ke) {
|
} catch (OpenJPAException ke) {
|
||||||
throw ke;
|
throw ke;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new StoreException(e).setFatal(true);
|
throw newConnectException(conf, factory2, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,14 +237,7 @@ public class DataSourceFactory {
|
||||||
|
|
||||||
return ds;
|
return ds;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new StoreException(_loc.get("conn-failed", factory2
|
throw newConnectException(conf, factory2, e);
|
||||||
? new Object[]{conf.getConnection2DriverName(),
|
|
||||||
conf.getConnection2URL(),
|
|
||||||
conf.getConnection2Properties()}
|
|
||||||
: new Object[]{conf.getConnectionDriverName(),
|
|
||||||
conf.getConnectionURL(),
|
|
||||||
conf.getConnectionProperties()}),
|
|
||||||
e);
|
|
||||||
} finally {
|
} finally {
|
||||||
if (conn != null)
|
if (conn != null)
|
||||||
try {
|
try {
|
||||||
|
@ -256,6 +249,18 @@ public class DataSourceFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static OpenJPAException newConnectException(JDBCConfiguration conf,
|
||||||
|
boolean factory2, Exception cause) {
|
||||||
|
return new UserException(_loc.get("conn-failed", factory2
|
||||||
|
? new Object[]{conf.getConnection2DriverName(),
|
||||||
|
conf.getConnection2URL(),
|
||||||
|
conf.getConnection2Properties()}
|
||||||
|
: new Object[]{conf.getConnectionDriverName(),
|
||||||
|
conf.getConnectionURL(),
|
||||||
|
conf.getConnectionProperties()}),
|
||||||
|
cause).setFatal(true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a data source with the given user name and password
|
* Return a data source with the given user name and password
|
||||||
* pre-configured as the defaults when {@link DataSource#getConnection}
|
* pre-configured as the defaults when {@link DataSource#getConnection}
|
||||||
|
|
|
@ -77,8 +77,8 @@ public class SimpleDriverDataSource
|
||||||
throws SQLException {
|
throws SQLException {
|
||||||
Connection con = getDriver().connect(_connectionURL, props);
|
Connection con = getDriver().connect(_connectionURL, props);
|
||||||
if (con == null) {
|
if (con == null) {
|
||||||
throw new UserException(_loc.get("conn-failed",
|
throw new SQLException(_loc.get("conn-failed",
|
||||||
_connectionDriverName, _connectionURL, props));
|
_connectionDriverName, _connectionURL, props).getMessage());
|
||||||
}
|
}
|
||||||
return con;
|
return con;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,198 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.openjpa.conf;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
import javax.persistence.EntityManagerFactory;
|
||||||
|
import javax.persistence.Persistence;
|
||||||
|
import javax.persistence.PersistenceException;
|
||||||
|
|
||||||
|
import junit.framework.AssertionFailedError;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.apache.openjpa.persistence.OpenJPAPersistence;
|
||||||
|
import org.apache.openjpa.util.UserException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies appropriate exception is thrown when an incorrect protocol or
|
||||||
|
* sub-protocol is specified in the JDBC URL. Per the JDBC specification, the
|
||||||
|
* Driver should return a null connection upon getConnection() when a bad driver
|
||||||
|
* is specified on the URL. OpenJPA must be able to handle this condition and
|
||||||
|
* return an appropriate message.
|
||||||
|
*
|
||||||
|
* OpenJPA JIRA: {@link http://issues.apache.org/jira/browse/OPENJPA-656}
|
||||||
|
*
|
||||||
|
* @author Jeremy Bauer
|
||||||
|
* @author Pinaki Poddar
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TestBadJdbcUrl extends TestCase {
|
||||||
|
public static final String GOOD_URL = "jdbc:derby:target/database/openjpa-derby-database;create=true";
|
||||||
|
public static final String GOOD_DRIVER = "org.apache.derby.jdbc.EmbeddedDriver";
|
||||||
|
public static final String GOOD_DATASOURCE = "org.apache.commons.dbcp.BasicDataSource";
|
||||||
|
|
||||||
|
public static final String BAD_DRIVER = "bad.driver";
|
||||||
|
public static final String BAD_URL_PROTOCOL = "bad.url.protocol";
|
||||||
|
public static final String BAD_URL_SUBPROTOCOL = "bad.url.sub.protocol";
|
||||||
|
public static final String BAD_CONN_PROPS = "connectionUrl=bad,connectionDriver=bad";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test specifying URL with bad protocol but a valid Driver.
|
||||||
|
*/
|
||||||
|
public void testBadUrlProtocolValueWithValidDriverClass() {
|
||||||
|
Properties p = new Properties();
|
||||||
|
p.put("openjpa.ConnectionDriverName", GOOD_DRIVER);
|
||||||
|
p.put("openjpa.ConnectionURL", BAD_URL_PROTOCOL);
|
||||||
|
verifyConnectException(p, PersistenceException.class,
|
||||||
|
UserException.class, GOOD_DRIVER, BAD_URL_PROTOCOL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test specifying URL with bad protocol but a valid DataSource.
|
||||||
|
*/
|
||||||
|
public void testBadUrlProtocolValueWithValidDataSource() {
|
||||||
|
Properties p = new Properties();
|
||||||
|
p.put("openjpa.ConnectionDriverName", GOOD_DATASOURCE);
|
||||||
|
p.put("openjpa.ConnectionURL", BAD_URL_PROTOCOL);
|
||||||
|
p.put("openjpa.ConnectionProperties", BAD_CONN_PROPS);
|
||||||
|
verifyConnectException(p, PersistenceException.class,
|
||||||
|
null, (String[])null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test specifying URL with bad sub-protocol but a valid Driver.
|
||||||
|
*/
|
||||||
|
public void testBadUrlSubprotocolValueWithValidDriverClass() {
|
||||||
|
Properties p = new Properties();
|
||||||
|
p.put("openjpa.ConnectionDriverName", GOOD_DRIVER);
|
||||||
|
p.put("openjpa.ConnectionURL", BAD_URL_SUBPROTOCOL);
|
||||||
|
verifyConnectException(p, PersistenceException.class,
|
||||||
|
UserException.class, GOOD_DRIVER, BAD_URL_SUBPROTOCOL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test specifying URL with bad sub-protocol but a valid Driver.
|
||||||
|
*/
|
||||||
|
public void testBadUrlSubprotocolValueWithValidDataSource() {
|
||||||
|
Properties p = new Properties();
|
||||||
|
p.put("openjpa.ConnectionDriverName", GOOD_DRIVER);
|
||||||
|
p.put("openjpa.ConnectionURL", BAD_URL_SUBPROTOCOL);
|
||||||
|
verifyConnectException(p, PersistenceException.class,
|
||||||
|
UserException.class, GOOD_DRIVER, BAD_URL_SUBPROTOCOL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test specifying Valid URL with an invalid Driver.
|
||||||
|
*/
|
||||||
|
public void testValidUrlWithInvalidDriver() {
|
||||||
|
Properties p = new Properties();
|
||||||
|
p.put("openjpa.ConnectionDriverName", BAD_DRIVER);
|
||||||
|
p.put("openjpa.ConnectionURL", GOOD_URL);
|
||||||
|
verifyConnectException(p, PersistenceException.class,
|
||||||
|
UserException.class, GOOD_URL, BAD_DRIVER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to connect with given properties and analyze exception for the
|
||||||
|
* existence of given target exception and error message strings.
|
||||||
|
*
|
||||||
|
* @param props
|
||||||
|
* the properties to initialize the persistence unit
|
||||||
|
* @param target
|
||||||
|
* the type expected exception to be raised.
|
||||||
|
* @param nested
|
||||||
|
* the type expected nested exception. null implies not to look
|
||||||
|
* for any.
|
||||||
|
* @param keys
|
||||||
|
* the strings that must occur in the exception message.
|
||||||
|
*/
|
||||||
|
private void verifyConnectException(Properties props, Class targetType,
|
||||||
|
Class nestedType, String... keys) {
|
||||||
|
EntityManagerFactory emf = null;
|
||||||
|
EntityManager em = null;
|
||||||
|
try {
|
||||||
|
emf = Persistence.createEntityManagerFactory("test", props);
|
||||||
|
em = emf.createEntityManager();
|
||||||
|
OpenJPAPersistence.cast(em).getConnection();
|
||||||
|
fail("Should have caught a " + targetType.getName());
|
||||||
|
} catch (Throwable t) {
|
||||||
|
assertException(t, targetType, nestedType);
|
||||||
|
assertMessage(t, keys);
|
||||||
|
} finally {
|
||||||
|
if (em != null)
|
||||||
|
em.close();
|
||||||
|
if (emf != null)
|
||||||
|
emf.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that the given targetType is assignable from actual. Asserts that
|
||||||
|
* the nestedType is a nested within the given actual Throwable
|
||||||
|
*
|
||||||
|
* @param actual
|
||||||
|
* @param targetType
|
||||||
|
* @param nestedType
|
||||||
|
*/
|
||||||
|
void assertException(final Throwable actual, Class targetType,
|
||||||
|
Class nestedTargetType) {
|
||||||
|
if (targetType == null)
|
||||||
|
return;
|
||||||
|
assertNotNull(actual);
|
||||||
|
Class actualType = actual.getClass();
|
||||||
|
if (!targetType.isAssignableFrom(actualType)) {
|
||||||
|
actual.printStackTrace();
|
||||||
|
fail(targetType.getName() + " is not assignable from "
|
||||||
|
+ actualType.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nestedTargetType != null) {
|
||||||
|
Throwable nested = actual.getCause();
|
||||||
|
Class nestedType = (nested == null) ? null : nested.getClass();
|
||||||
|
while (nestedType != null) {
|
||||||
|
if (nestedType.isAssignableFrom(nestedTargetType)) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
Throwable next = nested.getCause();
|
||||||
|
if (next == null || next == nested)
|
||||||
|
break;
|
||||||
|
nestedType = next.getClass();
|
||||||
|
nested = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
actual.printStackTrace();
|
||||||
|
fail("No nested type " + nestedTargetType + " in " + actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert that each of given keys are present in the message of the given
|
||||||
|
* Throwable.
|
||||||
|
*/
|
||||||
|
void assertMessage(Throwable actual, String... keys) {
|
||||||
|
if (actual == null || keys == null)
|
||||||
|
return;
|
||||||
|
String message = actual.getMessage();
|
||||||
|
for (String key : keys) {
|
||||||
|
assertTrue(key + " is not in " + message, message.contains(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue