/*
* EuroCarbDB, a framework for carbohydrate bioinformatics
*
* Copyright (c) 2006-2009, Eurocarb project, or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
* A copy of this license accompanies this distribution in the file LICENSE.txt.
*
* This program 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.
*
* Last commit: $Rev: 1870 $ by $Author: david@nixbioinf.org $ on $Date:: 2010-02-23 #$
*/
package org.eurocarbdb.dataaccess;
// stdlib imports
import java.util.*;
import java.io.File;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
// 3rd party imports
import org.apache.log4j.Logger;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationUtils;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.CompositeConfiguration;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.HibernateException;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.ProjectionList;
// eurocarb imports
import org.eurocarbdb.dataaccess.core.*;
// import org.eurocarbdb.dataaccess.hibernate.HibernateUtil;
import org.eurocarbdb.dataaccess.EntityManager;
// static imports
import static org.eurocarbdb.util.StringUtils.CR;
import static org.eurocarbdb.util.StringUtils.coerce;
import static org.eurocarbdb.util.StringUtils.repeat;
/* class Eurocarb *//**********************************************
*<p>
* Core class for exposing key elements of data access and funcionality
* for the Eurocarb platform.
*</p>
*<p>
* All access to EurocarbDB and associated data normally occurs through
* an {@link EntityManager} instance, which essentially acts as a factory class
* for EurocarbDB objects.
*</p>
*<p>
* Code using EntityManagers to create/manipulate data objects
* should statically import the getEntityManager methods from
* this class at their own convenience.
*</p>
*<p>
* ie:
*<tt>
* import static org.eurocarbdb.dataaccess.Eurocarb.getEntityManager;
*</tt>
*</p>
*<p>
* Access to project-wide constants and settings is provided through
* the getProperty method of this class.
*</p>
*
* @author mjh
*/
public final class Eurocarb
{
/** Logging handle. */
public static final Logger log = Logger.getLogger( Eurocarb.class );
/** This class is not intended to be instantiated. */
private Eurocarb() {}
/*
* multiple sections to this class:
* - EntityManager stuff
* - Project-wide configuration properties
* - user access & authentication
* - utility methods
*/
//~~~~~~~~~~~~~~~~~ EntityManager stuff ~~~~~~~~~~~~~~~~~~~~~~~
private static final Map<String,EntityManager> Entity_Managers
= new HashMap<String,EntityManager>();
/*/**************************************************************
*
* Register all default EMs here.
*/
static
{
registerEntityManager( "default", new HibernateEntityManager() );
}
/**
* Looks up a Eurocarb data object using its canonical id.
*/
public static final <T> T lookup( Class<T> c, int id )
{
return getEntityManager().lookup( c, id );
}
/* getEntityManager *//****************************************
*
* Returns the default EntityManager.
*/
public static final EntityManager getEntityManager()
{
return getEntityManager("default");
}
/**
* Clone of getEntityManager(), just prevents the need to cast my hand.
* @return
*/
public static final HibernateEntityManager getHibernateEntityManager(){
return (HibernateEntityManager) getEntityManager("default");
}
public static final Session getHibernateSession(){
return getHibernateEntityManager().getHibernateSession();
}
public static final Query getHqlQuery(String query){
return getHibernateEntityManager().getHibernateSession().createQuery(query);
}
/* getEntityManager *//****************************************
*
* Returns the EntityManager associated with the given name.
* The default EntityManager can be obtained via the String name
* "default".
*/
static final EntityManager getEntityManager( String name )
{
assert name != null;
EntityManager em = Entity_Managers.get( name );
assert( em != null );
return em;
}
/* registerEntityManager *//***********************************
*
* Registers an EntityManager for use.
*/
static final void registerEntityManager( String name, EntityManager em )
{
assert em != null;
Entity_Managers.put( name, em );
}
// mjh: this is a placeholder for functionality that may be added in the future
/*
static final void unregisterEntityManager( String name )
{
assert( Entity_Managers.contains( name ) );
Entity_Managers.remove( name );
}
*/
//~~~~~~~~~~~~~~~~~ User/Contributor stuff ~~~~~~~~~~~~~~~~~~~~
/**
* This is the ID of the {@link Contributor} that is "logged into" the current Thread.
* This will be 0 (the guest contributor id) if noone is logged into this Thread.
*/
static ThreadLocal<Integer> currentContributorId = new ThreadLocal<Integer>();
/** This is the {@link Contributor} that is logged into the current Thread. If noone
* is logged in atm, then this will be the "guest" contributor.
*/
static ThreadLocal<Contributor> currentContributor = new ThreadLocal<Contributor>();
/**
* Returns the {@link Contributor} whose contributor_id is bound
* to the current thread.
*/
public static final Contributor getCurrentContributor()
{
if ( currentContributor.get() != null )
return currentContributor.get();
Integer contrib_id = currentContributorId.get();
if ( contrib_id == null || contrib_id == 0 )
{
Contributor guest = Contributor.getGuestContributor();
assert currentContributor != null;
currentContributor.set( guest );
}
else if ( contrib_id < 0 )
{
throw new IllegalArgumentException(
"currentContributorId was < 0" );
}
else
{
Contributor user = getEntityManager().lookup(
Contributor.class, contrib_id );
if ( user == null )
{
log.warn(
"Invalid contributorId '"
+ contrib_id
+ "'"
);
return null;
}
else currentContributor.set( user );
}
return currentContributor.get();
}
//~~~~~~~~~~~~~~~~~~ Config/Property access ~~~~~~~~~~~~~~~~~~~
/** Where to find main property config file. */
public static final String EUROCARB_CONF = "eurocarbdb-core.properties";
/** Hash of project-wide properties. */
static CompositeConfiguration config = null;
// init property hash from conf file(s).
static void initConfig()
{
//if ( config == null )
config = new CompositeConfiguration();
try
{
// log.info("adding configuration: " + EUROCARB_OVERRIDES_CONF );
// config.addConfiguration(
// new PropertiesConfiguration( EUROCARB_OVERRIDES_CONF ) );
// log.info( "configured properties for core-api: \n"
// + ConfigurationUtils.toString( config ) );
log.info("adding core-api configuration: " + EUROCARB_CONF );
config.addConfiguration(
new PropertiesConfiguration( EUROCARB_CONF ) );
}
catch ( ConfigurationException ex )
{
throw new RuntimeException( ex );
}
if ( log.isInfoEnabled() )
{
log.info(
CR
+ repeat('=', 20 )
+ " configured eurocarb core-api properties "
+ repeat('=', 20 )
+ CR
+ ConfigurationUtils.toString( config )
+ CR
+ repeat('=', 80 )
);
}
}
/* getConfiguration *//****************************************
*
* Returns the current core-api configuration.
*/
public static final CompositeConfiguration getConfiguration()
{
if ( config == null )
initConfig();
return config;
}
/* getProperty *//*********************************************
*
* Shortcut method that returns the value of the passed property
* name. Throws an exception if the given property name doesn't
* exist in the property hash.
*/
public static final String getProperty( String property_name )
{
if (! getConfiguration().containsKey( property_name ) )
{
log.warn( "Given property '"
+ property_name
+ "' does not exist in current config" );
return null;
}
try
{
return (String) getConfiguration().getProperty( property_name );
}
catch ( Exception e )
{
log.warn( "Caught exception while looking up property '"
+ property_name
+ "':"
, e
);
return null;
}
}
/*
public static final void LogConfig()
{
StringBuffer sb = new StringBuffer();
sb.append("Configured Eurocarb properties:" + CR );
Iterator allKeys = config.getKeys();
while ( allKeys.hasNext() )
{
Object key = allKeys.next();
sb.append( " "
+ key
+ " = "
+ config.getProperty((String) key)
+ CR
);
}
log.info( sb.toString() );
}
*/
/**
* Same as {@link #getProperty}, except the property value is pre-cast to
* the given {@link Class}. Eg:
*<pre>
* int limit = getProperty("some_property_name", Integer.class );
*</pre>
* This method works fine for the majority of Java primitive types
* ({@link Integer}, {@link Long}, {@link Float}, {@link Double}, etc),
* with the exception of {@link Character}.
*
* @throws ClassCastException
* If the property value could not be coerced to the given class.
* @throws NumberFormatException
* If the desired class was a primitive numeric type and couldn't be parsed.
*/
public static final <T> T getProperty( String property_name, Class<T> as_class )
{
String property_value = getProperty( property_name );
return coerce( property_value, as_class );
}
/* getPropertyAsURI *//****************************************
*
* Convenience method to return the value of a property as a URI object.
* @deprecated use <tt>getProperty("property_name", URI.class );</tt>
*/
@Deprecated
public static final URI getPropertyAsURI( String property_name )
{
String url_property = getProperty( property_name );
// basic sanity check
if ( url_property == null || url_property.length() == 0 )
throw new RuntimeException( "Expected a value for property '"
+ url_property
+ "'"
);
// ensure it's a valid URI
URI uri;
try
{
uri = new URI( url_property );
}
catch ( URISyntaxException e )
{
throw new RuntimeException( "Malformed url syntax for property '"
+ url_property
+ "'"
);
}
return uri;
}
//~~~~~~~~~~~~~~~~~~~ UTILITY METHODS ~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* getRecentContributions *//**********************************
*
* Returns a {@link List} of given length of the most recently
* {@link Contributed} objects to the current data store, in order
* of most to least recent, or an empty list if there are no
* {@link Contributed} objects. Note that this method only
* returns additions -- modifications to older objects will not
* be included.
*
* @see Contributor.getMyRecentContributions(int)
*/
public static List<Contributed> getRecentContributions( int max_results )
{
// hibernate cannot limit polymorphic queries in the database
// we have to do it one class by one
log.debug("looking up all Contributed objects");
// get all contributed objects
ArrayList<Contributed> changes = new ArrayList<Contributed>();
changes.addAll( getRecentlyContributed( GlycanSequence.class, max_results));
changes.addAll( getRecentlyContributed( Evidence.class, max_results));
/**
* FIXME: I do have a fix in mind for this, but I want to make sure I catch
* everything that was going via BiologicalContext before I reimplement the
* Contributed interface on this class.
*/
//changes.addAll( getRecentlyContributed( BiologicalContext.class, max_results));
changes.addAll( getRecentlyContributed( Reference.class, max_results));
// sort by date
Collections.sort(
changes,
new Comparator<Contributed> ()
{
public int compare(Contributed o1, Contributed o2)
{
return - o1.getDateEntered().compareTo(o2.getDateEntered());
}
public boolean equals(Object obj)
{
return this==obj;
}
}
);
// get sublist
if (changes.size() < max_results) {
return changes;
}
return changes.subList( 0, max_results );
}
public static <T> List<T> getRecentlyContributed( Class<T> c, int max_results )
{
// does c implement Contributed?
if ( Contributed.class.isAssignableFrom( c ) )
{
/* TODO: remove explicit hibernate reference */
List results =
((HibernateEntityManager) getEntityManager())
.getHibernateSession()
.createCriteria( c )
.setResultTransformer( CriteriaSpecification.DISTINCT_ROOT_ENTITY )
.addOrder( Order.desc("dateEntered") )
.setMaxResults(max_results)
.list();
if ( results == null )
return Collections.emptyList();
return (List<T>) results;
}
else
{
List results =
((HibernateEntityManager) getEntityManager())
.getHibernateSession()
.createCriteria( c )
.addOrder( Order.desc("id") )
.setMaxResults(max_results)
.list();
if ( results == null )
return Collections.emptyList();
return (List<T>) results;
}
}
} // end class