/******************************************************************************* * Copyright (c) 2016 BREDEX GmbH. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * BREDEX GmbH - initial API and implementation and/or initial documentation *******************************************************************************/ package org.eclipse.jubula.client.core.persistence; import java.util.Collection; import javax.persistence.EntityManager; import javax.persistence.EntityTransaction; import javax.persistence.PersistenceException; import org.eclipse.jubula.client.core.model.INodePO; import org.eclipse.jubula.client.core.model.IPersistentObject; import org.eclipse.jubula.client.core.persistence.locking.LockManager; import org.eclipse.jubula.tools.internal.exception.ProjectDeletedException; /** * A class supporting transactions with fully integrated Session and Exception handling * The user does not receive any special report on the error, but the causing Exception is * properly displayed. * No exception handling or wrapping is done by this class * @author BREDEX GmbH * */ public class TransactionSupport { /** Private constructor */ private TransactionSupport() { // empty } /** Interface used for the transaction */ public interface ITransaction { /** * Sets the set of objects to be locked - these objects do not have * to be managed anywhere or can be managed by any session * @return the collection of objects */ public Collection<? extends IPersistentObject> getToLock(); /** * Sets the set of objects to be refreshed in the master session * @return the collection of objects */ public Collection<? extends IPersistentObject> getToRefresh(); /** * @return the collection of objects to be merged into the master session */ public Collection<? extends IPersistentObject> getToMerge(); /** * Executes the operations * @param sess the session to use * @throws Exception */ public abstract void run(EntityManager sess) throws Exception; } /** * Executes the transaction * @param op the operation * @throws PersistenceException * @throws PMException * @throws ProjectDeletedException */ public static void transact(ITransaction op) throws Exception { EntityManager sess = null; Persistor per = Persistor.instance(); boolean success = false; try { sess = per.openSession(); EntityTransaction tx = per.getTransaction(sess); LockManager.instance().lockPOs(sess, op.getToLock(), true); op.run(sess); per.commitTransaction(sess, tx); success = true; } finally { per.dropSession(sess); } mergeMasterSession(op); refreshMasterSession(op); } /** * Refreshes objects of the master session * @param op the objects - these don't need to be managed */ private static void refreshMasterSession(ITransaction op) throws PMRefreshFailedException { Collection<? extends IPersistentObject> toRefresh = op.getToRefresh(); if (toRefresh == null || toRefresh.isEmpty()) { return; } try { EntityManager master = GeneralStorage.getInstance(). getMasterSession(); for (IPersistentObject po : toRefresh) { po = master.find(po.getClass(), po.getId()); if (po != null) { master.refresh(po); } if (po instanceof INodePO) { // to set the parents of the children... ((INodePO) po).getUnmodifiableNodeList(); } } } catch (Exception e) { throw new PMRefreshFailedException(e); } } /** * Merges objects of the master session * @param op the objects - these don't need to be managed */ private static void mergeMasterSession(ITransaction op) throws PMRefreshFailedException { Collection<? extends IPersistentObject> toMerge = op.getToMerge(); if (toMerge == null || toMerge.isEmpty()) { return; } try { EntityManager master = GeneralStorage.getInstance(). getMasterSession(); for (IPersistentObject po : toMerge) { master.merge(po); } } catch (Exception e) { throw new PMRefreshFailedException(e); } } }