Hello Dean,
Sorry for the delay. Here is the EhCacheTicketRegistry.java with a
JA-SIG Licence. I send it both as an attachment and doing a copy-paste
in the email body in case the mailing mist would reject attachments.
Hope this helps,
Cyrille
/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.uportal.org/license.html
*/
package org.jasig.cas.ticket.registry.ehcache;
import java.util.Collection;
import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;
import org.inspektr.common.ioc.annotation.NotNull;
import org.jasig.cas.ticket.ServiceTicket;
import org.jasig.cas.ticket.Ticket;
import org.jasig.cas.ticket.TicketGrantingTicket;
import org.jasig.cas.ticket.registry.AbstractDistributedTicketRegistry;
import org.jasig.cas.ticket.registry.TicketRegistry;
import org.springframework.core.style.ToStringCreator;
/**
* <p>
* <a href="http://ehcache.sourceforge.net/">EHCache</a> based
distributed ticket registry.
* </p>
* <p>
* Use distinct caches for ticket granting tickets (TGT) and service
tickets (ST) for:
* <ul>
* <li>Tuning : use cache level time to live with different values for
TGT an ST.</li>
* <li>Tuning : have different replication strategies for TGT and ST
(ST should be synchronized more quickly).</li>
* <li>Monitoring : follow separately the number of TGT and ST.</li>
* <ul>
* </p>
*
* @author <a href="mailto:[email protected]">Cyrille Le Clerc</a>
*/
public class EhCacheTicketRegistry extends
AbstractDistributedTicketRegistry implements TicketRegistry {
@NotNull
protected Cache serviceTicketsCache;
@NotNull
protected Cache ticketGrantingTicketsCache;
@Override
public void addTicket(Ticket ticket) {
Element element = new Element(ticket.getId(), ticket);
if (ticket instanceof ServiceTicket) {
serviceTicketsCache.put(element);
} else if (ticket instanceof TicketGrantingTicket) {
ticketGrantingTicketsCache.put(element);
} else {
throw new IllegalArgumentException("Invalid ticket type " + ticket);
}
}
@Override
public boolean deleteTicket(String ticketId) {
boolean result;
if (ticketId.startsWith(TicketGrantingTicket.PREFIX)) {
result = ticketGrantingTicketsCache.remove(ticketId);
} else if (ticketId.startsWith(ServiceTicket.PREFIX)) {
result = serviceTicketsCache.remove(ticketId);
} else {
result = false;
if (log.isInfoEnabled()) {
log.info("Unsupported ticket prefix for ticketId '" +
ticketId + "', return " + result);
}
}
return result;
}
@Override
public Ticket getTicket(String ticketId) {
Element element;
if (ticketId.startsWith(TicketGrantingTicket.PREFIX)) {
element = ticketGrantingTicketsCache.get(ticketId);
} else if (ticketId.startsWith(ServiceTicket.PREFIX)) {
element = serviceTicketsCache.get(ticketId);
} else {
element = null;
if (log.isInfoEnabled()) {
log.info("Unsupported ticket prefix for ticketId '" +
ticketId + "', return " + element);
}
}
return element == null ? null :
getProxiedTicketInstance((Ticket)element.getValue());
}
@Override
public Collection<Ticket> getTickets() {
throw new UnsupportedOperationException("GetTickets not supported.");
}
public void setServiceTicketsCache(Cache serviceTicketsCache) {
this.serviceTicketsCache = serviceTicketsCache;
}
public void setTicketGrantingTicketsCache(Cache
ticketGrantingTicketsCache) {
this.ticketGrantingTicketsCache = ticketGrantingTicketsCache;
}
@Override
public String toString() {
return new
ToStringCreator(this).append("ticketGrantingTicketsCache",
this.ticketGrantingTicketsCache)
.append("serviceTicketsCache", this.serviceTicketsCache).toString();
}
@Override
protected void updateTicket(Ticket ticket) {
addTicket(ticket);
}
}
On Tue, Nov 3, 2009 at 9:52 PM, Dean Heisey <[email protected]> wrote:
>
> Hi Cyrille,
>
> Thanks for sharing your experience. If you can share the code that would
> be great, if not. I will implement my own.
>
> Dean
>
> -----Original Message-----
> From: Cyrille Le Clerc [mailto:[email protected]]
> Sent: Tuesday, November 03, 2009 12:56 AM
> To: [email protected]
> Subject: Re: [cas-user] CAS + EHCache Ticket Registry
>
> Hello Dean,
>
> We happily use a Distributed EHCache Ticket Registry on a high
> volume french portal that reaches a max of 40 ticket granting tickets
> and 80 service tickets created per second. That is about 120 tickets
> replicated per second.
>
> This EH Cache Ticket Registry has been used for more than six month
> without causing major issues and the traffic is increasing. We are
> very happy with EH Cache and RMI because they almost do not require
> configuration and tuning. We would have been interested in Memcached
> but we didn't have skills to provide 7x24 support on this technology
> we don't use in-house.
>
> For this, we have a cluster of three nodes :
> * HP ProLiant G5 dual quad cores 54xx Intel Xeon.
> * Red Hat Enterprise Linux 4 / 2.6.9-78.0.8.ELsmp 32 bits
> * Sun jdk 1.6.0.13
> * Tomcat 6.0.18
> * CAS 3.3.1
> * EHCache 1.6.1 with :
> ** Auto discovery of the peers
> ** RMI Synchronous Replicator for service tickets :
> service tickets validation doesn't benefit of server affinity
> and can occur few ms after creation
> ** RMI Asynchronous Replicator for the ticket granting tickets :
> ticket granting ticket benefit of server affinity because they
> are always accessed via the end user browser
> (no server-to-server exchanges)
>
> The CPU consumed by this application remain quite low and we have
> deployed other high traffic web applications on these physical
> servers.
>
> The biggest problem we faced was the saturation of the Network
> Interface Cards because we didn't know but we used and 100 Mbits/s
> switch (pretty surprising in 2009 ;-) ). The servers froze on RMI
> socket establishment calls. Once we upgraded to a Giga Bits Ethernet
> switch, everything came back to normal.
>
> Another point you may worry about is long
> stop-the-world-garbage-collection phases on peer servers if you set
> aggressive RMI read timeouts.
> We didn't feel the need to define RMI timeouts on our CAS cluster
> but we use it on another application that also heavily rely on
> Distributed Sync RMI EHCache and face sparse RMI timeouts that seem to
> be caused by long stop-the-world-garbage collections on peer servers.
>
> I am no longer member of the SSO team but I am sure we can give you
> the one hundred lines of code of the EHCacheTicketRegistry.
>
> Hope this helps,
>
> Cyrille
>
> --
> Cyrille Le Clerc
> [email protected] [email protected]
> http://blog.xebia.fr
>
> On Thu, Oct 29, 2009 at 10:29 PM, Scott Battaglia
> <[email protected]> wrote:
> >
> > On Thu, Oct 29, 2009 at 5:11 PM, Dean Heisey <[email protected]>
> > wrote:
> >>
> >> After reading through the old postings and the CASUM I have not found any
> >> mention of an EHCache backed ticket registry. I have two questions:
> >>
> >> 1) has anyone implemented one yet?
> >
> > When we first tried it, it didn't scale very well. We haven't tried with
> > newer versions.
> >
> >>
> >> 2) the Users Manual mentions terracotta and the default ticket registry.
> >> Does that actually work and has anyone implemented it?
> >
> > There have a been a few instances where its been deployed. We include a
> > sample config in SVN.
> >
> > Cheers,
> > Scott
> >
> >>
> >> Dean
> >> --
> >> View this message in context:
> >> http://n4.nabble.com/CAS-EHCache-Ticket-Registry-tp278045p278045.html
> >> Sent from the CAS Users mailing list archive at Nabble.com.
> >>
> >> --
> >> You are currently subscribed to [email protected] as:
> >> [email protected]
> >> To unsubscribe, change settings or access archives, see
> >> http://www.ja-sig.org/wiki/display/JSG/cas-user
> >
> > --
> > You are currently subscribed to [email protected] as:
> > [email protected]
> > To unsubscribe, change settings or access archives, see
> > http://www.ja-sig.org/wiki/display/JSG/cas-user
>
> --
> You are currently subscribed to [email protected] as:
> [email protected]
> To unsubscribe, change settings or access archives, see
> http://www.ja-sig.org/wiki/display/JSG/cas-user
>
> --
> You are currently subscribed to [email protected] as:
> [email protected]
> To unsubscribe, change settings or access archives, see
> http://www.ja-sig.org/wiki/display/JSG/cas-user
>
--
You are currently subscribed to [email protected] as:
[email protected]
To unsubscribe, change settings or access archives, see
http://www.ja-sig.org/wiki/display/JSG/cas-user/*
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
* distributed with this file and available online at
* http://www.uportal.org/license.html
*/
package org.jasig.cas.ticket.registry.ehcache;
import java.util.Collection;
import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;
import org.inspektr.common.ioc.annotation.NotNull;
import org.jasig.cas.ticket.ServiceTicket;
import org.jasig.cas.ticket.Ticket;
import org.jasig.cas.ticket.TicketGrantingTicket;
import org.jasig.cas.ticket.registry.AbstractDistributedTicketRegistry;
import org.jasig.cas.ticket.registry.TicketRegistry;
import org.springframework.core.style.ToStringCreator;
/**
* <p>
* <a href="http://ehcache.sourceforge.net/">EHCache</a> based distributed
ticket registry.
* </p>
* <p>
* Use distinct caches for ticket granting tickets (TGT) and service tickets
(ST) for:
* <ul>
* <li>Tuning : use cache level time to live with different values for TGT an
ST.</li>
* <li>Tuning : have different replication strategies for TGT and ST (ST should
be synchronized more quickly).</li>
* <li>Monitoring : follow separately the number of TGT and ST.</li>
* <ul>
* </p>
*
* @author <a href="mailto:[email protected]">Cyrille Le Clerc</a>
*/
public class EhCacheTicketRegistry extends AbstractDistributedTicketRegistry
implements TicketRegistry {
@NotNull
protected Cache serviceTicketsCache;
@NotNull
protected Cache ticketGrantingTicketsCache;
@Override
public void addTicket(Ticket ticket) {
Element element = new Element(ticket.getId(), ticket);
if (ticket instanceof ServiceTicket) {
serviceTicketsCache.put(element);
} else if (ticket instanceof TicketGrantingTicket) {
ticketGrantingTicketsCache.put(element);
} else {
throw new IllegalArgumentException("Invalid ticket type " + ticket);
}
}
@Override
public boolean deleteTicket(String ticketId) {
boolean result;
if (ticketId.startsWith(TicketGrantingTicket.PREFIX)) {
result = ticketGrantingTicketsCache.remove(ticketId);
} else if (ticketId.startsWith(ServiceTicket.PREFIX)) {
result = serviceTicketsCache.remove(ticketId);
} else {
result = false;
if (log.isInfoEnabled()) {
log.info("Unsupported ticket prefix for ticketId '" + ticketId
+ "', return " + result);
}
}
return result;
}
@Override
public Ticket getTicket(String ticketId) {
Element element;
if (ticketId.startsWith(TicketGrantingTicket.PREFIX)) {
element = ticketGrantingTicketsCache.get(ticketId);
} else if (ticketId.startsWith(ServiceTicket.PREFIX)) {
element = serviceTicketsCache.get(ticketId);
} else {
element = null;
if (log.isInfoEnabled()) {
log.info("Unsupported ticket prefix for ticketId '" + ticketId
+ "', return " + element);
}
}
return element == null ? null :
getProxiedTicketInstance((Ticket)element.getValue());
}
@Override
public Collection<Ticket> getTickets() {
throw new UnsupportedOperationException("GetTickets not supported.");
}
public void setServiceTicketsCache(Cache serviceTicketsCache) {
this.serviceTicketsCache = serviceTicketsCache;
}
public void setTicketGrantingTicketsCache(Cache ticketGrantingTicketsCache)
{
this.ticketGrantingTicketsCache = ticketGrantingTicketsCache;
}
@Override
public String toString() {
return new ToStringCreator(this).append("ticketGrantingTicketsCache",
this.ticketGrantingTicketsCache)
.append("serviceTicketsCache", this.serviceTicketsCache).toString();
}
@Override
protected void updateTicket(Ticket ticket) {
addTicket(ticket);
}
}