com.liferay.counter.service.persistence.CounterFinderImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.liferay.counter.service.persistence.CounterFinderImpl.java

Source

/**
 * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

package com.liferay.counter.service.persistence;

import com.liferay.counter.model.Counter;
import com.liferay.counter.model.CounterHolder;
import com.liferay.counter.model.CounterRegister;
import com.liferay.counter.model.impl.CounterImpl;
import com.liferay.portal.kernel.cache.CacheRegistryItem;
import com.liferay.portal.kernel.cache.CacheRegistryUtil;
import com.liferay.portal.kernel.concurrent.CompeteLatch;
import com.liferay.portal.kernel.dao.jdbc.DataAccess;
import com.liferay.portal.kernel.dao.orm.LockMode;
import com.liferay.portal.kernel.dao.orm.ObjectNotFoundException;
import com.liferay.portal.kernel.dao.orm.Session;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.util.CharPool;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.PropsKeys;
import com.liferay.portal.model.Dummy;
import com.liferay.portal.service.persistence.impl.BasePersistenceImpl;
import com.liferay.portal.util.PropsUtil;
import com.liferay.portal.util.PropsValues;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Brian Wing Shun Chan
 * @author Harry Mark
 * @author Michael Young
 * @author Shuyang Zhou
 * @author Edward Han
 */
public class CounterFinderImpl extends BasePersistenceImpl<Dummy> implements CacheRegistryItem, CounterFinder {

    public void afterPropertiesSet() {
        CacheRegistryUtil.register(this);
    }

    public List<String> getNames() throws SystemException {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;

        try {
            connection = getConnection();

            preparedStatement = connection.prepareStatement(_SQL_SELECT_NAMES);

            resultSet = preparedStatement.executeQuery();

            List<String> list = new ArrayList<String>();

            while (resultSet.next()) {
                list.add(resultSet.getString(1));
            }

            return list;
        } catch (SQLException sqle) {
            throw processException(sqle);
        } finally {
            DataAccess.cleanUp(connection, preparedStatement, resultSet);
        }
    }

    public String getRegistryName() {
        return CounterFinderImpl.class.getName();
    }

    public long increment() throws SystemException {
        return increment(_NAME);
    }

    public long increment(String name) throws SystemException {
        return increment(name, _MINIMUM_INCREMENT_SIZE);
    }

    public long increment(String name, int size) throws SystemException {
        if (size < _MINIMUM_INCREMENT_SIZE) {
            size = _MINIMUM_INCREMENT_SIZE;
        }

        CounterRegister counterRegister = getCounterRegister(name);

        return _competeIncrement(counterRegister, size);
    }

    public void invalidate() {
        _counterRegisterMap.clear();
    }

    public void rename(String oldName, String newName) throws SystemException {
        CounterRegister counterRegister = getCounterRegister(oldName);

        synchronized (counterRegister) {
            if (_counterRegisterMap.containsKey(newName)) {
                throw new SystemException("Cannot rename " + oldName + " to " + newName);
            }

            Connection connection = null;
            PreparedStatement preparedStatement = null;

            try {
                connection = getConnection();

                preparedStatement = connection.prepareStatement(_SQL_UPDATE_NAME_BY_NAME);

                preparedStatement.setString(1, newName);
                preparedStatement.setString(2, oldName);

                preparedStatement.executeUpdate();
            } catch (ObjectNotFoundException onfe) {
            } catch (Exception e) {
                throw processException(e);
            } finally {
                DataAccess.cleanUp(connection, preparedStatement);
            }

            counterRegister.setName(newName);

            _counterRegisterMap.put(newName, counterRegister);
            _counterRegisterMap.remove(oldName);
        }
    }

    public void reset(String name) throws SystemException {
        CounterRegister counterRegister = getCounterRegister(name);

        synchronized (counterRegister) {
            Session session = null;

            try {
                session = openSession();

                Counter counter = (Counter) session.get(CounterImpl.class, name);

                session.delete(counter);

                session.flush();
            } catch (ObjectNotFoundException onfe) {
            } catch (Exception e) {
                throw processException(e);
            } finally {
                closeSession(session);
            }

            _counterRegisterMap.remove(name);
        }
    }

    public void reset(String name, long size) throws SystemException {
        CounterRegister counterRegister = createCounterRegister(name, size);

        _counterRegisterMap.put(name, counterRegister);
    }

    protected CounterRegister createCounterRegister(String name) throws SystemException {

        return createCounterRegister(name, -1);
    }

