de.csw.expertfinder.persistence.PersistenceStoreFacade.java Source code

Java tutorial

Introduction

Here is the source code for de.csw.expertfinder.persistence.PersistenceStoreFacade.java

Source

/*******************************************************************************
 * This file is part of the Corporate Semantic Web Project at Freie Universitaet Berlin.
 * 
 * This work has been partially supported by the ``InnoProfile-Corporate Semantic Web" project funded by the German Federal
 * Ministry of Education and Research (BMBF) and the BMBF Innovation Initiative for the New German Laender - Entrepreneurial Regions.
 * 
 * http://www.corporate-semantic-web.de/
 * 
 * Freie Universitaet Berlin
 * Copyright (c) 2007-2013
 * 
 * Institut fuer Informatik
 * Working Group Corporate Semantic Web
 * Koenigin-Luise-Strasse 24-26
 * 14195 Berlin
 * 
 * http://www.mi.fu-berlin.de/en/inf/groups/ag-csw/
 * 
 * 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 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 or see <http://www.gnu.org/licenses/>
 ******************************************************************************/
package de.csw.expertfinder.persistence;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;

import de.csw.expertfinder.application.ApplicationData;
import de.csw.expertfinder.document.Author;
import de.csw.expertfinder.document.Category;
import de.csw.expertfinder.document.Concept;
import de.csw.expertfinder.document.ConceptSimilarity;
import de.csw.expertfinder.document.Document;
import de.csw.expertfinder.document.PersistableEntity;
import de.csw.expertfinder.document.Revision;
import de.csw.expertfinder.document.Section;
import de.csw.expertfinder.document.Word;
import de.csw.expertfinder.expertise.AuthorContribution;
import de.csw.expertfinder.expertise.AuthorCredibility;
import de.csw.expertfinder.util.Pair;

/**
 * This class implements all application specific persistence related
 * operations and hides the underlying persistence mechanism from the
 * rest of the application.
 *  
 * @author ralph
 */
public class PersistenceStoreFacade {

    private static PersistenceStoreFacade instance;

    private static final Logger log = Logger.getLogger(PersistenceStoreFacade.class);

    /**
     * Gets the singleton instance of this class.
     * @return the singleton instance of this class.
     */
    public static PersistenceStoreFacade get() {
        if (instance == null) {
            instance = new PersistenceStoreFacade();
        }
        return instance;
    }

    private SessionFactory sessionFactory;

    /**
     * private Constructor for {@link PersistenceStoreFacade}
     */
    private PersistenceStoreFacade() {
        Configuration conf = new Configuration();
        sessionFactory = conf.configure().buildSessionFactory();
    }

    /**
     * Begins a new transaction.
     */
    public void beginTransaction() {
        Session session = sessionFactory.getCurrentSession();
        session.beginTransaction();
    }

    /**
     * Commits all changes that have been made during the current transaction to
     * the persistence layer.
     */
    public void commitChanges() {
        Session session = sessionFactory.getCurrentSession();
        session.getTransaction().commit();
    }

    /**
     * Ends a read-only transaction.
     */
    public void endTransaction() {
        // the hibernate session does not distinguish between read only and
        // modifiying transactions. Read-only transactions are ended by calling
        // commit.

        commitChanges();
    }

    public void rollbackChanges() {
        Session session = sessionFactory.getCurrentSession();
        session.getTransaction().rollback();
    }

    /**
     * Persists the given entity's state to the database.
     * @param entity
     */
    public void save(PersistableEntity<? extends Serializable> entity) {
        Session session = sessionFactory.getCurrentSession();
        session.saveOrUpdate(entity);
    }

    /**
     * Deletes the given entity from the database.
     * @param entity
     */
    public void delete(PersistableEntity<? extends Serializable> entity) {
        Session session = sessionFactory.getCurrentSession();
        session.delete(entity);
    }

