com.openmeap.model.ModelServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.openmeap.model.ModelServiceImpl.java

Source

/*
 ###############################################################################
 #                                                                             #
 #    Copyright (C) 2011-2012 OpenMEAP, Inc.                                   #
 #    Credits to Jonathan Schang & Robert Thacher                              #
 #                                                                             #
 #    Released under the LGPLv3                                                #
 #                                                                             #
 #    OpenMEAP 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 of the License, or     #
 #    (at your option) any later version.                                      #
 #                                                                             #
 #    OpenMEAP 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 OpenMEAP.  If not, see <http://www.gnu.org/licenses/>.        #
 #                                                                             #
 ###############################################################################
 */

package com.openmeap.model;

import java.sql.SQLException;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceException;
import javax.persistence.Query;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;

import com.openmeap.event.ProcessingEvent;
import com.openmeap.model.dto.Application;
import com.openmeap.model.dto.ApplicationArchive;
import com.openmeap.model.dto.ApplicationVersion;
import com.openmeap.model.dto.Deployment;

/**
 * Intended to basically pass-through to the entity manager.
 * 
 * Implemented with the idea that a different persistence 
 * mechanism might one day be used.
 * 
 * @author schang
 */
@Transactional
public class ModelServiceImpl implements ModelService {
    private Logger logger = LoggerFactory.getLogger(ModelServiceImpl.class);

    private EntityManager entityManager = null;

    /**
     * Number of times to retry refreshing a model entity before failing the operation.
     * Using SQLite, sometimes the database file is locked by another process.
     */
    private int numberOfRefreshRetries = 3;

    /**
     * Amount of time to wait between each refresh retry.
     */
    private int refreshRetryInterval = 250;

    public void clearPersistenceContext() {
        entityManager.clear();
    }

    @Override
    public <T extends ModelEntity> T saveOrUpdate(T entity) throws PersistenceException {
        T entityToReturn = entity;
        try {
            // if we haven't loaded this object yet,
            // then attempt to do so
            if (!entityManager.contains(entity)) {
                entityToReturn = entityManager.merge(entity);
            }
            entityManager.persist(entityToReturn);
        } catch (PersistenceException pe) {
            throw new PersistenceException(pe);
        }
        return entityToReturn;
    }

    @Override
    public <T extends ModelEntity> void delete(T obj2Delete) throws PersistenceException {
        _delete(obj2Delete, null);
    }

    @Override
    public <T extends ModelEntity> void refresh(T entity) throws PersistenceException {
        int numRetries = numberOfRefreshRetries;
        boolean notSuccessful = false;
        do {
            try {
                if (entity != null) {
                    this._refresh(entity);
                }
            } catch (Exception e) {
                Throwable t = ExceptionUtils.getRootCause(e);
                if (!(t instanceof SQLException)) {
                    throw new PersistenceException(e);
                }
                logger.warn("Unable to refresh model entity, " + numRetries + " left.  " + t.getMessage());
                numRetries--;
                notSuccessful = true;
                try {
                    Thread.sleep(refreshRetryInterval);
                } catch (InterruptedException e1) {
                    throw new PersistenceException(
                            "Thread sleep interrupted during the refresh retry interval: " + e1.getMessage(), e1);
                }
            }
        } while (notSuccessful && numRetries != 0);
        if (numRetries == 0) {
            throw new PersistenceException(
                    "Unable to refresh model entity.  " + numberOfRefreshRetries + " retries failed");
        }
    }

    @SuppressWarnings("unchecked")
    public <T extends ModelEntity> T findByPrimaryKey(Class<T> clazz, Object pk) {
        try {
            T obj = (T) entityManager.find(clazz, pk);
            return obj;
        } catch (NoResultException nre) {
            return null;
        }
    }

    @SuppressWarnings("unchecked")
    public <T extends ModelEntity> List<T> findAll(Class<T> clazz) {
        Query q = entityManager.createQuery("select distinct a from " + clazz.getCanonicalName() + " a");
        try {
            return q.getResultList();
        } catch (NoResultException nre) {
            return null;
        }
    }

