All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apereo.cas.ticket.registry.HazelcastTicketRegistry Maven / Gradle / Ivy

package org.apereo.cas.ticket.registry;

import org.apereo.cas.ticket.Ticket;
import org.apereo.cas.ticket.TicketCatalog;
import org.apereo.cas.ticket.TicketDefinition;
import org.apereo.cas.util.LoggingUtils;

import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.map.IMap;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.DisposableBean;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * Hazelcast-based implementation of a {@link TicketRegistry}.
 * 

This implementation just wraps the Hazelcast's {@link IMap} * which is an extension of the standard Java's {@code ConcurrentMap}.

*

The heavy lifting of distributed data partitioning, network cluster discovery and * join, data replication, etc. is done by Hazelcast's Map implementation.

* * @author Dmitriy Kopylenko * @author Jonathan Johnson * @since 4.1.0 */ @Slf4j @RequiredArgsConstructor public class HazelcastTicketRegistry extends AbstractTicketRegistry implements AutoCloseable, DisposableBean { private final HazelcastInstance hazelcastInstance; private final TicketCatalog ticketCatalog; private final long pageSize; @Override public Ticket updateTicket(final Ticket ticket) { addTicket(ticket); return ticket; } @Override public void addTicket(final Ticket ticket) { val ttl = ticket.getExpirationPolicy().getTimeToLive(); if (ttl < 0) { throw new IllegalArgumentException("The expiration policy of ticket " + ticket.getId() + " is set to use a negative ttl"); } LOGGER.debug("Adding ticket [{}] with ttl [{}s]", ticket.getId(), ttl); val encTicket = encodeTicket(ticket); val metadata = this.ticketCatalog.find(ticket); val ticketMap = getTicketMapInstanceByMetadata(metadata); if (ticketMap != null) { ticketMap.set(encTicket.getId(), encTicket, ttl, TimeUnit.SECONDS); LOGGER.debug("Added ticket [{}] with ttl [{}s]", encTicket.getId(), ttl); } else { LOGGER.warn("Unable to locate ticket map for ticket metadata [{}]", metadata); } } @Override public Ticket getTicket(final String ticketId, final Predicate predicate) { val encTicketId = encodeTicketId(ticketId); if (StringUtils.isBlank(encTicketId)) { return null; } val metadata = this.ticketCatalog.find(ticketId); if (metadata != null) { val map = getTicketMapInstanceByMetadata(metadata); if (map != null) { val ticket = map.get(encTicketId); val result = decodeTicket(ticket); if (predicate.test(result)) { return result; } return null; } else { LOGGER.error("Unable to locate ticket map for ticket definition [{}]", metadata); } } LOGGER.warn("No ticket definition could be found in the catalog to match [{}]", ticketId); return null; } @Override public boolean deleteSingleTicket(final String ticketIdToDelete) { val encTicketId = encodeTicketId(ticketIdToDelete); val metadata = this.ticketCatalog.find(ticketIdToDelete); val map = getTicketMapInstanceByMetadata(metadata); return map != null && map.remove(encTicketId) != null; } @Override public long deleteAll() { return this.ticketCatalog.findAll() .stream() .map(this::getTicketMapInstanceByMetadata) .filter(Objects::nonNull) .mapToInt(instance -> { val size = instance.size(); instance.evictAll(); instance.clear(); return size; }) .sum(); } @Override public Collection getTickets() { return this.ticketCatalog.findAll() .stream() .map(metadata -> getTicketMapInstanceByMetadata(metadata).values()) .flatMap(tickets -> { if (pageSize > 0) { return tickets.stream().limit(pageSize).collect(Collectors.toList()).stream(); } return new ArrayList<>(tickets).stream(); }) .map(this::decodeTicket) .collect(Collectors.toSet()); } /** * Make sure we shutdown HazelCast when the context is destroyed. */ public void shutdown() { try { LOGGER.info("Shutting down Hazelcast instance [{}]", this.hazelcastInstance.getConfig().getInstanceName()); this.hazelcastInstance.shutdown(); } catch (final Exception e) { LOGGER.debug(e.getMessage()); } } @Override public void destroy() { close(); } @Override public void close() { shutdown(); } private IMap getTicketMapInstanceByMetadata(final TicketDefinition metadata) { val mapName = metadata.getProperties().getStorageName(); LOGGER.debug("Locating map name [{}] for ticket definition [{}]", mapName, metadata); return getTicketMapInstance(mapName); } private IMap getTicketMapInstance(@NonNull final String mapName) { try { val inst = hazelcastInstance.getMap(mapName); LOGGER.debug("Located Hazelcast map instance [{}]", mapName); return inst; } catch (final Exception e) { LoggingUtils.error(LOGGER, e); } return null; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy