com.bt.aloha.dao.StateInfoDaoImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.bt.aloha.dao.StateInfoDaoImpl.java

Source

/*
 * Aloha Open Source SIP Application Server- https://trac.osmosoft.com/Aloha
 *
 * Copyright (c) 2008, British Telecommunications plc. 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 3.0 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.
 *
 * You should have received a copy of the GNU Lesser General Public License along
 * with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

package com.bt.aloha.dao;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import javax.sql.DataSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.SqlLobValue;

import com.bt.aloha.state.StateInfoBase;
import com.bt.aloha.util.ConcurrentUpdateException;
import com.bt.aloha.util.ObjectSerialiser;

public class StateInfoDaoImpl<T extends StateInfoBase<T>> extends DaoBase implements StateInfoDao<T> {
    private static Log log = LogFactory.getLog(StateInfoDaoImpl.class);
    private static final String UNCHECKED = "unchecked";
    private static final String NULL_INFO_ID = "Null info id";
    private static final String INSERT_SQL = "insert into StateInfo (object_id, object_type, object_version, last_use_time, is_dead, force_housekeep, object_value) values(?, ?, ?, ?, ?, 0, ?)";
    private static final String SELECT_SQL = "select object_id, object_value from StateInfo where object_id=?";
    private static final String SELECT_ALL_SQL = "select object_id, object_value from StateInfo where object_type=?";
    private static final String DELETE_SQL = "delete from StateInfo where object_id=?";
    private static final String UPDATE_SQL = "update StateInfo set object_version=?, last_use_time=?, is_dead=?, object_value=? where object_id=? and object_version=?";
    private static final String SIZE_SQL = "select count(*) from StateInfo where object_type=?";
    private static final String STATEINFO_DELETE_BY_HOUSEKEEPER_FLAGS_SQL = "delete from StateInfo where last_use_time < ? and (is_dead = 1 or force_housekeep = 1) and object_type=?";
    private static final String STATEINFO_SELECT_BY_HOUSEKEEPER_FLAGS_SQL = "select * from StateInfo where last_use_time < ? and is_dead = 0 and object_type=?";
    private static final String STATEINFO_UPDATE_BY_HOUSEKEEPER_FLAGS_SQL = "update StateInfo set force_housekeep = 1 where last_use_time < ? and is_dead = 0 and object_type=?";

    private static class TRowMapper<T> implements RowMapper {
        private ObjectSerialiser objectSerialiser;

        public TRowMapper() {
            objectSerialiser = new ObjectSerialiser();
        }

        public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
            byte[] bytes = rs.getBytes("object_value");
            return objectSerialiser.deserialise(bytes);
        }
    }

    public StateInfoDaoImpl(DataSource dataSource) {
        super(dataSource);
        checkTableExistence();
    }

    private void checkTableExistence() {
        try {
            getJdbcTemplate().execute("select 1 from StateInfo");
        } catch (DataAccessException e) {
            throw new IllegalStateException("Error reading StateInfo table", e);
        }
    }

    public void add(StateInfoBase<T> info, String collectionTypeName) {
        if (collectionTypeName == null)
            throw new IllegalArgumentException("Cannot add null collection type to collection.");

        if (info == null)
            throw new IllegalArgumentException("Cannot add null info object to collection.");

        if (info.getId() == null)
            throw new IllegalArgumentException("Cannot add info object with null id to collection.");

        try {
            Object[] params = new Object[] { info.getId(), collectionTypeName, info.getVersionId(),
                    info.getLastUsedTime(), info.isDead() ? 1 : 0,
                    new SqlLobValue(new ObjectSerialiser().serialise(info)), };
            int[] types = new int[] { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.BIGINT, Types.INTEGER,
                    Types.BLOB };
            getJdbcTemplate().update(INSERT_SQL, params, types);
        } catch (DataIntegrityViolationException e) {
            throw new IllegalArgumentException(
                    String.format("Info %s already exists in database, use replaceDialog instead", info.getId()),
                    e);
        } catch (DataAccessException e) {
            throw new IllegalArgumentException(String.format("Cannot add info %s to database", info.getId()), e);
        }
    }

    @SuppressWarnings(UNCHECKED)
    public T get(String infoId) {
        if (infoId == null)
            throw new IllegalArgumentException(NULL_INFO_ID);

        try {
            Object[] params = new Object[] { infoId };
            int[] types = new int[] { Types.VARCHAR };

            List results = getJdbcTemplate().query(SELECT_SQL, params, types, new TRowMapper());

            if (results.size() > 1)
                throw new IllegalStateException(String.format("More than one info object with id %s", infoId));
            if (results.size() == 0) {
                log.debug(String.format("No info object for id %s , returning null ", infoId));
                return null;
            }
            return (T) results.get(0);

        } catch (DataAccessException e) {
            throw new IllegalArgumentException(String.format("Cannot retrieve info %s from database", infoId), e);
        }
    }

    public void remove(String infoId) {
        if (infoId == null)
            throw new IllegalArgumentException(NULL_INFO_ID);

        try {
            Object[] params = new Object[] { infoId };
            int[] types = new int[] { Types.VARCHAR };
            getJdbcTemplate().update(DELETE_SQL, params, types);
        } catch (DataAccessException e) {
            throw new IllegalArgumentException(String.format("Cannot delete info %s from database", infoId), e);
        }
    }

    public void replace(final T info) {
        if (info == null)
            throw new IllegalArgumentException("Cannot replace null info object in collection.");

        T newInfo = info.cloneObject();
        newInfo.updateVersionId();
        newInfo.updateLastUsedTime();

        int updated = 0;
        try {
            Object[] params = new Object[] { newInfo.getVersionId(), newInfo.getLastUsedTime(),
                    newInfo.isDead() ? 1 : 0, new SqlLobValue(new ObjectSerialiser().serialise(newInfo)),
                    info.getId(), info.getVersionId(), };
            int[] types = new int[] { Types.VARCHAR, Types.BIGINT, Types.INTEGER, Types.BLOB, Types.VARCHAR,
                    Types.VARCHAR };
            updated = getJdbcTemplate().update(UPDATE_SQL, params, types);
        } catch (DataAccessException e) {
            throw new IllegalArgumentException(String.format("Cannot update info %s in database", info.getId()), e);
        }
        if (updated == 0)
            throw new ConcurrentUpdateException(info.getId(),
                    String.format("Info %s modified in database, try again", info.getId()));

        info.setVersionId(newInfo.getVersionId());
        info.setLastUsedTime(newInfo.getLastUsedTime());
    }

    public int size(String collectionTypeName) {
        return getJdbcTemplate().queryForInt(SIZE_SQL, new Object[] { collectionTypeName });
    }

    @SuppressWarnings(UNCHECKED)
    public ConcurrentMap<String, T> getAll(String collectionTypeName) {
        List<T> all;
        Object[] params = new Object[] { collectionTypeName };
        try {
            all = getJdbcTemplate().query(SELECT_ALL_SQL, params, new TRowMapper());
        } catch (DataAccessException e) {
            throw new IllegalArgumentException("Cannot retrieve all info objects from database", e);
        }
        ConcurrentMap<String, T> map = new ConcurrentHashMap<String, T>();
        for (T item : all) {
            map.put(item.getId(), item);
        }
        return map;
    }

    public void housekeep(String collectionTypeName, long maxTimeToLive, RowCallbackHandler rowCallBackHandler) {
        try {
            log.debug(String.format("Housekeeping: current number of objects in database is %d",
                    size(collectionTypeName)));
            long houseKeepBefore = System.currentTimeMillis() - maxTimeToLive;
            Object[] params = new Object[] { houseKeepBefore, collectionTypeName };
            int[] types = new int[] { Types.BIGINT, Types.VARCHAR };
            int deleted = getJdbcTemplate().update(STATEINFO_DELETE_BY_HOUSEKEEPER_FLAGS_SQL, params, types);
            log.info(String.format("Removed %d objects from database", deleted));
            getJdbcTemplate().query(STATEINFO_SELECT_BY_HOUSEKEEPER_FLAGS_SQL, params, rowCallBackHandler);
            int updated = getJdbcTemplate().update(STATEINFO_UPDATE_BY_HOUSEKEEPER_FLAGS_SQL, params, types);
            log.info(String.format("Forced housekeeping on %d objects from database", updated));
        } catch (DataAccessException e) {
            log.error(String.format("Error occurred during database housekeeping: %s", e.getMessage()));
        }
    }

    @Override
    protected String getDeleteByHouseKeeperFlagsSql() {
        return STATEINFO_DELETE_BY_HOUSEKEEPER_FLAGS_SQL;
    }

    @Override
    protected String getFindByHouseKeeperFlagsSql() {
        return STATEINFO_SELECT_BY_HOUSEKEEPER_FLAGS_SQL;
    }

    @Override
    protected String getUpdateByHouseKeeperFlagsSql() {
        return STATEINFO_UPDATE_BY_HOUSEKEEPER_FLAGS_SQL;
    }
}