View | Details | Raw Unified | Return to bug 56698
Collapse All | Expand All

(-)a/java/org/apache/catalina/session/PersistentManagerBase.java (+47 lines)
Lines 135-140 public abstract class PersistentManagerBase extends ManagerBase Link Here
135
     */
135
     */
136
    private static final String name = "PersistentManagerBase";
136
    private static final String name = "PersistentManagerBase";
137
137
138
    /**
139
     * Key of the note of a session in which the timestamp of last backup is stored.
140
     */
141
    private static final String PERSISTED_LAST_ACCESSED_TIME = "org.apache.catalina.session.PersistentManagerBase.persistedLastAccessedTime";
142
138
143
139
    /**
144
    /**
140
     * Store object which will manage the Session store.
145
     * Store object which will manage the Session store.
Lines 177-182 public abstract class PersistentManagerBase extends ManagerBase Link Here
177
    private final Map<String,Object> sessionSwapInLocks = new HashMap<>();
182
    private final Map<String,Object> sessionSwapInLocks = new HashMap<>();
178
183
179
184
185
    /**
186
     * Only backup session once, while lastAccessedTime of the session is not changed
187
     */
188
    protected boolean backupOnceAfterAccess = false;
189
190
180
    // ------------------------------------------------------------- Properties
191
    // ------------------------------------------------------------- Properties
181
192
182
193
Lines 284-289 public abstract class PersistentManagerBase extends ManagerBase Link Here
284
295
285
296
286
    /**
297
    /**
298
     * Flag which determines if a session will be backed up only once after
299
     * reaching maxIdleBackup with same lastAccessedTime
300
     */
301
    public boolean getBackupOnceAfterAccess() {
302
303
        return this.backupOnceAfterAccess;
304
305
    }
306
307
    /**
308
     * Sets the flag, which determines if a session will be backed up only once
309
     * after reaching maxIdleBackup while lastAccessedTime is not changed, or
310
     * everytime when sessions will be checked for backup
311
     */
312
    public void setBackupOnceAfterAccess(boolean backupOnce) {
313
314
        if (this.backupOnceAfterAccess == backupOnce)
315
            return;
316
        boolean oldBackupOnceAfterAccess = this.backupOnceAfterAccess;
317
        this.backupOnceAfterAccess = backupOnce;
318
        support.firePropertyChange("backupOnceAfterAccess",
319
                                   Boolean.valueOf(oldBackupOnceAfterAccess),
320
                                   Boolean.valueOf(this.backupOnceAfterAccess));
321
322
    }
