| <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../../jacoco-resources/report.gif" type="image/gif"/><title>AbstractValidatingSessionManager.java</title><link rel="stylesheet" href="../../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../../index.html" class="el_report">Apache Shiro :: All (aggregate jar)</a> > <a href="../index.html" class="el_bundle">shiro-core</a> > <a href="index.source.html" class="el_package">org.apache.shiro.session.mgt</a> > <span class="el_source">AbstractValidatingSessionManager.java</span></div><h1>AbstractValidatingSessionManager.java</h1><pre class="source lang-java linenums">/* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.apache.shiro.session.mgt; |
| |
| import org.apache.shiro.authz.AuthorizationException; |
| import org.apache.shiro.session.ExpiredSessionException; |
| import org.apache.shiro.session.InvalidSessionException; |
| import org.apache.shiro.session.Session; |
| import org.apache.shiro.session.UnknownSessionException; |
| import org.apache.shiro.util.Destroyable; |
| import org.apache.shiro.util.LifecycleUtils; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import java.util.Collection; |
| |
| |
| /** |
| * Default business-tier implementation of the {@link ValidatingSessionManager} interface. |
| * |
| * @since 0.1 |
| */ |
| public abstract class AbstractValidatingSessionManager extends AbstractNativeSessionManager |
| implements ValidatingSessionManager, Destroyable { |
| |
| //TODO - complete JavaDoc |
| |
| <span class="fc" id="L44"> private static final Logger log = LoggerFactory.getLogger(AbstractValidatingSessionManager.class);</span> |
| |
| /** |
| * The default interval at which sessions will be validated (1 hour); |
| * This can be overridden by calling {@link #setSessionValidationInterval(long)} |
| */ |
| public static final long DEFAULT_SESSION_VALIDATION_INTERVAL = MILLIS_PER_HOUR; |
| |
| protected boolean sessionValidationSchedulerEnabled; |
| |
| /** |
| * Scheduler used to validate sessions on a regular basis. |
| */ |
| protected SessionValidationScheduler sessionValidationScheduler; |
| |
| protected long sessionValidationInterval; |
| |
| <span class="fc" id="L61"> public AbstractValidatingSessionManager() {</span> |
| <span class="fc" id="L62"> this.sessionValidationSchedulerEnabled = true;</span> |
| <span class="fc" id="L63"> this.sessionValidationInterval = DEFAULT_SESSION_VALIDATION_INTERVAL;</span> |
| <span class="fc" id="L64"> }</span> |
| |
| public boolean isSessionValidationSchedulerEnabled() { |
| <span class="fc" id="L67"> return sessionValidationSchedulerEnabled;</span> |
| } |
| |
| @SuppressWarnings({"UnusedDeclaration"}) |
| public void setSessionValidationSchedulerEnabled(boolean sessionValidationSchedulerEnabled) { |
| <span class="fc" id="L72"> this.sessionValidationSchedulerEnabled = sessionValidationSchedulerEnabled;</span> |
| <span class="fc" id="L73"> }</span> |
| |
| public void setSessionValidationScheduler(SessionValidationScheduler sessionValidationScheduler) { |
| <span class="fc" id="L76"> this.sessionValidationScheduler = sessionValidationScheduler;</span> |
| <span class="fc" id="L77"> }</span> |
| |
| public SessionValidationScheduler getSessionValidationScheduler() { |
| <span class="fc" id="L80"> return sessionValidationScheduler;</span> |
| } |
| |
| private void enableSessionValidationIfNecessary() { |
| <span class="fc" id="L84"> SessionValidationScheduler scheduler = getSessionValidationScheduler();</span> |
| <span class="fc bfc" id="L85" title="All 6 branches covered."> if (isSessionValidationSchedulerEnabled() && (scheduler == null || !scheduler.isEnabled())) {</span> |
| <span class="fc" id="L86"> enableSessionValidation();</span> |
| } |
| <span class="fc" id="L88"> }</span> |
| |
| /** |
| * If using the underlying default <tt>SessionValidationScheduler</tt> (that is, the |
| * {@link #setSessionValidationScheduler(SessionValidationScheduler) setSessionValidationScheduler} method is |
| * never called) , this method allows one to specify how |
| * frequently session should be validated (to check for orphans). The default value is |
| * {@link #DEFAULT_SESSION_VALIDATION_INTERVAL}. |
| * <p/> |
| * If you override the default scheduler, it is assumed that overriding instance 'knows' how often to |
| * validate sessions, and this attribute will be ignored. |
| * <p/> |
| * Unless this method is called, the default value is {@link #DEFAULT_SESSION_VALIDATION_INTERVAL}. |
| * |
| * @param sessionValidationInterval the time in milliseconds between checking for valid sessions to reap orphans. |
| */ |
| public void setSessionValidationInterval(long sessionValidationInterval) { |
| <span class="nc" id="L105"> this.sessionValidationInterval = sessionValidationInterval;</span> |
| <span class="nc" id="L106"> }</span> |
| |
| public long getSessionValidationInterval() { |
| <span class="fc" id="L109"> return sessionValidationInterval;</span> |
| } |
| |
| @Override |
| protected final Session doGetSession(final SessionKey key) throws InvalidSessionException { |
| <span class="fc" id="L114"> enableSessionValidationIfNecessary();</span> |
| |
| <span class="fc" id="L116"> log.trace("Attempting to retrieve session with key {}", key);</span> |
| |
| <span class="fc" id="L118"> Session s = retrieveSession(key);</span> |
| <span class="fc bfc" id="L119" title="All 2 branches covered."> if (s != null) {</span> |
| <span class="fc" id="L120"> validate(s, key);</span> |
| } |
| <span class="fc" id="L122"> return s;</span> |
| } |
| |
| /** |
| * Looks up a session from the underlying data store based on the specified session key. |
| * |
| * @param key the session key to use to look up the target session. |
| * @return the session identified by {@code sessionId}. |
| * @throws UnknownSessionException if there is no session identified by {@code sessionId}. |
| */ |
| protected abstract Session retrieveSession(SessionKey key) throws UnknownSessionException; |
| |
| protected Session createSession(SessionContext context) throws AuthorizationException { |
| <span class="fc" id="L135"> enableSessionValidationIfNecessary();</span> |
| <span class="fc" id="L136"> return doCreateSession(context);</span> |
| } |
| |
| protected abstract Session doCreateSession(SessionContext initData) throws AuthorizationException; |
| |
| protected void validate(Session session, SessionKey key) throws InvalidSessionException { |
| try { |
| <span class="fc" id="L143"> doValidate(session);</span> |
| <span class="fc" id="L144"> } catch (ExpiredSessionException ese) {</span> |
| <span class="fc" id="L145"> onExpiration(session, ese, key);</span> |
| <span class="fc" id="L146"> throw ese;</span> |
| <span class="nc" id="L147"> } catch (InvalidSessionException ise) {</span> |
| <span class="nc" id="L148"> onInvalidation(session, ise, key);</span> |
| <span class="nc" id="L149"> throw ise;</span> |
| <span class="fc" id="L150"> }</span> |
| <span class="fc" id="L151"> }</span> |
| |
| protected void onExpiration(Session s, ExpiredSessionException ese, SessionKey key) { |
| <span class="fc" id="L154"> log.trace("Session with id [{}] has expired.", s.getId());</span> |
| try { |
| <span class="fc" id="L156"> onExpiration(s);</span> |
| <span class="fc" id="L157"> notifyExpiration(s);</span> |
| } finally { |
| <span class="fc" id="L159"> afterExpired(s);</span> |
| } |
| <span class="fc" id="L161"> }</span> |
| |
| protected void onExpiration(Session session) { |
| <span class="fc" id="L164"> onChange(session);</span> |
| <span class="fc" id="L165"> }</span> |
| |
| protected void afterExpired(Session session) { |
| <span class="fc" id="L168"> }</span> |
| |
| protected void onInvalidation(Session s, InvalidSessionException ise, SessionKey key) { |
| <span class="nc bnc" id="L171" title="All 2 branches missed."> if (ise instanceof ExpiredSessionException) {</span> |
| <span class="nc" id="L172"> onExpiration(s, (ExpiredSessionException) ise, key);</span> |
| <span class="nc" id="L173"> return;</span> |
| } |
| <span class="nc" id="L175"> log.trace("Session with id [{}] is invalid.", s.getId());</span> |
| try { |
| <span class="nc" id="L177"> onStop(s);</span> |
| <span class="nc" id="L178"> notifyStop(s);</span> |
| } finally { |
| <span class="nc" id="L180"> afterStopped(s);</span> |
| } |
| <span class="nc" id="L182"> }</span> |
| |
| protected void doValidate(Session session) throws InvalidSessionException { |
| <span class="pc bpc" id="L185" title="1 of 2 branches missed."> if (session instanceof ValidatingSession) {</span> |
| <span class="fc" id="L186"> ((ValidatingSession) session).validate();</span> |
| } else { |
| <span class="nc" id="L188"> String msg = "The " + getClass().getName() + " implementation only supports validating " +</span> |
| <span class="nc" id="L189"> "Session implementations of the " + ValidatingSession.class.getName() + " interface. " +</span> |
| "Please either implement this interface in your session implementation or override the " + |
| <span class="nc" id="L191"> AbstractValidatingSessionManager.class.getName() + ".doValidate(Session) method to perform validation.";</span> |
| <span class="nc" id="L192"> throw new IllegalStateException(msg);</span> |
| } |
| <span class="fc" id="L194"> }</span> |
| |
| /** |
| * Subclass template hook in case per-session timeout is not based on |
| * {@link org.apache.shiro.session.Session#getTimeout()}. |
| * <p/> |
| * <p>This implementation merely returns {@link org.apache.shiro.session.Session#getTimeout()}</p> |
| * |
| * @param session the session for which to determine session timeout. |
| * @return the time in milliseconds the specified session may remain idle before expiring. |
| */ |
| protected long getTimeout(Session session) { |
| <span class="nc" id="L206"> return session.getTimeout();</span> |
| } |
| |
| protected SessionValidationScheduler createSessionValidationScheduler() { |
| ExecutorServiceSessionValidationScheduler scheduler; |
| |
| <span class="fc bfc" id="L212" title="All 2 branches covered."> if (log.isDebugEnabled()) {</span> |
| <span class="fc" id="L213"> log.debug("No sessionValidationScheduler set. Attempting to create default instance.");</span> |
| } |
| <span class="fc" id="L215"> scheduler = new ExecutorServiceSessionValidationScheduler(this);</span> |
| <span class="fc" id="L216"> scheduler.setInterval(getSessionValidationInterval());</span> |
| <span class="fc bfc" id="L217" title="All 2 branches covered."> if (log.isTraceEnabled()) {</span> |
| <span class="fc" id="L218"> log.trace("Created default SessionValidationScheduler instance of type [" + scheduler.getClass().getName() + "].");</span> |
| } |
| <span class="fc" id="L220"> return scheduler;</span> |
| } |
| |
| protected synchronized void enableSessionValidation() { |
| <span class="fc" id="L224"> SessionValidationScheduler scheduler = getSessionValidationScheduler();</span> |
| <span class="fc bfc" id="L225" title="All 2 branches covered."> if (scheduler == null) {</span> |
| <span class="fc" id="L226"> scheduler = createSessionValidationScheduler();</span> |
| <span class="fc" id="L227"> setSessionValidationScheduler(scheduler);</span> |
| } |
| // it is possible that that a scheduler was already created and set via 'setSessionValidationScheduler()' |
| // but would not have been enabled/started yet |
| <span class="pc bpc" id="L231" title="1 of 2 branches missed."> if (!scheduler.isEnabled()) {</span> |
| <span class="pc bpc" id="L232" title="1 of 2 branches missed."> if (log.isInfoEnabled()) {</span> |
| <span class="fc" id="L233"> log.info("Enabling session validation scheduler...");</span> |
| } |
| <span class="fc" id="L235"> scheduler.enableSessionValidation();</span> |
| <span class="fc" id="L236"> afterSessionValidationEnabled();</span> |
| } |
| <span class="fc" id="L238"> }</span> |
| |
| protected void afterSessionValidationEnabled() { |
| <span class="fc" id="L241"> }</span> |
| |
| protected synchronized void disableSessionValidation() { |
| <span class="fc" id="L244"> beforeSessionValidationDisabled();</span> |
| <span class="fc" id="L245"> SessionValidationScheduler scheduler = getSessionValidationScheduler();</span> |
| <span class="fc bfc" id="L246" title="All 2 branches covered."> if (scheduler != null) {</span> |
| try { |
| <span class="fc" id="L248"> scheduler.disableSessionValidation();</span> |
| <span class="pc bpc" id="L249" title="1 of 2 branches missed."> if (log.isInfoEnabled()) {</span> |
| <span class="fc" id="L250"> log.info("Disabled session validation scheduler.");</span> |
| } |
| <span class="nc" id="L252"> } catch (Exception e) {</span> |
| <span class="nc bnc" id="L253" title="All 2 branches missed."> if (log.isDebugEnabled()) {</span> |
| <span class="nc" id="L254"> String msg = "Unable to disable SessionValidationScheduler. Ignoring (shutting down)...";</span> |
| <span class="nc" id="L255"> log.debug(msg, e);</span> |
| } |
| <span class="fc" id="L257"> }</span> |
| <span class="fc" id="L258"> LifecycleUtils.destroy(scheduler);</span> |
| <span class="fc" id="L259"> setSessionValidationScheduler(null);</span> |
| } |
| <span class="fc" id="L261"> }</span> |
| |
| protected void beforeSessionValidationDisabled() { |
| <span class="fc" id="L264"> }</span> |
| |
| public void destroy() { |
| <span class="fc" id="L267"> disableSessionValidation();</span> |
| <span class="fc" id="L268"> }</span> |
| |
| /** |
| * @see ValidatingSessionManager#validateSessions() |
| */ |
| public void validateSessions() { |
| <span class="pc bpc" id="L274" title="1 of 2 branches missed."> if (log.isInfoEnabled()) {</span> |
| <span class="fc" id="L275"> log.info("Validating all active sessions...");</span> |
| } |
| |
| <span class="fc" id="L278"> int invalidCount = 0;</span> |
| |
| <span class="fc" id="L280"> Collection<Session> activeSessions = getActiveSessions();</span> |
| |
| <span class="pc bpc" id="L282" title="2 of 4 branches missed."> if (activeSessions != null && !activeSessions.isEmpty()) {</span> |
| <span class="fc bfc" id="L283" title="All 2 branches covered."> for (Session s : activeSessions) {</span> |
| try { |
| //simulate a lookup key to satisfy the method signature. |
| //this could probably stand to be cleaned up in future versions: |
| <span class="fc" id="L287"> SessionKey key = new DefaultSessionKey(s.getId());</span> |
| <span class="fc" id="L288"> validate(s, key);</span> |
| <span class="fc" id="L289"> } catch (InvalidSessionException e) {</span> |
| <span class="pc bpc" id="L290" title="1 of 2 branches missed."> if (log.isDebugEnabled()) {</span> |
| <span class="fc" id="L291"> boolean expired = (e instanceof ExpiredSessionException);</span> |
| <span class="fc bfc" id="L292" title="All 2 branches covered."> String msg = "Invalidated session with id [" + s.getId() + "]" +</span> |
| (expired ? " (expired)" : " (stopped)"); |
| <span class="fc" id="L294"> log.debug(msg);</span> |
| } |
| <span class="fc" id="L296"> invalidCount++;</span> |
| <span class="fc" id="L297"> }</span> |
| <span class="fc" id="L298"> }</span> |
| } |
| |
| <span class="pc bpc" id="L301" title="1 of 2 branches missed."> if (log.isInfoEnabled()) {</span> |
| <span class="fc" id="L302"> String msg = "Finished session validation.";</span> |
| <span class="pc bpc" id="L303" title="1 of 2 branches missed."> if (invalidCount > 0) {</span> |
| <span class="fc" id="L304"> msg += " [" + invalidCount + "] sessions were stopped.";</span> |
| } else { |
| <span class="nc" id="L306"> msg += " No sessions were stopped.";</span> |
| } |
| <span class="fc" id="L308"> log.info(msg);</span> |
| } |
| <span class="fc" id="L310"> }</span> |
| |
| protected abstract Collection<Session> getActiveSessions(); |
| } |
| </pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.3.201901230119</span></div></body></html> |