    @Override
    public Application findApplicationByName(String name) {
        Query q = entityManager.createQuery("select distinct a " + "from Application a " + "where a.name=:name");
        q.setParameter("name", name);
        try {
            return (Application) q.getSingleResult();
        } catch (NoResultException nre) {
            return null;
        }
    }

    @Override
    public ApplicationVersion findAppVersionByNameAndId(String appName, String identifier) {
        Query q = entityManager.createQuery("select distinct av " + "from ApplicationVersion av "
                + "inner join fetch av.application a " + "where av.identifier=:identifier " + "and a.name=:name");
        q.setParameter("name", appName);
        q.setParameter("identifier", identifier);
        try {
            ApplicationVersion ver = (ApplicationVersion) q.getSingleResult();
            return ver;
        } catch (NoResultException nre) {
            return null;
        }
    }

    @Override
    public List<Deployment> findDeploymentsByApplication(Application app) {
        Query q = entityManager
                .createQuery("select d " + "from Deployment d " + "inner join fetch d.applicationArchive aa "
                        + "inner join d.application a " + "where a.name=:name");
        q.setParameter("name", app.getName());
        try {
            @SuppressWarnings(value = { "unchecked" })
            List<Deployment> deployments = (List<Deployment>) q.getResultList();
            return deployments;
        } catch (NoResultException nre) {
            return null;
        }
    }

    @Override
    public List<Deployment> findDeploymentsByApplicationArchive(ApplicationArchive archive) {
        Query q = entityManager.createQuery("select distinct d " + "from Deployment d "
                + "inner join fetch d.applicationArchive aa " + "where aa.id=:id");
        q.setParameter("id", archive.getId());
        try {
            @SuppressWarnings(value = { "unchecked" })
            List<Deployment> deployments = (List<Deployment>) q.getResultList();
            return deployments;
        } catch (NoResultException nre) {
            return null;
        }
    }

    @Override
    public List<ApplicationVersion> findVersionsByApplicationArchive(ApplicationArchive archive) {
        Query q = entityManager.createQuery("select distinct av " + "from ApplicationVersion av "
                + "inner join fetch av.archive aa " + "where aa.id=:id ");
        q.setParameter("id", archive.getId());
        try {
            @SuppressWarnings(value = { "unchecked" })
            List<ApplicationVersion> versions = (List<ApplicationVersion>) q.getResultList();
            return versions;
        } catch (NoResultException nre) {
            return null;
        }
    }

    @Override
    public Deployment getLastDeployment(Application app) {
        Query q = entityManager.createQuery("select distinct d " + "from Deployment d join d.application "
                + "where d.application.id=:id " + "order by d.createDate desc");
        q.setParameter("id", app.getId());
        q.setMaxResults(1);
        try {
            Object o = q.getSingleResult();
            return (Deployment) o;
        } catch (NoResultException nre) {
            return null;
        }
    }

    @Override
    public ApplicationArchive getApplicationArchiveByDeployment(Deployment depl) {
        Query q = entityManager.createQuery("select distinct aa " + "from ApplicationArchive aa, Deployment d  "
                + "where d.applicationArchive=aa and d.id=:id ");
        q.setParameter("id", depl.getId());
        q.setMaxResults(1);
        try {
            Object o = q.getSingleResult();
            return ((ApplicationArchive) o);
        } catch (NoResultException nre) {
            return null;
        }
    }

    @Override
    public ApplicationArchive findApplicationArchiveByHashAndAlgorithm(Application app, String hash,
            String hashAlgorithm) {
        Query q = entityManager.createQuery(
                "select distinct ar " + "from ApplicationArchive ar " + "join fetch ar.application app "
                        + "where ar.hash=:hash " + "and ar.hashAlgorithm=:hashAlgorithm " + "and app.id=:appId");
        q.setParameter("hash", hash);
        q.setParameter("hashAlgorithm", hashAlgorithm);
        q.setParameter("appId", app.getId());
        q.setMaxResults(1);
        try {
            ApplicationArchive o = (ApplicationArchive) q.getSingleResult();
            return (ApplicationArchive) o;
        } catch (NoResultException nre) {
            return null;
        }
    }

