package org.skyscreamer.yoga.listener; import java.util.concurrent.atomic.AtomicInteger; import org.skyscreamer.yoga.exceptions.EntityCountExceededException; import org.skyscreamer.yoga.exceptions.YogaRuntimeException; import org.skyscreamer.yoga.listener.RenderingEvent; import org.skyscreamer.yoga.listener.RenderingEventType; import org.skyscreamer.yoga.listener.RenderingListener; import org.skyscreamer.yoga.mapper.YogaRequestContext; /** * This is a mechanism that will limit the number of children that are added to * a response. This is a security mechanism that will prevent potential yoga * induced OutOfMemoryError. * * @see RenderingListener * @see RenderingListenerRegistry * @see YogaRequestContext */ public class CountLimitRenderingListener implements RenderingListener { int maxCount = 0; public CountLimitRenderingListener( int maxCount ) { setMaxCount(maxCount); } public void setMaxCount(int maxCount) { if (maxCount <= 0) { throw new YogaRuntimeException( "CountLimitRenderingListener expects a positive maxCount" ); } this.maxCount = maxCount; } @Override public <T> void eventOccurred( RenderingEvent<T> event ) { if (event.getType() != RenderingEventType.POJO_CHILD) { return; } YogaRequestContext requestContext = event.getRequestContext(); AtomicInteger counter = (AtomicInteger) requestContext.getProperty( "child_counter" ); if (counter == null) { requestContext.setProperty( "child_counter", counter = new AtomicInteger() ); } if (counter.incrementAndGet() > maxCount) { throw new EntityCountExceededException("The maximum count of children: " + maxCount + " has been exceeded."); } } }