Skip to content

Commit db15344

Browse files
authored
Merge pull request #47 from utPLSQL/feature/compatibility_and_ora_libs
Feature/compatibility and ora libs Fixes several issues around compatibility Fixes #44 Fixes #41 Fixes #39 Fixes #38
2 parents 14401b5 + dd0dcdf commit db15344

File tree

10 files changed

+221
-12
lines changed

10 files changed

+221
-12
lines changed

.travis/create_release.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ VERSION=`date +%Y%m%d%H%M`
55

66
mkdir dist
77
mv target/appassembler utPLSQL-cli
8+
# Remove Oracle libraries du to licensing problems
9+
rm utPLSQL-cli/lib/ojdbc8*
10+
rm utPLSQL-cli/lib/orai18n*
11+
812
zip -r -q dist/utPLSQL-cli-${TRAVIS_BRANCH}-${VERSION}.zip utPLSQL-cli
913
zip -r -q utPLSQL-cli.zip utPLSQL-cli
1014

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ You can download development versions on [Bintray](https://bintray.com/viniciusa
1515
## Requirements
1616
* [Java SE Runtime Environment 8](http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html)
1717
* When using reporters for Sonar or Coveralls client needs to be invoked from project's root directory.
18+
* Due to Oracle license we can't ship the necessary oracle libraries directly with utPLSQL-cli. <b>Please download the libraries directly from oracle website and put the jars into the "lib" folder of your utPLSQL-cli installation</b>
19+
* Oracle JDBC driver: http://www.oracle.com/technetwork/database/features/jdbc/jdbc-ucp-122-3110062.html
20+
* If you are on a 11g database you might need the orai18n library, too: http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-112010-090769.html
1821

1922
## Compatibility
2023
The latest CLI is always compatible with all database frameworks of the same major version.

src/main/java/org/utplsql/cli/Cli.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
import com.beust.jcommander.JCommander;
44
import com.beust.jcommander.Parameter;
55
import com.beust.jcommander.ParameterException;
6+
import org.utplsql.api.exception.DatabaseNotCompatibleException;
7+
import org.utplsql.api.exception.UtPLSQLNotInstalledException;
8+
import org.utplsql.cli.exception.DatabaseConnectionFailed;
69

710
public class Cli {
811

@@ -34,6 +37,8 @@ public static void main(String[] args) {
3437
} else {
3538
jc.usage();
3639
}
40+
} catch ( DatabaseNotCompatibleException | UtPLSQLNotInstalledException | DatabaseConnectionFailed e ) {
41+
System.out.println(e.getMessage());
3742
} catch (Exception e) {
3843
e.printStackTrace();
3944
}

src/main/java/org/utplsql/cli/ConnectionInfo.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@
66

77
import java.io.File;
88
import java.sql.Connection;
9+
import java.sql.PreparedStatement;
10+
import java.sql.ResultSet;
911
import java.sql.SQLException;
1012

1113
public class ConnectionInfo {
1214

15+
private String databaseVersion;
16+
1317
static {
1418
String oracleHome = System.getenv("ORACLE_HOME");
1519
if (oracleHome != null) {
@@ -42,4 +46,40 @@ public ConnectionInfo convert(String s) {
4246
}
4347
}
4448

49+
public String getOracleDatabaseVersion() throws SQLException
50+
{
51+
try ( Connection conn = getConnection() ) {
52+
return getOracleDatabaseVersion(conn);
53+
}
54+
}
55+
56+
public String getOracleDatabaseVersion( Connection conn ) throws SQLException
57+
{
58+
if ( databaseVersion == null ) {
59+
databaseVersion = getOracleDatabaseVersionFromConnection( conn );
60+
}
61+
62+
return databaseVersion;
63+
}
64+
65+
/** TODO: Outsource this to Java-API
66+
*
67+
* @param conn
68+
* @return
69+
* @throws SQLException
70+
*/
71+
public static String getOracleDatabaseVersionFromConnection( Connection conn ) throws SQLException {
72+
assert conn != null;
73+
String result = null;
74+
try (PreparedStatement stmt = conn.prepareStatement("select version from product_component_version where product like 'Oracle Database%'"))
75+
{
76+
ResultSet rs = stmt.executeQuery();
77+
78+
if ( rs.next() )
79+
result = rs.getString(1);
80+
}
81+
82+
return result;
83+
}
84+
4585
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package org.utplsql.cli;
2+
3+
/** Simple class to check whether needed Oracle libraries are on classpath or not
4+
*
5+
* @author pesse
6+
*/
7+
class OracleLibraryChecker {
8+
9+
private static boolean classExists( String classFullName ){
10+
try
11+
{
12+
Class.forName(classFullName);
13+
14+
return true;
15+
}
16+
catch ( ClassNotFoundException e )
17+
{
18+
return false;
19+
}
20+
}
21+
22+
/** Checks if OJDBC library is on the classpath by searching for oracle.jdbc.OracleDriver class
23+
*
24+
* @return true or false
25+
*/
26+
public static boolean checkOjdbcExists() {
27+
return classExists("oracle.jdbc.OracleDriver");
28+
}
29+
30+
/** Checks if Orai18n library is on the classpath by searching for oracle.i18n.text.OraCharset
31+
*
32+
* @return true or false
33+
*/
34+
public static boolean checkOrai18nExists() {
35+
return classExists("oracle.i18n.text.OraCharset");
36+
}
37+
38+
39+
}

src/main/java/org/utplsql/cli/RunCommand.java

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33
import com.beust.jcommander.Parameter;
44
import com.beust.jcommander.Parameters;
55
import org.utplsql.api.*;
6+
import org.utplsql.api.compatibility.CompatibilityProxy;
7+
import org.utplsql.api.compatibility.OptionalFeatures;
68
import org.utplsql.api.exception.DatabaseNotCompatibleException;
79
import org.utplsql.api.exception.SomeTestsFailedException;
810
import org.utplsql.api.reporter.Reporter;
911
import org.utplsql.api.reporter.ReporterFactory;
12+
import org.utplsql.cli.exception.DatabaseConnectionFailed;
1013

1114
import java.io.File;
1215
import java.io.FileNotFoundException;
@@ -80,6 +83,8 @@ public class RunCommand {
8083
"most actual. Use this if you use CLI with a development version of utPLSQL-framework")
8184
private boolean skipCompatibilityCheck = false;
8285

86+
private CompatibilityProxy compatibilityProxy;
87+
8388
public ConnectionInfo getConnectionInfo() {
8489
return connectionInfoList.get(0);
8590
}
@@ -89,6 +94,9 @@ public List<String> getTestPaths() {
8994
}
9095

9196
public int run() throws Exception {
97+
98+
RunCommandChecker.checkOracleJDBCExists();
99+
92100
final ConnectionInfo ci = getConnectionInfo();
93101

94102
final List<Reporter> reporterList;
@@ -107,14 +115,27 @@ public int run() throws Exception {
107115
// Do the reporters initialization, so we can use the id to run and gather results.
108116
try (Connection conn = ci.getConnection()) {
109117

118+
// Check if orai18n exists if database version is 11g
119+
RunCommandChecker.checkOracleI18nExists(ci.getOracleDatabaseVersion(conn));
120+
110121
// First of all do a compatibility check and fail-fast
111-
checkFrameworkCompatibility(conn);
122+
compatibilityProxy = checkFrameworkCompatibility(conn);
112123

113124
reporterList = initReporters(conn, reporterOptionsList);
114125

115126
} catch (SQLException e) {
116-
System.out.println(e.getMessage());
117-
return Cli.DEFAULT_ERROR_CODE;
127+
if ( e.getErrorCode() == 1017 || e.getErrorCode() == 12514 ) {
128+
throw new DatabaseConnectionFailed(e);
129+
}
130+
else {
131+
throw e;
132+
}
133+
}
134+
135+
// Output a message if --failureExitCode is set but database framework is not capable of
136+
String msg = RunCommandChecker.getCheckFailOnErrorMessage(failureExitCode, compatibilityProxy.getDatabaseVersion());
137+
if ( msg != null ) {
138+
System.out.println(msg);
118139
}
119140

120141
ExecutorService executorService = Executors.newFixedThreadPool(1 + reporterList.size());
@@ -256,21 +277,19 @@ public List<ReporterOptions> getReporterOptionsList() {
256277
* @param conn Active Connection
257278
* @throws SQLException
258279
*/
259-
private void checkFrameworkCompatibility(Connection conn) throws SQLException {
280+
private CompatibilityProxy checkFrameworkCompatibility(Connection conn) throws SQLException {
260281

261-
if ( !skipCompatibilityCheck ) {
262-
try {
263-
DBHelper.failOnVersionCompatibilityCheckFailed(conn);
264-
} catch (DatabaseNotCompatibleException e) {
265-
System.out.println(e.getMessage());
282+
CompatibilityProxy proxy = new CompatibilityProxy(conn, skipCompatibilityCheck);
266283

267-
throw e;
268-
}
284+
if ( !skipCompatibilityCheck ) {
285+
proxy.failOnNotCompatible();
269286
}
270287
else {
271288
System.out.println("Skipping Compatibility check with framework version, expecting the latest version " +
272289
"to be installed in database");
273290
}
291+
292+
return proxy;
274293
}
275294

276295
public FileMapperOptions getMapperOptions(List<String> mappingParams, List<String> filePaths) {
@@ -320,4 +339,14 @@ public FileMapperOptions getMapperOptions(List<String> mappingParams, List<Strin
320339
return mapperOptions;
321340
}
322341

342+
/** Returns the version of the database framework if available
343+
*
344+
* @return
345+
*/
346+
public Version getDatabaseVersion() {
347+
if ( compatibilityProxy != null )
348+
return compatibilityProxy.getDatabaseVersion();
349+
350+
return null;
351+
}
323352
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package org.utplsql.cli;
2+
3+
import org.utplsql.api.Version;
4+
import org.utplsql.api.compatibility.OptionalFeatures;
5+
6+
/** Helper class to check several circumstances with RunCommand. Might need refactoring.
7+
*
8+
* @author pesse
9+
*/
10+
class RunCommandChecker {
11+
12+
/** Checks that ojdbc library exists
13+
*
14+
*/
15+
static void checkOracleJDBCExists()
16+
{
17+
if ( !OracleLibraryChecker.checkOjdbcExists() )
18+
{
19+
System.out.println("Could not find Oracle JDBC driver in classpath. Please download the jar from Oracle website" +
20+
" and copy it to the 'lib' folder of your utPLSQL-cli installation.");
21+
System.out.println("Download from http://www.oracle.com/technetwork/database/features/jdbc/jdbc-ucp-122-3110062.html");
22+
23+
throw new RuntimeException("Can't run utPLSQL-cli without Oracle JDBC driver");
24+
}
25+
}
26+
27+
/** Checks that orai18n library exists if database is an oracle 11
28+
*
29+
*/
30+
static void checkOracleI18nExists(String oracleDatabaseVersion )
31+
{
32+
if ( oracleDatabaseVersion.startsWith("11.") && !OracleLibraryChecker.checkOrai18nExists() )
33+
{
34+
System.out.println("Warning: Could not find Oracle i18n driver in classpath. Depending on the database charset " +
35+
"utPLSQL-cli might not run properly. It is recommended you download " +
36+
"the i18n driver from the Oracle website and copy it to the 'lib' folder of your utPLSQL-cli installation.");
37+
System.out.println("Download from http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-112010-090769.html");
38+
}
39+
}
40+
41+
/** Returns a warning message if failureExitCode is specified but database version is too low
42+
*
43+
* @param failureExitCode
44+
* @param databaseVersion
45+
*/
46+
static String getCheckFailOnErrorMessage(int failureExitCode, Version databaseVersion) {
47+
if ( failureExitCode != 1 && !OptionalFeatures.FAIL_ON_ERROR.isAvailableFor(databaseVersion)) {
48+
return "Your database framework version (" + databaseVersion.getNormalizedString() + ") is not able to " +
49+
"redirect failureCodes. Please upgrade to a newer version if you want to use that feature.";
50+
}
51+
52+
return null;
53+
}
54+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package org.utplsql.cli.exception;
2+
3+
import java.sql.SQLException;
4+
5+
public class DatabaseConnectionFailed extends SQLException {
6+
7+
public DatabaseConnectionFailed(SQLException cause ) {
8+
super( "Could not establish connection to database. Reason: " + cause.getMessage(), cause);
9+
}
10+
}

src/test/java/org/utplsql/cli/RunCommandTest.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import org.junit.Assert;
55
import org.junit.Test;
66
import org.utplsql.api.CustomTypes;
7+
import org.utplsql.api.compatibility.OptionalFeatures;
78

89
import java.util.List;
910

@@ -119,7 +120,12 @@ public void run_Default() {
119120

120121
try {
121122
int result = runCmd.run();
122-
Assert.assertEquals(2, result);
123+
124+
// Only expect failure-exit-code to work on several framework versions
125+
if (OptionalFeatures.FAIL_ON_ERROR.isAvailableFor(runCmd.getDatabaseVersion()) )
126+
Assert.assertEquals(2, result);
127+
else
128+
Assert.assertEquals(0, result);
123129
}
124130
catch ( Exception e ) {
125131
Assert.fail(e.getMessage());
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package org.utplsql.cli;
2+
3+
import org.junit.Assert;
4+
import org.junit.Test;
5+
import org.utplsql.api.Version;
6+
7+
public class TestRunCommandChecker {
8+
9+
@Test
10+
public void getCheckFailOnErrorMessage()
11+
{
12+
// FailOnError option should work since 3.0.3+ framework
13+
Assert.assertNotNull(RunCommandChecker.getCheckFailOnErrorMessage(2, new Version("3.0.0")));
14+
Assert.assertNotNull(RunCommandChecker.getCheckFailOnErrorMessage(2, new Version("3.0.1")));
15+
Assert.assertNotNull(RunCommandChecker.getCheckFailOnErrorMessage(2, new Version("3.0.2")));
16+
Assert.assertNull(RunCommandChecker.getCheckFailOnErrorMessage(2, new Version("3.0.3")));
17+
Assert.assertNull(RunCommandChecker.getCheckFailOnErrorMessage(2, new Version("3.0.4")));
18+
}
19+
}

0 commit comments

Comments
 (0)