001/** 002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.jboot.web.session; 017 018import com.google.common.collect.Maps; 019import com.google.common.collect.Sets; 020 021import javax.servlet.ServletContext; 022import javax.servlet.http.HttpSession; 023import javax.servlet.http.HttpSessionContext; 024import java.util.*; 025 026public class JbootHttpSession implements HttpSession { 027 028 private final String id; 029 030 private final long createdAt; 031 032 private volatile long lastAccessedAt; 033 034 private int maxInactiveInterval; 035 036 private final ServletContext servletContext; 037 038 private final Map<String, Object> newAttributes = Maps.newHashMap(); 039 private final Set<String> deleteAttribute = Sets.newHashSet(); 040 private final Map<String, Object> sessionStore; 041 042 private volatile boolean invalid = false; 043 private volatile boolean dataChanged = false; 044 private volatile boolean empty = false; 045 046 private volatile HttpSession originSession; 047 048 public JbootHttpSession(String id, ServletContext servletContext, Map<String, Object> sessionStore, HttpSession originSession) { 049 this.id = id; 050 this.servletContext = servletContext; 051 this.sessionStore = sessionStore; 052 this.createdAt = System.currentTimeMillis(); 053 this.lastAccessedAt = createdAt; 054 this.empty = sessionStore.isEmpty(); 055 this.originSession = originSession; 056 } 057 058 059 060 @Override 061 public long getCreationTime() { 062 return createdAt; 063 } 064 065 @Override 066 public String getId() { 067 return id; 068 } 069 070 @Override 071 public long getLastAccessedTime() { 072 return lastAccessedAt; 073 } 074 075 @Override 076 public ServletContext getServletContext() { 077 return servletContext; 078 } 079 080 @Override 081 public void setMaxInactiveInterval(int interval) { 082 this.maxInactiveInterval = interval; 083 } 084 085 @Override 086 public int getMaxInactiveInterval() { 087 return maxInactiveInterval; 088 } 089 090 @Override 091 @Deprecated 092 public HttpSessionContext getSessionContext() { 093 return null; 094 } 095 096 @Override 097 public Object getAttribute(String name) { 098 checkValid(); 099 if (newAttributes.containsKey(name)) { 100 return newAttributes.get(name); 101 } else if (deleteAttribute.contains(name)) { 102 return null; 103 } 104 return sessionStore.get(name); 105 } 106 107 @Override 108 public Object getValue(String name) { 109 return getAttribute(name); 110 } 111 112 @Override 113 public Enumeration<String> getAttributeNames() { 114 checkValid(); 115 Set<String> names = Sets.newHashSet(sessionStore.keySet()); 116 names.addAll(newAttributes.keySet()); 117 names.removeAll(deleteAttribute); 118 return Collections.enumeration(names); 119 } 120 121 @Override 122 public String[] getValueNames() { 123 checkValid(); 124 Set<String> names = Sets.newHashSet(sessionStore.keySet()); 125 names.addAll(newAttributes.keySet()); 126 names.removeAll(deleteAttribute); 127 return names.toArray(new String[0]); 128 } 129 130 @Override 131 public void setAttribute(String name, Object value) { 132 checkValid(); 133 if (value == null) { 134 removeAttribute(name); 135 return; 136 } 137 138 newAttributes.put(name, value); 139 deleteAttribute.remove(name); 140 empty = false; 141 dataChanged = true; 142 143 if (originSession != null) { 144 originSession.setAttribute(name, value); 145 } 146 147 } 148 149 @Override 150 public void putValue(String name, Object value) { 151 setAttribute(name, value); 152 } 153 154 @Override 155 public void removeAttribute(String name) { 156 checkValid(); 157 if (empty && newAttributes.isEmpty()) { 158 return; 159 } 160 161 if (!newAttributes.containsKey(name) && !sessionStore.containsKey(name)) { 162 return; 163 } 164 165 deleteAttribute.add(name); 166 newAttributes.remove(name); 167 dataChanged = true; 168 169 if (originSession != null) { 170 originSession.removeAttribute(name); 171 } 172 } 173 174 @Override 175 public void removeValue(String name) { 176 removeAttribute(name); 177 } 178 179 @Override 180 public void invalidate() { 181 invalid = true; 182 dataChanged = true; 183 184 if (originSession != null) { 185 originSession.invalidate(); 186 } 187 } 188 189 @Override 190 public boolean isNew() { 191 return Boolean.TRUE; 192 } 193 194 195 public boolean isDataChanged() { 196 return dataChanged; 197 } 198 199 200 public Map<String, Object> snapshot() { 201 Map<String, Object> snap = new HashMap<>(); 202 snap.putAll(sessionStore); 203 snap.putAll(newAttributes); 204 for (String name : deleteAttribute) { 205 snap.remove(name); 206 } 207 return snap; 208 } 209 210 public boolean isValid() { 211 return !invalid; 212 } 213 214 protected void checkValid() throws IllegalStateException { 215 if (invalid) { 216 throw new IllegalStateException("http session has invalidate"); 217 } 218 } 219 220 public boolean isEmpty() { 221 return empty; 222 } 223}