001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.shiro.session.mgt; 020 021import java.util.concurrent.Executors; 022import java.util.concurrent.ScheduledExecutorService; 023import java.util.concurrent.ThreadFactory; 024import java.util.concurrent.TimeUnit; 025import java.util.concurrent.atomic.AtomicInteger; 026 027import org.slf4j.Logger; 028import org.slf4j.LoggerFactory; 029 030 031/** 032 * SessionValidationScheduler implementation that uses a 033 * {@link ScheduledExecutorService} to call {@link ValidatingSessionManager#validateSessions()} every 034 * <em>{@link #getInterval interval}</em> milliseconds. 035 * 036 * @since 0.9 037 */ 038public class ExecutorServiceSessionValidationScheduler implements SessionValidationScheduler, Runnable { 039 040 //TODO - complete JavaDoc 041 042 /** Private internal log instance. */ 043 private static final Logger log = LoggerFactory.getLogger(ExecutorServiceSessionValidationScheduler.class); 044 045 ValidatingSessionManager sessionManager; 046 private ScheduledExecutorService service; 047 private long interval = DefaultSessionManager.DEFAULT_SESSION_VALIDATION_INTERVAL; 048 private boolean enabled = false; 049 private String threadNamePrefix = "SessionValidationThread-"; 050 051 public ExecutorServiceSessionValidationScheduler() { 052 super(); 053 } 054 055 public ExecutorServiceSessionValidationScheduler(ValidatingSessionManager sessionManager) { 056 this.sessionManager = sessionManager; 057 } 058 059 public ValidatingSessionManager getSessionManager() { 060 return sessionManager; 061 } 062 063 public void setSessionManager(ValidatingSessionManager sessionManager) { 064 this.sessionManager = sessionManager; 065 } 066 067 public long getInterval() { 068 return interval; 069 } 070 071 public void setInterval(long interval) { 072 this.interval = interval; 073 } 074 075 public boolean isEnabled() { 076 return this.enabled; 077 } 078 079 public void setThreadNamePrefix(String threadNamePrefix) { 080 this.threadNamePrefix = threadNamePrefix; 081 } 082 083 public String getThreadNamePrefix() { 084 return this.threadNamePrefix; 085 } 086 087 /** 088 * Creates a single thread {@link ScheduledExecutorService} to validate sessions at fixed intervals 089 * and enables this scheduler. The executor is created as a daemon thread to allow JVM to shut down 090 */ 091 //TODO Implement an integration test to test for jvm exit as part of the standalone example 092 // (so we don't have to change the unit test execution model for the core module) 093 public void enableSessionValidation() { 094 if (this.interval > 0l) { 095 this.service = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { 096 private final AtomicInteger count = new AtomicInteger(1); 097 098 public Thread newThread(Runnable r) { 099 Thread thread = new Thread(r); 100 thread.setDaemon(true); 101 thread.setName(threadNamePrefix + count.getAndIncrement()); 102 return thread; 103 } 104 }); 105 this.service.scheduleAtFixedRate(this, interval, interval, TimeUnit.MILLISECONDS); 106 } 107 this.enabled = true; 108 } 109 110 public void run() { 111 if (log.isDebugEnabled()) { 112 log.debug("Executing session validation..."); 113 } 114 Thread.currentThread().setUncaughtExceptionHandler((t, e) -> { 115 log.error("Error while validating the session, the thread will be stopped and session validation disabled", e); 116 this.disableSessionValidation(); 117 }); 118 long startTime = System.currentTimeMillis(); 119 try { 120 this.sessionManager.validateSessions(); 121 } catch (RuntimeException e) { 122 log.error("Error while validating the session", e); 123 //we don't stop the thread 124 } 125 long stopTime = System.currentTimeMillis(); 126 if (log.isDebugEnabled()) { 127 log.debug("Session validation completed successfully in " + (stopTime - startTime) + " milliseconds."); 128 } 129 } 130 131 public void disableSessionValidation() { 132 if (this.service != null) { 133 this.service.shutdownNow(); 134 } 135 this.enabled = false; 136 } 137}