package uk.ac.ebi.fg.myequivalents.dao;
import java.io.OutputStream;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import javax.persistence.Query;
import javax.xml.bind.Marshaller;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.hibernate.CacheMode;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import uk.ac.ebi.fg.myequivalents.managers.interfaces.BackupManager;
import uk.ac.ebi.fg.myequivalents.model.Describeable;
import uk.ac.ebi.fg.myequivalents.utils.jaxb.JAXBUtils;
import uk.ac.ebi.utils.reflection.ReflectionUtils;
/**
* Generic DAO for the {@link Describeable} types.
*
* <dl><dt>date</dt><dd>Jul 19, 2012</dd></dl>
* @author Marco Brandizi
*
*/
public class DescribeableDAO<D extends Describeable> extends AbstractTargetedDAO<D>
{
public DescribeableDAO ( EntityManager entityManager, Class<? super D> targetClass )
{
super ( entityManager, targetClass );
}
/**
* Setup the class corresponding to D automatically, extracting it by means of reflection.
*
* WARNING: This method won't work if the DAO extension you invoke it from still has a generic for D (which extends it).
* If you have such case, you need to either forbid this initialisation approach, or to declare the DAO abstract
* and use anonymous classes to instantiate specific DAOs.
*
*/
protected DescribeableDAO ( EntityManager entityManager )
{
this ( entityManager, null );
this.targetClass = ReflectionUtils.getTypeArgument ( DescribeableDAO.class, this.getClass(), 0 );
if ( targetClass == null )
throw new PersistenceException ( "Internal error: getTypeArgument() returns null for " + this.getClass ().getName () );
}
public void store ( D describeable )
{
Validate.notNull ( describeable, "Cannot update a null object" );
entityManager.merge ( describeable );
}
public void deleteAll ()
{
entityManager.createQuery ( "DELETE from " + targetClass.getName () ).executeUpdate ();
}
/**
* @param mustBePublic filters out those entities that are not {@link Describeable#isPublic()}.
*/
public D findByName ( String describeableName, boolean mustBePublic )
{
describeableName = StringUtils.trimToNull ( describeableName );
if ( describeableName == null ) return null;
String hql = "FROM " + targetClass.getName () + " WHERE name = '" + describeableName + "'";
if ( mustBePublic ) hql +=
" AND ( publicFlag = true OR publicFlag IS NULL AND ( releaseDate IS NULL OR releaseDate <= current_time() ) )";
Query q = entityManager.createQuery ( hql );
@SuppressWarnings ( "unchecked" )
List<D> results = q.getResultList ();
return results.isEmpty () ? null : results.iterator ().next ();
}
public D findByName ( String describeableName ) {
return findByName ( describeableName, true );
}
public D findByName ( D describeable, boolean mustBePublic )
{
if ( describeable == null ) return null;
return findByName ( describeable.getName (), mustBePublic );
}
public D findByName ( D describeable ) {
return findByName ( describeable, true );
}
/** TODO: requires isRestrictedToPublic */
public boolean exists ( String name )
{
name = StringUtils.trimToNull ( name );
if ( name == null ) return false;
Query q = entityManager.createQuery (
"SELECT name FROM " + targetClass.getName () + " WHERE name = '" + name + "'" );
@SuppressWarnings ( "unchecked" )
List<String> names = q.getResultList ();
return !names.isEmpty ();
}
/** TODO: requires isRestrictedToPublic */
public boolean exists ( D describeable )
{
if ( describeable == null ) return false;
return exists ( describeable.getName () );
}
public EntityManager getEntityManager ()
{
return entityManager;
}
public boolean delete ( String describeableName )
{
describeableName = StringUtils.trimToNull ( describeableName );
if ( describeableName == null ) return false;
Query q = entityManager.createQuery (
"DELETE from " + targetClass.getName () + " WHERE name = '" + describeableName + "'" );
return q.executeUpdate () > 0;
}
public boolean delete ( D describeable )
{
if ( describeable == null ) return false;
return delete ( describeable.getName () );
}
/**
* Dumps all the items in a range, in XML format. @see {@link BackupManager} for details.
*/
@SuppressWarnings ( "unchecked" )
public int dump ( OutputStream out, Integer offset, Integer limit )
{
Session session = (Session) this.entityManager.getDelegate ();
org.hibernate.Query q = session.createQuery ( "FROM " + this.targetClass.getName () );
q.setReadOnly ( true )
.setFetchSize ( 1000 )
.setCacheable ( false )
.setCacheMode ( CacheMode.IGNORE );
if ( offset != null && offset >= 0 ) q.setFirstResult ( offset );
if ( limit != null && offset < Integer.MAX_VALUE ) q.setMaxResults ( limit );
int ct = 0;
for ( ScrollableResults rs = q.scroll ( ScrollMode.FORWARD_ONLY ); rs.next (); )
{
D descr = (D) rs.get ( 0 );
JAXBUtils.marshal ( descr, targetClass, out, Marshaller.JAXB_FRAGMENT, true );
ct++;
}
return ct;
}
}