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.model.Dummy;
33 import com.liferay.portal.service.persistence.impl.BasePersistenceImpl;
34 import com.liferay.portal.util.PropsValues;
35
36 import java.sql.Connection;
37 import java.sql.PreparedStatement;
38 import java.sql.ResultSet;
39 import java.sql.SQLException;
40
41 import java.util.ArrayList;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.concurrent.ConcurrentHashMap;
45
46
54 public class CounterPersistenceImpl
55 extends BasePersistenceImpl<Dummy> implements CounterPersistence {
56
57 public List<String> getNames() throws SystemException {
58 Connection connection = null;
59 PreparedStatement ps = null;
60 ResultSet rs = null;
61
62 try {
63 connection = getConnection();
64
65 ps = connection.prepareStatement(_SQL_SELECT_NAMES);
66
67 rs = ps.executeQuery();
68
69 List<String> list = new ArrayList<String>();
70
71 while (rs.next()) {
72 list.add(rs.getString(1));
73 }
74
75 return list;
76 }
77 catch (SQLException sqle) {
78 throw processException(sqle);
79 }
80 finally {
81 DataAccess.cleanUp(connection, ps, rs);
82 }
83 }
84
85 public long increment() throws SystemException {
86 return increment(_NAME);
87 }
88
89 public long increment(String name) throws SystemException {
90 return increment(name, _MINIMUM_INCREMENT_SIZE);
91 }
92
93 public long increment(String name, int size) throws SystemException {
94 if (size < _MINIMUM_INCREMENT_SIZE) {
95 size = _MINIMUM_INCREMENT_SIZE;
96 }
97
98 CounterRegister register = getCounterRegister(name);
99
100 return competeIncrement(register, size);
101 }
102
103 public void rename(String oldName, String newName) throws SystemException {
104 CounterRegister register = getCounterRegister(oldName);
105
106 synchronized (register) {
107 if (_registerLookup.containsKey(newName)) {
108 throw new SystemException(
109 "Cannot rename " + oldName + " to " + newName);
110 }
111
112 Connection connection = null;
113 PreparedStatement ps = null;
114
115 try {
116 connection = getConnection();
117
118 ps = connection.prepareStatement(_SQL_UPDATE_NAME_BY_NAME);
119
120 ps.setString(1, newName);
121 ps.setString(2, oldName);
122
123 ps.executeUpdate();
124 }
125 catch (ObjectNotFoundException onfe) {
126 }
127 catch (Exception e) {
128 throw processException(e);
129 }
130 finally {
131 DataAccess.cleanUp(connection, ps);
132 }
133
134 register.setName(newName);
135
136 _registerLookup.put(newName, register);
137 _registerLookup.remove(oldName);
138 }
139 }
140
141 public void reset(String name) throws SystemException {
142 CounterRegister register = getCounterRegister(name);
143
144 synchronized (register) {
145 Connection connection = null;
146 PreparedStatement ps = null;
147
148 try {
149 connection = getConnection();
150
151 ps = connection.prepareStatement(_SQL_DELETE_BY_NAME);
152
153 ps.setString(1, name);
154
155 ps.executeUpdate();
156 }
157 catch (ObjectNotFoundException onfe) {
158 }
159 catch (Exception e) {
160 throw processException(e);
161 }
162 finally {
163 DataAccess.cleanUp(connection, ps);
164 }
165
166 _registerLookup.remove(name);
167 }
168 }
169
170 public void reset(String name, long size) throws SystemException {
171 CounterRegister register = createCounterRegister(name, size);
172
173 _registerLookup.put(name, register);
174 }
175
176 protected CounterRegister createCounterRegister(String name)
177 throws SystemException {
178
179 return createCounterRegister(name, -1);
180 }
181
182 protected CounterRegister createCounterRegister(String name, long size)
183 throws SystemException {
184
185 long rangeMin = -1;
186 long rangeMax = -1;
187
188 Connection connection = null;
189 PreparedStatement ps = null;
190 ResultSet rs = null;
191
192 try {
193 connection = getConnection();
194
195 ps = connection.prepareStatement(_SQL_SELECT_ID_BY_NAME);
196
197 ps.setString(1, name);
198
199 rs = ps.executeQuery();
200
201 if (rs.next()) {
202 rangeMin = rs.getLong(1);
203 rangeMax = rangeMin + PropsValues.COUNTER_INCREMENT;
204
205 rs.close();
206 ps.close();
207
208 ps = connection.prepareStatement(_SQL_UPDATE_ID_BY_NAME);
209
210 ps.setLong(1, rangeMax);
211 ps.setString(2, name);
212 }
213 else {
214 rangeMin = _DEFAULT_CURRENT_ID;
215 rangeMax = rangeMin + PropsValues.COUNTER_INCREMENT;
216
217 rs.close();
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 rs.close();
337 ps.close();
338
339 ps = connection.prepareStatement(_SQL_UPDATE_ID_BY_NAME);
340
341 ps.setLong(1, rangeMax);
342 ps.setString(2, register.getName());
343
344 ps.executeUpdate();
345
346 register.setCounterHolder(
347 new CounterHolder(newValue, rangeMax));
348 }
349 }
350 catch (Exception e) {
351 throw processException(e);
352 }
353 finally {
354 DataAccess.cleanUp(connection, ps, rs);
355
356
358 latch.done();
359 }
360
361 return newValue;
362 }
363
364 private static final int _DEFAULT_CURRENT_ID = 0;
365
366 private static final int _MINIMUM_INCREMENT_SIZE = 1;
367
368 private static final String _NAME = Counter.class.getName();
369
370 private static final String _SQL_DELETE_BY_NAME =
371 "delete from Counter where name = ?";
372
373 private static final String _SQL_INSERT =
374 "insert into Counter(name, currentId) values (?, ?)";
375
376 private static final String _SQL_SELECT_ID_BY_NAME =
377 "select currentId from Counter where name = ?";
378
379 private static final String _SQL_SELECT_NAMES =
380 "select name from Counter order by name asc";
381
382 private static final String _SQL_UPDATE_ID_BY_NAME =
383 "update Counter set currentId = ? where name = ?";
384
385 private static final String _SQL_UPDATE_NAME_BY_NAME =
386 "update Counter set name = ? where name = ?";
387
388 private static final Map<String, CounterRegister> _registerLookup =
389 new ConcurrentHashMap<String, CounterRegister>();
390
391 }