package ameba.lib; import ameba.websocket.WebSocketException; import org.glassfish.jersey.internal.util.Producer; import org.glassfish.jersey.process.internal.RequestScope; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.reflect.Field; import java.security.PrivilegedAction; import java.util.concurrent.Callable; import static java.lang.invoke.MethodType.methodType; /** * <p>JerseyScopeDelegate class.</p> * * @author icode * */ public class JerseyScopeDelegate { private static final MethodHandles.Lookup lookup = ((PrivilegedAction<MethodHandles.Lookup>) () -> { try { Field field = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP"); field.setAccessible(true); return (MethodHandles.Lookup) field.get(null); } catch (NoSuchFieldException | IllegalAccessException e) { throw new WebSocketException(e); } }).run(); private static final MethodHandle RETRIEVE_CURRENT_HANDLE = getMethodHandle( "retrieveCurrent", RequestScope.Instance.class ); private static final MethodHandle SET_CURRENT_HANDLE = getMethodHandle( "setCurrent", void.class, RequestScope.Instance.class ); private static final MethodHandle RESUME_CURRENT_HANDLE = getMethodHandle( "resumeCurrent", void.class, RequestScope.Instance.class ); private RequestScope scope; /** * <p>Constructor for JerseyScopeDelegate.</p> * * @param scope a {@link org.glassfish.jersey.process.internal.RequestScope} object. */ public JerseyScopeDelegate(RequestScope scope) { this.scope = scope; } private static MethodHandle getMethodHandle(String name, Class rtype, Class... args) { try { return lookup.findSpecial( RequestScope.class, name, methodType(rtype, args), RequestScope.class ); } catch (NoSuchMethodException | IllegalAccessException e) { throw new WebSocketException(e); } } /** * <p>createInstance.</p> * * @return a {@link org.glassfish.jersey.process.internal.RequestScope.Instance} object. */ public RequestScope.Instance createInstance() { return scope.createInstance(); } /** * <p>retrieveCurrent.</p> * * @return a {@link org.glassfish.jersey.process.internal.RequestScope.Instance} object. */ public RequestScope.Instance retrieveCurrent() { try { return (RequestScope.Instance) RETRIEVE_CURRENT_HANDLE.invokeExact(this.scope); } catch (Throwable throwable) { throw new WebSocketException(throwable); } } /** * <p>setCurrent.</p> * * @param instance a {@link org.glassfish.jersey.process.internal.RequestScope.Instance} object. */ public void setCurrent(RequestScope.Instance instance) { try { SET_CURRENT_HANDLE.invokeExact(this.scope, instance); } catch (Throwable throwable) { throw new WebSocketException(throwable); } } /** * <p>resumeCurrent.</p> * * @param oldInstance a {@link org.glassfish.jersey.process.internal.RequestScope.Instance} object. */ public void resumeCurrent(RequestScope.Instance oldInstance) { try { RESUME_CURRENT_HANDLE.invokeExact(this.scope, oldInstance); } catch (Throwable throwable) { throw new WebSocketException(throwable); } } /** * <p>isActive.</p> * * @return a boolean. */ public boolean isActive() { return scope.isActive(); } /** * <p>referenceCurrent.</p> * * @return a {@link org.glassfish.jersey.process.internal.RequestScope.Instance} object. * @throws java.lang.IllegalStateException if any. */ public RequestScope.Instance referenceCurrent() throws IllegalStateException { return scope.referenceCurrent(); } public RequestScope.Instance current() { return scope.current(); } /** * <p>suspendCurrent.</p> * * @return a {@link org.glassfish.jersey.process.internal.RequestScope.Instance} object. */ public RequestScope.Instance suspendCurrent() { return scope.suspendCurrent(); } /** * <p>runInScope.</p> * * @param scopeInstance a {@link org.glassfish.jersey.process.internal.RequestScope.Instance} object. * @param task a {@link java.lang.Runnable} object. */ public void runInScope(RequestScope.Instance scopeInstance, Runnable task) { scope.runInScope(scopeInstance, task); } /** * <p>runInScope.</p> * * @param task a {@link java.lang.Runnable} object. */ public void runInScope(Runnable task) { scope.runInScope(task); } /** * <p>runInScope.</p> * * @param scopeInstance a {@link org.glassfish.jersey.process.internal.RequestScope.Instance} object. * @param task a {@link java.util.concurrent.Callable} object. * @param <T> a T object. * @return a T object. * @throws java.lang.Exception if any. */ public <T> T runInScope(RequestScope.Instance scopeInstance, Callable<T> task) throws Exception { return scope.runInScope(scopeInstance, task); } /** * <p>runInScope.</p> * * @param task a {@link java.util.concurrent.Callable} object. * @param <T> a T object. * @return a T object. * @throws java.lang.Exception if any. */ public <T> T runInScope(Callable<T> task) throws Exception { return scope.runInScope(task); } /** * <p>runInScope.</p> * * @param scopeInstance a {@link org.glassfish.jersey.process.internal.RequestScope.Instance} object. * @param task a {@link org.glassfish.jersey.internal.util.Producer} object. * @param <T> a T object. * @return a T object. */ public <T> T runInScope(RequestScope.Instance scopeInstance, Producer<T> task) { return scope.runInScope(scopeInstance, task); } /** * <p>runInScope.</p> * * @param task a {@link org.glassfish.jersey.internal.util.Producer} object. * @param <T> a T object. * @return a T object. */ public <T> T runInScope(Producer<T> task) { return scope.runInScope(task); } /** * <p>enterScope.</p> * * @return a {@link org.glassfish.jersey.process.internal.RequestScope.Instance} object. */ public RequestScope.Instance enterScope() { final RequestScope.Instance oldInstance = retrieveCurrent(); final RequestScope.Instance instance = createInstance(); setCurrent(instance); return oldInstance; } /** * <p>leaveScope.</p> * * @param oldInstance a {@link org.glassfish.jersey.process.internal.RequestScope.Instance} object. */ public void leaveScope(RequestScope.Instance oldInstance) { retrieveCurrent().release(); resumeCurrent(oldInstance); } /** * <p>shutdown.</p> */ public void shutdown() { scope.shutdown(); } }