    /**
     * Merges the given entity's properties with its equivalent (an entity with
     * the same identifier) stored in the current session and persists it. If no
     * such object exists in the session, it will be loaded from the persistence
     * layer.
     * 
     * @param entity
     * @return the merged entity.
     */
    @SuppressWarnings("unchecked")
    public PersistableEntity<? extends Serializable> merge(PersistableEntity<? extends Serializable> entity) {
        Session session = sessionFactory.getCurrentSession();
        return (PersistableEntity<? extends Serializable>) session.merge(entity);
    }

    /**
     * Retrieves a document by its title.
     * @param title the document's title
     * @return
     */
    public Document getDocument(String title) {
        Session session = sessionFactory.getCurrentSession();
        Criteria criteria = session.createCriteria(Document.class).add(Restrictions.eq("title", title));
        Document result = (Document) criteria.uniqueResult();
        return result;
    }

    /**
     * Retrieves a document by its title.
     * @param title the document's title
     * @return
     */
    public Document getDocument(Long id) {
        Session session = sessionFactory.getCurrentSession();
        Criteria criteria = session.createCriteria(Document.class).add(Restrictions.eq("id", id));
        Document result = (Document) criteria.uniqueResult();
        return result;
    }

    /**
     * Gets a Revision by id. Sections and words are not loaded.
     * @return the Revision with the specified id
     */
    public Revision getRevision(Long id) {
        Session session = sessionFactory.getCurrentSession();
        Criteria criteria = session.createCriteria(Revision.class).add(Restrictions.eq("id", id));
        Revision result = (Revision) criteria.uniqueResult();
        return result;
    }

    /**
     * Gets the latest revision for the given document in the database. Words and sections are not loaded.
     * @param document
     * @return
     */
    public Revision getLatestPersistedRevision(Document document) {
        Session session = sessionFactory.getCurrentSession();
        Query query = session
                .createQuery(
                        "from Revision where id = (select max(id) from Revision r where r.document = :document)")
                .setEntity("document", document);
        Revision result = (Revision) query.uniqueResult();
        return result;
    }

    /**
     * Gets the latest revision for the document with the given id in the database. Words and sections are not loaded.
     * @param documentId
     * @return
     */
    public Revision getLatestPersistedRevision(Long documentId) {
        Session session = sessionFactory.getCurrentSession();
        Query query = session.createQuery(
                "from Revision where id = (select max(id) from Revision r where r.document.id = :documentId)")
                .setLong("documentId", documentId);
        Revision result = (Revision) query.uniqueResult();
        return result;
    }

    /**
     * Returns the number of revisions the given document has.
     * @param document a document
     * @return the number of revisions the given document has.
     */
    public long getRevisionCount(Document document) {
        Session session = sessionFactory.getCurrentSession();
        Query query = session.createQuery(
                "select distinct count(r.id) from Revision r, Document d where r.document = :document group by d.id")
                .setEntity("document", document);

        Object result = query.uniqueResult();

        return result == null ? 0L : (Long) result;
    }

    /**
     * Gets the latest revision for the given document in the database with words and sections loaded.
     * @param document
     * @return
     */
    @SuppressWarnings("unchecked")
    public Revision getLatestPersistedRevisionLoadFull(Document document) {
        Session session = sessionFactory.getCurrentSession();

        // get the latest revision
        Revision revision = getLatestPersistedRevision(document);

        // get all current (not deleted) sections for this document (those that exist in the latest revision)
        // Note that sections are not directly connected to one revision. 
        Query query = session
                .createQuery("select s from Section s, Revision r " + "where s.revisionDeleted is null "
                        + "and s.revisionCreated = r " + "and r.document = :document " + "order by s.startPos")
                .setEntity("document", document);
        List<Section> sections = query.list();

        revision.setSections(sections);

        // get words for each section.
        for (Section section : sections) {
            query = session.createQuery("from Word w " + "where w.revisionDeleted is null "
                    + "and w.section = :section " + "order by w.startPos").setEntity("section", section);
            List<Word> wordsForSection = query.list();
            section.setWords(wordsForSection);
        }

        return revision;
    }

