blob: ea5b3a4e760e7f4016aef41aa7c4415dec343867 [file] [log] [blame]
/*
* Copyright (c) 2008-2013, 2016-2020 Eike Stepper (Loehne, Germany) and others.
* 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:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.emf.cdo.server;
import org.eclipse.emf.cdo.server.IStoreAccessor.CommitContext;
import org.eclipse.emf.cdo.spi.server.InternalSession;
import org.eclipse.net4j.util.io.IOUtil;
import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
import org.eclipse.net4j.util.om.OMPlatform;
import java.util.concurrent.Callable;
/**
* Provides server-side consumers with the {@link IStoreAccessor store accessor} that is valid in the context of a
* specific {@link ISession session} during read operations or a specific {@link CommitContext commit context} during
* write operations.
*
* @author Eike Stepper
* @since 2.0
*/
public final class StoreThreadLocal
{
private static final boolean DEBUG_SESSION = OMPlatform.INSTANCE.isProperty("org.eclipse.emf.cdo.server.StoreThreadLocal.DEBUG_SESSION");
private static final ThreadLocal<InternalSession> SESSION = new ThreadLocal<>();
private static final ThreadLocal<IStoreAccessor> ACCESSOR = new ThreadLocal<>();
private static final ThreadLocal<IStoreAccessor.CommitContext> COMMIT_CONTEXT = new ThreadLocal<>();
private StoreThreadLocal()
{
}
/**
* @since 4.11
*/
public static Runnable wrap(ISession session, Runnable runnable)
{
return () -> {
setSession((InternalSession)session);
try
{
runnable.run();
}
finally
{
release();
}
};
}
/**
* @since 4.11
*/
public static <T> Callable<T> wrap(ISession session, Callable<T> callable)
{
return () -> {
setSession((InternalSession)session);
try
{
return callable.call();
}
finally
{
release();
}
};
}
/**
* @since 3.0
*/
public static void setSession(InternalSession session)
{
if (session == null)
{
REMOVE_SESSION();
}
else
{
SET_SESSION(session);
}
ACCESSOR.remove();
COMMIT_CONTEXT.remove();
}
/**
* Returns the session associated with the current thread.
*
* @return Never <code>null</code>.
* @throws IllegalStateException
* if no session is associated with the current thread.
* @since 3.0
*/
public static InternalSession getSession() throws NoSessionRegisteredException
{
InternalSession session = SESSION.get();
if (session == null)
{
throw new NoSessionRegisteredException();
}
return session;
}
/**
* @since 4.2
*/
public static boolean hasSession()
{
return SESSION.get() != null;
}
public static void setAccessor(IStoreAccessor accessor)
{
if (accessor == null)
{
ACCESSOR.remove();
REMOVE_SESSION();
}
else
{
ACCESSOR.set(accessor);
SET_SESSION(accessor.getSession());
}
}
public static IStoreAccessor getAccessor() throws NoSessionRegisteredException
{
IStoreAccessor accessor = ACCESSOR.get();
if (accessor == null)
{
ISession session = getSession();
IStore store = session.getManager().getRepository().getStore();
accessor = store.getReader(session);
ACCESSOR.set(accessor);
}
return accessor;
}
/**
* @since 4.7
*/
public static boolean hasAccessor()
{
return ACCESSOR.get() != null;
}
public static void setCommitContext(IStoreAccessor.CommitContext commitContext)
{
if (commitContext == null)
{
COMMIT_CONTEXT.remove();
}
else
{
COMMIT_CONTEXT.set(commitContext);
}
}
public static IStoreAccessor.CommitContext getCommitContext()
{
return COMMIT_CONTEXT.get();
}
/**
* @since 4.7
*/
public static boolean hasCommitContext()
{
return COMMIT_CONTEXT.get() != null;
}
/**
* @since 4.2
*/
public static void release()
{
try
{
IStoreAccessor accessor = ACCESSOR.get();
if (accessor != null)
{
if (LifecycleUtil.isActive(accessor))
{
accessor.release();
}
}
}
finally
{
remove();
}
}
/**
* @since 4.5
*/
public static void remove()
{
ACCESSOR.remove();
REMOVE_SESSION();
COMMIT_CONTEXT.remove();
}
private static void SET_SESSION(InternalSession session)
{
if (session != null)
{
if (DEBUG_SESSION)
{
InternalSession oldSession = SESSION.get();
if (oldSession != null)
{
throw new IllegalStateException("Session already registered: " + oldSession);
}
IOUtil.OUT().println("Set " + session + " --> " + Thread.currentThread().getName());
}
SESSION.set(session);
}
}
private static void REMOVE_SESSION()
{
if (DEBUG_SESSION)
{
InternalSession session = SESSION.get();
if (session != null)
{
IOUtil.OUT().println(" Remove " + session + " --> " + Thread.currentThread().getName());
}
}
SESSION.remove();
}
/**
* An {@link IllegalStateException} that can be thrown from {@link StoreThreadLocal#getSession()}.
*
* @author Eike Stepper
* @since 4.2
*/
public static final class NoSessionRegisteredException extends IllegalStateException
{
private static final long serialVersionUID = 1L;
public NoSessionRegisteredException()
{
super("session == null");
}
}
}