/* * eXist Open Source Native XML Database * Copyright (C) 2001-07 The eXist Project * http://exist-db.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * $Id$ */ package org.exist.http; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.exist.scheduler.JobException; import org.exist.scheduler.JobException.JobExceptionAction; import org.exist.scheduler.ScheduledJobInfo; import org.exist.scheduler.Scheduler; import org.exist.scheduler.UserJavaJob; import org.exist.storage.BrokerPool; import org.exist.xquery.value.Sequence; import java.util.Map; import java.util.Properties; public class SessionManager { public static final String SESSION_MANAGER = "session-manager"; public final static long TIMEOUT = 120000; public final static long TIMEOUT_CHECK_PERIOD = 2000; public final static int NO_SESSION = -1; private final static Logger LOG = LogManager.getLogger(SessionManager.class); private static class QueryResult { long lastAccess; final String queryString; final Sequence sequence; private QueryResult(final String query, final Sequence sequence) { this.queryString = query; this.sequence = sequence; this.lastAccess = System.currentTimeMillis(); } protected Sequence sequence() { lastAccess = System.currentTimeMillis(); return sequence; } } public static class TimeoutCheck extends UserJavaJob { public TimeoutCheck() { } public String getName() { return "REST_TimeoutCheck"; } public void setName(final String name) { } public void execute(final BrokerPool brokerpool, final Map<String, ?> params) throws JobException { final SessionManager manager = (SessionManager)params.get(SESSION_MANAGER); if (manager == null) { throw new JobException(JobExceptionAction.JOB_ABORT, "parameter 'session-manager' is not set"); } manager.timeoutCheck(); } } private QueryResult[] slots = new QueryResult[32]; public SessionManager(final BrokerPool pool) { final TimeoutCheck task = new TimeoutCheck(); final Scheduler scheduler = pool.getScheduler(); for (final ScheduledJobInfo job : scheduler.getScheduledJobs()) { if (task.getName().equals(job.getName())) { return; } } final Properties props = new Properties(); props.put(SESSION_MANAGER, this); scheduler.createPeriodicJob(TIMEOUT_CHECK_PERIOD, task, 2000, props); } public int add(final String query, final Sequence sequence) { final int len = slots.length; for (int i = 0; i < len; i++) { if (slots[i] == null) { slots[i] = new QueryResult(query, sequence); return i; } } // no free slots, resize final QueryResult[] t = new QueryResult[(len * 3) / 2]; System.arraycopy(slots, 0, t, 0, len); t[len] = new QueryResult(query, sequence); slots = t; return len; } public Sequence get(final String query, final int sessionId) { if (sessionId < 0 || sessionId >= slots.length) { return null; // out of scope } final QueryResult cached = slots[sessionId]; if (cached == null) { return null; } if (cached.queryString.equals(query)) { return cached.sequence(); } // wrong query return null; } public void release(final int sessionId) { if (sessionId < 0 || sessionId >= slots.length) { return; // out of scope } slots[sessionId] = null; } protected void timeoutCheck() { final long now = System.currentTimeMillis(); for (int i = 0; i < slots.length; i++) { if (slots[i] != null && now - slots[i].lastAccess > TIMEOUT) { if (LOG.isDebugEnabled()) { LOG.debug("Removing cached query result for session " + i); } slots[i] = null; } } } }