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 package com.s3auth.hosts;
31
32 import com.jcabi.aspects.Immutable;
33 import com.jcabi.aspects.Loggable;
34 import com.jcabi.jdbc.JdbcSession;
35 import com.jcabi.jdbc.Outcome;
36 import java.io.File;
37 import java.io.IOException;
38 import java.sql.Connection;
39 import java.sql.ResultSet;
40 import java.sql.SQLException;
41 import java.sql.Statement;
42 import java.util.HashMap;
43 import java.util.Map;
44 import java.util.Properties;
45 import lombok.EqualsAndHashCode;
46 import org.h2.Driver;
47
48
49
50
51
52
53
54
55 @Immutable
56 @EqualsAndHashCode(of = "jdbc")
57 @Loggable(Loggable.DEBUG)
58 final class H2DomainStatsData implements DomainStatsData {
59
60
61
62 private static final String CREATE = new StringBuilder("CREATE TABLE ")
63 .append("IF NOT EXISTS DOMAIN_STATS( ")
64 .append("ID INT IDENTITY,")
65 .append("DOMAIN VARCHAR(255),")
66 .append("BYTES INT,")
67 .append("CREATE_TIME TIMESTAMP")
68 .append(" )").toString();
69
70
71
72
73 private static final String INSERT = new StringBuilder("INSERT INTO ")
74 .append("DOMAIN_STATS (DOMAIN, BYTES, CREATE_TIME) ")
75 .append("values (?, ?, CURRENT_TIMESTAMP())").toString();
76
77
78
79
80 private static final Outcome<Stats> STATS = new Outcome<Stats>() {
81 @Override
82 public Stats handle(final ResultSet rset, final Statement stmt)
83 throws SQLException {
84 rset.next();
85 return new Stats.Simple(rset.getLong(1));
86 }
87 };
88
89
90
91
92 private static final Outcome<Map<String, Stats>> STATS_ALL =
93 new Outcome<Map<String, Stats>>() {
94 @Override
95 @SuppressWarnings("PMD.UseConcurrentHashMap")
96 public Map<String, Stats> handle(final ResultSet rset,
97 final Statement stmt) throws SQLException {
98 final Map<String, Stats> stats = new HashMap<String, Stats>();
99 while (rset.next()) {
100 stats.put(
101 rset.getString(1), new Stats.Simple(rset.getLong(2))
102 );
103 }
104 return stats;
105 }
106 };
107
108
109
110
111 private final transient String jdbc;
112
113
114
115
116
117 H2DomainStatsData() throws IOException {
118 this(new File("s3auth-domainStats"));
119 }
120
121
122
123
124
125
126 H2DomainStatsData(final File file) throws IOException {
127 this.jdbc = String.format("jdbc:h2:file:%s", file.getAbsolutePath());
128 try {
129 new JdbcSession(this.connection()).sql(CREATE).execute();
130 } catch (final SQLException ex) {
131 throw new IOException(ex);
132 }
133 }
134
135 @Override
136 public void put(final String domain, final Stats stats) throws IOException {
137 try {
138 new JdbcSession(this.connection())
139 .sql(INSERT)
140 .set(domain)
141 .set(stats.bytesTransferred())
142 .execute();
143 } catch (final SQLException ex) {
144 throw new IOException(ex);
145 }
146 }
147
148 @Override
149 public Stats get(final String domain) throws IOException {
150 try {
151 final JdbcSession session = new JdbcSession(this.connection())
152 .autocommit(false);
153
154 final Stats result = session
155 .sql("SELECT SUM(BYTES) FROM DOMAIN_STATS WHERE DOMAIN = ? FOR UPDATE")
156 .set(domain)
157 .select(STATS);
158 session.sql("DELETE FROM DOMAIN_STATS WHERE DOMAIN = ?")
159 .set(domain)
160 .execute()
161 .commit();
162 return result;
163 } catch (final SQLException ex) {
164 throw new IOException(ex);
165 }
166 }
167
168 @Override
169 @SuppressWarnings("PMD.UseConcurrentHashMap")
170 public Map<String, Stats> all() throws IOException {
171 try {
172 final JdbcSession session = new JdbcSession(this.connection())
173 .autocommit(false);
174
175 final Map<String, Stats> result = session
176 .sql("SELECT DOMAIN, SUM(BYTES) FROM DOMAIN_STATS GROUP BY DOMAIN FOR UPDATE")
177 .select(STATS_ALL);
178 session.sql("DELETE FROM DOMAIN_STATS").execute().commit();
179 return result;
180 } catch (final SQLException ex) {
181 throw new IOException(ex);
182 }
183 }
184
185
186
187
188
189
190 private Connection connection() throws SQLException {
191 return new Driver().connect(this.jdbc, new Properties());
192 }
193 }