/******************************************************************************* * Copyright (c) 2004, 2010 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.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.persistence.EntityManager; import javax.persistence.LockModeType; import javax.persistence.PersistenceException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jubula.client.core.businessprocess.ParamNameBP; import org.eclipse.jubula.client.core.businessprocess.ProjectNameBP; import org.eclipse.jubula.client.core.i18n.Messages; import org.eclipse.jubula.client.core.model.IPersistentObject; import org.eclipse.jubula.client.core.model.IProjectPO; import org.eclipse.jubula.client.core.model.IReusedProjectPO; import org.eclipse.jubula.tools.internal.constants.StringConstants; import org.eclipse.jubula.tools.internal.exception.JBException; import org.eclipse.jubula.tools.internal.exception.JBFatalAbortException; import org.eclipse.jubula.tools.internal.exception.JBRuntimeException; import org.eclipse.jubula.tools.internal.exception.ProjectDeletedException; import org.eclipse.jubula.tools.internal.messagehandling.MessageIDs; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author BREDEX GmbH * @created 13.10.2004 */ public class GeneralStorage implements IEntityManagerProvider { /** standard logging */ private static final Logger LOG = LoggerFactory.getLogger(GeneralStorage.class); /** * Comment for <code>instance</code> */ private static GeneralStorage instance = null; /** * associated project with childrenList of testsuites and additional list * of object for specification tree (specTestCases and categories) **/ private IProjectPO m_project = null; /** The reused projects managed by the main session */ private Map<Long, IProjectPO> m_reusedProjects = null; /** * <code>m_masterSession</code>session only for objects to display * **/ private EntityManager m_masterSession = null; /** List of listeners for reloaded session. */ private Set<IReloadedSessionListener> m_reloadSessionListeners = new HashSet<IReloadedSessionListener>(); /** list of listeners for refreshed object */ private Set<IDataModifiedListener> m_dataModifiedListeners = new HashSet<IDataModifiedListener>(); /** * only for persistence */ private GeneralStorage() { // nothing } /** * @return Returns the instance. */ public static synchronized GeneralStorage getInstance() { if (instance == null) { instance = new GeneralStorage(); } return instance; } /** * @return Returns the project. */ public IProjectPO getProject() { return m_project; } /** Nulls the project */ public void nullProject() { m_project = null; m_reusedProjects = null; } /** * Sets the project and loads the reused projects into the master session * @param project the project * @throws JBException the exception */ public void setProjectLoadReused(IProjectPO project) throws JBException { m_project = project; if (project == null) { m_reusedProjects = null; return; } m_reusedProjects = new HashMap<>(); for (IReusedProjectPO reused : project.getUsedProjects()) { IProjectPO reusedP = ProjectPM.loadReusedProjectInMasterSession( reused); if (reusedP != null) { m_reusedProjects.put(reusedP.getId(), reusedP); } } } /** * Returns the reused projects * @return the ID => ProjectPO map */ public Map<Long, IProjectPO> getReusedProjects() { return m_reusedProjects; } /** * @return Returns the masterSession. */ public EntityManager getMasterSession() { if (m_masterSession == null) { m_masterSession = Persistor.instance().openSession(); } return m_masterSession; } /** * dispose (to be able to open a new db connection) */ public void dispose() { try { clearMasterSession(); } catch (PMException e) { LOG.error(Messages.ClearingOfMasterSessionFailed, e); } Persistor.instance().dropSession(m_masterSession); m_masterSession = null; m_project = null; } /** * */ public void reset() { final EntityManager masterSession = GeneralStorage.getInstance() .getMasterSession(); try { clearMasterSession(); Persistor.instance().dropSession(masterSession); m_masterSession = Persistor.instance().openSession(); } catch (PMException e) { LOG.warn(Messages.ResetFailed, e); } m_project = null; } /** * @throws PMException in case of problem with evicting of objects */ private void clearMasterSession() throws PMException { final EntityManager masterSession = GeneralStorage.getInstance() .getMasterSession(); ParamNameBP.getInstance().clearParamNames(); try { masterSession.clear(); } catch (PersistenceException e) { throw new PMException(Messages.ClearingOfMasterSessionFailed, MessageIDs.E_DATABASE_GENERAL); } } /** * recovers a faulty session, no data is reloaded */ public void recoverSession() { try { if (getMasterSession() != null && getMasterSession().isOpen()) { Persistor.instance().dropSession(getMasterSession()); } m_masterSession = Persistor.instance().openSession(); if (m_project != null) { getMasterSession().lock(m_project, LockModeType.NONE); } } catch (PersistenceException e) { handleFatalError(e); } catch (JBRuntimeException e) { handleFatalError(e); } } /** * @param t cause of error */ public static void handleFatalError(Throwable t) { final String msg = Messages.NonRecoverableError + StringConstants.DOT; LOG.error(msg, t); throw new JBFatalAbortException(msg, t, MessageIDs.E_NON_RECOVERABLE); } /** * reopen the session and reload any object in master session * * @param monitor The progress monitor for this operation. * @throws ProjectDeletedException if the project was deleted in another * instance */ public void reloadMasterSession(IProgressMonitor monitor) throws ProjectDeletedException { ProjectNameBP.getInstance().clearCache(); try { NodePM.getInstance().setUseCache(true); if (m_project != null) { // loadProjectInROSession will do a complete reset ProjectPM.loadProjectInROSession(m_project); if (m_project == null) { reset(); throw new ProjectDeletedException( Messages.ProjectWasDeleted, MessageIDs.E_CURRENT_PROJ_DEL); } fireSessionReloaded(monitor); } } catch (PersistenceException e) { handleFatalError(e); } catch (PMReadException e) { handleFatalError(e); } finally { NodePM.getInstance().setUseCache(false); } } /** * Adds the IReloadedSessionListener. * @param listener the IReloadedSessionListener to be added. */ public void addReloadedSessListener(IReloadedSessionListener listener) { m_reloadSessionListeners.add(listener); } /** * Removes the IReloadedSessionListener. * @param listener the IReloadedSessionListener. */ public void removeReloadedSessListener(IReloadedSessionListener listener) { m_reloadSessionListeners.remove(listener); } /** * notifies the IReloadedSessionListener * * @param monitor The progress monitor for this operation. */ public void fireSessionReloaded(IProgressMonitor monitor) { Set<IReloadedSessionListener> listeners = new HashSet<IReloadedSessionListener>(m_reloadSessionListeners); for (IReloadedSessionListener listener : listeners) { try { listener.reloadData(monitor); } catch (Throwable e) { LOG.error(Messages.InvocationOfListenerForReloadingSessionFailed + StringConstants.DOT); } } } /** * listener for reloaded session * warning: this listener is only provided for notification about events * inside of GeneralStorage * Don't use this listener for other purpose! * */ public interface IReloadedSessionListener { /** * callback method * * @param monitor The progress monitor for this operation. */ public void reloadData(IProgressMonitor monitor); } /** * listener for refreshed persistent object * warning: this listener is only provided for notification about events * inside of GeneralStorage * Don't use this listener for other purpose! * */ public interface IDataModifiedListener { /** * callback method * @param po refreshed object */ public void dataModified(IPersistentObject po); } /** * @param l listener to add */ public void addDataModifiedListener(IDataModifiedListener l) { m_dataModifiedListeners.add(l); } /** * @param l listener to remove */ public void removeDataModifiedListener(IDataModifiedListener l) { m_dataModifiedListeners.remove(l); } /** * notifies the IDataModifiedListener * @param po modified persistent object */ public void fireDataModified(IPersistentObject po) { Set<IDataModifiedListener> listeners = new HashSet<IDataModifiedListener>(m_dataModifiedListeners); for (IDataModifiedListener listener : listeners) { try { listener.dataModified(po); } catch (Throwable e) { LOG.error(Messages.InvocationOfListenerForReloadingSessionFailed + StringConstants.DOT); } } } /** * Ensures that the given project is still in the DB. Please be aware that * there is still a slightly chance that the project is delete at this * very moment. * @param project Project to verify * @throws ProjectDeletedException if the project is not in the DB */ public void validateProjectExists(IProjectPO project) throws ProjectDeletedException { if (!ProjectPM.doesProjectExist(project.getId())) { throw new ProjectDeletedException(Messages.ProjectNotInDB, MessageIDs.E_CURRENT_PROJ_DEL); } } /** * * {@inheritDoc} */ public EntityManager getEntityManager() { return getMasterSession(); } }