/******************************************************************************* * Copyright 2016 * Ubiquitous Knowledge Processing (UKP) Lab * Technische Universität Darmstadt * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package de.tudarmstadt.ukp.lmf.transform; import java.lang.reflect.Method; import java.util.Date; import java.util.List; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistryBuilder; import de.tudarmstadt.ukp.lmf.hibernate.HibernateConnect; import de.tudarmstadt.ukp.lmf.model.interfaces.IHasParentSpecificTable; import de.tudarmstadt.ukp.lmf.model.miscellaneous.EVarType; import de.tudarmstadt.ukp.lmf.transform.UBYLMFClassMetadata.UBYLMFFieldMetadata; /** * Abstract base class for all resource transformations requiring a * Hibernate session (i.e., transformations requring database access). * @author Christian M. Meyer */ public abstract class UBYHibernateTransformer extends UBYXMLTransformer { protected Session session; protected Transaction tx; protected SessionFactory sessionFactory; public UBYHibernateTransformer(final DBConfig dbConfig) { super(); Configuration cfg = HibernateConnect.getConfiguration(dbConfig); sessionFactory = cfg.buildSessionFactory( new ServiceRegistryBuilder().applySettings( cfg.getProperties()).buildServiceRegistry()); } /** Adds the given child element to the list (which should be a member of * the specified parent), saves the child, and updates the parent. To * reduce the memory footprint, the changes are periodically committed, * and the parent object is cleared. */ @SuppressWarnings({"rawtypes", "unchecked"}) protected void saveListElement(final Object parent, final List list, final Object child) { list.add(child); saveCascade(child, parent); commitCounter++; if(commitCounter % COMMIT_STEP == 0){ commit(); session.clear(); session.update(parent); list.clear(); } } /** Saves all elements of the list and updates their parent (in contrast * to {@link #saveCascade(Object, Object)}, which would also save the * parent and lead to "element already exists" Hibernate exception). */ @SuppressWarnings("rawtypes") protected void saveList(final Object parent, final List list) { for (Object obj : list) saveCascade(obj, parent); session.update(parent); } /** Saves the specified object and all its children to the Hibernate session. * For objects implementing the {@link IHasParentSpecificTable} interface, * a parent should be specified, which is used to derive the table name. */ protected void saveCascade(final Object obj, final Object parent){ Class<?> objClass = obj.getClass(); obj.toString(); // It can happen that a Hibernate object is not initialized properly // --> force initialization of object by calling its toString() method Class<?> parentClass = objClass; if(parent != null){ parentClass = parent.getClass(); parent.toString(); // Force initialization of parent by calling its toString() method } // Identify dependent child objects and save them. UBYLMFClassMetadata classMeta = getClassMetadata(objClass); for (UBYLMFFieldMetadata fieldMeta : classMeta.getFields()) { EVarType varType = fieldMeta.getVarType(); if (varType != EVarType.CHILDREN && varType != EVarType.CHILD) continue; Method getter = fieldMeta.getGetter(); Object retObj = null; try { retObj = getter.invoke(obj); } catch (Exception e) { e.printStackTrace(); } if (retObj == null) continue; if (varType == EVarType.CHILD) saveCascade(retObj, obj); else if (varType == EVarType.CHILDREN) for (Object el : (Iterable<?>) retObj) saveCascade(el, obj); } try { if (obj instanceof IHasParentSpecificTable) session.save(objClass.getSimpleName() + "_" + parentClass.getSimpleName(), obj); else session.save(obj); } catch(Exception ex) { System.err.println("CAN'T SAVE "+objClass.getSimpleName()+" PARENT: "+parentClass.getSimpleName() +": "+ex.getMessage()); } } /** Shorthand for {@link #saveCascade(Object, Object)} with an empty * parent (i.e., the second parameter is null). */ protected void saveCascade(final Object obj){ saveCascade(obj, null); } /** Returns the object of the given class with the specified ID from the * Hibernate session. */ protected Object getLmfObjectById(final Class<?> clazz, final String id) { return session.get(clazz, id); } /** Opens a Hibernate session. */ protected void openSession() { session = sessionFactory.openSession(); tx = session.beginTransaction(); } /** Closes the Hibernate session. */ protected void closeSession() { tx.commit(); session.close(); } /** Commits changes made to the Hibernate session. */ protected void commit() { System.out.println(new Date(System.currentTimeMillis()) + ": COMMIT " + commitCounter); tx.commit(); tx = session.beginTransaction(); } }