From a80a379d2f7aac17229be562ffa196a6ca865079 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Wed, 28 Jul 2021 18:27:52 +1000 Subject: [PATCH 1/5] Issue #6556 Ensure context classloader set when operating on memcache. Signed-off-by: Jan Bartel --- .../session/MemcachedSessionDataMap.java | 47 ++++++++++++++++-- .../session/AbstractSessionDataStore.java | 41 ++-------------- .../jetty/server/session/RunnableResult.java | 49 +++++++++++++++++++ 3 files changed, 95 insertions(+), 42 deletions(-) create mode 100644 jetty-server/src/main/java/org/eclipse/jetty/server/session/RunnableResult.java diff --git a/jetty-memcached/jetty-memcached-sessions/src/main/java/org/eclipse/jetty/memcached/session/MemcachedSessionDataMap.java b/jetty-memcached/jetty-memcached-sessions/src/main/java/org/eclipse/jetty/memcached/session/MemcachedSessionDataMap.java index 531da8eaf1b3..53d967e0ed3b 100644 --- a/jetty-memcached/jetty-memcached-sessions/src/main/java/org/eclipse/jetty/memcached/session/MemcachedSessionDataMap.java +++ b/jetty-memcached/jetty-memcached-sessions/src/main/java/org/eclipse/jetty/memcached/session/MemcachedSessionDataMap.java @@ -21,6 +21,7 @@ import net.rubyeye.xmemcached.MemcachedClient; import net.rubyeye.xmemcached.XMemcachedClientBuilder; import net.rubyeye.xmemcached.transcoders.SerializingTranscoder; +import org.eclipse.jetty.server.session.RunnableResult; import org.eclipse.jetty.server.session.SessionContext; import org.eclipse.jetty.server.session.SessionData; import org.eclipse.jetty.server.session.SessionDataMap; @@ -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,9 +142,13 @@ public void setHeartbeats(boolean heartbeats) @Override public void initialize(SessionContext context) { + if (isStarted()) + throw new IllegalStateException("Context set after MemcachedSessionDataMap started"); + try { - _builder.setTranscoder(new SessionDataTranscoder()); + _context = context; + _builder.setTranscoder(new SessionDataTranscoder(_context.getContext().getClassLoader())); _client = _builder.build(); _client.setEnableHeartBeat(isHeartbeats()); } @@ -155,14 +161,47 @@ 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 RunnableResult result = new RunnableResult<>(); + + Runnable r = () -> + { + try + { + result.setResult(_client.get(id)); + } + catch (Exception e) + { + result.setException(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 RunnableResult result = new RunnableResult<>(); + Runnable r = () -> + { + try + { + _client.set(id, _expirySec, data); + } + catch (Exception e) + { + result.setException(e); + } + }; + _context.run(r); + result.throwIfException(); } @Override diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStore.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStore.java index 49ee9690f160..e24a446820d4 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStore.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStore.java @@ -40,41 +40,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 the type of the result. - */ - private class Result - { - 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,7 +136,7 @@ public SessionData load(String id) throws Exception if (!isStarted()) throw new IllegalStateException("Not started"); - final Result result = new Result<>(); + final RunnableResult result = new RunnableResult<>(); Runnable r = () -> { @@ -214,7 +179,7 @@ public void store(String id, SessionData data) throws Exception //set the last saved time to now data.setLastSaved(System.currentTimeMillis()); - final Result result = new Result<>(); + final RunnableResult result = new RunnableResult<>(); Runnable r = () -> { try @@ -238,7 +203,7 @@ public void store(String id, SessionData data) throws Exception @Override public boolean exists(String id) throws Exception { - Result result = new Result<>(); + RunnableResult result = new RunnableResult<>(); Runnable r = () -> { try diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/RunnableResult.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/RunnableResult.java new file mode 100644 index 000000000000..e68419d58289 --- /dev/null +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/RunnableResult.java @@ -0,0 +1,49 @@ +// +// ======================================================================== +// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +package org.eclipse.jetty.server.session; + +/** + * Small utility class to allow us to + * return a result and an Exception + * from invocation of Runnables. + * + * @param the type of the result. + */ +public class RunnableResult +{ + private V _result; + private Exception _exception; + + public void setResult(V result) + { + _result = result; + } + + public void setException(Exception exception) + { + _exception = exception; + } + + public void throwIfException() throws Exception + { + if (_exception != null) + throw _exception; + } + + public V getOrThrow() throws Exception + { + throwIfException(); + return _result; + } +} \ No newline at end of file From 9679b0c54f890a8a0bdce8cbb2bb16111ee40dca Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Thu, 29 Jul 2021 10:01:23 +1000 Subject: [PATCH 2/5] Issue #6556 Fix arg Signed-off-by: Jan Bartel --- .../jetty/memcached/session/MemcachedSessionDataMap.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jetty-memcached/jetty-memcached-sessions/src/main/java/org/eclipse/jetty/memcached/session/MemcachedSessionDataMap.java b/jetty-memcached/jetty-memcached-sessions/src/main/java/org/eclipse/jetty/memcached/session/MemcachedSessionDataMap.java index 53d967e0ed3b..8c7e6b980fda 100644 --- a/jetty-memcached/jetty-memcached-sessions/src/main/java/org/eclipse/jetty/memcached/session/MemcachedSessionDataMap.java +++ b/jetty-memcached/jetty-memcached-sessions/src/main/java/org/eclipse/jetty/memcached/session/MemcachedSessionDataMap.java @@ -148,7 +148,7 @@ public void initialize(SessionContext context) try { _context = context; - _builder.setTranscoder(new SessionDataTranscoder(_context.getContext().getClassLoader())); + _builder.setTranscoder(new SessionDataTranscoder()); _client = _builder.build(); _client.setEnableHeartBeat(isHeartbeats()); } From d438a1b3a6d5590e6681781329f1942adbc43e95 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Thu, 29 Jul 2021 14:09:56 +1000 Subject: [PATCH 3/5] Issue #6556 Use FuturePromise Signed-off-by: Jan Bartel --- .../session/MemcachedSessionDataMap.java | 15 +++--- .../session/AbstractSessionDataStore.java | 24 +++++---- .../jetty/server/session/RunnableResult.java | 49 ------------------- .../org/eclipse/jetty/util/FuturePromise.java | 21 ++++++++ 4 files changed, 43 insertions(+), 66 deletions(-) delete mode 100644 jetty-server/src/main/java/org/eclipse/jetty/server/session/RunnableResult.java diff --git a/jetty-memcached/jetty-memcached-sessions/src/main/java/org/eclipse/jetty/memcached/session/MemcachedSessionDataMap.java b/jetty-memcached/jetty-memcached-sessions/src/main/java/org/eclipse/jetty/memcached/session/MemcachedSessionDataMap.java index 8c7e6b980fda..78e81f833587 100644 --- a/jetty-memcached/jetty-memcached-sessions/src/main/java/org/eclipse/jetty/memcached/session/MemcachedSessionDataMap.java +++ b/jetty-memcached/jetty-memcached-sessions/src/main/java/org/eclipse/jetty/memcached/session/MemcachedSessionDataMap.java @@ -21,11 +21,11 @@ import net.rubyeye.xmemcached.MemcachedClient; import net.rubyeye.xmemcached.XMemcachedClientBuilder; import net.rubyeye.xmemcached.transcoders.SerializingTranscoder; -import org.eclipse.jetty.server.session.RunnableResult; 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; @@ -164,17 +164,17 @@ public SessionData load(String id) throws Exception if (!isStarted()) throw new IllegalStateException("Not started"); - final RunnableResult result = new RunnableResult<>(); + final FuturePromise result = new FuturePromise<>(); Runnable r = () -> { try { - result.setResult(_client.get(id)); + result.succeeded(_client.get(id)); } catch (Exception e) { - result.setException(e); + result.failed(e); } }; @@ -188,20 +188,21 @@ public void store(String id, SessionData data) throws Exception if (!isStarted()) throw new IllegalStateException("Not started"); - final RunnableResult result = new RunnableResult<>(); + final FuturePromise result = new FuturePromise<>(); Runnable r = () -> { try { _client.set(id, _expirySec, data); + result.succeeded(Boolean.TRUE); } catch (Exception e) { - result.setException(e); + result.failed(e); } }; _context.run(r); - result.throwIfException(); + result.getOrThrow(); } @Override diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStore.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStore.java index e24a446820d4..365e7ed4383e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStore.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStore.java @@ -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; @@ -136,21 +138,22 @@ public SessionData load(String id) throws Exception if (!isStarted()) throw new IllegalStateException("Not started"); - final RunnableResult result = new RunnableResult<>(); - + final FuturePromise 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(); } @@ -179,7 +182,7 @@ public void store(String id, SessionData data) throws Exception //set the last saved time to now data.setLastSaved(System.currentTimeMillis()); - final RunnableResult result = new RunnableResult<>(); + final FuturePromise result = new FuturePromise<>(); Runnable r = () -> { try @@ -187,32 +190,33 @@ public void store(String id, SessionData data) throws Exception //call the specific store method, passing in previous save time doStore(id, data, lastSave); data.clean(); //unset all dirty flags + result.succeeded(Boolean.TRUE); } 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 { - RunnableResult result = new RunnableResult<>(); + FuturePromise result = new FuturePromise<>(); Runnable r = () -> { try { - result.setResult(doExists(id)); + result.succeeded(doExists(id)); } catch (Exception e) { - result.setException(e); + result.failed(e); } }; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/RunnableResult.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/RunnableResult.java deleted file mode 100644 index e68419d58289..000000000000 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/RunnableResult.java +++ /dev/null @@ -1,49 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others. -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License v. 2.0 which is available at -// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// ======================================================================== -// - -package org.eclipse.jetty.server.session; - -/** - * Small utility class to allow us to - * return a result and an Exception - * from invocation of Runnables. - * - * @param the type of the result. - */ -public class RunnableResult -{ - private V _result; - private Exception _exception; - - public void setResult(V result) - { - _result = result; - } - - public void setException(Exception exception) - { - _exception = exception; - } - - public void throwIfException() throws Exception - { - if (_exception != null) - throw _exception; - } - - public V getOrThrow() throws Exception - { - throwIfException(); - return _result; - } -} \ No newline at end of file diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/FuturePromise.java b/jetty-util/src/main/java/org/eclipse/jetty/util/FuturePromise.java index ad8ab65aa207..186128ccf7ce 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/FuturePromise.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/FuturePromise.java @@ -118,6 +118,27 @@ public C get() throws InterruptedException, ExecutionException throw (CancellationException)new CancellationException().initCause(_cause); throw new ExecutionException(_cause); } + + /** + * Return the result if completed successfully + * or rethrow the Exception + * + * @return the computed result + * @throws Exception + */ + 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 From 627a34aeb682cc432d2a3cc50916efd95ec800c8 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Thu, 29 Jul 2021 14:20:53 +1000 Subject: [PATCH 4/5] Issue #6556 Also use FuturePromise Signed-off-by: Jan Bartel --- .../jetty/memcached/session/MemcachedSessionDataMap.java | 4 ++-- .../jetty/server/session/AbstractSessionDataStore.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/jetty-memcached/jetty-memcached-sessions/src/main/java/org/eclipse/jetty/memcached/session/MemcachedSessionDataMap.java b/jetty-memcached/jetty-memcached-sessions/src/main/java/org/eclipse/jetty/memcached/session/MemcachedSessionDataMap.java index 78e81f833587..0d503bc5dba6 100644 --- a/jetty-memcached/jetty-memcached-sessions/src/main/java/org/eclipse/jetty/memcached/session/MemcachedSessionDataMap.java +++ b/jetty-memcached/jetty-memcached-sessions/src/main/java/org/eclipse/jetty/memcached/session/MemcachedSessionDataMap.java @@ -188,13 +188,13 @@ public void store(String id, SessionData data) throws Exception if (!isStarted()) throw new IllegalStateException("Not started"); - final FuturePromise result = new FuturePromise<>(); + final FuturePromise result = new FuturePromise<>(); Runnable r = () -> { try { _client.set(id, _expirySec, data); - result.succeeded(Boolean.TRUE); + result.succeeded(null); } catch (Exception e) { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStore.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStore.java index 365e7ed4383e..524bccb5d881 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStore.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStore.java @@ -182,7 +182,7 @@ public void store(String id, SessionData data) throws Exception //set the last saved time to now data.setLastSaved(System.currentTimeMillis()); - final FuturePromise result = new FuturePromise<>(); + final FuturePromise result = new FuturePromise<>(); Runnable r = () -> { try @@ -190,7 +190,7 @@ public void store(String id, SessionData data) throws Exception //call the specific store method, passing in previous save time doStore(id, data, lastSave); data.clean(); //unset all dirty flags - result.succeeded(Boolean.TRUE); + result.succeeded(null); } catch (Exception e) { From ef40ad2aec28c32f2d2b9d74973301f54694daf0 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Fri, 30 Jul 2021 16:59:44 +1000 Subject: [PATCH 5/5] Issue #6556 change after review Signed-off-by: Jan Bartel --- .../main/java/org/eclipse/jetty/util/FuturePromise.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/FuturePromise.java b/jetty-util/src/main/java/org/eclipse/jetty/util/FuturePromise.java index 186128ccf7ce..deae5c669c0a 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/FuturePromise.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/FuturePromise.java @@ -121,10 +121,13 @@ public C get() throws InterruptedException, ExecutionException /** * Return the result if completed successfully - * or rethrow the Exception + * 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 + * @throws Exception if the cause is an Exception or Error, + * otherwise an ExecutionException wrapping the cause */ public C getOrThrow() throws Exception {