    /**
     * Returns all distinct words as a set of Strings for a given document.
     * @param document
     * @return all distinct words as a set of Strings for the given document
     */
    public List<String> getBagOfWordsForLatestRevision(Document document) {
        Session session = sessionFactory.getCurrentSession();
        SQLQuery q = session.createSQLQuery(
                "select distinct word from word w,  revision r " + "where w.id_revision_created = r.id "
                        + "and w.id_revision_deleted is null " + "and r.id_document = :documentId");

        q.setLong("documentId", document.getId());
        q.addScalar("word", Hibernate.STRING);

        List<String> result = q.list();

        return result;
    }

    /**
     * Returns the author with the given name or null if no such author existst.
     * @param name
     * @return
     */
    public Author getAuthor(String name) {
        Session session = sessionFactory.getCurrentSession();
        Criteria criteria = session.createCriteria(Author.class).add(Restrictions.eq("name", name));
        Author result = (Author) criteria.uniqueResult();
        return result;
    }

    /**
     * Returns the concept with the given URI or null if no such concept exists.
     * @param uri
     * @return
     */
    public Concept getConcept(String uri) {
        Session session = sessionFactory.getCurrentSession();
        Criteria criteria = session.createCriteria(Concept.class).add(Restrictions.eq("uri", uri));
        Concept result = (Concept) criteria.uniqueResult();
        return result;
    }

    /**
     * Returns the section of the given document with the given title.
     * @param document the document.
     * @param title the section's title.
     * @return the section of the given document with the given title, or null if no such section exists.
     */
    public Section getSection(Document document, String title) {
        Session session = sessionFactory.getCurrentSession();
        Query query = session.createQuery(
                "from Section s, Revision r where s.revisionCreated = r and r.document = :document and s.tite = :title")
                .setEntity("document", document).setEntity("title", title);

        Section result = (Section) query.uniqueResult();
        return result;
    }

    /**
     * Retrieves all not deleted sections for the given document.
     * @param document the document
     * @return all not deleted sections for the given document.
     */
    @SuppressWarnings("unchecked")
    public List<Section> getSections(Document document) {
        Session session = sessionFactory.getCurrentSession();
        Query query = session.createQuery(
                "from Section s, Revision r where s.revisionCreated = r and s.revisionDeleted = null and r.document = :document")
                .setEntity("document", document);

        List<Section> result = (List<Section>) query.list();
        return result;
    }

    /**
     * Returns the category with the given name or null if no such category exists.
     * @param name a category name
     * @return the category with the given name or null if no such category exists.
     */
    public Category getCategory(String name) {
        Session session = sessionFactory.getCurrentSession();
        Criteria criteria = session.createCriteria(Category.class).add(Restrictions.eq("name", name));
        Category result = (Category) criteria.uniqueResult();
        return result;
    }

    /**
     * Retrieves the concepts that are most similar to the given concept. The
     * number of returned concepts can be limited by the limit parameter.
     * 
     * @param concept
     *            the concept for which the most similar concepts are seeked.
     * @param limit
     *            an integer determining the maximum number of concepts
     *            returned.
     * @return a list containing the most similar concepts to the given concept,
     *         along with the respective similarity values, limited by the limit
     *         parameter.
     */
    @SuppressWarnings("unchecked")
    public List<ConceptSimilarity> getBestConceptSimilarities(Concept concept, int limit) {
        Session session = sessionFactory.getCurrentSession();
        Query query = session.createQuery(
                "from ConceptSimilarity cs where cs.concept1 = :concept or cs.concept2 = :concept order by similarity desc")
                .setEntity("concept", concept).setMaxResults(limit);

        List<ConceptSimilarity> result = (List<ConceptSimilarity>) query.list();
        return result;
    }