    @Override
    public int countDeploymentsByHashAndHashAlg(String hash, String hashAlg) {
        Query q = entityManager
                .createQuery("select count(d) " + "from Deployment d " + "left join d.applicationArchive aa "
                        + "where aa.hash=:hash " + "and aa.hashAlgorithm=:hashAlgorithm");
        q.setParameter("hash", hash);
        q.setParameter("hashAlgorithm", hashAlg);
        try {
            Number ret = (Number) q.getSingleResult();
            return ret.intValue();
        } catch (NoResultException nre) {
            return 0;
        }
    }

    @Override
    public int countVersionsByHashAndHashAlg(String hash, String hashAlg) {
        Query q = entityManager.createQuery("select count(av) " + "from ApplicationVersion av "
                + "left join av.archive ar " + "where ar.hash=:hash " + "and ar.hashAlgorithm=:hashAlgorithm");
        q.setParameter("hash", hash);
        q.setParameter("hashAlgorithm", hashAlg);
        try {
            Number ret = (Number) q.getSingleResult();
            return ret.intValue();
        } catch (NoResultException nre) {
            return 0;
        }
    }

    @Override
    public int countApplicationArchivesByHashAndHashAlg(String hash, String hashAlg) {
        Query q = entityManager.createQuery("select count(ar) " + "from ApplicationArchive ar "
                + "where ar.hash=:hash " + "and ar.hashAlgorithm=:hashAlgorithm ");
        q.setParameter("hash", hash);
        q.setParameter("hashAlgorithm", hashAlg);
        try {
            Number ret = (Number) q.getSingleResult();
            return ret.intValue();
        } catch (NoResultException nre) {
            return 0;
        }
    }

    @Override
    public <E extends ModelEntity, T extends ModelEntity> List<T> getOrdered(E entity, String listMethod,
            Comparator<T> comparator) {
        EntityManager entityManager = getEntityManager();
        entityManager.getTransaction().begin();
        entityManager.merge(entity);
        List<T> ents;
        try {
            ents = (List<T>) entity.getClass().getMethod(listMethod).invoke(entity);
        } catch (Exception e) {
            throw new PersistenceException(e);
        }
        Collections.sort(ents, comparator);
        entityManager.getTransaction().commit();
        return ents;
    }

    // ACCESSORS

    public void setEntityManager(EntityManager manager) {
        entityManager = manager;
    }

    public EntityManager getEntityManager() {
        return entityManager;
    }

    /**
     * Amount of time to wait between each refresh retry.
     */
    public void setRefreshRetryInterval(int refreshRetryInterval) {
        this.refreshRetryInterval = refreshRetryInterval;
    }

    /**
     * Number of times to retry refreshing a model entity before failing the operation.
     * Using SQLite, sometimes the database file is locked by another process.
     */
    public void setNumberOfRefreshRetries(int numberOfRefreshRetries) {
        this.numberOfRefreshRetries = numberOfRefreshRetries;
    }

    // PRIVATE METHODS

    private <T extends ModelEntity> void _delete(T entity, List<ProcessingEvent> events)
            throws PersistenceException {
        // give the event notifiers an opportunity to act, prior to deletion
        entity.remove();
        entityManager.remove(entity);
    }

    private void _refresh(ModelEntity obj2Refresh) {
        if (!entityManager.contains(obj2Refresh)) {
            entityManager.merge(obj2Refresh);
        }
        entityManager.refresh(obj2Refresh);
    }

    @Override
    public ModelService begin() {
        entityManager.getTransaction().begin();
        return this;
    }

    @Override
    public ModelService commit() {
        entityManager.getTransaction().commit();
        return this;
    }

    @Override
    public ModelService rollback() {
        if (entityManager.isOpen() && entityManager.getTransaction().isActive()) {
            entityManager.getTransaction().rollback();
        }
        return this;
    }
}