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
54 public class CounterPersistence extends BasePersistenceImpl {
55
56 public static int getCounterIncrement() {
57 return PropsValues.COUNTER_INCREMENT;
58 }
59
60 public List<String> getNames() throws SystemException {
61 Connection con = null;
62 PreparedStatement ps = null;
63 ResultSet rs = null;
64
65 try {
66 con = getConnection();
67
68 ps = con.prepareStatement(_SQL_SELECT_NAMES);
69
70 rs = ps.executeQuery();
71
72 List<String> list = new ArrayList<String>();
73
74 while (rs.next()) {
75 list.add(rs.getString(1));
76 }
77
78 return list;
79 }
80 catch (SQLException sqle) {
81 throw processException(sqle);
82 }
83 finally {
84 DataAccess.cleanUp(con, ps, rs);
85 }
86 }
87
88 public long increment() throws SystemException {
89 return increment(_NAME);
90 }
91
92 public long increment(String name) throws SystemException {
93 return increment(name, _MINIMUM_INCREMENT_SIZE);
94 }
95
96 public long increment(String name, int size) throws SystemException {
97 if (size < _MINIMUM_INCREMENT_SIZE) {
98 size = _MINIMUM_INCREMENT_SIZE;
99 }
100
101 CounterRegister register = getCounterRegister(name);
102
103 return competeIncrement(register, size);
104 }
105
106 public void rename(String oldName, String newName) throws SystemException {
107 CounterRegister register = getCounterRegister(oldName);
108
109 synchronized (register) {
110 if (_registerLookup.containsKey(newName)) {
111 throw new SystemException(
112 "Cannot rename " + oldName + " to " + newName);
113 }
114
115 Connection con = null;
116 PreparedStatement ps = null;
117
118 try {
119 con = getConnection();
120
121 ps = con.prepareStatement(_SQL_UPDATE_NAME_BY_NAME);
122
123 ps.setString(1, newName);
124 ps.setString(2, oldName);
125
126 ps.executeUpdate();
127 }
128 catch (ObjectNotFoundException onfe) {
129 }
130 catch (Exception e) {
131 throw processException(e);
132 }
133 finally {
134 DataAccess.cleanUp(con, ps);
135 }
136
137 register.setName(newName);
138
139 _registerLookup.put(newName, register);
140 _registerLookup.remove(oldName);
141 }
142 }
143
144 public void reset(String name) throws SystemException {
145 CounterRegister register = getCounterRegister(name);
146
147 synchronized (register) {
148 Connection con = null;
149 PreparedStatement ps = null;
150
151 try {
152 con = getConnection();
153
154 ps = con.prepareStatement(_SQL_DELETE_BY_NAME);
155
156 ps.setString(1, name);
157
158 ps.executeUpdate();
159 }
160 catch (ObjectNotFoundException onfe) {
161 }
162 catch (Exception e) {
163 throw processException(e);
164 }
165 finally {
166 DataAccess.cleanUp(con, ps);
167 }
168
169 _registerLookup.remove(name);
170 }
171 }
172
173 public void reset(String name, long size) throws SystemException {
174 CounterRegister register = createCounterRegister(name, size);
175
176 _registerLookup.put(name, register);
177 }
178
179 protected CounterRegister createCounterRegister(String name)
180 throws SystemException {
181
182 return createCounterRegister(name, -1);
183 }
184
185 protected CounterRegister createCounterRegister(String name, long size)
186 throws SystemException {
187
188 long rangeMin = -1;
189 long rangeMax = -1;
190
191 Connection con = null;
192 PreparedStatement ps = null;
193 ResultSet rs = null;
194
195 try {
196 con = getConnection();
197
198 ps = con.prepareStatement(_SQL_SELECT_ID_BY_NAME);
199
200 ps.setString(1, name);
201
202 rs = ps.executeQuery();
203
204 if (rs.next()) {
205 rangeMin = rs.getLong(1);
206 rangeMax = rangeMin + PropsValues.COUNTER_INCREMENT;
207
208 ps.close();
209
210 ps = con.prepareStatement(_SQL_UPDATE_ID_BY_NAME);
211
212 ps.setLong(1, rangeMax);
213 ps.setString(2, name);
214 }
215 else {
216 rangeMin = _DEFAULT_CURRENT_ID;
217 rangeMax = rangeMin + PropsValues.COUNTER_INCREMENT;
218
219 ps.close();
220
221 ps = con.prepareStatement(_SQL_INSERT);
222
223 ps.setString(1, name);
224 ps.setLong(2, rangeMax);
225 }
226
227 ps.executeUpdate();
228 }
229 catch (Exception e) {
230 throw processException(e);
231 }
232 finally {
233 DataAccess.cleanUp(con, ps, rs);
234 }
235
236 if (size > rangeMin) {
237 rangeMin = size;
238 }
239
240 CounterRegister register = new CounterRegister(
241 name, rangeMin, rangeMax, PropsValues.COUNTER_INCREMENT);
242
243 return register;
244 }
245
246 protected Connection getConnection() throws SQLException {
247 Connection con = getDataSource().getConnection();
248
249 con.setAutoCommit(true);
250
251 return con;
252 }
253
254 protected CounterRegister getCounterRegister(String name)
255 throws SystemException {
256
257 CounterRegister register = _registerLookup.get(name);
258
259 if (register != null) {
260 return register;
261 }
262 else {
263 synchronized (_registerLookup) {
264
265
267 register = _registerLookup.get(name);
268
269 if (register == null) {
270 register = createCounterRegister(name);
271
272 _registerLookup.put(name, register);
273 }
274
275 return register;
276 }
277 }
278 }
279
280 private long competeIncrement(CounterRegister register, int size)
281 throws SystemException {
282
283 CounterHolder holder = register.getCounterHolder();
284
285
287 long newValue = holder.addAndGet(size);
288
289 if (newValue <= holder.getRangeMax()) {
290 return newValue;
291 }
292
293
295 CompeteLatch latch = register.getCompeteLatch();
296
297 if (!latch.compete()) {
298
299
301 latch.await();
302
303
305 return competeIncrement(register, size);
306 }
307
308
310 Connection con = null;
311 PreparedStatement ps = null;
312 ResultSet rs = null;
313
314 try {
315
316
318 holder = register.getCounterHolder();
319 newValue = holder.addAndGet(size);
320
321 if (newValue > holder.getRangeMax()) {
322 con = getConnection();
323
324 ps = con.prepareStatement(_SQL_SELECT_ID_BY_NAME);
325
326 ps.setString(1, register.getName());
327
328 rs = ps.executeQuery();
329
330 rs.next();
331
332 long currentId = rs.getLong(1);
333
334 newValue = currentId + 1;
335 long rangeMax = currentId + register.getRangeSize();
336
337 ps.close();
338
339 ps = con.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(con, 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 }