From 900f50f513bf4587f243052e648ca97129f326f9 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Fri, 25 Aug 2023 09:12:49 -0500 Subject: [PATCH 1/2] Issue #10271 - new jetty-home `pid` module (#10272) * Issue #10271 - new jetty-home module `pid` Signed-off-by: Joakim Erdfelt --- jetty-home/src/main/resources/bin/jetty.sh | 14 +-- .../src/main/resources/etc/jetty-started.xml | 15 ---- jetty-home/src/main/resources/etc/jetty.conf | 2 +- .../src/main/config/etc/jetty-state.xml | 12 +++ .../src/main/config/modules/state.mod | 17 ++++ .../jetty/server/StateLifeCycleListener.java | 89 +++++++++++++++++++ jetty-util/src/main/config/etc/jetty-pid.xml | 8 ++ jetty-util/src/main/config/modules/pid.mod | 19 ++++ .../java/org/eclipse/jetty/util/PidFile.java | 83 +++++++++++++++++ .../FileNoticeLifeCycleListener.java | 2 + .../tests/distribution/DistributionTests.java | 41 +++++++++ 11 files changed, 280 insertions(+), 22 deletions(-) delete mode 100644 jetty-home/src/main/resources/etc/jetty-started.xml create mode 100644 jetty-server/src/main/config/etc/jetty-state.xml create mode 100644 jetty-server/src/main/config/modules/state.mod create mode 100644 jetty-server/src/main/java/org/eclipse/jetty/server/StateLifeCycleListener.java create mode 100644 jetty-util/src/main/config/etc/jetty-pid.xml create mode 100644 jetty-util/src/main/config/modules/pid.mod create mode 100644 jetty-util/src/main/java/org/eclipse/jetty/util/PidFile.java diff --git a/jetty-home/src/main/resources/bin/jetty.sh b/jetty-home/src/main/resources/bin/jetty.sh index ebcf0f43296..c2a6fb8ed78 100755 --- a/jetty-home/src/main/resources/bin/jetty.sh +++ b/jetty-home/src/main/resources/bin/jetty.sh @@ -330,7 +330,7 @@ CYGWIN*) JETTY_STATE="`cygpath -w $JETTY_STATE`";; esac -JETTY_ARGS=(${JETTY_ARGS[*]} "jetty.state=$JETTY_STATE") +JETTY_ARGS=(${JETTY_ARGS[*]} "jetty.state=$JETTY_STATE" "jetty.pid=$JETTY_PID") ################################################## # Get the list of config.xml files from jetty.conf @@ -457,6 +457,7 @@ case "$ACTION" in exit fi + # Startup from a service file if [ $UID -eq 0 ] && type start-stop-daemon > /dev/null 2>&1 then unset CH_USER @@ -482,6 +483,7 @@ case "$ACTION" in exit 1 fi + # Startup if switching users (not as a service, or from root) if [ -n "$JETTY_USER" ] && [ `whoami` != "$JETTY_USER" ] then unset SU_SHELL @@ -492,16 +494,14 @@ case "$ACTION" in touch "$JETTY_PID" chown "$JETTY_USER" "$JETTY_PID" - # FIXME: Broken solution: wordsplitting, pathname expansion, arbitrary command execution, etc. su - "$JETTY_USER" $SU_SHELL -c " cd \"$JETTY_BASE\" echo ${RUN_ARGS[*]} start-log-file=\"$JETTY_START_LOG\" | xargs ${JAVA} > /dev/null & - disown \$! - echo \$! > \"$JETTY_PID\"" + disown $(pgrep -P $!)" else + # Startup if not switching users echo ${RUN_ARGS[*]} | xargs ${JAVA} > /dev/null & - disown $! - echo $! > "$JETTY_PID" + disown $(pgrep -P $!) fi fi @@ -523,6 +523,7 @@ case "$ACTION" in stop) echo -n "Stopping Jetty: " + # Stop from a service file if [ $UID -eq 0 ] && type start-stop-daemon > /dev/null 2>&1; then start-stop-daemon -K -p"$JETTY_PID" -d"$JETTY_HOME" -a "$JAVA" -s HUP @@ -535,6 +536,7 @@ case "$ACTION" in sleep 1 done else + # Stop from a non-service path if [ ! -f "$JETTY_PID" ] ; then echo "ERROR: no pid found at $JETTY_PID" exit 1 diff --git a/jetty-home/src/main/resources/etc/jetty-started.xml b/jetty-home/src/main/resources/etc/jetty-started.xml deleted file mode 100644 index 11a2e151795..00000000000 --- a/jetty-home/src/main/resources/etc/jetty-started.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/jetty-home/src/main/resources/etc/jetty.conf b/jetty-home/src/main/resources/etc/jetty.conf index d4ceba4d2f3..1dfe2076ced 100644 --- a/jetty-home/src/main/resources/etc/jetty.conf +++ b/jetty-home/src/main/resources/etc/jetty.conf @@ -8,4 +8,4 @@ # Each line in this file becomes an argument to start.jar # in addition to those found in the start.ini file # ======================================================= -jetty-started.xml +--module=pid,state diff --git a/jetty-server/src/main/config/etc/jetty-state.xml b/jetty-server/src/main/config/etc/jetty-state.xml new file mode 100644 index 00000000000..f2ab5c98f80 --- /dev/null +++ b/jetty-server/src/main/config/etc/jetty-state.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/jetty-server/src/main/config/modules/state.mod b/jetty-server/src/main/config/modules/state.mod new file mode 100644 index 00000000000..5a4e09de420 --- /dev/null +++ b/jetty-server/src/main/config/modules/state.mod @@ -0,0 +1,17 @@ +# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/ + +[description] +Creates and updates state file used by jetty.sh + +[tags] +start + +[depends] +server + +[xml] +etc/jetty-state.xml + +[ini-template] +## State file path +# jetty.state=${jetty.base}/jetty.state \ No newline at end of file diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/StateLifeCycleListener.java b/jetty-server/src/main/java/org/eclipse/jetty/server/StateLifeCycleListener.java new file mode 100644 index 00000000000..bf7fcdb2f3b --- /dev/null +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/StateLifeCycleListener.java @@ -0,0 +1,89 @@ +// +// ======================================================================== +// Copyright (c) 1995 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; + +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.eclipse.jetty.util.component.LifeCycle; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.nio.file.StandardOpenOption.APPEND; +import static java.nio.file.StandardOpenOption.CREATE; +import static java.nio.file.StandardOpenOption.WRITE; + +/** + * A LifeCycle Listener that writes state changes to a file. + *