    /**
     * Retrieves all concept similarites from the persistent store.
     * @return a list containing all concept similarites.
     */
    @SuppressWarnings("unchecked")
    public List<ConceptSimilarity> getAllConceptSimilarities() {
        Session session = sessionFactory.getCurrentSession();
        Query query = session.createQuery("from ConceptSimilarity");
        List<ConceptSimilarity> result = (List<ConceptSimilarity>) query.list();
        return result;
    }

    /**
     * Returns the concepts that are most similar to the given concept, i.e.
     * that have the (same) highest similarity value. In contrast to
     * {@link #getBestConceptSimilarities(Concept, int)}, which returns the n
     * best matches, this matches looks for the highest similarity value for the
     * given concept and returns only the concept with this similarity value.
     * 
     * @param concept a concept.
     * @return The concept or concepts with the highest similarity to the given concept.
     */
    @SuppressWarnings("unchecked")
    public List<Concept> getMostSimilarConcepts(Concept concept) {
        Session session = sessionFactory.getCurrentSession();
        Query query = session.createQuery("from ConceptSimilarity cs "
                + "where (cs.concept1 = :concept or cs.concept2 = :concept) "
                + "and similarity = (select max(similarity) from ConceptSimilarity where concept1 = :concept or concept2 = :concept)")
                .setEntity("concept", concept);

        List<ConceptSimilarity> queryResult = (List<ConceptSimilarity>) query.list();

        ArrayList<Concept> result = new ArrayList<Concept>();
        for (ConceptSimilarity cs : queryResult) {
            Concept concept1 = cs.getConcept1();
            Concept concept2 = cs.getConcept2();
            result.add(concept.equals(concept1) ? concept2 : concept1);
        }
        return result;
    }

    /**
     * All concepts with a minimal similarity
     * @param concept
     * @return
     */
    @SuppressWarnings("unchecked")
    public List<Pair<Concept, Double>> getMostSimilarConcepts(Concept concept, double minSimilarity) {
        Session session = sessionFactory.getCurrentSession();
        Query query = session
                .createQuery(
                        "from ConceptSimilarity cs " + "where (cs.concept1 = :concept or cs.concept2 = :concept) "
                                + "and similarity > :minSimilarity")
                .setEntity("concept", concept).setDouble("minSimilarity", minSimilarity);

        List<ConceptSimilarity> queryResult = (List<ConceptSimilarity>) query.list();

        ArrayList<Pair<Concept, Double>> result = new ArrayList<Pair<Concept, Double>>();
        for (ConceptSimilarity cs : queryResult) {
            Concept concept1 = cs.getConcept1();
            Concept concept2 = cs.getConcept2();
            result.add(concept.equals(concept1) ? new Pair<Concept, Double>(concept2, cs.getSimilarity())
                    : new Pair<Concept, Double>(concept1, cs.getSimilarity()));
        }
        return result;
    }

    /**
     * Retrieves the concept similarity value for the given concepts.
     * @param concept1 a concept.
     * @param concept2 a second concept.
     * @return the concept similarity value for the given concepts.
     */
    public Double getConceptSimilarity(Concept concept1, Concept concept2) {
        Session session = sessionFactory.getCurrentSession();
        Query query = session.createQuery(
                "select cs.similarity from ConceptSimilarity cs where cs.concept1 = :concept1 and cs.concept2 = :concept2 or cs.concept1 = :concept2 and cs.concept2 = :concept1")
                .setEntity("concept1", concept1).setEntity("concept2", concept2);
        return (Double) query.uniqueResult();
    }

