Index: BioSQLRichObjectBuilder.java
===================================================================
--- BioSQLRichObjectBuilder.java	(revision 7539)
+++ BioSQLRichObjectBuilder.java	(working copy)
@@ -18,8 +18,8 @@
  *      http://www.biojava.org/
  *
  */
+package org.biojavax.bio.db.biosql;
 
-package org.biojavax.bio.db.biosql;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
@@ -36,7 +36,6 @@
 import org.biojavax.bio.taxa.SimpleNCBITaxon;
 import org.biojavax.ontology.SimpleComparableOntology;
 
-
 /**
  * Takes requests for RichObjects and sees if it can load them from a Hibernate
  * database. If it can, it returns the loaded objects. Else, it creates them
@@ -45,20 +44,23 @@
  * makes it memory-efficient.
  * @author Richard Holland
  * @author David Scott
+ * @author Deepak Sheoran
  * @since 1.5
  */
+@SuppressWarnings({"unchecked", "rawtypes"})
 public class BioSQLRichObjectBuilder implements RichObjectBuilder {
-    
+
     private Object session;
     private Method createQuery;
     private Method setParameter;
     private Method uniqueResult;
     private Method persist;
-    
+
     /**
      * Creates a new instance of SimpleRichObjectBuilder. The session parameter
      * is a Hibernate Session object and must not be null. It is this session
      * that database objects will be retrieved from/persisted to.
+     * @param session
      * @see <a href="http://www.hibernate.org/hib_docs/v3/api/org/hibernate/Session.html"> org.hibernate.Session</a>
      */
     public BioSQLRichObjectBuilder(Object session) {
@@ -67,16 +69,17 @@
             Class hibernateSession = session.getClass();
             Class realHibernateSession = Class.forName("org.hibernate.Session");
             // Test to see if our parameter is really a Session
-            if (!realHibernateSession.isAssignableFrom(hibernateSession))
+            if (!realHibernateSession.isAssignableFrom(hibernateSession)) {
                 throw new IllegalArgumentException("Parameter must be a org.hibernate.Session object");
+            }
             this.session = session;
             // Lookup the createQuery and persist methods
             this.createQuery = hibernateSession.getMethod("createQuery", new Class[]{String.class});
-            this.persist = hibernateSession.getMethod("persist", new Class[]{String.class,Object.class});
+            this.persist = hibernateSession.getMethod("persist", new Class[]{String.class, Object.class});
             // Lazy load the Query class from Hibernate.
             Class hibernateQuery = Class.forName("org.hibernate.Query");
             // Lookup the setParameter and uniqueQuery methods
-            this.setParameter = hibernateQuery.getMethod("setParameter", new Class[]{int.class,Object.class});
+            this.setParameter = hibernateQuery.getMethod("setParameter", new Class[]{int.class, Object.class});
             this.uniqueResult = hibernateQuery.getMethod("uniqueResult", new Class[]{});
         } catch (ClassNotFoundException e) {
             throw new RuntimeException(e);
@@ -84,7 +87,7 @@
             throw new RuntimeException(e);
         }
     }
