/* * 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; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.LockModeType; import javax.persistence.PersistenceContext; import javax.validation.constraints.NotNull; import org.jasig.cas.ticket.ServiceTicket; import org.jasig.cas.ticket.ServiceTicketImpl; import org.jasig.cas.ticket.Ticket; import org.jasig.cas.ticket.TicketGrantingTicketImpl; import org.springframework.transaction.annotation.Transactional; /** * JPA implementation of a CAS {@link TicketRegistry}. This implementation of * ticket registry is suitable for HA environments. * * @author Scott Battaglia * @author Marvin S. Addison * * @since 3.2.1 * */ public final class JpaTicketRegistry extends AbstractDistributedTicketRegistry { @NotNull @PersistenceContext private EntityManager entityManager; @NotNull private String ticketGrantingTicketPrefix = "TGT"; protected void updateTicket(final Ticket ticket) { entityManager.merge(ticket); logger.debug("Updated ticket [{}].", ticket); } @Transactional(readOnly = false) public void addTicket(final Ticket ticket) { entityManager.persist(ticket); logger.debug("Added ticket [{}] to registry.", ticket); } @Transactional(readOnly = false) public boolean deleteTicket(final String ticketId) { final Ticket ticket = getRawTicket(ticketId); if (ticket == null) { return false; } if (ticket instanceof ServiceTicket) { removeTicket(ticket); logger.debug("Deleted ticket [{}] from the registry.", ticket); return true; } deleteTicketAndChildren(ticket); logger.debug("Deleted ticket [{}] and its children from the registry.", ticket); return true; } private void deleteTicketAndChildren(final Ticket ticket) { final List<TicketGrantingTicketImpl> ticketGrantingTicketImpls = entityManager .createQuery("select t from TicketGrantingTicketImpl t where t.ticketGrantingTicket.id = :id", TicketGrantingTicketImpl.class) .setLockMode(LockModeType.PESSIMISTIC_WRITE) .setParameter("id", ticket.getId()) .getResultList(); final List<ServiceTicketImpl> serviceTicketImpls = entityManager .createQuery("select s from ServiceTicketImpl s where s.ticketGrantingTicket.id = :id", ServiceTicketImpl.class) .setParameter("id", ticket.getId()) .getResultList(); for (final ServiceTicketImpl s : serviceTicketImpls) { removeTicket(s); } for (final TicketGrantingTicketImpl t : ticketGrantingTicketImpls) { deleteTicketAndChildren(t); } removeTicket(ticket); } private void removeTicket(final Ticket ticket) { try { if (logger.isDebugEnabled()) { final Date creationDate = new Date(ticket.getCreationTime()); logger.debug("Removing Ticket [{}] created: {}", ticket, creationDate.toString()); } entityManager.remove(ticket); } catch (final Exception e) { logger.error("Error removing {} from registry.", ticket, e); } } @Transactional(readOnly=true) public Ticket getTicket(final String ticketId) { return getProxiedTicketInstance(getRawTicket(ticketId)); } private Ticket getRawTicket(final String ticketId) { try { if (ticketId.startsWith(this.ticketGrantingTicketPrefix)) { return entityManager.find(TicketGrantingTicketImpl.class, ticketId, LockModeType.PESSIMISTIC_WRITE); } return entityManager.find(ServiceTicketImpl.class, ticketId); } catch (final Exception e) { logger.error("Error getting ticket {} from registry.", ticketId, e); } return null; } @Transactional(readOnly=true) public Collection<Ticket> getTickets() { final List<TicketGrantingTicketImpl> tgts = entityManager .createQuery("select t from TicketGrantingTicketImpl t", TicketGrantingTicketImpl.class) .getResultList(); final List<ServiceTicketImpl> sts = entityManager .createQuery("select s from ServiceTicketImpl s", ServiceTicketImpl.class) .getResultList(); final List<Ticket> tickets = new ArrayList<Ticket>(); tickets.addAll(tgts); tickets.addAll(sts); return tickets; } public void setTicketGrantingTicketPrefix(final String ticketGrantingTicketPrefix) { this.ticketGrantingTicketPrefix = ticketGrantingTicketPrefix; } @Override protected boolean needsCallback() { return false; } @Transactional(readOnly=true) public int sessionCount() { return countToInt(entityManager.createQuery( "select count(t) from TicketGrantingTicketImpl t").getSingleResult()); } @Transactional(readOnly=true) public int serviceTicketCount() { return countToInt(entityManager.createQuery("select count(t) from ServiceTicketImpl t").getSingleResult()); } private int countToInt(final Object result) { final int intval; if (result instanceof Long) { intval = ((Long) result).intValue(); } else if (result instanceof Integer) { intval = (Integer) result; } else { // Must be a Number of some kind intval = ((Number) result).intValue(); } return intval; } }