package org.apereo.cas.ticket.registry;

import org.apereo.cas.logout.LogoutManager;
import org.apereo.cas.ticket.ServiceTicket;
import org.apereo.cas.ticket.Ticket;
import org.apereo.cas.ticket.TicketGrantingTicket;
import org.apereo.cas.ticket.registry.support.LockingStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.Collection;
import java.util.stream.Collectors;

/**
 * This is {@link DefaultTicketRegistryCleaner}.
 *
 * @author Misagh Moayyed
 * @since 5.0.0
 */
@Transactional(transactionManager = "ticketTransactionManager", readOnly = false)
public class DefaultTicketRegistryCleaner implements TicketRegistryCleaner, Serializable {
    private static final long serialVersionUID = -8581398063126547772L;
    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultTicketRegistryCleaner.class);

    private final LogoutManager logoutManager;
    private final TicketRegistry ticketRegistry;
    private final LockingStrategy lockingStrategy;

    public DefaultTicketRegistryCleaner(final LockingStrategy lockingStrategy, 
                                        final LogoutManager logoutManager, 
                                        final TicketRegistry ticketRegistry) {
        this.lockingStrategy = lockingStrategy;
        this.logoutManager = logoutManager;
        this.ticketRegistry = ticketRegistry;
    }
    
    @Override
    public void clean() {
        try {
            if (!isCleanerSupported()) {
                LOGGER.trace("Ticket registry cleaner is not supported by [{}]. No cleaner processes will run.",
                        getClass().getSimpleName());
                return;
            }

            LOGGER.debug("Attempting to acquire ticket cleanup lock.");
            if (!this.lockingStrategy.acquire()) {
                LOGGER.info("Could not obtain lock. Aborting cleanup. The ticket registry may not support self-service maintenance.");
                return;
            }
            LOGGER.debug("Acquired lock. Proceeding with cleanup.");
            cleanInternal();
        } catch (final Exception e) {
            LOGGER.error(e.getMessage(), e);
        } finally {
            LOGGER.debug("Releasing ticket cleanup lock.");
            this.lockingStrategy.release();
            LOGGER.debug("Finished ticket cleanup.");
        }
    }

    /**
     * Clean tickets.
     */
    protected void cleanInternal() {
        final Collection<Ticket> ticketsToRemove = ticketRegistry.getTickets()
                .stream()
                .filter(Ticket::isExpired)
                .collect(Collectors.toSet());
        LOGGER.debug("[{}] expired tickets found.", ticketsToRemove.size());

        int count = 0;

        for (final Ticket ticket : ticketsToRemove) {
            if (ticket instanceof TicketGrantingTicket) {
                LOGGER.debug("Cleaning up expired ticket-granting ticket [{}]", ticket.getId());
                logoutManager.performLogout((TicketGrantingTicket) ticket);
                count += ticketRegistry.deleteTicket(ticket.getId());
            } else if (ticket instanceof ServiceTicket) {
                LOGGER.debug("Cleaning up expired service ticket [{}]", ticket.getId());
                count += ticketRegistry.deleteTicket(ticket.getId());
            } else {
                LOGGER.warn("Unknown ticket type [{}] found to clean", ticket.getClass().getSimpleName());
            }
        }
        LOGGER.info("[{}] expired tickets removed.", count);
    }

    /**
     * Indicates whether the registry supports automatic ticket cleanup.
     * Generally, a registry that is able to return a collection of available
     * tickets should be able to support the cleanup process. Default is {@code true}.
     *
     * @return true/false.
     */
    protected boolean isCleanerSupported() {
        return true;
    }
}

@@ -428,73 +428,8 @@
 ble;
-%0Aimport java.util.Collection;%0Aimport java.util.stream.Collectors;
 %0A%0A/*
@@ -2473,42 +2473,26 @@
 nal 
-Collection%3CTicket%3E ticketsToRemove
+int ticketsDeleted
  = t
@@ -2608,193 +2608,37 @@
    .
-collect(Collectors.toSet());%0A        LOGGER.debug(%22%5B%7B%7D%5D expired tickets found.%22, ticketsToRemove.size());%0A%0A        int count = 0;%0A%0A        for (final Ticket ticket : ticketsToRemove) %7B%0A
+mapToInt(ticket -%3E %7B%0A        
     
@@ -2699,32 +2699,40 @@
                 
+ 
+       
 LOGGER.debug(%22Cl
@@ -2812,16 +2812,24 @@
         
+        
 logoutMa
@@ -2892,32 +2892,38 @@
             
-count +=
+        return
  ticketRegis
@@ -2964,24 +2964,32 @@
             
+        
 %7D else if (t
@@ -3030,32 +3030,40 @@
                 
+   
+     
 LOGGER.debug(%22Cl
@@ -3139,16 +3139,22 @@
     
-count +=
+        return
  tic
@@ -3203,24 +3203,32 @@
             
+        
 %7D else %7B%0A   
@@ -3220,24 +3220,32 @@
    %7D else %7B%0A
+        
             
@@ -3331,32 +3331,74 @@
 tSimpleName());%0A
+                        return 0;%0A        
             %7D%0A  
@@ -3395,33 +3395,67 @@
       %7D%0A        
+      
-%7D
+  %7D)%0A                .sum();%0A
 %0A        LOGGER.
@@ -3496,13 +3496,22 @@
 .%22, 
-count
+ticketsDeleted
 );%0A 

Use streams in default cleaner (#2779)