    /**
     * Convenience method. Retrieves the concept similarity value for the
     * concepts with the given URIs.
     * 
     * @see #getConceptSimilarity(Concept, Concept).
     * @param conceptURI1
     *            URI of the first concept.
     * @param conceptURI2
     *            URI of the second concept.
     * @return the concept similarity value for the concepts with the given
     *         URIs.
     */
    public Double getConceptSimilarity(String conceptURI1, String conceptURI2) {
        Session session = sessionFactory.getCurrentSession();
        Query query = session
                .createQuery("select cs.similarity from ConceptSimilarity cs "
                        + "where cs.concept1.uri = :conceptURI1 and cs.concept2.uri = :conceptURI2 "
                        + "or cs.concept1.uri = :conceptURI2 and cs.concept2.uri = :conceptURI1")
                .setString("conceptURI1", conceptURI1).setString("conceptURI2", conceptURI2);
        return (Double) query.uniqueResult();
    }

    /**
     * 
     * @param concept
     * @param author
     * @return
     */
    public List<Object[]> getContributionForConcept(Concept concept, Author author) {
        return getContributionForConcept(concept.getId(), author.getId());
    }

    /**
     * 
     * @param concept
     * @param author
     * @return
     */
    public List<Object[]> getContributionForConcept(long conceptId, long authorId) {
        Session session = sessionFactory.getCurrentSession();
        SQLQuery query = session.createSQLQuery(
                "select  d.id as documentId, rc.count as rcCount, rd.count as rdCount, rd.id_author as deletor "
                        + "from word w " + "join  revision rc " + "on w.id_revision_created = rc.id "
                        + "and rc.id_author = :authorId " + "join document d " + "on rc.id_document = d.id  "
                        + "left outer join revision rd " + "on w.id_revision_deleted = rd.id "
                        + "where w.id_concept = :conceptId");
        query.setLong("authorId", authorId);
        query.setLong("conceptId", conceptId);
        query.addScalar("documentId", Hibernate.LONG);
        query.addScalar("rcCount", Hibernate.LONG);
        query.addScalar("rdCount", Hibernate.LONG);
        query.addScalar("deletor", Hibernate.LONG);

        return query.list();
    }

    /**
     * Retrieves all topics the given author has contributed to.
     * 
     * @param author
     * @return
     */
    @SuppressWarnings("unchecked")
    public List<Concept> getContributedTopics(Author author) {
        Session session = sessionFactory.getCurrentSession();
        Query query = session.createQuery("select distinct c from Concept c, Word w, Revision rc "
                + "where w.concept = c " + "and w.revisionCreated = rc " + "and rc.author = :author ");

        query.setEntity("author", author);
        return query.list();
    }

    /**
     * Retrieves all topics the given author has contributed to.
     * 
     * @param author
     * @return
     */
    @SuppressWarnings("unchecked")
    public List<Concept> getIndirectContributedTopics(Author author) {
        Session session = sessionFactory.getCurrentSession();
        Query query = session.createQuery(
                "select distinct c " + "from Concept c, Word w, Revision rc, Section s, SectionConcept sc "
                        + "where rc.author = :author " + "and w.revisionCreated = rc "
                        + "and sc.section = w.section " + "and sc.concept = c ");

        query.setEntity("author", author);
        return query.list();
    }

    /**
     * Retrieves all authors that have directly contributed to the given
     * topic.
     * 
     * @param topic
     * @return
     */
    @SuppressWarnings("unchecked")
    public List<Author> getAuthorsWhoContributedToTopic(Concept topic) {
        Session session = sessionFactory.getCurrentSession();
        Query query = session.createQuery("select distinct a from Author a, Word w, Revision rc "
                + "where w.concept = :topic " + "and w.revisionCreated = rc " + "and rc.author = a ");

        query.setEntity("topic", topic);
        return query.list();
    }

    /**
     * Gets cached author contributions by author.
     * @param author
     * @return
     */
    @SuppressWarnings("unchecked")
    public List<AuthorContribution> getCachedAuthorContributions(Author author) {
        Session session = sessionFactory.getCurrentSession();
        Query query = session.createQuery("from AuthorContribution ac where ac.author = :author");
        query.setEntity("author", author);
        return query.list();
    }