This can be used with the jetty.sh script to wait for successful startup. + */ +public class StateLifeCycleListener implements LifeCycle.Listener +{ + private static final Logger LOG = LoggerFactory.getLogger(StateLifeCycleListener.class); + + private final Path _filename; + + public StateLifeCycleListener(String filename) + { + _filename = Paths.get(filename).toAbsolutePath(); + + if (LOG.isDebugEnabled()) + LOG.debug("State File: {}", _filename); + } + + private void writeState(String action, LifeCycle lifecycle) + { + try (Writer out = Files.newBufferedWriter(_filename, UTF_8, WRITE, CREATE, APPEND)) + { + out.append(action).append(" ").append(lifecycle.toString()).append("\n"); + } + catch (Exception e) + { + LOG.warn("Unable to write state", e); + } + } + + @Override + public void lifeCycleStarting(LifeCycle event) + { + writeState("STARTING", event); + } + + @Override + public void lifeCycleStarted(LifeCycle event) + { + writeState("STARTED", event); + } + + @Override + public void lifeCycleFailure(LifeCycle event, Throwable cause) + { + writeState("FAILED", event); + } + + @Override + public void lifeCycleStopping(LifeCycle event) + { + writeState("STOPPING", event); + } + + @Override + public void lifeCycleStopped(LifeCycle event) + { + writeState("STOPPED", event); + } +} diff --git a/jetty-util/src/main/config/etc/jetty-pid.xml b/jetty-util/src/main/config/etc/jetty-pid.xml new file mode 100644 index 00000000000..7ca3084a28c --- /dev/null +++ b/jetty-util/src/main/config/etc/jetty-pid.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/jetty-util/src/main/config/modules/pid.mod b/jetty-util/src/main/config/modules/pid.mod new file mode 100644 index 00000000000..3e08fc545a9 --- /dev/null +++ b/jetty-util/src/main/config/modules/pid.mod @@ -0,0 +1,19 @@ +# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/ + +[description] +Creates the PID file for the Jetty process + +[tags] +start + +[before] +server +threadpool +jvm + +[xml] +etc/jetty-pid.xml + +[ini-template] +## PID file path +# jetty.pid=${jetty.base}/jetty.pid \ No newline at end of file diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/PidFile.java b/jetty-util/src/main/java/org/eclipse/jetty/util/PidFile.java new file mode 100644 index 00000000000..8abaca626bc --- /dev/null +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/PidFile.java @@ -0,0 +1,83 @@ +// +// ======================================================================== +// Copyright (c) 1995 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.util; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.eclipse.jetty.util.annotation.Name; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.nio.file.StandardOpenOption.CREATE; +import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; +import static java.nio.file.StandardOpenOption.WRITE; + +/** + * Create a PID file for the running process. + * + *

