1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package fr.paris.lutece.util.sql;
35
36 import fr.paris.lutece.portal.service.database.AppConnectionService;
37 import fr.paris.lutece.portal.service.database.PluginConnectionService;
38 import fr.paris.lutece.portal.service.plugin.Plugin;
39 import fr.paris.lutece.portal.service.util.AppException;
40
41 import org.apache.commons.lang3.StringUtils;
42 import org.apache.logging.log4j.LogManager;
43 import org.apache.logging.log4j.Logger;
44
45 import java.sql.Connection;
46 import java.sql.PreparedStatement;
47 import java.sql.SQLException;
48
49
50
51
52 public class Transaction
53 {
54
55
56
57 public static final int OPENED = -1;
58
59
60
61
62 public static final int COMMITTED = 0;
63
64
65
66
67 public static final int ROLLEDBACK = 1;
68 private static final String MESSAGE_PLUGIN = "Plugin : '";
69 private static final String DEFAULT_MODULE_NAME = "core";
70 private static final String LOGGER_DEBUG_SQL = "lutece.debug.sql.";
71
72
73
74
75 private String _strSQL = StringUtils.EMPTY;
76
77
78 private Connection _connection;
79
80
81 private PluginConnectionService _connectionService;
82
83
84 private String _strPluginName;
85
86
87 private Logger _logger;
88 private PreparedStatement _statement;
89 private int _nStatus = OPENED;
90 private boolean _bAutoCommit;
91
92
93
94
95 public Transaction( )
96 {
97 beginTransaction( null );
98 }
99
100
101
102
103
104
105
106 public Transaction( Plugin plugin )
107 {
108 beginTransaction( plugin );
109 }
110
111
112
113
114
115
116
117
118
119
120 public PreparedStatement prepareStatement( String strSQL ) throws SQLException
121 {
122 return prepareStatement( strSQL, null, true );
123 }
124
125
126
127
128
129
130
131
132
133
134 public PreparedStatement prepareStatement( String strSQL, Integer autoGeneratedKeys ) throws SQLException
135 {
136 return prepareStatement( strSQL, autoGeneratedKeys, true );
137 }
138
139
140
141
142
143
144
145
146
147
148 public PreparedStatement prepareStatement( String strSQL, boolean bLogQueries ) throws SQLException
149 {
150 return prepareStatement( strSQL, null, bLogQueries );
151 }
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166 public PreparedStatement prepareStatement( String strSQL, Integer autoGeneratedKeys, boolean bLogQueries ) throws SQLException
167 {
168
169 if ( _statement != null )
170 {
171 _statement.close( );
172 }
173
174
175 _strSQL = strSQL;
176
177 if ( _connection == null )
178 {
179 throw new SQLException( MESSAGE_PLUGIN + _strPluginName + "' - Connection has been closed. The new prepared statement can not be created : "
180 + ( bLogQueries ? _strSQL : "(query log disabled)" ) );
181 }
182
183 if ( autoGeneratedKeys != null )
184 {
185 _statement = _connection.prepareStatement( _strSQL, autoGeneratedKeys );
186 }
187 else
188 {
189 _statement = _connection.prepareStatement( _strSQL );
190 }
191
192 return _statement;
193 }
194
195
196
197
198
199
200 public PreparedStatement getStatement( )
201 {
202 return _statement;
203 }
204
205
206
207
208
209
210
211 public void executeStatement( ) throws SQLException
212 {
213 _logger.debug( "{} {}' - EXECUTE STATEMENT : {}", MESSAGE_PLUGIN, _strPluginName, _strSQL );
214 _statement.executeUpdate( );
215 }
216
217
218
219
220 public void commit( )
221 {
222 try
223 {
224 if ( _connection == null )
225 {
226 throw new SQLException( MESSAGE_PLUGIN + _strPluginName + "' - Transaction has already been closed and can not be committed" );
227 }
228
229 _connection.commit( );
230 _logger.debug( "{} {}' - COMMIT TRANSACTION", MESSAGE_PLUGIN, _strPluginName );
231 closeTransaction( COMMITTED );
232 }
233 catch( SQLException e )
234 {
235 rollback( e );
236 }
237 }
238
239
240
241
242 public void rollback( )
243 {
244 rollback( null );
245 }
246
247
248
249
250
251
252
253 public void rollback( Exception e )
254 {
255 if ( e != null )
256 {
257 _logger.error( "Transaction Error - Rollback in progress {}", e.getMessage( ), e.getCause( ) );
258 }
259
260 try
261 {
262 if ( _connection != null )
263 {
264 _connection.rollback( );
265 _logger.debug( "{} {}' - ROLLBACK TRANSACTION", MESSAGE_PLUGIN, _strPluginName );
266 }
267 else
268 {
269 _logger.debug( "{} {}' - TRANSACTION HAS ALREADY BEEN ROLLED BACK", MESSAGE_PLUGIN, _strPluginName );
270 }
271 }
272 catch( SQLException ex )
273 {
274 _logger.error( "Transaction Error - Rollback error : {}", ex.getMessage( ), ex );
275 }
276 finally
277 {
278 closeTransaction( ROLLEDBACK );
279 }
280 }
281
282
283
284
285
286
287 public int getStatus( )
288 {
289 return _nStatus;
290 }
291
292
293
294
295
296
297 protected Connection getConnection( )
298 {
299 return _connection;
300 }
301
302
303
304
305
306
307
308 protected void beginTransaction( Plugin plugin )
309 {
310 if ( plugin != null )
311 {
312 _strPluginName = plugin.getName( );
313 _connectionService = plugin.getConnectionService( );
314 }
315 else
316 {
317 _strPluginName = DEFAULT_MODULE_NAME;
318 _connectionService = AppConnectionService.getDefaultConnectionService( );
319 }
320
321 if ( _connectionService == null )
322 {
323 throw new AppException( "Database access error. Please check component installations and db.properties." );
324 }
325
326 _logger = LogManager.getLogger( LOGGER_DEBUG_SQL + _strPluginName );
327 _logger.debug( "{}{}' - BEGIN TRANSACTION", MESSAGE_PLUGIN, _strPluginName );
328
329 try
330 {
331 _connection = _connectionService.getConnection( );
332
333
334 _bAutoCommit = _connection.getAutoCommit( );
335 _connection.setAutoCommit( false );
336 }
337 catch( SQLException e )
338 {
339 rollback( e );
340 }
341 }
342
343
344
345
346
347
348
349 private void closeTransaction( int nStatus )
350 {
351 _nStatus = nStatus;
352
353 try
354 {
355 if ( _statement != null )
356 {
357 _statement.close( );
358 }
359
360
361 if ( _connection != null )
362 {
363 _connection.setAutoCommit( _bAutoCommit );
364 }
365 }
366 catch( SQLException ex )
367 {
368 _logger.error( "Transaction Error - Unable to close transaction {}", ex.getMessage( ), ex );
369 }
370 finally
371 {
372 _connectionService.freeConnection( _connection );
373 _connection = null;
374 }
375 }
376
377
378
379
380
381 @Override
382 protected void finalize( ) throws Throwable
383 {
384 if ( _nStatus == OPENED )
385 {
386 _logger.error( "The transaction has not been commited" );
387 closeTransaction( OPENED );
388 }
389
390 super.finalize( );
391 }
392 }