1
22
23 package com.liferay.counter.service.persistence;
24
25 import com.liferay.counter.model.Counter;
26 import com.liferay.counter.model.CounterHolder;
27 import com.liferay.counter.model.CounterRegister;
28 import com.liferay.portal.SystemException;
29 import com.liferay.portal.kernel.concurrent.CompeteLatch;
30 import com.liferay.portal.kernel.dao.jdbc.DataAccess;
31 import com.liferay.portal.kernel.dao.orm.ObjectNotFoundException;
32 import com.liferay.portal.service.persistence.impl.BasePersistenceImpl;
33 import com.liferay.portal.util.PropsValues;
34
35 import java.sql.Connection;
36 import java.sql.PreparedStatement;
37 import java.sql.ResultSet;
38 import java.sql.SQLException;
39
40 import java.util.ArrayList;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.concurrent.ConcurrentHashMap;
44
45
53 public class CounterPersistence extends BasePersistenceImpl {
54
55 public static int getCounterIncrement() {
56 return PropsValues.COUNTER_INCREMENT;
57 }
58
59 public List<String> getNames() throws SystemException {
60 Connection connection = null;
61 PreparedStatement ps = null;
62 ResultSet rs = null;
63
64 try {
65 connection = getConnection();
66
67 ps = connection.prepareStatement(_SQL_SELECT_NAMES);
68
69 rs = ps.executeQuery();
70
71 List<String> list = new ArrayList<String>();
72
73 while (rs.next()) {
74 list.add(rs.getString(1));
75 }
76
77 return list;
78 }
79 catch (SQLException sqle) {
80 throw processException(sqle);
81 }
82 finally {
83 DataAccess.cleanUp(connection, ps, rs);
84 }
85 }
86
87 public long increment() throws SystemException {
88 return increment(_NAME);
89 }
90
91 public long increment(String name) throws SystemException {
92 return increment(name, _MINIMUM_INCREMENT_SIZE);
93 }
94
95 public long increment(String name, int size) throws SystemException {
96 if (size < _MINIMUM_INCREMENT_SIZE) {
97 size = _MINIMUM_INCREMENT_SIZE;
98 }
99
100 CounterRegister register = getCounterRegister(name);
101
102 return competeIncrement(register, size);
103 }
104
105 public void rename(String oldName, String newName) throws SystemException {
106 CounterRegister register = getCounterRegister(oldName);
107
108 synchronized (register) {
109 if (_registerLookup.containsKey(newName)) {
110 throw new SystemException(
111 "Cannot rename " + oldName + " to " + newName);
112 }
113
114 Connection connection = null;
115 PreparedStatement ps = null;
116
117 try {
118 connection = getConnection();
119
120 ps = connection.prepareStatement(_SQL_UPDATE_NAME_BY_NAME);
121
122 ps.setString(1, newName);
123 ps.setString(2, oldName);
124
125 ps.executeUpdate();
126 }
127 catch (ObjectNotFoundException onfe) {
128 }
129 catch (Exception e) {
130 throw processException(e);
131 }
132 finally {
133 DataAccess.cleanUp(connection, ps);
134 }
135
136 register.setName(newName);
137
138 _registerLookup.put(newName, register);
139 _registerLookup.remove(oldName);
140 }
141 }
142
143 public void reset(String name) throws SystemException {
144 CounterRegister register = getCounterRegister(name);
145
146 synchronized (register) {
147 Connection connection = null;
148 PreparedStatement ps = null;
149
150 try {
151 connection = getConnection();
152
153 ps = connection.prepareStatement(_SQL_DELETE_BY_NAME);
154
155 ps.setString(1, name);
156
157 ps.executeUpdate();
158 }
159 catch (ObjectNotFoundException onfe) {
160 }
161 catch (Exception e) {
162 throw processException(e);
163 }
164 finally {
165 DataAccess.cleanUp(connection, ps);
166 }
167
168 _registerLookup.remove(name);
169 }
170 }
171
172 public void reset(String name, long size) throws SystemException {
173 CounterRegister register = createCounterRegister(name, size);
174
175 _registerLookup.put(name, register);
176 }
177
178 protected CounterRegister createCounterRegister(String name)
179 throws SystemException {
180
181 return createCounterRegister(name, -1);
182 }
183
184 protected CounterRegister createCounterRegister(String name, long size)
185 throws SystemException {
186
187 long rangeMin = -1;
188 long rangeMax = -1;
189
190 Connection connection = null;
191 PreparedStatement ps = null;
192 ResultSet rs = null;
193
194 try {
195 connection = getConnection();
196
197 ps = connection.prepareStatement(_SQL_SELECT_ID_BY_NAME);
198
199 ps.setString(1, name);
200
201 rs = ps.executeQuery();
202
203 if (rs.next()) {
204 rangeMin = rs.getLong(1);
205 rangeMax = rangeMin + PropsValues.COUNTER_INCREMENT;
206
207 ps.close();
208
209 ps = connection.prepareStatement(_SQL_UPDATE_ID_BY_NAME);
210
211 ps.setLong(1, rangeMax);
212 ps.setString(2, name);
213 }
214 else {
215 rangeMin = _DEFAULT_CURRENT_ID;
216 rangeMax = rangeMin + PropsValues.COUNTER_INCREMENT;
217
218 ps.close();
219
220 ps = connection.prepareStatement(_SQL_INSERT);
221
222 ps.setString(1, name);
223 ps.setLong(2, rangeMax);
224 }
225
226 ps.executeUpdate();
227 }
228 catch (Exception e) {
229 throw processException(e);
230 }
231 finally {
232 DataAccess.cleanUp(connection, ps, rs);
233 }
234
235 if (size > rangeMin) {
236 rangeMin = size;
237 }
238
239 CounterRegister register = new CounterRegister(
240 name, rangeMin, rangeMax, PropsValues.COUNTER_INCREMENT);
241
242 return register;
243 }
244
245 protected Connection getConnection() throws SQLException {
246 Connection connection = getDataSource().getConnection();
247
248 connection.setAutoCommit(true);
249
250 return connection;
251 }
252
253 protected CounterRegister getCounterRegister(String name)
254 throws SystemException {
255
256 CounterRegister register = _registerLookup.get(name);
257
258 if (register != null) {
259 return register;
260 }
261 else {
262 synchronized (_registerLookup) {
263
264
266 register = _registerLookup.get(name);
267
268 if (register == null) {
269 register = createCounterRegister(name);
270
271 _registerLookup.put(name, register);
272 }
273
274 return register;
275 }
276 }
277 }
278
279 private long competeIncrement(CounterRegister register, int size)
280 throws SystemException {
281
282 CounterHolder holder = register.getCounterHolder();
283
284
286 long newValue = holder.addAndGet(size);
287
288 if (newValue <= holder.getRangeMax()) {
289 return newValue;
290 }
291
292
294 CompeteLatch latch = register.getCompeteLatch();
295
296 if (!latch.compete()) {
297
298
300 latch.await();
301
302
304 return competeIncrement(register, size);
305 }
306
307
309 Connection connection = null;
310 PreparedStatement ps = null;
311 ResultSet rs = null;
312
313 try {
314
315
317 holder = register.getCounterHolder();
318 newValue = holder.addAndGet(size);
319
320 if (newValue > holder.getRangeMax()) {
321 connection = getConnection();
322
323 ps = connection.prepareStatement(_SQL_SELECT_ID_BY_NAME);
324
325 ps.setString(1, register.getName());
326
327 rs = ps.executeQuery();
328
329 rs.next();
330
331 long currentId = rs.getLong(1);
332
333 newValue = currentId + 1;
334 long rangeMax = currentId + register.getRangeSize();
335
336 ps.close();
337
338 ps = connection.prepareStatement(_SQL_UPDATE_ID_BY_NAME);
339
340 ps.setLong(1, rangeMax);
341 ps.setString(2, register.getName());
342
343 ps.executeUpdate();
344
345 register.setCounterHolder(
346 new CounterHolder(newValue, rangeMax));
347 }
348 }
349 catch (Exception e) {
350 throw processException(e);
351 }
352 finally {
353 DataAccess.cleanUp(connection, ps, rs);
354
355
357 latch.done();
358 }
359
360 return newValue;
361 }
362
363 private static final int _DEFAULT_CURRENT_ID = 0;
364
365 private static final int _MINIMUM_INCREMENT_SIZE = 1;
366
367 private static final String _NAME = Counter.class.getName();
368
369 private static final String _SQL_DELETE_BY_NAME =
370 "delete from Counter where name = ?";
371
372 private static final String _SQL_INSERT =
373 "insert into Counter(name, currentId) values (?, ?)";
374
375 private static final String _SQL_SELECT_ID_BY_NAME =
376 "select currentId from Counter where name = ?";
377
378 private static final String _SQL_SELECT_NAMES =
379 "select name from Counter order by name asc";
380
381 private static final String _SQL_UPDATE_ID_BY_NAME =
382 "update Counter set currentId = ? where name = ?";
383
384 private static final String _SQL_UPDATE_NAME_BY_NAME =
385 "update Counter set name = ? where name = ?";
386
387 private static final Map<String, CounterRegister> _registerLookup =
388 new ConcurrentHashMap<String, CounterRegister>();
389
390 }