package org.simantics.acorn; import java.nio.file.Path; import java.util.concurrent.ConcurrentHashMap; import org.simantics.db.Database; import org.simantics.db.Session; import org.simantics.db.SessionErrorHandler; import org.simantics.db.SessionManager; import org.simantics.db.SessionReference; import org.simantics.db.authentication.UserAuthenticationAgent; import org.simantics.db.common.utils.Logger; import org.simantics.db.event.SessionEvent; import org.simantics.db.event.SessionListener; import org.simantics.db.exception.DatabaseException; import org.simantics.db.exception.RuntimeDatabaseException; import org.simantics.db.service.LifecycleSupport; import org.simantics.utils.datastructures.ListenerList; import fi.vtt.simantics.procore.internal.SessionImplDb; import fi.vtt.simantics.procore.internal.SessionImplSocket; public class AcornSessionManagerImpl implements SessionManager { private static AcornSessionManagerImpl INSTANCE; private ConcurrentHashMap sessionMap = new ConcurrentHashMap<>(); private ListenerList sessionListeners = new ListenerList<>(SessionListener.class); private SessionErrorHandler errorHandler; private Database database; private AcornSessionManagerImpl() {} void finish() { sessionMap = null; sessionListeners = null; } @Override public void addSessionListener(SessionListener listener) { sessionListeners.add(listener); } @Override public Session createSession(SessionReference sessionReference, UserAuthenticationAgent authAgent) throws DatabaseException { SessionImplDb sessionImpl = new SessionImplDb(this, authAgent); boolean ok = false; try { Path dbFolder = sessionReference.getServerReference().getDBFolder(); database = AcornDatabaseManager.getDatabase(dbFolder); Database.Session dbSession = database.newSession(sessionImpl); sessionImpl.connect(sessionReference, dbSession); sessionMap.put(sessionImpl, dbSession); fireSessionOpened(sessionImpl); ok = true; } catch (Throwable e) { Logger.defaultLogError("Connection failed. See exception for details.", e); try { fireSessionClosed(sessionImpl, e); sessionMap.remove(sessionImpl); sessionImpl = null; } catch (Throwable t) { } throw new DatabaseException(e); } finally { if (!ok && null != sessionImpl) sessionImpl.getService(LifecycleSupport.class).close(); } return sessionImpl; } @Override public void removeSessionListener(SessionListener listener) { sessionListeners.remove(listener); } private void fireSessionOpened(SessionImplSocket session) { SessionEvent se = new SessionEvent(session, null); for (SessionListener listener : sessionListeners.getListeners()) { listener.sessionOpened(se); } } private void fireSessionClosed(SessionImplSocket session, Throwable cause) { SessionEvent se = new SessionEvent(session, cause); for (SessionListener listener : sessionListeners.getListeners()) { listener.sessionClosed(se); } } @Override public void shutdown(Session s, Throwable cause) { SessionImplSocket sis = (SessionImplSocket) s; if (null == sis) return; try { fireSessionClosed(sis, cause); } finally { sessionMap.remove(s); } } @Override public SessionErrorHandler getErrorHandler() { return errorHandler; } @Override public void setErrorHandler(SessionErrorHandler errorHandler) { this.errorHandler = errorHandler; } public synchronized static AcornSessionManagerImpl getInstance() { if (INSTANCE == null) INSTANCE = new AcornSessionManagerImpl(); return INSTANCE; } @Override public Database getDatabase() { return database; } public GraphClientImpl2 getClient() { if (sessionMap.values().size() > 1) throw new RuntimeDatabaseException("Currently only one GraphClientImpl2 per session is supported!"); org.simantics.db.Database.Session client = sessionMap.values().iterator().next(); return (GraphClientImpl2) client; } }