You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sb...@apache.org on 2015/10/09 16:47:03 UTC
[2/7] ignite git commit: Fix REST authentication.
Fix REST authentication.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/f025714e
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/f025714e
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/f025714e
Branch: refs/heads/ignite-1093-2
Commit: f025714ef0d21ffff7ebf6088c254f26dd9aa3fc
Parents: f60cba7
Author: ashutak <as...@gridgain.com>
Authored: Wed Oct 7 16:11:18 2015 +0300
Committer: ashutak <as...@gridgain.com>
Committed: Wed Oct 7 16:11:18 2015 +0300
----------------------------------------------------------------------
.../JettyRestProcessorAbstractSelfTest.java | 27 +-
.../apache/ignite/IgniteSystemProperties.java | 3 +
.../processors/rest/GridRestProcessor.java | 356 +++++++++++++++++--
.../handlers/cache/GridCacheCommandHandler.java | 2 +-
.../ignite/internal/util/IgniteUtils.java | 2 +-
5 files changed, 341 insertions(+), 49 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ignite/blob/f025714e/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java
index 8db4cd7..ac0edff 100644
--- a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java
@@ -84,6 +84,13 @@ public abstract class JettyRestProcessorAbstractSelfTest extends AbstractRestPro
protected abstract int restPort();
/**
+ * @return Security enabled flag. Should be the same with {@code ctx.security().enabled()}.
+ */
+ protected boolean securityEnabled() {
+ return false;
+ }
+
+ /**
* @param params Command parameters.
* @return Returned content.
* @throws Exception If failed.
@@ -133,7 +140,7 @@ public abstract class JettyRestProcessorAbstractSelfTest extends AbstractRestPro
return "\\{\\\"affinityNodeId\\\":\\\"\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}\\\"\\," +
"\\\"error\\\":\\\"\\\"\\," +
"\\\"response\\\":\\\"" + res + "\\\"\\," +
- "\\\"sessionToken\\\":\\\"\\\"," +
+ "\\\"sessionToken\\\":\\\"" + (securityEnabled() && success ? ".+" : "") + "\\\"," +
"\\\"successStatus\\\":" + (success ? 0 : 1) + "\\}";
}
@@ -157,7 +164,7 @@ public abstract class JettyRestProcessorAbstractSelfTest extends AbstractRestPro
private String integerPattern(int res, boolean success) {
return "\\{\\\"error\\\":\\\"\\\"\\," +
"\\\"response\\\":" + res + "\\," +
- "\\\"sessionToken\\\":\\\"\\\"," +
+ "\\\"sessionToken\\\":\\\"" + (securityEnabled() && success ? ".+" : "") + "\\\"," +
"\\\"successStatus\\\":" + (success ? 0 : 1) + "\\}";
}
@@ -170,7 +177,7 @@ public abstract class JettyRestProcessorAbstractSelfTest extends AbstractRestPro
return "\\{\\\"affinityNodeId\\\":\\\"\\\"\\," +
"\\\"error\\\":\\\"\\\"\\," +
"\\\"response\\\":" + res + "\\," +
- "\\\"sessionToken\\\":\\\"\\\"," +
+ "\\\"sessionToken\\\":\\\"" + (securityEnabled() && success ? ".+" : "") + "\\\"," +
"\\\"successStatus\\\":" + (success ? 0 : 1) + "\\}";
}
@@ -183,7 +190,7 @@ public abstract class JettyRestProcessorAbstractSelfTest extends AbstractRestPro
return "\\{\\\"affinityNodeId\\\":\\\"\\\"\\," +
"\\\"error\\\":\\\"\\\"\\," +
"\\\"response\\\":" + res + "\\," +
- "\\\"sessionToken\\\":\\\"\\\"," +
+ "\\\"sessionToken\\\":\\\"" + (securityEnabled() && success ? ".+" : "") + "\\\"," +
"\\\"successStatus\\\":" + (success ? 0 : 1) + "\\}";
}
@@ -196,7 +203,7 @@ public abstract class JettyRestProcessorAbstractSelfTest extends AbstractRestPro
return "\\{\\\"affinityNodeId\\\":\\\"\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}\\\"\\," +
"\\\"error\\\":\\\"\\\"\\," +
"\\\"response\\\":" + res + "\\," +
- "\\\"sessionToken\\\":\\\"\\\"," +
+ "\\\"sessionToken\\\":\\\"" + (securityEnabled() && success ? ".+" : "") + "\\\"," +
"\\\"successStatus\\\":" + (success ? 0 : 1) + "\\}";
}
@@ -209,7 +216,7 @@ public abstract class JettyRestProcessorAbstractSelfTest extends AbstractRestPro
return "\\{\\\"affinityNodeId\\\":\\\"\\\"\\," +
"\\\"error\\\":\\\"\\\"\\," +
"\\\"response\\\":" + res + "\\," +
- "\\\"sessionToken\\\":\\\"\\\"," +
+ "\\\"sessionToken\\\":\\\"" + (securityEnabled() && success ? ".+" : "") + "\\\"," +
"\\\"successStatus\\\":" + (success ? 0 : 1) + "\\}";
}
@@ -222,7 +229,7 @@ public abstract class JettyRestProcessorAbstractSelfTest extends AbstractRestPro
return "\\{\\\"affinityNodeId\\\":\\\"(\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12})?\\\"\\," +
"\\\"error\\\":\\\"\\\"\\," +
"\\\"response\\\":" + res + "\\," +
- "\\\"sessionToken\\\":\\\"\\\"," +
+ "\\\"sessionToken\\\":\\\"" + (securityEnabled() && success ? ".+" : "") + "\\\"," +
"\\\"successStatus\\\":" + (success ? 0 : 1) + "\\}";
}
@@ -234,7 +241,7 @@ public abstract class JettyRestProcessorAbstractSelfTest extends AbstractRestPro
private String pattern(String res, boolean success) {
return "\\{\\\"error\\\":\\\"" + (!success ? ".+" : "") + "\\\"\\," +
"\\\"response\\\":" + res + "\\," +
- "\\\"sessionToken\\\":\\\"\\\"," +
+ "\\\"sessionToken\\\":\\\"" + (securityEnabled() && success ? ".+" : "") + "\\\"," +
"\\\"successStatus\\\":" + (success ? 0 : 1) + "\\}";
}
@@ -246,7 +253,7 @@ public abstract class JettyRestProcessorAbstractSelfTest extends AbstractRestPro
private String stringPattern(String res, boolean success) {
return "\\{\\\"error\\\":\\\"" + (!success ? ".+" : "") + "\\\"\\," +
"\\\"response\\\":\\\"" + res + "\\\"\\," +
- "\\\"sessionToken\\\":\\\"\\\"," +
+ "\\\"sessionToken\\\":\\\"" + (securityEnabled() && success ? ".+" : "") + "\\\"," +
"\\\"successStatus\\\":" + (success ? 0 : 1) + "\\}";
}
@@ -1316,4 +1323,4 @@ public abstract class JettyRestProcessorAbstractSelfTest extends AbstractRestPro
return id;
}
}
-}
\ No newline at end of file
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/f025714e/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
index 1e4c8b7..5d3b08b 100644
--- a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
+++ b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
@@ -96,6 +96,9 @@ public final class IgniteSystemProperties {
*/
public static final String IGNITE_JETTY_LOG_NO_OVERRIDE = "IGNITE_JETTY_LOG_NO_OVERRIDE";
+ /** This property allow rewriting default ({@code 30}) rest session expire time (in seconds). */
+ public static final String IGNITE_REST_SESSION_TIMEOUT = "IGNITE_REST_SESSION_TIMEOUT";
+
/**
* This property allows to override maximum count of task results stored on one node
* in REST processor.
http://git-wip-us.apache.org/repos/asf/ignite/blob/f025714e/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestProcessor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestProcessor.java
index d606ba4..d54c8bb 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestProcessor.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.processors.rest;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.EnumMap;
import java.util.HashMap;
@@ -30,7 +31,9 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.atomic.AtomicLong;
import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteSystemProperties;
import org.apache.ignite.configuration.ConnectorConfiguration;
import org.apache.ignite.configuration.ConnectorMessageInterceptor;
import org.apache.ignite.internal.GridKernalContext;
@@ -53,8 +56,10 @@ import org.apache.ignite.internal.processors.security.SecurityContext;
import org.apache.ignite.internal.util.GridSpinReadWriteLock;
import org.apache.ignite.internal.util.future.GridFinishedFuture;
import org.apache.ignite.internal.util.typedef.C1;
+import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.X;
import org.apache.ignite.internal.util.typedef.internal.LT;
+import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.internal.util.worker.GridWorker;
import org.apache.ignite.internal.util.worker.GridWorkerFuture;
@@ -65,6 +70,7 @@ import org.apache.ignite.plugin.security.AuthenticationContext;
import org.apache.ignite.plugin.security.SecurityCredentials;
import org.apache.ignite.plugin.security.SecurityException;
import org.apache.ignite.plugin.security.SecurityPermission;
+import org.apache.ignite.thread.IgniteThread;
import org.jsr166.LongAdder8;
import static org.apache.ignite.internal.processors.rest.GridRestResponse.STATUS_AUTH_FAILED;
@@ -80,8 +86,11 @@ public class GridRestProcessor extends GridProcessorAdapter {
private static final String HTTP_PROTO_CLS =
"org.apache.ignite.internal.processors.rest.protocols.http.jetty.GridJettyRestProtocol";
- /** */
- public static final byte[] ZERO_BYTES = new byte[0];
+ /** Delay between sessions timeout checks. */
+ private static final int SES_TIMEOUT_CHECK_DELAY = 1_000;
+
+ /** Default session timout. */
+ private static final int DEFAULT_SES_TIMEOUT = 30_000;
/** Protocols. */
private final Collection<GridRestProtocol> protos = new ArrayList<>();
@@ -98,8 +107,14 @@ public class GridRestProcessor extends GridProcessorAdapter {
/** Workers count. */
private final LongAdder8 workersCnt = new LongAdder8();
- /** SecurityContext map. */
- private ConcurrentMap<UUID, SecurityContext> sesMap = new ConcurrentHashMap<>();
+ /** ClientId-SessionId map. */
+ private final ConcurrentMap<UUID, UUID> clientId2SesId = new ConcurrentHashMap<>();
+
+ /** SessionId-Session map. */
+ private final ConcurrentMap<UUID, Session> sesId2Ses = new ConcurrentHashMap<>();
+
+ /** */
+ private final Thread sesTimeoutCheckerThread;
/** Protocol handler. */
private final GridRestProtocolHandler protoHnd = new GridRestProtocolHandler() {
@@ -112,6 +127,9 @@ public class GridRestProcessor extends GridProcessorAdapter {
}
};
+ /** Session time to live. */
+ private final long sesTtl;
+
/**
* @param req Request.
* @return Future.
@@ -195,22 +213,40 @@ public class GridRestProcessor extends GridProcessorAdapter {
if (log.isDebugEnabled())
log.debug("Received request from client: " + req);
- SecurityContext subjCtx = null;
-
if (ctx.security().enabled()) {
+ Session ses;
+
try {
- subjCtx = authenticate(req);
+ ses = session(req);
+ }
+ catch (IgniteCheckedException e) {
+ GridRestResponse res = new GridRestResponse(STATUS_FAILED, e.getMessage());
- authorize(req, subjCtx);
+ return new GridFinishedFuture<>(res);
+ }
+
+ assert ses != null;
+
+ req.clientId(ses.clientId);
+ req.sessionToken(U.uuidToBytes(ses.sesId));
+
+ if (log.isDebugEnabled())
+ log.debug("Next clientId and sessionToken were extracted according to request: " +
+ "[clientId="+req.clientId()+", sesTok="+Arrays.toString(req.sessionToken())+"]");
+
+ SecurityContext secCtx0 = ses.secCtx;
+
+ try {
+ if (secCtx0 == null)
+ ses.secCtx = secCtx0 = authenticate(req);
+
+ authorize(req, secCtx0);
}
catch (SecurityException e) {
- assert subjCtx != null;
+ assert secCtx0 != null;
GridRestResponse res = new GridRestResponse(STATUS_SECURITY_CHECK_FAILED, e.getMessage());
- updateSession(req, subjCtx);
- res.sessionTokenBytes(ZERO_BYTES);
-
return new GridFinishedFuture<>(res);
}
catch (IgniteCheckedException e) {
@@ -228,16 +264,18 @@ public class GridRestProcessor extends GridProcessorAdapter {
return new GridFinishedFuture<>(
new IgniteCheckedException("Failed to find registered handler for command: " + req.command()));
- final SecurityContext subjCtx0 = subjCtx;
-
return res.chain(new C1<IgniteInternalFuture<GridRestResponse>, GridRestResponse>() {
@Override public GridRestResponse apply(IgniteInternalFuture<GridRestResponse> f) {
GridRestResponse res;
+ boolean failed = false;
+
try {
res = f.get();
}
catch (Exception e) {
+ failed = true;
+
if (!X.hasCause(e, VisorClusterGroupEmptyException.class))
LT.error(log, e, "Failed to handle request: " + req.command());
@@ -249,10 +287,8 @@ public class GridRestProcessor extends GridProcessorAdapter {
assert res != null;
- if (ctx.security().enabled()) {
- updateSession(req, subjCtx0);
- res.sessionTokenBytes(ZERO_BYTES);
- }
+ if (ctx.security().enabled() && !failed)
+ res.sessionTokenBytes(req.sessionToken());
interceptResponse(res, req);
@@ -262,10 +298,137 @@ public class GridRestProcessor extends GridProcessorAdapter {
}
/**
+ * @param req Request.
+ * @return Not null session.
+ * @throws IgniteCheckedException If failed.
+ */
+ private Session session(final GridRestRequest req) throws IgniteCheckedException {
+ final UUID clientId = req.clientId();
+ final byte[] sesTok = req.sessionToken();
+
+ while (true) {
+ if (F.isEmpty(sesTok) && clientId == null) {
+ Session ses = Session.random();
+
+ UUID oldSesId = clientId2SesId.put(ses.clientId, ses.sesId);
+
+ assert oldSesId == null : "Got an illegal state for request: " + req;
+
+ Session oldSes = sesId2Ses.put(ses.sesId, ses);
+
+ assert oldSes == null : "Got an illegal state for request: " + req;
+
+ return ses;
+ }
+
+ if (F.isEmpty(sesTok) && clientId != null) {
+ UUID sesId = clientId2SesId.get(clientId);
+
+ if (sesId == null) {
+ Session ses = Session.fromClientId(clientId);
+
+ if (clientId2SesId.putIfAbsent(ses.clientId, ses.sesId) != null)
+ continue; // Another thread already register session with the clientId.
+
+ Session prevSes = sesId2Ses.put(ses.sesId, ses);
+
+ assert prevSes == null : "Got an illegal state for request: " + req;
+
+ return ses;
+ }
+ else {
+ Session ses = sesId2Ses.get(sesId);
+
+ if (ses == null || !ses.touch())
+ continue; // Need to wait while timeout thread complete removing of timed out sessions.
+
+ return ses;
+ }
+ }
+
+ if (!F.isEmpty(sesTok) && clientId == null) {
+ UUID sesId = U.bytesToUuid(sesTok, 0);
+
+ Session ses = sesId2Ses.get(sesId);
+
+ if (ses == null)
+ throw new IgniteCheckedException("Failed to handle request - unknown session token " +
+ "(maybe expired session) [sesTok=" + U.byteArray2HexString(sesTok) + "]");
+
+ if (!ses.touch())
+ continue; // Need to wait while timeout thread complete removing of timed out sessions.
+
+ return ses;
+ }
+
+ if (!F.isEmpty(sesTok) && clientId != null) {
+ UUID sesId = clientId2SesId.get(clientId);
+
+ if (sesId == null || !sesId.equals(U.bytesToUuid(sesTok, 0)))
+ throw new IgniteCheckedException("Failed to handle request - unsupported case (misamatched " +
+ "clientId and session token) [clientId=" + clientId + ", sesTok=" +
+ U.byteArray2HexString(sesTok) + "]");
+
+ Session ses = sesId2Ses.get(sesId);
+
+ if (ses == null)
+ throw new IgniteCheckedException("Failed to handle request - unknown session token " +
+ "(maybe expired session) [sesTok=" + U.byteArray2HexString(sesTok) + "]");
+
+ if (!ses.touch())
+ continue; // Need to wait while timeout thread complete removing of timed out sessions.
+
+ return ses;
+ }
+
+ assert false : "Got an unreachable state.";
+ }
+ }
+
+ /**
* @param ctx Context.
*/
public GridRestProcessor(GridKernalContext ctx) {
super(ctx);
+
+ long sesExpTime0;
+ String sesExpTime = null;
+
+ try {
+ sesExpTime = System.getProperty(IgniteSystemProperties.IGNITE_REST_SESSION_TIMEOUT);
+
+ if (sesExpTime != null)
+ sesExpTime0 = Long.valueOf(sesExpTime) * 1000;
+ else
+ sesExpTime0 = DEFAULT_SES_TIMEOUT;
+ }
+ catch (NumberFormatException ignore) {
+ U.warn(log, "Failed parsing IGNITE_REST_SESSION_TIMEOUT system variable [IGNITE_REST_SESSION_TIMEOUT="
+ + sesExpTime + "]");
+
+ sesExpTime0 = DEFAULT_SES_TIMEOUT;
+ }
+
+ sesTtl = sesExpTime0;
+
+ sesTimeoutCheckerThread = new IgniteThread(ctx.gridName(), "session-timeout-worker",
+ new GridWorker(ctx.gridName(), "session-timeout-worker", log) {
+ @Override protected void body() throws InterruptedException {
+ while (!isCancelled()) {
+ Thread.sleep(SES_TIMEOUT_CHECK_DELAY);
+
+ for (Map.Entry<UUID, Session> e : sesId2Ses.entrySet()) {
+ Session ses = e.getValue();
+
+ if (ses.isTimedOut(sesTtl)) {
+ sesId2Ses.remove(ses.sesId, ses);
+
+ clientId2SesId.remove(ses.clientId, ses.sesId);
+ }
+ }
+ }
+ }
+ });
}
/** {@inheritDoc} */
@@ -310,6 +473,10 @@ public class GridRestProcessor extends GridProcessorAdapter {
for (GridRestProtocol proto : protos)
proto.onKernalStart();
+ sesTimeoutCheckerThread.setDaemon(true);
+
+ sesTimeoutCheckerThread.start();
+
startLatch.countDown();
if (log.isDebugEnabled())
@@ -334,6 +501,8 @@ public class GridRestProcessor extends GridProcessorAdapter {
}
}
+ U.interrupt(sesTimeoutCheckerThread);
+
if (interrupted)
Thread.currentThread().interrupt();
@@ -483,13 +652,8 @@ public class GridRestProcessor extends GridProcessorAdapter {
* @throws IgniteCheckedException If authentication failed.
*/
private SecurityContext authenticate(GridRestRequest req) throws IgniteCheckedException {
- UUID clientId = req.clientId();
- SecurityContext secCtx = clientId == null ? null : sesMap.get(clientId);
+ assert req.clientId() != null;
- if (secCtx != null)
- return secCtx;
-
- // Authenticate client if invalid session.
AuthenticationContext authCtx = new AuthenticationContext();
authCtx.subjectType(REMOTE_CLIENT);
@@ -531,18 +695,6 @@ public class GridRestProcessor extends GridProcessorAdapter {
}
/**
- * Update session.
- * @param req REST request.
- * @param sCtx Security context.
- */
- private void updateSession(GridRestRequest req, SecurityContext sCtx) {
- if (sCtx != null) {
- UUID id = req.clientId();
- sesMap.put(id, sCtx);
- }
- }
-
- /**
* @param req REST request.
* @param sCtx Security context.
* @throws SecurityException If authorization failed.
@@ -719,4 +871,134 @@ public class GridRestProcessor extends GridProcessorAdapter {
X.println(">>> protosSize: " + protos.size());
X.println(">>> handlersSize: " + handlers.size());
}
-}
\ No newline at end of file
+
+ /**
+ * Session.
+ */
+ private static class Session {
+ /** Expiration flag. It's a final state of lastToucnTime. */
+ private static final Long TIMEDOUT_FLAG = 0L;
+
+ /** Client id. */
+ private final UUID clientId;
+
+ /** Session token id. */
+ private final UUID sesId;
+
+ /** Security context. */
+ private volatile SecurityContext secCtx;
+
+ /**
+ * Time when session is used last time.
+ * If this time was set at TIMEDOUT_FLAG, then it should never be changed.
+ */
+ private final AtomicLong lastTouchTime = new AtomicLong(U.currentTimeMillis());
+
+ /**
+ * @param clientId Client ID.
+ * @param sesId session ID.
+ */
+ private Session(UUID clientId, UUID sesId) {
+ this.clientId = clientId;
+ this.sesId = sesId;
+ }
+
+ /**
+ * Static constructor.
+ *
+ * @return New session instance with random client ID and random session ID.
+ */
+ static Session random() {
+ return new Session(UUID.randomUUID(), UUID.randomUUID());
+ }
+
+ /**
+ * Static constructor.
+ *
+ * @param clientId Client ID.
+ * @return New session instance with given client ID and random session ID.
+ */
+ static Session fromClientId(UUID clientId) {
+ return new Session(clientId, UUID.randomUUID());
+ }
+
+ /**
+ * Static constructor.
+ *
+ * @param sesTokId Session token ID.
+ * @return New session instance with random client ID and given session ID.
+ */
+ static Session fromSessionToken(UUID sesTokId) {
+ return new Session(UUID.randomUUID(), sesTokId);
+ }
+
+ /**
+ * Checks expiration of session and if expired then sets TIMEDOUT_FLAG.
+ *
+ * @param sesTimeout Session timeout.
+ * @return <code>True</code> if expired.
+ * @see #touch()
+ */
+ boolean isTimedOut(long sesTimeout) {
+ long time0 = lastTouchTime.get();
+
+ if (time0 == TIMEDOUT_FLAG)
+ return true;
+
+ return U.currentTimeMillis() - time0 > sesTimeout && lastTouchTime.compareAndSet(time0, TIMEDOUT_FLAG);
+ }
+
+ /**
+ * Checks whether session at expired state (EPIRATION_FLAG) or not, if not then tries to update last touch time.
+ *
+ * @return {@code False} if session timed out (not successfully touched).
+ * @see #isTimedOut(long)
+ */
+ boolean touch() {
+ while (true) {
+ long time0 = lastTouchTime.get();
+
+ if (time0 == TIMEDOUT_FLAG)
+ return false;
+
+ boolean success = lastTouchTime.compareAndSet(time0, U.currentTimeMillis());
+
+ if (success)
+ return true;
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean equals(Object o) {
+ if (this == o)
+ return true;
+
+ if (!(o instanceof Session))
+ return false;
+
+ Session ses = (Session)o;
+
+ if (clientId != null ? !clientId.equals(ses.clientId) : ses.clientId != null)
+ return false;
+
+ if (sesId != null ? !sesId.equals(ses.sesId) : ses.sesId != null)
+ return false;
+
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ @Override public int hashCode() {
+ int res = clientId != null ? clientId.hashCode() : 0;
+
+ res = 31 * res + (sesId != null ? sesId.hashCode() : 0);
+
+ return res;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(Session.class, this);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/f025714e/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheCommandHandler.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheCommandHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheCommandHandler.java
index b3af2f2..9d32c17 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheCommandHandler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheCommandHandler.java
@@ -1391,4 +1391,4 @@ public class GridCacheCommandHandler extends GridRestCommandHandlerAdapter {
return c.sizeAsync(new CachePeekMode[]{CachePeekMode.PRIMARY});
}
}
-}
\ No newline at end of file
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/f025714e/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
index e5090cb..3c1913a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
@@ -9302,4 +9302,4 @@ public abstract class IgniteUtils {
throw new IgniteInterruptedCheckedException(e);
}
}
-}
\ No newline at end of file
+}