-    
+
     /**
      * {@inheritDoc}
      * Attempts to look up the details of the object in the database. If it
@@ -94,35 +97,147 @@
     public Object buildObject(Class clazz, List paramsList) {
         // convert the params list to remove nulls as we can't process those.
         List ourParamsList = new ArrayList(paramsList);
-        for (Iterator i = ourParamsList.iterator(); i.hasNext(); ) 
-        	if (i.next()==null) i.remove();
-        // Create the Hibernate query to look it up with
-        String queryText;
-        String queryType;
-        if (SimpleNamespace.class.isAssignableFrom(clazz)) {
-            queryText = "from Namespace as ns where ns.name = ?";
-            queryType = "Namespace";
-        } else if (SimpleComparableOntology.class.isAssignableFrom(clazz)) {
-            queryText = "from Ontology as o where o.name = ?";
-            queryType = "Ontology";
-        } else if (SimpleNCBITaxon.class.isAssignableFrom(clazz)) {
-            queryText = "from Taxon as o where o.NCBITaxID = ?";
-            queryType = "Taxon";
-        } else if (SimpleCrossRef.class.isAssignableFrom(clazz)) {
-            queryText = "from CrossRef as cr where cr.dbname = ? and cr.accession = ? and cr.version = ?";
-            queryType = "CrossRef";
-        } else if (SimpleDocRef.class.isAssignableFrom(clazz)) {
-        	queryType = "DocRef";
-        	// convert List constructor to String representation for query
-        	ourParamsList.set(0, DocRefAuthor.Tools.generateAuthorString((List)ourParamsList.get(0), true));
-        	if (ourParamsList.size()<3) {
-        		queryText = "from DocRef as cr where cr.authors = ? and cr.location = ? and cr.title is null";
-        	} else {
-        		queryText = "from DocRef as cr where cr.authors = ? and cr.location = ? and cr.title = ?";
-        	}        
-        } else throw new IllegalArgumentException("Don't know how to handle objects of type "+clazz);
-        // Run the query.
+        for (Iterator i = ourParamsList.iterator(); i.hasNext();) {
+            if (i.next() == null) {
+                i.remove();
+            }
+        }
+        // Try to Run the appropriate query.
         try {
+            // Create the Hibernate query to look it up with
+            String queryText;
+            String queryType;
+            if (SimpleNamespace.class.isAssignableFrom(clazz)) {
+                queryText = "from Namespace as ns where ns.name = ?";
+                queryType = "Namespace";
+                Object result = this.excuteQuery(clazz, queryText, ourParamsList);
+                if (result != null) {
+                    return result;
+                } else {
+                    return this.createNewObject(clazz, queryType, ourParamsList);
+                }
+            } else if (SimpleComparableOntology.class.isAssignableFrom(clazz)) {
+                queryText = "from Ontology as o where o.name = ?";
+                queryType = "Ontology";
+                Object result = this.excuteQuery(clazz, queryText, ourParamsList);
+                if (result != null) {
+                    return result;
+                } else {
+                    return this.createNewObject(clazz, queryType, ourParamsList);
+                }
+            } else if (SimpleNCBITaxon.class.isAssignableFrom(clazz)) {
+                queryText = "from Taxon as o where o.NCBITaxID = ?";
+                queryType = "Taxon";
+                Object result = this.excuteQuery(clazz, queryText, ourParamsList);
+                if (result != null) {
+                    return result;
+                } else {
+                    return this.createNewObject(clazz, queryType, ourParamsList);
+                }
+            } else if (SimpleCrossRef.class.isAssignableFrom(clazz)) {
+                queryText = "from CrossRef as cr where cr.dbname = ? and cr.accession = ? and cr.version = ?";
+                queryType = "CrossRef";
+                Object result = this.excuteQuery(clazz, queryText, ourParamsList);
+                if (result != null) {
+                    return result;
+                } else {
+                    return this.createNewObject(clazz, queryType, ourParamsList);
+                }
+            } else if (SimpleDocRef.class.isAssignableFrom(clazz)) {
+                queryType = "DocRef";
+                // convert List constructor to String representation for query
+                ourParamsList.set(0, DocRefAuthor.Tools.generateAuthorString((List) ourParamsList.get(0), true));
+                // first check if record exists with pubmed or mediline id
+                if (ourParamsList.size() == 5 || ourParamsList.size() == 6) {
+                    ArrayList crossRefParams = new ArrayList();
+                    queryText = "from DocRef as cr where cr.crossref = (select id from CrossRef as cref where cref.dbname = ? and cref.accession = ? and cref.version = ?)";
+                    crossRefParams.add(ourParamsList.get(ourParamsList.size() - 3)); // get dbname
+                    crossRefParams.add(ourParamsList.get(ourParamsList.size() - 2)); // get accession
+                    crossRefParams.add(ourParamsList.get(ourParamsList.size() - 1)); // get version
+                    Object result = this.excuteQuery(clazz, queryText, crossRefParams);
+                    if (result != null) {
+                        return result;
+                    }
+                    // clean up ourparamslist variable
+                    ourParamsList.remove(ourParamsList.get(ourParamsList.size() - 3));
+                    ourParamsList.remove(ourParamsList.get(ourParamsList.size() - 2));
+                    ourParamsList.remove(ourParamsList.get(ourParamsList.size() - 1));
+                }
+                // check on the base of authors, title, location
+                if (ourParamsList.size() == 3) {
+                    queryText = "from DocRef as cr where cr.authors = ? and cr.location = ? and cr.title = ?";
+                    Object result = this.excuteQuery(clazz, queryText, ourParamsList);
+                    if (result != null) {
+                        return result;
+                    } else {
+                        return this.createNewObject(clazz, queryType, ourParamsList);
+                    }
+                } else if (ourParamsList.size() == 2) {
+                    queryText = "from DocRef as cr where cr.authors = ? and cr.location = ? and cr.title is null";
+                    Object result = this.excuteQuery(clazz, queryText, ourParamsList);
+                    if (result != null) {
+                        return result;
+                    } else {
+                        return this.createNewObject(clazz, queryType, ourParamsList);
+                    }
+                } else {
+                    throw new IllegalArgumentException("Don't know how to handle parameter of size:" + paramsList.size() + " for objects of type " + clazz);
+                }
+            } else {
+                throw new IllegalArgumentException("Don't know how to handle objects of type " + clazz);
+            }
+        } catch (IllegalArgumentException e) {
+            throw e;
+        }
+    }
+
+    /**
+     * It will create a new class object of given class with given class type
+     * and list of params
+     * @param clazz
+     * @param queryType
+     * @param ourParamsList
+     * @return
+     */
+    private Object createNewObject(Class clazz, String queryType, List ourParamsList) {
+        try {
+            // Load the class
+            Class[] types = new Class[ourParamsList.size()];
+            // Find its constructor with given params
+            for (int i = 0; i < ourParamsList.size(); i++) {
+                if (ourParamsList.get(i) instanceof Set) {
+                    types[i] = Set.class;
+                } else if (ourParamsList.get(i) instanceof Map) {
+                    types[i] = Map.class;
+                } else if (ourParamsList.get(i) instanceof List) {
+                    types[i] = List.class;
+                } else {
+                    types[i] = ourParamsList.get(i).getClass();
+                }
+            }
+            Constructor c = clazz.getConstructor(types);
+            // Instantiate it with the parameters
+            Object o = c.newInstance(ourParamsList.toArray());
+            // Persist and return it.
+            this.persist.invoke(this.session, new Object[]{queryType, o});
+            return o;
+        } catch (Exception e) {
+            // Throw the exception with our nice message
+            throw new RuntimeException("Error while trying to call new " + this.formatException(clazz, ourParamsList), e);
+        }
+    }
+
+    /**
+     * It will execute a the given query for a class with given params and return
+     * a object of given class
+     * @param clazz
+     * @param query
+     * @param queryText
+     * @param ourParamsList
+     * @return
+     */
+    private Object excuteQuery(Class clazz, String queryText, List ourParamsList) {
+        try {
             // Build the query object
             Object query = this.createQuery.invoke(this.session, new Object[]{queryText});
             // Set the parameters
@@ -130,41 +245,31 @@
                 query = this.setParameter.invoke(query, new Object[]{new Integer(i), ourParamsList.get(i)});
             }
             // Get the results
-            Object result = this.uniqueResult.invoke(query, (Object[])null);
-            // Return the found object, if found
-            if (result!=null) return result;
-            // Create, persist and return the new object otherwise
-            else {
-                // Load the class
-                Class[] types = new Class[ourParamsList.size()];
-                // Find its constructor with given params
-                for (int i = 0; i < ourParamsList.size(); i++) {
-                    if (ourParamsList.get(i) instanceof Set) types[i] = Set.class;
-                    else if (ourParamsList.get(i) instanceof Map) types[i] = Map.class;
-                    else if (ourParamsList.get(i) instanceof List) types[i] = List.class;
-                    else types[i] = ourParamsList.get(i).getClass();
-                }
-                Constructor c = clazz.getConstructor(types);
-                // Instantiate it with the parameters
-                Object o = c.newInstance(ourParamsList.toArray());
-                // Persist and return it.
-                this.persist.invoke(this.session, new Object[]{queryType,o});
-                return o;
-            }
+            return this.uniqueResult.invoke(query, (Object[]) null);
         } catch (Exception e) {
-            // Write a useful message explaining what we were trying to do. It will
-            // be in the form "class(param,param...)".
-            StringBuffer paramsstuff = new StringBuffer();
-            paramsstuff.append(clazz);
-            paramsstuff.append("(");
-            for (int i = 0; i < ourParamsList.size(); i++) {
-                if (i>0) paramsstuff.append(",");
-            	paramsstuff.append(ourParamsList.get(i).getClass());
-            }
-            paramsstuff.append(")");
             // Throw the exception with our nice message
-            throw new RuntimeException("Error while trying to call new "+paramsstuff,e);
+            throw new RuntimeException("Error while trying to call new " + this.formatException(clazz, ourParamsList), e);
         }
     }
-    
+
+    /**
+     * Write a useful message explaining what we were trying to do. It will
+     * be in the form "class(param,param...)".
+     * @param clazz
+     * @param ourParamsList
+     * @return
+     */
+    private String formatException(Class clazz, List ourParamsList) {
+        StringBuffer paramsstuff = new StringBuffer();
+        paramsstuff.append(clazz);
+        paramsstuff.append("(");
+        for (int i = 0; i < ourParamsList.size(); i++) {
+            if (i > 0) {
+                paramsstuff.append(",");
+            }
+            paramsstuff.append(ourParamsList.get(i).getClass());
+        }
+        paramsstuff.append(")");
+        return paramsstuff.toString();
+    }
 }
