RedissonSession.java 16.9 KB
Newer Older
N
Nikita 已提交
1
/**
N
Nikita Koksharov 已提交
2
 * Copyright (c) 2013-2021 Nikita Koksharov
N
Nikita 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.redisson.tomcat;

import org.apache.catalina.session.StandardSession;
import org.redisson.api.RMap;
20
import org.redisson.api.RSet;
21
import org.redisson.api.RTopic;
N
Nikita 已提交
22
import org.redisson.tomcat.RedissonSessionManager.ReadMode;
23
import org.redisson.tomcat.RedissonSessionManager.UpdateMode;
N
Nikita 已提交
24

25 26 27 28 29 30 31
import java.io.IOException;
import java.lang.reflect.Field;
import java.security.Principal;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
32
import java.util.concurrent.atomic.AtomicInteger;
33

N
Nikita 已提交
34 35 36 37 38 39 40 41
/**
 * Redisson Session object for Apache Tomcat
 * 
 * @author Nikita Koksharov
 *
 */
public class RedissonSession extends StandardSession {

N
Nikita 已提交
42 43 44 45 46 47
    private static final String IS_NEW_ATTR = "session:isNew";
    private static final String IS_VALID_ATTR = "session:isValid";
    private static final String THIS_ACCESSED_TIME_ATTR = "session:thisAccessedTime";
    private static final String MAX_INACTIVE_INTERVAL_ATTR = "session:maxInactiveInterval";
    private static final String LAST_ACCESSED_TIME_ATTR = "session:lastAccessedTime";
    private static final String CREATION_TIME_ATTR = "session:creationTime";
48
    private static final String IS_EXPIRATION_LOCKED = "session:isExpirationLocked";
49 50
    private static final String PRINCIPAL_ATTR = "session:principal";
    private static final String AUTHTYPE_ATTR = "session:authtype";
N
Nikita 已提交
51
    
52 53 54
    public static final Set<String> ATTRS = new HashSet<String>(Arrays.asList(
            IS_NEW_ATTR, IS_VALID_ATTR, 
            THIS_ACCESSED_TIME_ATTR, MAX_INACTIVE_INTERVAL_ATTR, 
55 56
            LAST_ACCESSED_TIME_ATTR, CREATION_TIME_ATTR, IS_EXPIRATION_LOCKED,
            PRINCIPAL_ATTR, AUTHTYPE_ATTR
57
            ));
N
Nikita 已提交
58
    
59
    private boolean isExpirationLocked;
60
    private boolean loaded;
N
Nikita 已提交
61 62 63
    private final RedissonSessionManager redissonManager;
    private final Map<String, Object> attrs;
    private RMap<String, Object> map;
64
    private final RTopic topic;
65
    private final ReadMode readMode;
66
    private final UpdateMode updateMode;
67

68 69
    private final AtomicInteger usages = new AtomicInteger();
    private Map<String, Object> loadedAttributes = Collections.emptyMap();
70
    private Map<String, Object> updatedAttributes = Collections.emptyMap();
71
    private Set<String> removedAttributes = Collections.emptySet();
72

73
    private final boolean broadcastSessionEvents;
74
    private final boolean broadcastSessionUpdates;
75

76
    public RedissonSession(RedissonSessionManager manager, ReadMode readMode, UpdateMode updateMode, boolean broadcastSessionEvents, boolean broadcastSessionUpdates) {
N
Nikita 已提交
77 78 79
        super(manager);
        this.redissonManager = manager;
        this.readMode = readMode;
80
        this.updateMode = updateMode;
81
        this.topic = redissonManager.getTopic();
82
        this.broadcastSessionEvents = broadcastSessionEvents;
83
        this.broadcastSessionUpdates = broadcastSessionUpdates;
N
Nikita 已提交
84
        
85 86
        if (updateMode == UpdateMode.AFTER_REQUEST) {
            removedAttributes = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
87 88 89
        }
        if (readMode == ReadMode.REDIS) {
            loadedAttributes = new ConcurrentHashMap<>();
90
            updatedAttributes = new ConcurrentHashMap<>();
91 92
        }
        
N
Nikita 已提交
93 94 95 96 97 98 99 100 101 102 103 104 105
        try {
            Field attr = StandardSession.class.getDeclaredField("attributes");
            attrs = (Map<String, Object>) attr.get(this);
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    private static final long serialVersionUID = -2518607181636076487L;

    @Override
    public Object getAttribute(String name) {
        if (readMode == ReadMode.REDIS) {
106 107 108 109 110 111 112 113
            if (!isValidInternal()) {
                throw new IllegalStateException(sm.getString("standardSession.getAttribute.ise"));
            }

            if (name == null) {
                return null;
            }

114
            if (removedAttributes.contains(name)) {
115 116 117
                return super.getAttribute(name);
            }

118 119 120 121 122 123 124 125 126
            Object value = loadedAttributes.get(name);
            if (value == null) {
                value = map.get(name);
                if (value != null) {
                    loadedAttributes.put(name, value);
                }
            }

            return value;
127 128 129 130 131 132 133 134 135 136 137
        } else {
            if (!loaded) {
                synchronized (this) {
                    if (!loaded) {
                        Map<String, Object> storedAttrs = map.readAllMap();
                        
                        load(storedAttrs);
                        loaded = true;
                    }
                }
            }
N
Nikita 已提交
138 139 140 141 142
        }

        return super.getAttribute(name);
    }
    
143 144 145 146 147 148 149
    @Override
    public Enumeration<String> getAttributeNames() {
        if (readMode == ReadMode.REDIS) {
            if (!isValidInternal()) {
                throw new IllegalStateException
                    (sm.getString("standardSession.getAttributeNames.ise"));
            }
150 151 152 153 154

            Set<String> attributeKeys = new HashSet<>();
            attributeKeys.addAll(map.readAllKeySet());
            attributeKeys.addAll(loadedAttributes.keySet());
            return Collections.enumeration(attributeKeys);
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
        }
        
        return super.getAttributeNames();
    }

    @Override
    public String[] getValueNames() {
        if (readMode == ReadMode.REDIS) {
            if (!isValidInternal()) {
                throw new IllegalStateException
                    (sm.getString("standardSession.getAttributeNames.ise"));
            }
            Set<String> keys = map.readAllKeySet();
            return keys.toArray(new String[keys.size()]);
        }
        
        return super.getValueNames();
    }
    
N
Nikita 已提交
174
    public void delete() {
175 176 177 178
        if (map == null) {
            map = redissonManager.getMap(id);
        }
        
179
        if (broadcastSessionEvents) {
180 181 182
            RSet<String> set = redissonManager.getNotifiedNodes(id);
            set.add(redissonManager.getNodeId());
            set.expire(60, TimeUnit.SECONDS);
183
            map.fastPut(IS_EXPIRATION_LOCKED, true);
184 185 186 187
            map.expire(60, TimeUnit.SECONDS);
        } else {
            map.delete();
        }
188
        if (readMode == ReadMode.MEMORY && this.broadcastSessionUpdates) {
189
            topic.publish(new AttributesClearMessage(redissonManager.getNodeId(), getId()));
190
        }
N
Nikita 已提交
191
        map = null;
192
        loadedAttributes.clear();
193
        updatedAttributes.clear();
N
Nikita 已提交
194 195 196 197 198 199 200 201
    }
    
    @Override
    public void setCreationTime(long time) {
        super.setCreationTime(time);

        if (map != null) {
            Map<String, Object> newMap = new HashMap<String, Object>(3);
N
Nikita 已提交
202 203 204
            newMap.put(CREATION_TIME_ATTR, creationTime);
            newMap.put(LAST_ACCESSED_TIME_ATTR, lastAccessedTime);
            newMap.put(THIS_ACCESSED_TIME_ATTR, thisAccessedTime);
N
Nikita 已提交
205
            map.putAll(newMap);
206
            if (readMode == ReadMode.MEMORY && this.broadcastSessionUpdates) {
207
                topic.publish(createPutAllMessage(newMap));
208
            }
N
Nikita 已提交
209 210 211 212 213 214 215 216
        }
    }
    
    @Override
    public void access() {
        super.access();
        
        if (map != null) {
217
            fastPut(THIS_ACCESSED_TIME_ATTR, thisAccessedTime);
218
            expireSession();
N
Nikita 已提交
219 220
        }
    }
N
Nikita 已提交
221

222
    protected void expireSession() {
223 224 225
        if (isExpirationLocked) {
            return;
        }
226 227 228 229
        if (maxInactiveInterval >= 0) {
            map.expire(maxInactiveInterval + 60, TimeUnit.SECONDS);
        }
    }
230

231
    protected AttributesPutAllMessage createPutAllMessage(Map<String, Object> newMap) {
232
        Map<String, Object> map = new HashMap<String, Object>();
233
        for (Entry<String, Object> entry : newMap.entrySet()) {
234
            map.put(entry.getKey(), entry.getValue());
235
        }
236
        try {
237
            return new AttributesPutAllMessage(redissonManager.getNodeId(), getId(), map, this.map.getCodec().getMapValueEncoder());
238 239 240
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
241 242
    }
    
N
Nikita 已提交
243 244 245 246 247
    @Override
    public void setMaxInactiveInterval(int interval) {
        super.setMaxInactiveInterval(interval);
        
        if (map != null) {
N
Nikita 已提交
248
            fastPut(MAX_INACTIVE_INTERVAL_ATTR, maxInactiveInterval);
249
            expireSession();
N
Nikita 已提交
250 251
        }
    }
252 253

    private void fastPut(String name, Object value) {
254 255 256
        if (map == null) {
            return;
        }
257
        map.fastPut(name, value);
258
        if (readMode == ReadMode.MEMORY && this.broadcastSessionUpdates) {
259
            try {
260
                topic.publish(new AttributeUpdateMessage(redissonManager.getNodeId(), getId(), name, value, this.map.getCodec().getMapValueEncoder()));
261 262 263
            } catch (IOException e) {
                throw new IllegalStateException(e);
            }
264 265
        }
    }
266 267 268 269 270

    @Override
    public void setPrincipal(Principal principal) {
        super.setPrincipal(principal);

271 272 273
        if (principal == null) {
            removeRedisAttribute(PRINCIPAL_ATTR);
        } else {
274 275 276 277 278 279 280 281
            fastPut(PRINCIPAL_ATTR, principal);
        }
    }

    @Override
    public void setAuthType(String authType) {
        super.setAuthType(authType);

282 283 284
        if (authType == null) {
            removeRedisAttribute(AUTHTYPE_ATTR);
        } else {
285 286 287 288
            fastPut(AUTHTYPE_ATTR, authType);
        }
    }

N
Nikita 已提交
289 290 291 292 293 294 295 296 297
    @Override
    public void setValid(boolean isValid) {
        super.setValid(isValid);
        
        if (map != null) {
            if (!isValid && !map.isExists()) {
                return;
            }
            
N
Nikita 已提交
298
            fastPut(IS_VALID_ATTR, isValid);
N
Nikita 已提交
299 300 301 302 303 304 305 306
        }
    }
    
    @Override
    public void setNew(boolean isNew) {
        super.setNew(isNew);
        
        if (map != null) {
N
Nikita 已提交
307
            fastPut(IS_NEW_ATTR, isNew);
N
Nikita 已提交
308 309 310 311 312 313 314 315
        }
    }
    
    @Override
    public void endAccess() {
        boolean oldValue = isNew;
        super.endAccess();

316
        if (map != null) {
317
            Map<String, Object> newMap = new HashMap<>(3);
318
            if (isNew != oldValue) {
319
                newMap.put(IS_NEW_ATTR, isNew);
320 321 322 323
            }
            newMap.put(LAST_ACCESSED_TIME_ATTR, lastAccessedTime);
            newMap.put(THIS_ACCESSED_TIME_ATTR, thisAccessedTime);
            map.putAll(newMap);
324
            if (readMode == ReadMode.MEMORY && this.broadcastSessionUpdates) {
325 326 327
                topic.publish(createPutAllMessage(newMap));
            }
            expireSession();
N
Nikita 已提交
328 329
        }
    }
330

N
Nikita 已提交
331
    
332 333 334 335
    public void superSetAttribute(String name, Object value, boolean notify) {
        super.setAttribute(name, value, notify);
    }
    
N
Nikita 已提交
336 337 338 339
    @Override
    public void setAttribute(String name, Object value, boolean notify) {
        super.setAttribute(name, value, notify);
        
340 341 342 343
        if (value == null) {
            return;
        }
        if (updateMode == UpdateMode.DEFAULT && map != null) {
344
            fastPut(name, value);
N
Nikita 已提交
345
        }
346 347
        if (readMode == ReadMode.REDIS) {
            loadedAttributes.put(name, value);
348
            updatedAttributes.put(name, value);
349
        }
350 351 352
        if (updateMode == UpdateMode.AFTER_REQUEST) {
            removedAttributes.remove(name);
        }
N
Nikita 已提交
353 354
    }
    
355 356 357
    public void superRemoveAttributeInternal(String name, boolean notify) {
        super.removeAttributeInternal(name, notify);
    }
358 359 360 361 362 363 364 365 366 367 368 369 370

    @Override
    public long getIdleTimeInternal() {
        long idleTime = super.getIdleTimeInternal();
        if (map != null && readMode == ReadMode.REDIS) {
            if (idleTime >= getMaxInactiveInterval() * 1000) {
                load(map.getAll(RedissonSession.ATTRS));
                idleTime = super.getIdleTimeInternal();
            }
        }
        return idleTime;
    }

N
Nikita 已提交
371 372 373
    @Override
    protected void removeAttributeInternal(String name, boolean notify) {
        super.removeAttributeInternal(name, notify);
374 375 376 377 378

        removeRedisAttribute(name);
    }

    private void removeRedisAttribute(String name) {
379
        if (updateMode == UpdateMode.DEFAULT && map != null) {
N
Nikita 已提交
380
            map.fastRemove(name);
381
            if (readMode == ReadMode.MEMORY && this.broadcastSessionUpdates) {
382
                topic.publish(new AttributeRemoveMessage(redissonManager.getNodeId(), getId(), new HashSet<String>(Arrays.asList(name))));
383
            }
N
Nikita 已提交
384
        }
385 386
        if (readMode == ReadMode.REDIS) {
            loadedAttributes.remove(name);
387
            updatedAttributes.remove(name);
388
        }
389 390 391
        if (updateMode == UpdateMode.AFTER_REQUEST) {
            removedAttributes.add(name);
        }
N
Nikita 已提交
392
    }
393

N
Nikita 已提交
394
    public void save() {
395 396 397 398
        if (map == null) {
            map = redissonManager.getMap(id);
        }
        
N
Nikita 已提交
399
        Map<String, Object> newMap = new HashMap<String, Object>();
N
Nikita 已提交
400 401 402 403 404 405
        newMap.put(CREATION_TIME_ATTR, creationTime);
        newMap.put(LAST_ACCESSED_TIME_ATTR, lastAccessedTime);
        newMap.put(THIS_ACCESSED_TIME_ATTR, thisAccessedTime);
        newMap.put(MAX_INACTIVE_INTERVAL_ATTR, maxInactiveInterval);
        newMap.put(IS_VALID_ATTR, isValid);
        newMap.put(IS_NEW_ATTR, isNew);
406 407 408 409 410 411
        if (principal != null) {
            newMap.put(PRINCIPAL_ATTR, principal);
        }
        if (authType != null) {
            newMap.put(AUTHTYPE_ATTR, authType);
        }
412 413 414
        if (broadcastSessionEvents) {
            newMap.put(IS_EXPIRATION_LOCKED, isExpirationLocked);
        }
415 416 417 418 419 420

        if (readMode == ReadMode.MEMORY) {
            if (attrs != null) {
                for (Entry<String, Object> entry : attrs.entrySet()) {
                    newMap.put(entry.getKey(), entry.getValue());
                }
N
Nikita 已提交
421
            }
422 423 424
        } else {
            newMap.putAll(updatedAttributes);
            updatedAttributes.clear();
N
Nikita 已提交
425
        }
426

N
Nikita 已提交
427
        map.putAll(newMap);
428
        map.fastRemove(removedAttributes.toArray(new String[0]));
429
        
430
        if (readMode == ReadMode.MEMORY && this.broadcastSessionUpdates) {
431
            topic.publish(createPutAllMessage(newMap));
432 433 434
            
            if (updateMode == UpdateMode.AFTER_REQUEST) {
                if (!removedAttributes.isEmpty()) {
435
                    topic.publish(new AttributeRemoveMessage(redissonManager.getNodeId(), getId(), new HashSet<>(removedAttributes)));
436 437
                }
            }
438
        }
439

440
        removedAttributes.clear();
441

442
        expireSession();
N
Nikita 已提交
443 444 445
    }
    
    public void load(Map<String, Object> attrs) {
N
Nikita 已提交
446
        Long creationTime = (Long) attrs.remove(CREATION_TIME_ATTR);
N
Nikita 已提交
447 448 449
        if (creationTime != null) {
            this.creationTime = creationTime;
        }
N
Nikita 已提交
450
        Long lastAccessedTime = (Long) attrs.remove(LAST_ACCESSED_TIME_ATTR);
N
Nikita 已提交
451 452 453
        if (lastAccessedTime != null) {
            this.lastAccessedTime = lastAccessedTime;
        }
N
Nikita 已提交
454
        Integer maxInactiveInterval = (Integer) attrs.remove(MAX_INACTIVE_INTERVAL_ATTR);
N
Nikita 已提交
455 456 457
        if (maxInactiveInterval != null) {
            this.maxInactiveInterval = maxInactiveInterval;
        }
N
Nikita 已提交
458
        Long thisAccessedTime = (Long) attrs.remove(THIS_ACCESSED_TIME_ATTR);
N
Nikita 已提交
459 460 461
        if (thisAccessedTime != null) {
            this.thisAccessedTime = thisAccessedTime;
        }
N
Nikita 已提交
462
        Boolean isValid = (Boolean) attrs.remove(IS_VALID_ATTR);
N
Nikita 已提交
463 464 465
        if (isValid != null) {
            this.isValid = isValid;
        }
N
Nikita 已提交
466
        Boolean isNew = (Boolean) attrs.remove(IS_NEW_ATTR);
N
Nikita 已提交
467 468 469
        if (isNew != null) {
            this.isNew = isNew;
        }
470 471 472 473
        Boolean isExpirationLocked = (Boolean) attrs.remove(IS_EXPIRATION_LOCKED);
        if (isExpirationLocked != null) {
            this.isExpirationLocked = isExpirationLocked;
        }
474 475 476 477 478 479 480 481
        Principal p = (Principal) attrs.remove(PRINCIPAL_ATTR);
        if (p != null) {
            this.principal = p;
        }
        String authType = (String) attrs.remove(AUTHTYPE_ATTR);
        if (authType != null) {
            this.authType = authType;
        }
N
Nikita 已提交
482

483 484 485 486
        if (readMode == ReadMode.MEMORY) {
            for (Entry<String, Object> entry : attrs.entrySet()) {
                super.setAttribute(entry.getKey(), entry.getValue(), false);
            }
N
Nikita 已提交
487 488 489
        }
    }
    
490 491 492 493
    @Override
    public void recycle() {
        super.recycle();
        map = null;
494
        loadedAttributes.clear();
495 496
        updatedAttributes.clear();
        removedAttributes.clear();
497 498 499 500 501 502 503
    }

    public void startUsage() {
        usages.incrementAndGet();
    }

    public void endUsage() {
504 505 506
        // don't decrement usages if startUsage wasn't called
//        if (usages.decrementAndGet() == 0) {
        if (usages.get() == 0 || usages.decrementAndGet() == 0) {
507 508
            loadedAttributes.clear();
        }
509
    }
N
Nikita 已提交
510
}