Skip to content

Commit

Permalink
Issue #6556 Ensure context classloader set when operating on memcache. (
Browse files Browse the repository at this point in the history
#6557)

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

Signed-off-by: Jan Bartel <janb@webtide.com>
  • Loading branch information
janbartel committed Aug 2, 2021
1 parent 409a2fc commit 90a72b0
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 48 deletions.
Expand Up @@ -25,6 +25,7 @@
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;
Expand All @@ -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
Expand Down Expand Up @@ -140,8 +142,12 @@ public void setHeartbeats(boolean heartbeats)
@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());
Expand All @@ -155,14 +161,48 @@ public void initialize(SessionContext context)
@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
{
_client.set(id, _expirySec, data);
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
Expand Down
Expand Up @@ -15,8 +15,10 @@

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;
Expand All @@ -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.
*
Expand Down Expand Up @@ -171,21 +138,22 @@ public SessionData load(String id) throws Exception
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();
}

Expand Down Expand Up @@ -214,40 +182,41 @@ public void store(String id, SessionData data) throws Exception
//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
{
//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);
}
};

Expand Down
24 changes: 24 additions & 0 deletions jetty-util/src/main/java/org/eclipse/jetty/util/FuturePromise.java
Expand Up @@ -118,6 +118,30 @@ public C get() throws InterruptedException, ExecutionException
throw (CancellationException)new CancellationException().initCause(_cause);
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
Expand Down

0 comments on commit 90a72b0

Please sign in to comment.