    /**
     * Gets cached author contributions by topic.
     * @param topic
     * @return
     */
    @SuppressWarnings("unchecked")
    public List<AuthorContribution> getCachedAuthorContributions(Concept topic) {
        Session session = sessionFactory.getCurrentSession();
        Query query = session.createQuery("from AuthorContribution ac where ac.concept = :topic");
        query.setEntity("topic", topic);
        return query.list();
    }

    /**
     * Retrieves all authors that have indirectly contributed to the given
     * topic.
     * 
     * @param topic
     * @return
     */
    @SuppressWarnings("unchecked")
    public List<Author> getAuthorsWhoIndirectlyContributedToTopic(Concept topic) {
        Session session = sessionFactory.getCurrentSession();
        Query query = session.createQuery(
                "select distinct a " + "from Author a, Word w, Revision rc, Section s, SectionConcept sc "
                        + "where sc.concept = :topic " + "and w.concept is not null "
                        + "and w.revisionCreated = rc " + "and sc.section = w.section " + "and rc.author = a");

        query.setEntity("topic", topic);
        return query.list();
    }

    /**
     * Gets all contributions by a given author to a given concept by section
     * (or document, because the top level section spans and has the same title
     * as the document itself).<br/>
     * For performance reasons, this method does not return an object graph but
     * a list of arrays of ids and other numbers (see returns section).
     * 
     * @return A list of Object[] arrays. The items in each object array are:<br/>
     *         0: the document id (Long)<br/>
     *         1: the section id (Long)<br/>
     *         2: the section level (Integer)<br/>
     *         3: the id of the revision where the contribution was added (Long)<br/>
     *         4: the id of the revision where the contribution was deleted or
     *            null if the contribution has not been deleted (Long)<br/>
     *         5: the id of the author who has deleted the contribution or null
     *            if the contribution has not been deleted (Long)<br/>
     *         6: a similarity value between 0.0 and 1.0 if a section could not
     *            be mapped to any concept but one of its parent sections or the
     *            document itself (Double). If one or more concepts could be found
     *            for this section, this value is null.<br/>
     * 
     */
    @SuppressWarnings("unchecked")
    public List<Object[]> getContributionsToSectionsWithConceptForAuthor(Concept concept, Author author) {
        Session session = sessionFactory.getCurrentSession();

        SQLQuery query = session.createSQLQuery(
                "select d.id as documentId, s.id as sectionId, s.level as sectionLevel, revCreated.count as revisionCreated, revDeleted.count as revisionDeleted, a.id as deletor, sc.similarity as similarity "
                        + "from word w " +

                        "join revision revCreated " + "   on w.id_revision_created = revCreated.id "
                        + "   and revCreated.id_author = :authorId " + "left outer join revision revDeleted "
                        + "   on w.id_revision_deleted = revDeleted.id " + "left outer join author a "
                        + "   on revDeleted.id_author = a.id " + "join section s " + "   on w.id_section = s.id "
                        + "join section_has_concept sc " + "   on sc.id_section = s.id "
                        + "   and sc.id_concept = :conceptId " + "join document d "
                        + "   on d.id = revCreated.id_document " + "where w.id_concept is null "
                        + "group by word, sectionId, revisionCreated, revisionDeleted "
                        + "order by documentId, sectionId, revisionCreated, revisionDeleted");

        query.addScalar("documentId", Hibernate.LONG).addScalar("sectionId", Hibernate.LONG)
                .addScalar("sectionLevel", Hibernate.INTEGER).addScalar("revisionCreated", Hibernate.LONG)
                .addScalar("revisionDeleted", Hibernate.LONG).addScalar("deletor", Hibernate.LONG)
                .addScalar("similarity", Hibernate.DOUBLE);

        query.setLong("conceptId", concept.getId());
        query.setLong("authorId", author.getId());

        return (List<Object[]>) query.list();
    }

