Merge branch 'felix-work'
[gigi.git] / src / org / cacert / gigi / database / DatabaseConnection.java
1 package org.cacert.gigi.database;
2
3 import java.sql.Connection;
4 import java.sql.DriverManager;
5 import java.sql.PreparedStatement;
6 import java.sql.ResultSet;
7 import java.sql.SQLException;
8 import java.sql.Statement;
9 import java.util.HashMap;
10 import java.util.Properties;
11
12 public class DatabaseConnection {
13
14     public static final int CONNECTION_TIMEOUT = 24 * 60 * 60;
15
16     private Connection c;
17
18     private HashMap<String, GigiPreparedStatement> statements = new HashMap<String, GigiPreparedStatement>();
19
20     private static Properties credentials;
21
22     private Statement adHoc;
23
24     public DatabaseConnection() {
25         try {
26             Class.forName(credentials.getProperty("sql.driver"));
27         } catch (ClassNotFoundException e) {
28             e.printStackTrace();
29         }
30         tryConnect();
31
32     }
33
34     private void tryConnect() {
35         try {
36             c = DriverManager.getConnection(credentials.getProperty("sql.url") + "?zeroDateTimeBehavior=convertToNull", credentials.getProperty("sql.user"), credentials.getProperty("sql.password"));
37             PreparedStatement ps = c.prepareStatement("SET SESSION wait_timeout=?, time_zone='+0:00';");
38             ps.setInt(1, CONNECTION_TIMEOUT);
39             ps.execute();
40             ps.close();
41             adHoc = c.createStatement();
42         } catch (SQLException e) {
43             e.printStackTrace();
44         }
45     }
46
47     public GigiPreparedStatement prepare(String query) {
48         ensureOpen();
49         GigiPreparedStatement statement = statements.get(query);
50         if (statement == null) {
51             try {
52                 statement = new GigiPreparedStatement(c.prepareStatement(query, Statement.RETURN_GENERATED_KEYS));
53             } catch (SQLException e) {
54                 throw new Error(e);
55             }
56             statements.put(query, statement);
57         }
58         return statement;
59     }
60
61     private long lastAction = System.currentTimeMillis();
62
63     private void ensureOpen() {
64         if (System.currentTimeMillis() - lastAction > CONNECTION_TIMEOUT * 1000L) {
65             try {
66                 ResultSet rs = adHoc.executeQuery("SELECT 1");
67                 rs.close();
68                 lastAction = System.currentTimeMillis();
69                 return;
70             } catch (SQLException e) {
71             }
72             statements.clear();
73             tryConnect();
74         }
75         lastAction = System.currentTimeMillis();
76     }
77
78     private static ThreadLocal<DatabaseConnection> instances = new ThreadLocal<DatabaseConnection>() {
79
80         @Override
81         protected DatabaseConnection initialValue() {
82             return new DatabaseConnection();
83         }
84     };
85
86     public static DatabaseConnection getInstance() {
87         return instances.get();
88     }
89
90     public static boolean isInited() {
91         return credentials != null;
92     }
93
94     public static void init(Properties conf) {
95         if (credentials != null) {
96             throw new Error("Re-initiaizing is forbidden.");
97         }
98         credentials = conf;
99     }
100
101     public void beginTransaction() throws SQLException {
102         c.setAutoCommit(false);
103     }
104
105     public void commitTransaction() throws SQLException {
106         c.commit();
107         c.setAutoCommit(true);
108     }
109
110     public void quitTransaction() {
111         try {
112             if ( !c.getAutoCommit()) {
113                 c.rollback();
114                 c.setAutoCommit(true);
115             }
116         } catch (SQLException e) {
117             e.printStackTrace();
118         }
119     }
120 }