323
324
    /**
287
     * Return true, if the session id is loaded in memory
325
     * Return true, if the session id is loaded in memory
288
     * otherwise false is returned
326
     * otherwise false is returned
289
     *
327
     *
Lines 988-993 public abstract class PersistentManagerBase extends ManagerBase Link Here
988
                synchronized (session) {
1026
                synchronized (session) {
989
                    if (!session.isValid())
1027
                    if (!session.isValid())
990
                        continue;
1028
                        continue;
1029
                    long lastAccessedTime = session.getLastAccessedTime();
1030
                    if (backupOnceAfterAccess) {
1031
                        Long persistedLastAccessedTime = (Long) session.getNote(PERSISTED_LAST_ACCESSED_TIME);
1032
                        if (persistedLastAccessedTime != null &&
1033
                                lastAccessedTime == persistedLastAccessedTime.longValue())
1034
                            continue;
1035
                    }
991
                    int timeIdle = (int) (session.getIdleTime() / 1000L);
1036
                    int timeIdle = (int) (session.getIdleTime() / 1000L);
992
                    if (timeIdle > maxIdleBackup) {
1037
                    if (timeIdle > maxIdleBackup) {
993
                        if (log.isDebugEnabled())
1038
                        if (log.isDebugEnabled())
Lines 1001-1006 public abstract class PersistentManagerBase extends ManagerBase Link Here
1001
                        } catch (IOException e) {
1046
                        } catch (IOException e) {
1002
                            // This is logged in writeSession()
1047
                            // This is logged in writeSession()
1003
                        }
1048
                        }
1049
                        if (backupOnceAfterAccess)
1050
                            session.setNote(PERSISTED_LAST_ACCESSED_TIME, Long.valueOf(lastAccessedTime));
1004
                    }
1051
                    }
1005
                }
1052
                }
1006
            }
1053
            }
(-)a/java/org/apache/catalina/session/mbeans-descriptors.xml (+4 lines)
Lines 215-220 Link Here
215
                 type="int"
215
                 type="int"
216
            writeable="false"/>
216
            writeable="false"/>
217
217
218
    <attribute   name="backupOnceAfterAccess"
219
          description="Flag whether sessions should be saved only once after access"
220
                 type="boolean"/>
221
218
    <attribute   name="className"
222
    <attribute   name="className"
219
          description="Fully qualified class name of the managed object"
223
          description="Fully qualified class name of the managed object"
220
                 type="java.lang.String"
224
                 type="java.lang.String"
(-)a/test/org/apache/catalina/session/TestPersistentManager.java (+221 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
package org.apache.catalina.session;
18
19
import java.beans.PropertyChangeListener;
20
import java.io.IOException;
21
import java.util.ArrayList;
22
import java.util.Arrays;
23
import java.util.List;
24
25
import javax.servlet.ServletException;
26
import javax.servlet.http.HttpServlet;
27
import javax.servlet.http.HttpServletRequest;
28
import javax.servlet.http.HttpServletResponse;
29
30
import org.apache.catalina.Context;
31
import org.apache.catalina.LifecycleException;
32
import org.apache.catalina.Manager;
33
import org.apache.catalina.Session;
34
import org.apache.catalina.Store;
35
import org.apache.catalina.startup.Tomcat;
36
import org.apache.catalina.startup.TomcatBaseTest;
37
import org.junit.After;
38
import org.junit.Assert;
39
import org.junit.Before;
40
import org.junit.Test;
41
42
public class TestPersistentManager extends TomcatBaseTest {
43
44
    private final String ACTIVITY_CHECK = "org.apache.catalina.session.StandardSession.ACTIVITY_CHECK";
45
46
    private String oldActivityCheck;
47
48
    @Before
49
    public void setActivityCheck() {
50
        oldActivityCheck = System.setProperty(ACTIVITY_CHECK, "true");
51
    }
52
53
    @After
54
    public void resetActivityCheck() {
55
        if (oldActivityCheck != null) {
56
            System.setProperty(ACTIVITY_CHECK, oldActivityCheck);
57
        } else {
58
            System.clearProperty(ACTIVITY_CHECK);
59
        }
60
    }
61
62
    @Test
63
    public void backsUpEveryTime() throws Exception {
64
65
        // Setup Tomcat instance
66
        Tomcat tomcat = getTomcatInstance();
67
        // Must have a real docBase - just use temp
68
        Context ctx = tomcat.addContext("",
69
                System.getProperty("java.io.tmpdir"));
70
71
        Tomcat.addServlet(ctx, "DummyServlet", new DummyServlet());
72
        ctx.addServletMapping("/dummy", "DummyServlet");
73
74
        PersistentManager manager = new PersistentManager();
75
        DummyStore store = new DummyStore();
76
77
        manager.setStore(store);
78
        manager.setMaxIdleBackup(0);
79
        manager.setDistributable(true);
80
        ctx.setManager(manager);
81
        tomcat.start();
82
        String sessionId = getUrl("http://localhost:" + getPort() + "/dummy")
83
                .toString();
84
        sleepABit();
85
86
        manager.processPersistenceChecks();
87
        Assert.assertEquals(store.getSavedIds(), Arrays.asList(sessionId));
88
89
        // session was not access, but will be saved anyway
90
        manager.processPersistenceChecks();
91
        Assert.assertEquals(store.getSavedIds(),
92
                Arrays.asList(sessionId, sessionId));
93
    }
94
95
    @Test
96
    public void backsUpOnce() throws IOException, LifecycleException {
97
98
        // Setup Tomcat instance
99
        Tomcat tomcat = getTomcatInstance();
100
        // Must have a real docBase - just use temp
101
        Context ctx = tomcat.addContext("",
102
                System.getProperty("java.io.tmpdir"));
103
104
        Tomcat.addServlet(ctx, "DummyServlet", new DummyServlet());
105
        ctx.addServletMapping("/dummy", "DummyServlet");
106
107
        PersistentManager manager = new PersistentManager();
108
        DummyStore store = new DummyStore();
109
110
        manager.setStore(store);
111
        manager.setMaxIdleBackup(0);
112
        manager.setDistributable(true);
113
        manager.setBackupOnceAfterAccess(true);
114
        ctx.setManager(manager);
115
        tomcat.start();
116
        String sessionId = getUrl("http://localhost:" + getPort() + "/dummy")
117
                .toString();
118
        sleepABit();
119
120
        manager.processPersistenceChecks();
121
        Assert.assertEquals(Arrays.asList(sessionId), store.getSavedIds());
122
123
        // session was not accessed, so no save will be performed
124
        manager.processPersistenceChecks();
125
        Assert.assertEquals(Arrays.asList(sessionId), store.getSavedIds());
126
127
        // access session
128
        manager.findSession(sessionId).access();
129
        manager.findSession(sessionId).endAccess();
130
        sleepABit();
131
132
        // session was accessed, so it will be saved once again
133
        manager.processPersistenceChecks();
134
        Assert.assertEquals(Arrays.asList(sessionId, sessionId),
135
                store.getSavedIds());
136
137
        // session was not accessed, so once again no save will happen
138
        manager.processPersistenceChecks();
139
        Assert.assertEquals(Arrays.asList(sessionId, sessionId),
140
                store.getSavedIds());
141
    }
142
143
    private void sleepABit() {
144
        try {
145
            Thread.sleep(1000);
146
        } catch (InterruptedException e) {
147
            // ignore Interrupt
148
        }
149
    }
150
151
    private static class DummyServlet extends HttpServlet {
152
153
        private static final long serialVersionUID = -3696433049266123995L;
154
155
        @Override
156
        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
157
                throws ServletException, IOException {
158
            resp.getWriter().print(req.getSession().getId());
159
        }
160
161
    }
162
163
    private static class DummyStore implements Store {
164
165
        private Manager manager;
166
        private List<String> savedIds = new ArrayList<String>();
167
168
        List<String> getSavedIds() {
169
            return savedIds;
170
        }
171
172
        @Override
173
        public Manager getManager() {
174
            return this.manager;
175
        }
176
177
        @Override
178
        public void setManager(Manager manager) {
179
            this.manager = manager;
180
        }
181
182
        @Override
183
        public int getSize() throws IOException {
184
            return 0;
185
        }
186
187
        @Override
188
        public void addPropertyChangeListener(PropertyChangeListener listener) {
189
        }
190
191
        @Override
192
        public String[] keys() throws IOException {
193
            return null;
194
        }
195
196
        @Override
197
        public Session load(String id) throws ClassNotFoundException,
198
                IOException {
199
            // TODO Auto-generated method stub
200
            return null;
201
        }
202
203
        @Override
204
        public void remove(String id) throws IOException {
205
        }
206
207
        @Override
208
        public void clear() throws IOException {
209
        }
210
211
        @Override
212
        public void removePropertyChangeListener(PropertyChangeListener listener) {
213
        }
214
215
        @Override
216
        public void save(Session session) throws IOException {
217
            savedIds.add(session.getId());
218
        }
219
220
    }
221
}
(-)a/webapps/docs/config/manager.xml (+7 lines)
Lines 200-205 Link Here
200
200
201
    <attributes>
201
    <attributes>
202
202
203
      <attribute name="backupOnceAfterAccess" required="false">
204
        <p>If sessions should be backed up only once while not accessed. If
205
        <code>false</code> all sessions which are not accessed for
206
        <code>maxIdelBackup</code> will be backed up every time. Default is
207
        <code>false</code>.</p>
208
      </attribute>
209
203
      <attribute name="className" required="true">
210
      <attribute name="className" required="true">
204
        <p>It has the same meaning as described in the
211
        <p>It has the same meaning as described in the
205
        <a href="#Common_Attributes">Common Attributes</a> above.
212
        <a href="#Common_Attributes">Common Attributes</a> above.

Return to bug 56698