package org.genedb.db.loading; import org.genedb.util.TwoKeyMap; import org.gmod.schema.mapped.CvTerm; import org.gmod.schema.mapped.Synonym; import org.gmod.schema.utils.ObjectManager; import org.apache.log4j.Logger; import org.hibernate.Session; import java.util.List; /** * Manage the creation of synonyms during organism loading. * * A SynonymManager object contains a cache of all existing synonyms, * and will return a cached object in preference to creating a new one. * If the cached synonym was not previously requested in the current session, * it is merged before returning. (Thus it is essential to call * {@link #startSession(Session)} whenever a session is started in which * {@link #getSynonym(String,String)} may be called.) * <p> * This mechanism saves the overhead of checking the database every time a synonym * is required, which - according to JProfiler, on the S. mansoni load - * is what the loader spent the majority of its time doing when * {@link ObjectManager#getSynonym(String,String)} was used to create synonyms. * <p> * During the loading life-cycle, each {@link EmblLoader} has a single SynonymManager * instance. For each EMBL file loaded, a new Hibernate session is created and * {@link #startSession(Session)} is called. * * @author rh11 * */ class SynonymManager { private ObjectManager objectManager; private Session session; private static final Logger logger = Logger.getLogger(SynonymManager.class); SynonymManager() { // empty } SynonymManager(ObjectManager objectManager) { this.objectManager = objectManager; } public void setObjectManager(ObjectManager objectManager) { this.objectManager = objectManager; } private boolean preloaded = false; /** * Must be called when a new Hibernate session is started. * @param session the newly-started session */ public void startSession(Session session) { logger.debug("Starting new session"); this.session = session; if (!preloaded) { preload(); preloaded = true; } detachedSynonymsByType.putAll(synonymsByType); synonymsByType.clear(); } private void preload() { logger.debug("Preloading synonyms"); @SuppressWarnings("unchecked") List<Object[]> list = session.createQuery( "select s.type.name, s.name, s from Synonym s" ).list(); for (Object[] array: list) { synonymsByType.put( (String)array[0], (String)array[1], (Synonym)array[2]); } } private TwoKeyMap<String,String,Synonym> detachedSynonymsByType = new TwoKeyMap<String,String,Synonym>(); private TwoKeyMap<String,String,Synonym> synonymsByType = new TwoKeyMap<String,String,Synonym>(); /** * Fetch a synonym from the local cache. Failing that, create a new one. * * @param synonymType the synonym type (should be a term in the <code>genedb_synonym_type</code> CV). * @param synonymString the actual synonym * @return the cached or newly-created synonym object */ public synchronized Synonym getSynonym(String synonymType, String synonymString) { logger.debug(String.format("Looking for synonym '%s:%s'", synonymType, synonymString)); if (session == null) { throw new IllegalStateException("getSynonym called with no session"); } if (synonymsByType.containsKey(synonymType, synonymString)) { logger.debug("Synonym found in cache"); return synonymsByType.get(synonymType, synonymString); } if (detachedSynonymsByType.containsKey(synonymType, synonymString)) { logger.debug("Synonym found in detached cache. Merging"); Synonym mergedSynonym = (Synonym) session.merge(detachedSynonymsByType.get(synonymType, synonymString)); detachedSynonymsByType.remove(synonymType, synonymString); synonymsByType.put(synonymType, synonymString, mergedSynonym); return mergedSynonym; } logger.debug(String.format("Synonym '%s:%s' not found in cache", synonymType, synonymString)); CvTerm synonymTypeCvTerm = (CvTerm) session.load(CvTerm.class, objectManager.getIdOfExistingCvTerm("genedb_synonym_type", synonymType)); Synonym synonym = new Synonym(synonymTypeCvTerm, synonymString, synonymString); synonymsByType.put(synonymType, synonymString, synonym); return synonym; } }