Issue #6556 Ensure context classloader set when operating on memcache. (#6557)

* Issue #6556 Ensure context classloader set when operating on memcache.

Signed-off-by: Jan Bartel <janb@webtide.com>
This commit is contained in:
Jan Bartel 2021-08-02 10:04:51 +10:00 committed by GitHub
parent 409a2fc9ff
commit 90a72b0798
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 81 additions and 48 deletions

View File

@ -25,6 +25,7 @@ import org.eclipse.jetty.server.session.SessionContext;
import org.eclipse.jetty.server.session.SessionData;
import org.eclipse.jetty.server.session.SessionDataMap;
import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
@ -43,6 +44,7 @@ public class MemcachedSessionDataMap extends AbstractLifeCycle implements Sessio
protected int _expirySec = 0;
protected boolean _heartbeats = true;
protected XMemcachedClientBuilder _builder;
protected SessionContext _context;
/**
* SessionDataTranscoder
@ -140,8 +142,12 @@ public class MemcachedSessionDataMap extends AbstractLifeCycle implements Sessio
@Override
public void initialize(SessionContext context)
{
if (isStarted())
throw new IllegalStateException("Context set after MemcachedSessionDataMap started");
try
{
_context = context;
_builder.setTranscoder(new SessionDataTranscoder());
_client = _builder.build();
_client.setEnableHeartBeat(isHeartbeats());
@ -155,14 +161,48 @@ public class MemcachedSessionDataMap extends AbstractLifeCycle implements Sessio
@Override
public SessionData load(String id) throws Exception
{
SessionData data = _client.get(id);
return data;
if (!isStarted())
throw new IllegalStateException("Not started");
final FuturePromise<SessionData> result = new FuturePromise<>();
Runnable r = () ->
{
try
{
result.succeeded(_client.get(id));
}
catch (Exception e)
{
result.failed(e);
}
};
_context.run(r);
return result.getOrThrow();
}
@Override
public void store(String id, SessionData data) throws Exception
{
if (!isStarted())
throw new IllegalStateException("Not started");
final FuturePromise<Void> result = new FuturePromise<>();
Runnable r = () ->
{
try
{
_client.set(id, _expirySec, data);
result.succeeded(null);
}
catch (Exception e)
{
result.failed(e);
}
};
_context.run(r);
result.getOrThrow();
}
@Override

View File

@ -15,8 +15,10 @@ package org.eclipse.jetty.server.session;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
@ -40,41 +42,6 @@ public abstract class AbstractSessionDataStore extends ContainerLifeCycle implem
protected long _lastOrphanSweepTime = 0; //last time in ms that we deleted orphaned sessions
protected int _savePeriodSec = DEFAULT_SAVE_PERIOD_SEC; //time in sec between saves
/**
* Small utility class to allow us to
* return a result and an Exception
* from invocation of Runnables.
*
* @param <V> the type of the result.
*/
private class Result<V>
{
private V _result;
private Exception _exception;
public void setResult(V result)
{
_result = result;
}
public void setException(Exception exception)
{
_exception = exception;
}
private void throwIfException() throws Exception
{
if (_exception != null)
throw _exception;
}
public V getOrThrow() throws Exception
{
throwIfException();
return _result;
}
}
/**
* Check if a session for the given id exists.
*
@ -171,21 +138,22 @@ public abstract class AbstractSessionDataStore extends ContainerLifeCycle implem
if (!isStarted())
throw new IllegalStateException("Not started");
final Result<SessionData> result = new Result<>();
final FuturePromise<SessionData> result = new FuturePromise<>();
Runnable r = () ->
{
try
{
result.setResult(doLoad(id));
result.succeeded(doLoad(id));
}
catch (Exception e)
{
result.setException(e);
result.failed(e);
}
};
_context.run(r);
return result.getOrThrow();
}
@ -214,7 +182,7 @@ public abstract class AbstractSessionDataStore extends ContainerLifeCycle implem
//set the last saved time to now
data.setLastSaved(System.currentTimeMillis());
final Result<Object> result = new Result<>();
final FuturePromise<Void> result = new FuturePromise<>();
Runnable r = () ->
{
try
@ -222,32 +190,33 @@ public abstract class AbstractSessionDataStore extends ContainerLifeCycle implem
//call the specific store method, passing in previous save time
doStore(id, data, lastSave);
data.clean(); //unset all dirty flags
result.succeeded(null);
}
catch (Exception e)
{
//reset last save time if save failed
data.setLastSaved(lastSave);
result.setException(e);
result.failed(e);
}
};
_context.run(r);
result.throwIfException();
result.getOrThrow();
}
}
@Override
public boolean exists(String id) throws Exception
{
Result<Boolean> result = new Result<>();
FuturePromise<Boolean> result = new FuturePromise<>();
Runnable r = () ->
{
try
{
result.setResult(doExists(id));
result.succeeded(doExists(id));
}
catch (Exception e)
{
result.setException(e);
result.failed(e);
}
};

View File

@ -119,6 +119,30 @@ public class FuturePromise<C> implements Future<C>, Promise<C>
throw new ExecutionException(_cause);
}
/**
* Return the result if completed successfully
* or in the case of failure, throw the
* Exception/Error, or an ExecutionException wrapping
* the cause if it is neither an Exception or Error.
*
* @return the computed result
* @throws Exception if the cause is an Exception or Error,
* otherwise an ExecutionException wrapping the cause
*/
public C getOrThrow() throws Exception
{
_latch.await();
if (_cause == COMPLETED)
return _result;
if (_cause instanceof Exception)
throw (Exception)_cause;
if (_cause instanceof Error)
throw (Error)_cause;
throw new ExecutionException(_cause);
}
@Override
public C get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
{