001
014
015 package com.liferay.counter.service.persistence.impl;
016
017 import com.liferay.counter.model.Counter;
018 import com.liferay.counter.model.CounterHolder;
019 import com.liferay.counter.model.CounterRegister;
020 import com.liferay.counter.model.impl.CounterImpl;
021 import com.liferay.counter.service.persistence.CounterFinder;
022 import com.liferay.portal.kernel.cache.CacheRegistryItem;
023 import com.liferay.portal.kernel.cache.CacheRegistryUtil;
024 import com.liferay.portal.kernel.concurrent.CompeteLatch;
025 import com.liferay.portal.kernel.dao.jdbc.DataAccess;
026 import com.liferay.portal.kernel.dao.orm.LockMode;
027 import com.liferay.portal.kernel.dao.orm.ObjectNotFoundException;
028 import com.liferay.portal.kernel.dao.orm.Session;
029 import com.liferay.portal.kernel.exception.SystemException;
030 import com.liferay.portal.kernel.util.CharPool;
031 import com.liferay.portal.kernel.util.GetterUtil;
032 import com.liferay.portal.kernel.util.PropsKeys;
033 import com.liferay.portal.model.Dummy;
034 import com.liferay.portal.service.persistence.impl.BasePersistenceImpl;
035 import com.liferay.portal.util.PropsUtil;
036 import com.liferay.portal.util.PropsValues;
037
038 import java.sql.Connection;
039 import java.sql.PreparedStatement;
040 import java.sql.ResultSet;
041 import java.sql.SQLException;
042
043 import java.util.ArrayList;
044 import java.util.List;
045 import java.util.Map;
046 import java.util.concurrent.ConcurrentHashMap;
047
048
055 public class CounterFinderImpl
056 extends BasePersistenceImpl<Dummy>
057 implements CacheRegistryItem, CounterFinder {
058
059 @Override
060 public void afterPropertiesSet() {
061 CacheRegistryUtil.register(this);
062 }
063
064 @Override
065 public List<String> getNames() {
066 Connection connection = null;
067 PreparedStatement preparedStatement = null;
068 ResultSet resultSet = null;
069
070 try {
071 connection = getConnection();
072
073 preparedStatement = connection.prepareStatement(_SQL_SELECT_NAMES);
074
075 resultSet = preparedStatement.executeQuery();
076
077 List<String> list = new ArrayList<String>();
078
079 while (resultSet.next()) {
080 list.add(resultSet.getString(1));
081 }
082
083 return list;
084 }
085 catch (SQLException sqle) {
086 throw processException(sqle);
087 }
088 finally {
089 DataAccess.cleanUp(connection, preparedStatement, resultSet);
090 }
091 }
092
093 @Override
094 public String getRegistryName() {
095 return CounterFinderImpl.class.getName();
096 }
097
098 @Override
099 public long increment() {
100 return increment(_NAME);
101 }
102
103 @Override
104 public long increment(String name) {
105 return increment(name, _MINIMUM_INCREMENT_SIZE);
106 }
107
108 @Override
109 public long increment(String name, int size) {
110 if (size < _MINIMUM_INCREMENT_SIZE) {
111 size = _MINIMUM_INCREMENT_SIZE;
112 }
113
114 CounterRegister counterRegister = getCounterRegister(name);
115
116 return _competeIncrement(counterRegister, size);
117 }
118
119 @Override
120 public void invalidate() {
121 _counterRegisterMap.clear();
122 }
123
124 @Override
125 public void rename(String oldName, String newName) {
126 CounterRegister counterRegister = getCounterRegister(oldName);
127
128 synchronized (counterRegister) {
129 if (_counterRegisterMap.containsKey(newName)) {
130 throw new SystemException(
131 "Cannot rename " + oldName + " to " + newName);
132 }
133
134 Connection connection = null;
135 PreparedStatement preparedStatement = null;
136
137 try {
138 connection = getConnection();
139
140 preparedStatement = connection.prepareStatement(
141 _SQL_UPDATE_NAME_BY_NAME);
142
143 preparedStatement.setString(1, newName);
144 preparedStatement.setString(2, oldName);
145
146 preparedStatement.executeUpdate();
147 }
148 catch (ObjectNotFoundException onfe) {
149 }
150 catch (Exception e) {
151 throw processException(e);
152 }
153 finally {
154 DataAccess.cleanUp(connection, preparedStatement);
155 }
156
157 counterRegister.setName(newName);
158
159 _counterRegisterMap.put(newName, counterRegister);
160 _counterRegisterMap.remove(oldName);
161 }
162 }
163
164 @Override
165 public void reset(String name) {
166 CounterRegister counterRegister = getCounterRegister(name);
167
168 synchronized (counterRegister) {
169 Session session = null;
170
171 try {
172 session = openSession();
173
174 Counter counter = (Counter)session.get(CounterImpl.class, name);
175
176 session.delete(counter);
177
178 session.flush();
179 }
180 catch (ObjectNotFoundException onfe) {
181 }
182 catch (Exception e) {
183 throw processException(e);
184 }
185 finally {
186 closeSession(session);
187 }
188
189 _counterRegisterMap.remove(name);
190 }
191 }
192
193 @Override
194 public void reset(String name, long size) {
195 CounterRegister counterRegister = createCounterRegister(name, size);
196
197 _counterRegisterMap.put(name, counterRegister);
198 }
199
200 protected CounterRegister createCounterRegister(String name) {
201 return createCounterRegister(name, -1);
202 }
203
204 protected CounterRegister createCounterRegister(String name, long size) {
205 long rangeMin = -1;
206 int rangeSize = getRangeSize(name);
207
208 Connection connection = null;
209 PreparedStatement preparedStatement = null;
210 ResultSet resultSet = null;
211
212 try {
213 connection = getConnection();
214
215 preparedStatement = connection.prepareStatement(
216 _SQL_SELECT_ID_BY_NAME);
217
218 preparedStatement.setString(1, name);
219
220 resultSet = preparedStatement.executeQuery();
221
222 if (!resultSet.next()) {
223 rangeMin = _DEFAULT_CURRENT_ID;
224
225 if (size > rangeMin) {
226 rangeMin = size;
227 }
228
229 resultSet.close();
230 preparedStatement.close();
231
232 preparedStatement = connection.prepareStatement(_SQL_INSERT);
233
234 preparedStatement.setString(1, name);
235 preparedStatement.setLong(2, rangeMin);
236
237 preparedStatement.executeUpdate();
238 }
239 }
240 catch (Exception e) {
241 throw processException(e);
242 }
243 finally {
244 DataAccess.cleanUp(connection, preparedStatement, resultSet);
245 }
246
247 CounterHolder counterHolder = _obtainIncrement(name, rangeSize, size);
248
249 return new CounterRegister(name, counterHolder, rangeSize);
250 }
251
252 protected Connection getConnection() throws SQLException {
253 Connection connection = getDataSource().getConnection();
254
255 return connection;
256 }
257
258 protected CounterRegister getCounterRegister(String name) {
259 CounterRegister counterRegister = _counterRegisterMap.get(name);
260
261 if (counterRegister != null) {
262 return counterRegister;
263 }
264
265 synchronized (_counterRegisterMap) {
266
267
268
269 counterRegister = _counterRegisterMap.get(name);
270
271 if (counterRegister == null) {
272 counterRegister = createCounterRegister(name);
273
274 _counterRegisterMap.put(name, counterRegister);
275 }
276
277 return counterRegister;
278 }
279 }
280
281 protected int getRangeSize(String name) {
282 if (name.equals(_NAME)) {
283 return PropsValues.COUNTER_INCREMENT;
284 }
285
286 String incrementType = null;
287
288 int pos = name.indexOf(CharPool.POUND);
289
290 if (pos != -1) {
291 incrementType = name.substring(0, pos);
292 }
293 else {
294 incrementType = name;
295 }
296
297 Integer rangeSize = _rangeSizeMap.get(incrementType);
298
299 if (rangeSize == null) {
300 rangeSize = GetterUtil.getInteger(
301 PropsUtil.get(
302 PropsKeys.COUNTER_INCREMENT_PREFIX + incrementType),
303 PropsValues.COUNTER_INCREMENT);
304
305 _rangeSizeMap.put(incrementType, rangeSize);
306 }
307
308 return rangeSize.intValue();
309 }
310
311 private long _competeIncrement(CounterRegister counterRegister, int size) {
312 CounterHolder counterHolder = counterRegister.getCounterHolder();
313
314
315
316 long newValue = counterHolder.addAndGet(size);
317
318 if (newValue <= counterHolder.getRangeMax()) {
319 return newValue;
320 }
321
322
323
324 CompeteLatch completeLatch = counterRegister.getCompeteLatch();
325
326 if (!completeLatch.compete()) {
327
328
329
330 try {
331 completeLatch.await();
332 }
333 catch (InterruptedException ie) {
334 throw processException(ie);
335 }
336
337
338
339 return _competeIncrement(counterRegister, size);
340 }
341
342
343
344 try {
345
346
347
348 counterHolder = counterRegister.getCounterHolder();
349 newValue = counterHolder.addAndGet(size);
350
351 if (newValue > counterHolder.getRangeMax()) {
352 CounterHolder newCounterHolder = _obtainIncrement(
353 counterRegister.getName(), counterRegister.getRangeSize(),
354 0);
355
356 newValue = newCounterHolder.addAndGet(size);
357
358 counterRegister.setCounterHolder(newCounterHolder);
359 }
360 }
361 catch (Exception e) {
362 throw processException(e);
363 }
364 finally {
365
366
367
368 completeLatch.done();
369 }
370
371 return newValue;
372 }
373
374 private CounterHolder _obtainIncrement(
375 String counterName, long range, long size) {
376
377 Session session = null;
378
379 try {
380 session = openSession();
381
382 Counter counter = (Counter)session.get(
383 CounterImpl.class, counterName, LockMode.UPGRADE);
384
385 long newValue = counter.getCurrentId();
386
387 if (size > newValue) {
388 newValue = size;
389 }
390
391 long rangeMax = newValue + range;
392
393 counter.setCurrentId(rangeMax);
394
395 CounterHolder counterHolder = new CounterHolder(newValue, rangeMax);
396
397 session.saveOrUpdate(counter);
398
399 session.flush();
400
401 return counterHolder;
402 }
403 catch (Exception e) {
404 throw processException(e);
405 }
406 finally {
407 closeSession(session);
408 }
409 }
410
411 private static final int _DEFAULT_CURRENT_ID = 0;
412
413 private static final int _MINIMUM_INCREMENT_SIZE = 1;
414
415 private static final String _NAME = Counter.class.getName();
416
417 private static final String _SQL_INSERT =
418 "insert into Counter(name, currentId) values (?, ?)";
419
420 private static final String _SQL_SELECT_ID_BY_NAME =
421 "select currentId from Counter where name = ?";
422
423 private static final String _SQL_SELECT_NAMES =
424 "select name from Counter order by name asc";
425
426 private static final String _SQL_UPDATE_NAME_BY_NAME =
427 "update Counter set name = ? where name = ?";
428
429 private final Map<String, CounterRegister> _counterRegisterMap =
430 new ConcurrentHashMap<String, CounterRegister>();
431 private final Map<String, Integer> _rangeSizeMap =
432 new ConcurrentHashMap<String, Integer>();
433
434 }