1
2
3
4
5
6
7
8
9
10
11
12
13
14 package ch.qos.logback.core.db;
15
16 import java.lang.reflect.InvocationTargetException;
17 import java.lang.reflect.Method;
18 import java.sql.Connection;
19 import java.sql.PreparedStatement;
20 import java.sql.ResultSet;
21 import java.sql.SQLException;
22 import java.sql.Statement;
23
24 import ch.qos.logback.core.UnsynchronizedAppenderBase;
25 import ch.qos.logback.core.db.dialect.DBUtil;
26 import ch.qos.logback.core.db.dialect.SQLDialect;
27 import ch.qos.logback.core.db.dialect.SQLDialectCode;
28
29
30
31
32
33
34 public abstract class DBAppenderBase<E> extends UnsynchronizedAppenderBase<E> {
35
36 protected ConnectionSource connectionSource;
37 protected boolean cnxSupportsGetGeneratedKeys = false;
38 protected boolean cnxSupportsBatchUpdates = false;
39 protected SQLDialect sqlDialect;
40
41 protected abstract Method getGeneratedKeysMethod();
42
43 protected abstract String getInsertSQL();
44
45 @Override
46 public void start() {
47
48 if (connectionSource == null) {
49 throw new IllegalStateException("DBAppender cannot function without a connection source");
50 }
51
52 sqlDialect = DBUtil.getDialectFromCode(connectionSource.getSQLDialectCode());
53 if (getGeneratedKeysMethod() != null) {
54 cnxSupportsGetGeneratedKeys = connectionSource.supportsGetGeneratedKeys();
55 } else {
56 cnxSupportsGetGeneratedKeys = false;
57 }
58 cnxSupportsBatchUpdates = connectionSource.supportsBatchUpdates();
59 if (!cnxSupportsGetGeneratedKeys && (sqlDialect == null)) {
60 throw new IllegalStateException(
61 "DBAppender cannot function if the JDBC driver does not support getGeneratedKeys method *and* without a specific SQL dialect");
62 }
63
64
65 super.start();
66 }
67
68
69
70
71 public ConnectionSource getConnectionSource() {
72 return connectionSource;
73 }
74
75
76
77
78
79 public void setConnectionSource(ConnectionSource connectionSource) {
80 this.connectionSource = connectionSource;
81 }
82
83 @Override
84 public void append(E eventObject) {
85 Connection connection = null;
86 PreparedStatement insertStatement = null;
87 try {
88 connection = connectionSource.getConnection();
89 connection.setAutoCommit(false);
90
91 if (cnxSupportsGetGeneratedKeys) {
92 String EVENT_ID_COL_NAME = "EVENT_ID";
93
94 if (connectionSource.getSQLDialectCode() == SQLDialectCode.POSTGRES_DIALECT) {
95 EVENT_ID_COL_NAME = EVENT_ID_COL_NAME.toLowerCase();
96 }
97 insertStatement = connection.prepareStatement(getInsertSQL(), new String[] { EVENT_ID_COL_NAME });
98 } else {
99 insertStatement = connection.prepareStatement(getInsertSQL());
100 }
101
102 long eventId;
103
104 synchronized (this) {
105 subAppend(eventObject, connection, insertStatement);
106 eventId = selectEventId(insertStatement, connection);
107 }
108 secondarySubAppend(eventObject, connection, eventId);
109
110 connection.commit();
111 } catch (Throwable sqle) {
112 addError("problem appending event", sqle);
113 } finally {
114 DBHelper.closeStatement(insertStatement);
115 DBHelper.closeConnection(connection);
116 }
117 }
118
119 protected abstract void subAppend(E eventObject, Connection connection, PreparedStatement statement) throws Throwable;
120
121 protected abstract void secondarySubAppend(E eventObject, Connection connection, long eventId) throws Throwable;
122
123 @SuppressWarnings("resource")
124 protected long selectEventId(PreparedStatement insertStatement, Connection connection) throws SQLException, InvocationTargetException {
125 ResultSet rs = null;
126 Statement idStatement = null;
127 try {
128 boolean gotGeneratedKeys = false;
129 if (cnxSupportsGetGeneratedKeys) {
130 try {
131 rs = (ResultSet) getGeneratedKeysMethod().invoke(insertStatement, (Object[]) null);
132 gotGeneratedKeys = true;
133 } catch (InvocationTargetException ex) {
134 Throwable target = ex.getTargetException();
135 if (target instanceof SQLException) {
136 throw (SQLException) target;
137 }
138 throw ex;
139 } catch (IllegalAccessException ex) {
140 addWarn("IllegalAccessException invoking PreparedStatement.getGeneratedKeys", ex);
141 }
142 }
143
144 if (!gotGeneratedKeys) {
145 idStatement = connection.createStatement();
146 idStatement.setMaxRows(1);
147 String selectInsertIdStr = sqlDialect.getSelectInsertId();
148 rs = idStatement.executeQuery(selectInsertIdStr);
149 }
150
151
152
153 rs.next();
154 long eventId = rs.getLong(1);
155 return eventId;
156 } finally {
157 if (rs != null) {
158 try {
159 rs.close();
160 } catch (SQLException e) {
161 }
162 }
163 DBHelper.closeStatement(idStatement);
164 }
165 }
166
167 @Override
168 public void stop() {
169 super.stop();
170 }
171 }