1 package com.atlassian.activeobjects.internal;
2
3 import net.java.ao.ActiveObjectsException;
4 import net.java.ao.EntityManager;
5 import org.slf4j.Logger;
6 import org.slf4j.LoggerFactory;
7
8 import java.sql.Connection;
9 import java.sql.DatabaseMetaData;
10 import java.sql.SQLException;
11 import java.sql.SQLNonTransientConnectionException;
12 import java.sql.SQLTransientConnectionException;
13
14 public final class ActiveObjectsSqlException extends ActiveObjectsException {
15 private final Logger logger = LoggerFactory.getLogger(this.getClass());
16
17 private Database database;
18 private Driver driver;
19
20 public ActiveObjectsSqlException(EntityManager entityManager, SQLException cause) {
21 super(cause);
22
23
24
25 if (!isConnectionException(cause)) {
26 getInformation(entityManager);
27 }
28 }
29
30 public SQLException getSqlException() {
31 return (SQLException) getCause();
32 }
33
34 @Override
35 public String getMessage() {
36 return "There was a SQL exception thrown by the Active Objects library:\n" + database + "\n" + driver + "\n\n" +
37 super.getMessage();
38 }
39
40 private void getInformation(EntityManager entityManager) {
41 try (Connection connection = entityManager.getProvider().getConnection()) {
42 if (connection != null && !connection.isClosed()) {
43 final DatabaseMetaData metaData = connection.getMetaData();
44 database = getDatabase(metaData);
45 driver = getDriver(metaData);
46 }
47 } catch (SQLException e) {
48 logger.debug("Could not load database connection meta data", e);
49 addSuppressed(e);
50 }
51 }
52
53 private static Database getDatabase(DatabaseMetaData metaData) throws SQLException {
54 return new Database(
55 metaData.getDatabaseProductName(),
56 metaData.getDatabaseProductVersion(),
57 String.valueOf(metaData.getDatabaseMinorVersion()),
58 String.valueOf(metaData.getDatabaseMajorVersion()));
59 }
60
61 private static Driver getDriver(DatabaseMetaData metaData) throws SQLException {
62 return new Driver(
63 metaData.getDriverName(),
64 metaData.getDriverVersion());
65 }
66
67 private static boolean isConnectionException(SQLException e) {
68 return e instanceof SQLNonTransientConnectionException || e instanceof SQLTransientConnectionException;
69 }
70
71 private static final class Database {
72 private final String name;
73 private final String version;
74 private final String minorVersion;
75 private final String majorVersion;
76
77 Database(String name, String version, String minorVersion, String majorVersion) {
78 this.name = name;
79 this.version = version;
80 this.minorVersion = minorVersion;
81 this.majorVersion = majorVersion;
82 }
83
84 @Override
85 public String toString() {
86 return "Database:\n"
87 + "\t- name:" + name + "\n"
88 + "\t- version:" + version + "\n"
89 + "\t- minor version:" + minorVersion + "\n"
90 + "\t- major version:" + majorVersion;
91 }
92 }
93
94 private static final class Driver {
95 private final String name;
96 private final String version;
97
98 Driver(String name, String version) {
99 this.name = name;
100 this.version = version;
101 }
102
103 @Override
104 public String toString() {
105 return "Driver:\n"
106 + "\t- name:" + name + "\n"
107 + "\t- version:" + version;
108 }
109 }
110 }