+ * Will register itself in a {@link Runtime#addShutdownHook(Thread)} + * to cleanup the PID file it created during normal JVM shutdown. + *

+ */ +public class PidFile extends Thread +{ + private static final Logger LOG = LoggerFactory.getLogger(PidFile.class); + private static final Set activeFiles = ConcurrentHashMap.newKeySet(); + + public static void create(@Name("file") String filename) throws IOException + { + Path pidFile = Paths.get(filename).toAbsolutePath(); + + if (activeFiles.add(pidFile)) + { + Runtime.getRuntime().addShutdownHook(new PidFile(pidFile)); + + if (Files.exists(pidFile)) + LOG.info("Overwriting existing PID file: {}", pidFile); + + // Create the PID file as soon as possible. + long pid = ProcessHandle.current().pid(); + Files.writeString(pidFile, Long.toString(pid), UTF_8, CREATE, WRITE, TRUNCATE_EXISTING); + if (LOG.isDebugEnabled()) + LOG.debug("PID file: {}", pidFile); + } + } + + private final Path pidFile; + + private PidFile(Path pidFile) + { + this.pidFile = pidFile; + } + + @Override + public void run() + { + try + { + Files.deleteIfExists(pidFile); + } + catch (Throwable t) + { + LOG.info("Unable to remove PID file: {}", pidFile, t); + } + } +} diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/component/FileNoticeLifeCycleListener.java b/jetty-util/src/main/java/org/eclipse/jetty/util/component/FileNoticeLifeCycleListener.java index 98b07afaf63..93ee1e16f82 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/component/FileNoticeLifeCycleListener.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/component/FileNoticeLifeCycleListener.java @@ -22,7 +22,9 @@ import org.slf4j.LoggerFactory; /** * A LifeCycle Listener that writes state changes to a file. *

This can be used with the jetty.sh script to wait for successful startup. + * @deprecated use {@code org.eclipse.jetty.server.StateLifeCycleListener} instead */ +@Deprecated public class FileNoticeLifeCycleListener implements LifeCycle.Listener { private static final Logger LOG = LoggerFactory.getLogger(FileNoticeLifeCycleListener.class); diff --git a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/DistributionTests.java b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/DistributionTests.java index 7ba60185a7c..60a8c4746df 100644 --- a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/DistributionTests.java +++ b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/DistributionTests.java @@ -23,6 +23,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; +import java.time.Duration; import java.util.Arrays; import java.util.List; import java.util.Queue; @@ -64,6 +65,7 @@ import org.junit.jupiter.api.condition.OS; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +import static org.awaitility.Awaitility.await; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; @@ -107,6 +109,45 @@ public class DistributionTests extends AbstractJettyHomeTest } } + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void testPidFile(boolean includeJettyPidConfig) throws Exception + { + String jettyVersion = System.getProperty("jettyVersion"); + JettyHomeTester distribution = JettyHomeTester.Builder.newInstance() + .jettyVersion(jettyVersion) + .mavenLocalRepository(System.getProperty("mavenRepoPath")) + .build(); + + try (JettyHomeTester.Run run1 = distribution.start("--add-modules=http,pid")) + { + assertTrue(run1.awaitFor(10, TimeUnit.SECONDS)); + assertEquals(0, run1.getExitValue()); + + Path pidfile = run1.getConfig().getJettyBase().resolve("jetty.pid"); + + int port = distribution.freePort(); + + String[] args = new String[includeJettyPidConfig ? 2 : 1]; + args[0] = "jetty.http.port=" + port; + if (includeJettyPidConfig) + args[1] = "jetty.pid=" + pidfile; + + try (JettyHomeTester.Run run2 = distribution.start(args)) + { + assertTrue(run2.awaitConsoleLogsFor("Started Server@", 10, TimeUnit.SECONDS)); + + assertTrue(Files.isRegularFile(pidfile), "PID file should exist"); + + startHttpClient(); + ContentResponse response = client.GET("http://localhost:" + port); + assertEquals(HttpStatus.NOT_FOUND_404, response.getStatus()); + } + + await().atMost(Duration.ofSeconds(10)).until(() -> !Files.exists(pidfile)); + } + } + @Test public void testQuickStartGenerationAndRun() throws Exception { From 1965a943f9bcd6f62969f4b345dbcb6b3c75619c Mon Sep 17 00:00:00 2001 From: Ludovic Orban Date: Wed, 30 Aug 2023 14:02:02 +0200 Subject: [PATCH 2/2] #9928 backport Request.beginNanoTime() from 12.0.x Signed-off-by: Ludovic Orban --- .../org/eclipse/jetty/http/HttpParser.java | 9 ++++++ .../java/org/eclipse/jetty/http/MetaData.java | 28 +++++++++++++++++-- .../jetty/server/HttpChannelOverHttp.java | 13 ++++++++- .../eclipse/jetty/server/HttpConnection.java | 5 ++++ .../org/eclipse/jetty/server/Request.java | 10 +++++++ 5 files changed, 61 insertions(+), 4 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java index 8d910ae7b0d..4a2bea642ff 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java @@ -26,6 +26,7 @@ import org.eclipse.jetty.http.HttpTokens.EndOfContent; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.HostPort; import org.eclipse.jetty.util.Index; +import org.eclipse.jetty.util.NanoTime; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.Utf8StringBuilder; import org.slf4j.Logger; @@ -249,6 +250,7 @@ public class HttpParser private ByteBuffer _contentChunk; private int _length; private final StringBuilder _string = new StringBuilder(); + private long _beginNanoTime = Long.MIN_VALUE; private static HttpCompliance compliance() { @@ -300,6 +302,11 @@ public class HttpParser _complianceListener = (ComplianceViolation.Listener)(_handler instanceof ComplianceViolation.Listener ? _handler : null); } + public long getBeginNanoTime() + { + return _beginNanoTime; + } + public HttpHandler getHandler() { return _handler; @@ -1517,6 +1524,8 @@ public class HttpParser _methodString = null; _endOfContent = EndOfContent.UNKNOWN_CONTENT; _header = null; + if (buffer.hasRemaining()) + _beginNanoTime = NanoTime.now(); quickStart(buffer); } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java index bc7cc82998d..6ddc9237100 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MetaData.java @@ -17,6 +17,8 @@ import java.util.Collections; import java.util.Iterator; import java.util.function.Supplier; +import org.eclipse.jetty.util.NanoTime; + public class MetaData implements Iterable { /** @@ -115,6 +117,7 @@ public class MetaData implements Iterable { private final String _method; private final HttpURI _uri; + private final long _beginNanoTime; public Request(HttpFields fields) { @@ -126,11 +129,19 @@ public class MetaData implements Iterable this(method, uri, version, fields, Long.MIN_VALUE); } + public Request(long beginNanoTime, String method, HttpURI uri, HttpVersion version, HttpFields fields) + { + this(beginNanoTime, method, uri, version, fields, Long.MIN_VALUE); + } + public Request(String method, HttpURI uri, HttpVersion version, HttpFields fields, long contentLength) { - super(version, fields, contentLength); - _method = method; - _uri = uri.asImmutable(); + this(method, uri.asImmutable(), version, fields, contentLength, null); + } + + public Request(long beginNanoTime, String method, HttpURI uri, HttpVersion version, HttpFields fields, long contentLength) + { + this(beginNanoTime, method, uri.asImmutable(), version, fields, contentLength, null); } public Request(String method, String scheme, HostPortHttpField authority, String uri, HttpVersion version, HttpFields fields, long contentLength) @@ -141,10 +152,21 @@ public class MetaData implements Iterable } public Request(String method, HttpURI uri, HttpVersion version, HttpFields fields, long contentLength, Supplier trailers) + { + this(NanoTime.now(), method, uri, version, fields, contentLength, trailers); + } + + public Request(long beginNanoTime, String method, HttpURI uri, HttpVersion version, HttpFields fields, long contentLength, Supplier trailers) { super(version, fields, contentLength, trailers); _method = method; _uri = uri; + _beginNanoTime = beginNanoTime; + } + + public long getBeginNanoTime() + { + return _beginNanoTime; } @Override diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java index 4c5b8f14489..ca6cb672a12 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java @@ -36,6 +36,7 @@ import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EofException; +import org.eclipse.jetty.util.NanoTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -340,6 +341,7 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque @Override public boolean headerComplete() { + _requestBuilder.beginNanoTime(_httpConnection.getBeginNanoTime()); _metadata = _requestBuilder.build(); onRequest(_metadata); @@ -705,6 +707,7 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque private final HttpURI.Mutable _uriBuilder = HttpURI.build(); private String _method; private HttpVersion _version; + private long _beginNanoTime = Long.MIN_VALUE; public String method() { @@ -719,6 +722,13 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque _fieldsBuilder.clear(); } + public void beginNanoTime(long nanoTime) + { + if (nanoTime == Long.MIN_VALUE) + nanoTime++; + _beginNanoTime = nanoTime; + } + public HttpFields.Mutable getFields() { return _fieldsBuilder; @@ -726,7 +736,8 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque public MetaData.Request build() { - return new MetaData.Request(_method, _uriBuilder, _version, _fieldsBuilder); + long nanoTime = _beginNanoTime == Long.MIN_VALUE ? NanoTime.now() : _beginNanoTime; + return new MetaData.Request(nanoTime, _method, _uriBuilder, _version, _fieldsBuilder); } public HttpVersion version() diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java index b363986c529..5b971525fe8 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java @@ -107,6 +107,11 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http LOG.debug("New HTTP Connection {}", this); } + public long getBeginNanoTime() + { + return _parser.getBeginNanoTime(); + } + public HttpConfiguration getHttpConfiguration() { return _config; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 3535d03f0a4..0667c02da46 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -1709,6 +1709,16 @@ public class Request implements HttpServletRequest _secure = secure; } + /** + *

Get the nanoTime at which the request arrived to a connector, obtained via {@link System#nanoTime()}. + * This method can be used when measuring latencies.

+ * @return The nanoTime at which the request was received/created in nanoseconds + */ + public long getBeginNanoTime() + { + return _metaData.getBeginNanoTime(); + } + @Override public boolean isUserInRole(String role) {