com.vmware.appfactory.common.base.AbstractDaoImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.vmware.appfactory.common.base.AbstractDaoImpl.java

Source

/* ***********************************************************************
 * VMware ThinApp Factory
 * Copyright (c) 2009-2013 VMware, Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ***********************************************************************/

package com.vmware.appfactory.common.base;

import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Projections;
import org.springframework.transaction.annotation.Transactional;

import com.vmware.appfactory.common.dao.AfDao;
import com.vmware.thinapp.common.util.AfCalendar;

/**
 * This base DAO implementation does many of the common persistence functions
 * for records, including find() (by ID), update(), save(), etc. It is abstract,
 * so must be extended by a specific DAO for each record subclass.
 * @param <T> The model class
 */
@Transactional
public abstract class AbstractDaoImpl<T extends AbstractRecord> implements AfDao<T> {
    @Resource(name = "sessionFactory")
    private SessionFactory _sessionFactory;

    protected Class<T> _class;

    /**
     * Create a new instance. Only subclasses can call this.
     */
    @SuppressWarnings("unchecked")
    protected AbstractDaoImpl() {
        try {
            _class = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        } catch (Exception e) {
            /**
             * This does not occur when the actual derived classes
             * are instantiated (which is good), but it is thrown
             * when a (Hibernate?) wrapper class is created, such
             * as FeedDaoImpl$$EnhancerByCGLIB$$6c02440b.
             *
             * It seems safe to just ignore those cases.
             */
        }
    }

    /**
     * Get the current hibernate session.
     * @return
     */
    public Session getCurrentSession() {
        return _sessionFactory.getCurrentSession();
    }

    /**
     * Search for a record by ID, return null if not found.
     */
    @SuppressWarnings("unchecked")
    @Override
    public T find(Long id) {
        if (id == null) {
            return null;
        }
        Session session = getCurrentSession();
        T record = (T) session.get(_class, id);
        return record;
    }

    /**
     * Search for records by their IDs, return a list of results.
     */
    @Override
    public List<T> findAll(List<Long> ids, boolean includeMisses) {
        List<T> records = new ArrayList<T>();

        for (Long id : ids) {
            T record = find(id);
            if (record != null || includeMisses) {
                records.add(record);
            }
        }
        return records;
    }

    /**
     * Helper method that simplifies data loopups based on a criterion.
     *
     * @param criterion
     * @return
     */
    @SuppressWarnings("unchecked")
    protected List<T> findByCriterion(Criterion criterion) {
        Criteria criteria = getCurrentSession().createCriteria(_class);
        if (criterion != null) {
            criteria.add(criterion);
        }

        // Return distinct root entities. If not set, we can get duplicate rows.
        criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
        return criteria.list();
    }

    /**
     * Returns the number of records matching the given criterion.
     *
     * @param criterion   condition to match
     * @return     a value from 0 to the number or rows in the table
     */
    protected long countByCriterion(Criterion criterion) {
        Criteria criteria = getCurrentSession().createCriteria(_class);
        if (criterion != null) {
            criteria.add(criterion);
        }

        // Return distinct root entities. If not set, we can get duplicate rows.
        criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
        criteria.setProjection(Projections.rowCount());
        return (Long) criteria.uniqueResult();
    }

    /**
     * Get all records.
     */
    @SuppressWarnings("unchecked")
    @Override
    public List<T> findAll() {
        String hql = "from " + _class.getName();
        Query q = getCurrentSession().createQuery(hql);
        return q.list();
    }

    /**
     * Create a new record. A new ID will be assigned by the database, and the
     * 'created' time stamp field will be set.
     */
    @Override
    public Long create(T record) {
        Session session = getCurrentSession();
        record.setCreated(AfCalendar.Now());
        record.setModified(record.getCreated());
        session.save(record);
        session.flush();
        return record.getId();
    }

    /**
     * Update an existing record. The 'modified' time stamp field will be set.
     */
    @Override
    public void update(T record) {
        Session session = getCurrentSession();
        record.setModified(AfCalendar.Now());
        session.update(record);
        session.flush();
    }

    /**
     * Calls either 'create' or 'update' as appropriate.
     */
    @Override
    public void createOrUpdate(T record) {
        if (record.getId() == null) {
            create(record);
        } else {
            update(record);
        }
    }

    /**
     * Delete a record from the database.
     */
    @Override
    public void delete(T record) {
        Session session = getCurrentSession();
        session.delete(record);
        session.flush();
    }

    /**
     * Delete multiple records from the database.
     */
    @Override
    public void delete(List<T> records) {
        Session session = getCurrentSession();
        for (T record : records) {
            session.delete(record);
        }
        session.flush();
    }

    /**
     * Delete EVERY record from the table.
     */
    @Override
    public void deleteAll() {
        Session session = getCurrentSession();
        String hql = "delete from " + _class.getName();
        Query q = session.createQuery(hql);
        q.executeUpdate();
        session.flush();
    }

    /**
     * Count all records.
     */
    @Override
    public long countAll() {
        Criteria criteria = getCurrentSession().createCriteria(_class);
        criteria.setProjection(Projections.rowCount());
        return ((Long) criteria.uniqueResult()).longValue();
    }

    /**
     * Flush pending transactions to the database.
     */
    @Override
    public void flush() {
        Session session = getCurrentSession();
        session.flush();
    }

    /**
     * Search a column for the given value. If not found, return it.
     * Otherwise, try variations on the name until no match is found, and
     * return that.
     *
     * TODO: We create "Copy #X of value", which is not localized.
     *
     * @param column Column name (without the underscore)
     * @param currentValue
     * @return
     */
    protected String findUniqueValue(String column, String currentValue) {
        String hqlTemplate = "from " + _class.getName() + " where _" + column + " = :value";

        /* First check the current name */
        if (query1(hqlTemplate, "value", currentValue).isEmpty()) {
            return currentValue;
        }

        /* Now try variations until we succeed */
        String newValue = "Copy of " + currentValue;
        int index = 1;
        while (!query1(hqlTemplate, "value", newValue).isEmpty()) {
            newValue = "Copy #" + (++index) + " of " + currentValue;
        }

        return newValue;
    }

    /**
     * Utility function to execute a template HQL query with
     * one parameter.
     *
     * @param template HQL template.
     * @param placeHolder
     * @param value
     * @return
     */
    private List<?> query1(String template, String placeHolder, String value) {
        return getCurrentSession().createQuery(template).setParameter(placeHolder, value).list();
    }

    @Override()
    public long lastModified() {
        String FIND_LAST_MODIFIED_HQL = "from " + _class.getName() + " order by _modified desc";

        AbstractRecord record = (AbstractRecord) getCurrentSession().createQuery(FIND_LAST_MODIFIED_HQL)
                .setMaxResults(1).uniqueResult();
        if (null == record) {
            return -1;
        }
        return record.getModified();
    }
}