1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.counter.service.persistence;
24  
25  import com.liferay.counter.model.Counter;
26  import com.liferay.counter.model.CounterRegister;
27  import com.liferay.portal.SystemException;
28  import com.liferay.portal.dao.orm.hibernate.SessionImpl;
29  import com.liferay.portal.kernel.dao.jdbc.DataAccess;
30  import com.liferay.portal.kernel.dao.orm.LockMode;
31  import com.liferay.portal.kernel.dao.orm.ObjectNotFoundException;
32  import com.liferay.portal.kernel.dao.orm.Query;
33  import com.liferay.portal.kernel.dao.orm.Session;
34  import com.liferay.portal.kernel.job.IntervalJob;
35  import com.liferay.portal.kernel.job.JobSchedulerUtil;
36  import com.liferay.portal.kernel.util.GetterUtil;
37  import com.liferay.portal.kernel.util.ListUtil;
38  import com.liferay.portal.service.persistence.impl.BasePersistenceImpl;
39  import com.liferay.portal.util.PropsKeys;
40  import com.liferay.portal.util.PropsUtil;
41  
42  import java.sql.Connection;
43  
44  import java.util.ArrayList;
45  import java.util.HashMap;
46  import java.util.Iterator;
47  import java.util.List;
48  import java.util.Map;
49  
50  import org.hibernate.SessionFactory;
51  
52  /**
53   * <a href="CounterPersistence.java.html"><b><i>View Source</i></b></a>
54   *
55   * @author Brian Wing Shun Chan
56   * @author Harry Mark
57   * @author Michael Young
58   *
59   */
60  public class CounterPersistence extends BasePersistenceImpl {
61  
62      public static int getCounterIncrement() {
63          return _COUNTER_INCREMENT;
64      }
65  
66      public void afterPropertiesSet() {
67          JobSchedulerUtil.schedule(_connectionHeartbeatJob);
68      }
69  
70      public synchronized Connection getConnection() throws Exception {
71          if ((_connection == null) || _connection.isClosed()) {
72              _connection = getDataSource().getConnection();
73  
74              _connection.setAutoCommit(true);
75          }
76  
77          return _connection;
78      }
79  
80      public void destroy() {
81          JobSchedulerUtil.unschedule(_connectionHeartbeatJob);
82  
83          DataAccess.cleanUp(_connection);
84      }
85  
86      public List<String> getNames() throws SystemException {
87          Session session = null;
88  
89          try {
90              Connection connection = getConnection();
91  
92              session = new SessionImpl(_sessionFactory.openSession(connection));
93  
94              List<String> list = new ArrayList<String>();
95  
96              Query q = session.createQuery("FROM " + Counter.class.getName());
97  
98              Iterator<Counter> itr = q.iterate();
99  
100             while (itr.hasNext()) {
101                 Counter counter = itr.next();
102 
103                 list.add(counter.getName());
104             }
105 
106             return ListUtil.sort(list);
107         }
108         catch (Exception e) {
109             throw processException(e);
110         }
111         finally {
112             session.close();
113         }
114     }
115 
116     public long increment() throws SystemException {
117         return increment(_NAME);
118     }
119 
120     public long increment(String name) throws SystemException {
121         return increment(name, _MINIMUM_INCREMENT_SIZE);
122     }
123 
124     public long increment(String name, int size)
125         throws SystemException {
126 
127         if (size < _MINIMUM_INCREMENT_SIZE) {
128             size = _MINIMUM_INCREMENT_SIZE;
129         }
130 
131         CounterRegister register = getCounterRegister(name);
132 
133         synchronized (register) {
134             long newValue = register.getCurrentValue() + size;
135 
136             if (newValue > register.getRangeMax()) {
137                 Session session = null;
138 
139                 try {
140                     Connection connection = getConnection();
141 
142                     session = new SessionImpl(
143                         _sessionFactory.openSession(connection));
144 
145                     Counter counter = (Counter)session.get(
146                         Counter.class, register.getName());
147 
148                     newValue = counter.getCurrentId() + 1;
149 
150                     long rangeMax =
151                         counter.getCurrentId() + register.getRangeSize();
152 
153                     counter.setCurrentId(rangeMax);
154 
155                     session.save(counter);
156                     session.flush();
157 
158                     register.setCurrentValue(newValue);
159                     register.setRangeMax(rangeMax);
160                 }
161                 catch (Exception e) {
162                     throw processException(e);
163                 }
164                 finally {
165                     session.close();
166                 }
167             }
168             else {
169                 register.setCurrentValue(newValue);
170             }
171 
172             return newValue;
173         }
174     }
175 
176     public void rename(String oldName, String newName)
177         throws SystemException {
178 
179         CounterRegister register = getCounterRegister(oldName);
180 
181         synchronized (register) {
182             if (_registerLookup.containsKey(newName)) {
183                 throw new SystemException(
184                     "Cannot rename " + oldName + " to " + newName);
185             }
186 
187             Session session = null;
188 
189             try {
190                 Connection connection = getConnection();
191 
192                 session = new SessionImpl(
193                     _sessionFactory.openSession(connection));
194 
195                 Counter counter = (Counter)session.load(Counter.class, oldName);
196 
197                 long currentId = counter.getCurrentId();
198 
199                 session.delete(counter);
200 
201                 counter = new Counter();
202 
203                 counter.setName(newName);
204                 counter.setCurrentId(currentId);
205 
206                 session.save(counter);
207 
208                 session.flush();
209             }
210             catch (ObjectNotFoundException onfe) {
211             }
212             catch (Exception e) {
213                 throw processException(e);
214             }
215             finally {
216                 session.close();
217             }
218 
219             register.setName(newName);
220 
221             _registerLookup.put(newName, register);
222             _registerLookup.remove(oldName);
223         }
224     }
225 
226     public void reset(String name) throws SystemException {
227         CounterRegister register = getCounterRegister(name);
228 
229         synchronized (register) {
230             Session session = null;
231 
232             try {
233                 Connection connection = getConnection();
234 
235                 session = new SessionImpl(
236                     _sessionFactory.openSession(connection));
237 
238                 Counter counter = (Counter)session.load(Counter.class, name);
239 
240                 session.delete(counter);
241 
242                 session.flush();
243             }
244             catch (ObjectNotFoundException onfe) {
245             }
246             catch (Exception e) {
247                 throw processException(e);
248             }
249             finally {
250                 session.close();
251             }
252 
253             _registerLookup.remove(name);
254         }
255     }
256 
257     public void reset(String name, long size) throws SystemException {
258         CounterRegister register = createCounterRegister(name, size);
259 
260         synchronized (register) {
261             _registerLookup.put(name, register);
262         }
263     }
264 
265     public void setConnectionHeartbeatJob(IntervalJob connectionHeartbeatJob) {
266         _connectionHeartbeatJob = connectionHeartbeatJob;
267     }
268 
269     public void setSessionFactory(SessionFactory sessionFactory) {
270         _sessionFactory = sessionFactory;
271     }
272 
273     protected synchronized CounterRegister getCounterRegister(String name)
274         throws SystemException {
275 
276         CounterRegister register = _registerLookup.get(name);
277 
278         if (register == null) {
279             register = createCounterRegister(name);
280 
281             _registerLookup.put(name, register);
282         }
283 
284         return register;
285     }
286 
287     protected synchronized CounterRegister createCounterRegister(String name)
288         throws SystemException {
289 
290         return createCounterRegister(name, -1);
291     }
292 
293     protected synchronized CounterRegister createCounterRegister(
294             String name, long size)
295         throws SystemException {
296 
297         long rangeMin = 0;
298         long rangeMax = 0;
299 
300         Session session = null;
301 
302         try {
303             Connection connection = getConnection();
304 
305             session = new SessionImpl(
306                 _sessionFactory.openSession(connection));
307 
308             Counter counter = (Counter)session.get(
309                 Counter.class, name, LockMode.UPGRADE);
310 
311             if (counter == null) {
312                 rangeMin = _DEFAULT_CURRENT_ID;
313 
314                 counter = new Counter();
315 
316                 counter.setName(name);
317             }
318             else {
319                 rangeMin = counter.getCurrentId();
320             }
321 
322             if (size >= _DEFAULT_CURRENT_ID) {
323                 rangeMin = size;
324             }
325 
326             rangeMax = rangeMin + _COUNTER_INCREMENT;
327 
328             counter.setCurrentId(rangeMax);
329 
330             session.save(counter);
331             session.flush();
332         }
333         catch (Exception e) {
334             throw processException(e);
335         }
336         finally {
337             session.close();
338         }
339 
340         CounterRegister register = new CounterRegister(
341             name, rangeMin, rangeMax, _COUNTER_INCREMENT);
342 
343         return register;
344     }
345 
346     private static final int _DEFAULT_CURRENT_ID = 0;
347 
348     private static final int _MINIMUM_INCREMENT_SIZE = 1;
349 
350     private static final int _COUNTER_INCREMENT = GetterUtil.getInteger(
351         PropsUtil.get(PropsKeys.COUNTER_INCREMENT), _MINIMUM_INCREMENT_SIZE);
352 
353     private static final String _NAME = Counter.class.getName();
354 
355     private static Map<String, CounterRegister> _registerLookup =
356         new HashMap<String, CounterRegister>();
357 
358     private Connection _connection;
359     private IntervalJob _connectionHeartbeatJob;
360     private SessionFactory _sessionFactory;
361 
362 }