org.jasig.cas.ticket.registry.support.BatchedTicketRegistryCleaner.java Source code

Java tutorial

Introduction

Here is the source code for org.jasig.cas.ticket.registry.support.BatchedTicketRegistryCleaner.java

Source

/*
 * Licensed to Jasig under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Jasig 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 the following location:
 *
 *   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.jasig.cas.ticket.registry.support;

import org.apache.commons.collections.CollectionUtils;
import org.jasig.cas.ticket.Ticket;
import org.jasig.cas.ticket.registry.BatchableTicketRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import javax.annotation.PostConstruct;
import java.util.Collection;

/**
 * This class tries to address the issue with ${@link DefaultTicketRegistryCleaner} when used in conjunction with a
 * ${@link org.jasig.cas.ticket.registry.JpaTicketRegistry} discussed in the below thread by processing the tickets in
 * the registry in batches. This should prevent the CAS server from running out of memory in certain scenarios (ie when
 * a large number of tickets get created in a short period of time) when the ticket registry cleaner runs.
 *
 * http://jasig.275507.n4.nabble.com/JpaTicketRegistry-A-Sinking-Ship-td4256973.html
 *
 * @author Ahsan Rabbani
 * @since 4.0
 */
public class BatchedTicketRegistryCleaner extends AbstractTicketRegistryCleaner {

    /** The Commons Logging instance. */
    private final Logger logger = LoggerFactory.getLogger(getClass());

    private static final int DEFAULT_BATCH_SIZE = 2000;

    private int batchSize = DEFAULT_BATCH_SIZE;

    @PostConstruct
    public void init() {
        Assert.isInstanceOf(BatchableTicketRegistry.class, ticketRegistry,
                "ticketRegistry must be of type BatchableTicketRegistry");
    }

    @Override
    public void clean() {
        logger.info("Beginning ticket cleanup.");

        logger.debug("Attempting to acquire ticket cleanup lock.");
        if (!lock.acquire()) {
            logger.info("Could not obtain lock.  Aborting cleanup.");
            return;
        }
        logger.debug("Acquired lock.  Proceeding with cleanup.");

        try {
            logger.info("Processing TicketGrantingTickets for cleanup.");
            int numTicketsRemoved = cleanTickets(new BatchedTicketRetriever() {
                @Override
                public Collection<Ticket> getBatch(final int offset, final int batchSize) {
                    return ((BatchableTicketRegistry) ticketRegistry).getTicketGrantingTicketBatch(offset,
                            batchSize);
                }
            });
            logger.info("{} total TicketGrantingTickets removed.", numTicketsRemoved);

            logger.info("Processing ServiceTickets for cleanup.");
            numTicketsRemoved = cleanTickets(new BatchedTicketRetriever() {
                @Override
                public Collection<Ticket> getBatch(final int offset, final int batchSize) {
                    return ((BatchableTicketRegistry) ticketRegistry).getServiceTicketBatch(offset, batchSize);
                }
            });
            logger.info("{} total ServiceTickets removed.", numTicketsRemoved);
        } finally {
            logger.debug("Releasing ticket cleanup lock.");
            lock.release();
        }

        logger.info("Finished ticket cleanup.");
    }

    int cleanTickets(final BatchedTicketRetriever ticketRetriever) {
        int offset = 0;
        int numTicketsRemoved = 0;

        Collection<Ticket> ticketBatch;
        while (CollectionUtils.isNotEmpty(ticketBatch = ticketRetriever.getBatch(offset, batchSize))) {
            int ticketsRemovedFromBatch = registryCleanerHelper.deleteExpiredTickets(ticketRegistry, logoutManager,
                    ticketBatch, logUserOutOfServices);
            offset += (ticketBatch.size() - ticketsRemovedFromBatch);
            numTicketsRemoved += ticketsRemovedFromBatch;
        }

        return numTicketsRemoved;
    }

    interface BatchedTicketRetriever {
        Collection<Ticket> getBatch(int offset, int batchSize);
    }

    /**
     * Batch size to use when retrieving tickets from the registry to process. The default is 2000.
     *
     * @param batchSize batch size to use when retrieving tickets from the registry
     */
    public void setBatchSize(final int batchSize) {
        this.batchSize = batchSize;
    }

}