    /**
     * Retrieves ALL different words that are currently in the entire wiki (not
     * deleted), along with the number of their occurences.
     * 
     * @return A list of Object[] arrays. The first object in each array is an
     *         Integer representing the number of occurrences of the word
     *         (grouped by their lemmas), the second object is a String
     *         containing the word's lemma itself.
     */
    @SuppressWarnings("unchecked")
    public List<Object[]> getAllNonDeletedWords() {
        Session session = sessionFactory.getCurrentSession();
        SQLQuery query = session.createSQLQuery("select count(*) as wordcount, word from word "
                + "where id_revision_deleted is null " + "group by word");
        query.addScalar("wordcount", Hibernate.INTEGER).addScalar("word", Hibernate.STRING);

        return (List<Object[]>) query.list();
    }

    /**
     * Retrieves an arbitary entity from the persistence layer.
     * @param id The unique identifier for the entity.
     * @param type the entity's class.
     * @return
     */
    @SuppressWarnings("rawtypes")
    public PersistableEntity getEntity(Serializable id, Class type) {
        Session session = sessionFactory.getCurrentSession();
        return (PersistableEntity) session.get(type, id);
    }

    /**
     * Deletes all entries from the concept similarity cache.
     */
    public void clearConceptSimilarityCache() {
        Session session = sessionFactory.getCurrentSession();
        Query query = session.createQuery("delete ConceptSimilarity");
        int count = query.executeUpdate();
        log.info("Deleted " + count + " entries from the concept similarity cache.");
    }

    /**
     * Retrieves the value for the given key from the application data table.
     * 
     * @param key
     *            the key.
     * @return the value for the given key from the application data table or
     *         null if such value exists.
     */
    public String getApplicationData(String key) {
        Session session = sessionFactory.getCurrentSession();
        Criteria criteria = session.createCriteria(ApplicationData.class).add(Restrictions.eq("key", key))
                .setProjection(Projections.property("value"));

        return (String) criteria.uniqueResult();
    }

    public AuthorCredibility getAuthorCredibility(Author author, Concept concept) {
        Session session = sessionFactory.getCurrentSession();
        Query query = session
                .createQuery("from AuthorCredibility ac where ac.author = :author and ac.concept = :concept");
        query.setEntity("author", author);
        query.setEntity("concept", concept);
        return (AuthorCredibility) query.uniqueResult();
    }

    /**
     * Stores a the given key-value pair in the application data table.
     * @param key
     * @param value
     */
    public void saveApplicationData(String key, String value) {
        Session session = sessionFactory.getCurrentSession();
        ApplicationData entity = (ApplicationData) session.get(ApplicationData.class, key);
        if (entity == null) {
            entity = new ApplicationData(key, value);
        }
        session.save(entity);
    }

    /**
     * Returns an SQLQuery object, initialized with the given query String.
     * @param queryString
     * @return an SQLQuery object, initialized with the given query String.
     */
    public SQLQuery createSQLQuery(String queryString) {
        Session session = sessionFactory.getCurrentSession();
        return session.createSQLQuery(queryString);
    }

    /**
     * Returns a Query object for HQL queries, initialized with the given query String.
     * @param queryString
     * @return an Query object, initialized with the given query String.
     */
    public Query createHQLQuery(String queryString) {
        Session session = sessionFactory.getCurrentSession();
        return session.createQuery(queryString);
    }

    /**
     * Commits changes to the persistence layer before committing the entire
     * transaction.
     */
    public void flush() {
        sessionFactory.getCurrentSession().flush();
    }

    /**
     * Clears the cache to avoid OOMs.
     */
    public void clearCache() {
        sessionFactory.getCurrentSession().clear();
    }

    /**
     * Close the hibernate session, releasing the database conncection.
     * @see java.lang.Object#finalize()
     */
    protected void finalize() throws Throwable {
        sessionFactory.getCurrentSession().close();
    }

}