    protected CounterRegister createCounterRegister(String name, long size) throws SystemException {

        long rangeMin = -1;
        int rangeSize = getRangeSize(name);

        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;

        try {
            connection = getConnection();

            preparedStatement = connection.prepareStatement(_SQL_SELECT_ID_BY_NAME);

            preparedStatement.setString(1, name);

            resultSet = preparedStatement.executeQuery();

            if (!resultSet.next()) {
                rangeMin = _DEFAULT_CURRENT_ID;

                if (size > rangeMin) {
                    rangeMin = size;
                }

                resultSet.close();
                preparedStatement.close();

                preparedStatement = connection.prepareStatement(_SQL_INSERT);

                preparedStatement.setString(1, name);
                preparedStatement.setLong(2, rangeMin);

                preparedStatement.executeUpdate();
            }
        } catch (Exception e) {
            throw processException(e);
        } finally {
            DataAccess.cleanUp(connection, preparedStatement, resultSet);
        }

        CounterHolder counterHolder = _obtainIncrement(name, rangeSize, size);

        return new CounterRegister(name, counterHolder, rangeSize);
    }

    protected Connection getConnection() throws SQLException {
        Connection connection = getDataSource().getConnection();

        return connection;
    }

    protected CounterRegister getCounterRegister(String name) throws SystemException {

        CounterRegister counterRegister = _counterRegisterMap.get(name);

        if (counterRegister != null) {
            return counterRegister;
        } else {
            synchronized (_counterRegisterMap) {

                // Double check

                counterRegister = _counterRegisterMap.get(name);

                if (counterRegister == null) {
                    counterRegister = createCounterRegister(name);

                    _counterRegisterMap.put(name, counterRegister);
                }

                return counterRegister;
            }
        }
    }

    protected int getRangeSize(String name) {
        if (name.equals(_NAME)) {
            return PropsValues.COUNTER_INCREMENT;
        }

        String incrementType = null;

        int pos = name.indexOf(CharPool.POUND);

        if (pos != -1) {
            incrementType = name.substring(0, pos);
        } else {
            incrementType = name;
        }

        Integer rangeSize = _rangeSizeMap.get(incrementType);

        if (rangeSize == null) {
            rangeSize = GetterUtil.getInteger(PropsUtil.get(PropsKeys.COUNTER_INCREMENT_PREFIX + incrementType),
                    PropsValues.COUNTER_INCREMENT);

            _rangeSizeMap.put(incrementType, rangeSize);
        }

        return rangeSize.intValue();
    }

    private long _competeIncrement(CounterRegister counterRegister, int size) throws SystemException {

        CounterHolder counterHolder = counterRegister.getCounterHolder();

        // Try to use the fast path

        long newValue = counterHolder.addAndGet(size);

        if (newValue <= counterHolder.getRangeMax()) {
            return newValue;
        }

        // Use the slow path

        CompeteLatch completeLatch = counterRegister.getCompeteLatch();

        if (!completeLatch.compete()) {

            // Loser thread has to wait for the winner thread to finish its job

            try {
                completeLatch.await();
            } catch (InterruptedException ie) {
                throw processException(ie);
            }

            // Compete again

            return _competeIncrement(counterRegister, size);
        }

        // Winner thread

        try {

            // Double check

            counterHolder = counterRegister.getCounterHolder();
            newValue = counterHolder.addAndGet(size);

            if (newValue > counterHolder.getRangeMax()) {
                CounterHolder newCounterHolder = _obtainIncrement(counterRegister.getName(),
                        counterRegister.getRangeSize(), 0);

                newValue = newCounterHolder.addAndGet(size);

                counterRegister.setCounterHolder(newCounterHolder);
            }
        } catch (Exception e) {
            throw processException(e);
        } finally {

            // Winner thread opens the latch so that loser threads can continue

            completeLatch.done();
        }

        return newValue;
    }

    private CounterHolder _obtainIncrement(String counterName, long range, long size) throws SystemException {

        Session session = null;

        try {
            session = openSession();

            Counter counter = (Counter) session.get(CounterImpl.class, counterName, LockMode.UPGRADE);

            long newValue = counter.getCurrentId();

            if (size > newValue) {
                newValue = size;
            }

            long rangeMax = newValue + range;

            counter.setCurrentId(rangeMax);

            CounterHolder counterHolder = new CounterHolder(newValue, rangeMax);

            session.saveOrUpdate(counter);

            session.flush();

            return counterHolder;
        } catch (Exception e) {
            throw processException(e);
        } finally {
            closeSession(session);
        }
    }

    private static final int _DEFAULT_CURRENT_ID = 0;

    private static final int _MINIMUM_INCREMENT_SIZE = 1;

    private static final String _NAME = Counter.class.getName();

    private static final String _SQL_INSERT = "insert into Counter(name, currentId) values (?, ?)";

    private static final String _SQL_SELECT_ID_BY_NAME = "select currentId from Counter where name = ?";

    private static final String _SQL_SELECT_NAMES = "select name from Counter order by name asc";

    private static final String _SQL_UPDATE_NAME_BY_NAME = "update Counter set name = ? where name = ?";

    private Map<String, CounterRegister> _counterRegisterMap = new ConcurrentHashMap<String, CounterRegister>();
    private Map<String, Integer> _rangeSizeMap = new ConcurrentHashMap<String, Integer>();

}