Repository: wicket
Updated Branches:
  refs/heads/WICKET-6055-non-blocking-lazy [created] cfb75dd64


WICKET-6055 non-blocking lazy loading


Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/cfb75dd6
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/cfb75dd6
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/cfb75dd6

Branch: refs/heads/WICKET-6055-non-blocking-lazy
Commit: cfb75dd64d54972a9b604101ff840c7c5cf80d35
Parents: eb64b2a
Author: Sven Meier <svenme...@apache.org>
Authored: Fri Oct 20 14:25:15 2017 +0200
Committer: Sven Meier <svenme...@apache.org>
Committed: Fri Oct 20 14:25:15 2017 +0200

----------------------------------------------------------------------
 .../wicket/ajax/AbstractAjaxTimerBehavior.java  |  16 +-
 .../examples/ajax/builtin/LazyLoadingPage.html  |  21 +-
 .../examples/ajax/builtin/LazyLoadingPage.java  | 137 ++++++++--
 .../ajax/markup/html/AjaxLazyLoadPanel.java     | 258 ++++++++++++-------
 .../markup/html/AjaxLazyLoadPanelTester.java    |  10 +-
 .../html/AjaxLazyLoadPanelTesterTest.java       |   2 +-
 .../org/apache/wicket/util/value/LongValue.java |  21 ++
 7 files changed, 331 insertions(+), 134 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/cfb75dd6/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractAjaxTimerBehavior.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractAjaxTimerBehavior.java
 
b/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractAjaxTimerBehavior.java
index 0c9a276..10dbb9b 100644
--- 
a/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractAjaxTimerBehavior.java
+++ 
b/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractAjaxTimerBehavior.java
@@ -112,6 +112,8 @@ public abstract class AbstractAjaxTimerBehavior extends 
AbstractDefaultAjaxBehav
        @Override
        protected final void respond(final AjaxRequestTarget target)
        {
+               Component component = getComponent();
+               
                if (shouldTrigger())
                {
                        onTimer(target);
@@ -124,7 +126,7 @@ public abstract class AbstractAjaxTimerBehavior extends 
AbstractDefaultAjaxBehav
                        }
                }
 
-               clearTimeout(target.getHeaderResponse());
+               clearTimeout(component, target.getHeaderResponse());
        }
 
        /**
@@ -181,9 +183,9 @@ public abstract class AbstractAjaxTimerBehavior extends 
AbstractDefaultAjaxBehav
                
headerResponse.render(OnLoadHeaderItem.forScript(getJsTimeoutCall(updateInterval)));
        }
 
-       private void clearTimeout(IHeaderResponse headerResponse)
+       private void clearTimeout(Component component, IHeaderResponse 
headerResponse)
        {
-               
headerResponse.render(OnLoadHeaderItem.forScript("Wicket.Timer.clear('" + 
getComponent().getMarkupId() + "');"));
+               
headerResponse.render(OnLoadHeaderItem.forScript("Wicket.Timer.clear('" + 
component.getMarkupId() + "');"));
        }
 
        /**
@@ -200,7 +202,7 @@ public abstract class AbstractAjaxTimerBehavior extends 
AbstractDefaultAjaxBehav
 
                        if (target != null)
                        {
-                               clearTimeout(target.getHeaderResponse());
+                               clearTimeout(getComponent(), 
target.getHeaderResponse());
                        }
                }
        }
@@ -208,13 +210,15 @@ public abstract class AbstractAjaxTimerBehavior extends 
AbstractDefaultAjaxBehav
        @Override
        public void onRemove(Component component)
        {
-               
component.getRequestCycle().find(IPartialPageRequestHandler.class).ifPresent(target
 -> clearTimeout(target.getHeaderResponse()));
+               
component.getRequestCycle().find(IPartialPageRequestHandler.class).ifPresent(target
 -> clearTimeout(component, target.getHeaderResponse()));
        }
 
        @Override
        protected void onUnbind()
        {
-               
getComponent().getRequestCycle().find(IPartialPageRequestHandler.class).ifPresent(target
 -> clearTimeout(target.getHeaderResponse()));
+               Component component = getComponent();
+               
+               
component.getRequestCycle().find(IPartialPageRequestHandler.class).ifPresent(target
 -> clearTimeout(component, target.getHeaderResponse()));
        }
 
        /**

http://git-wip-us.apache.org/repos/asf/wicket/blob/cfb75dd6/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/LazyLoadingPage.html
----------------------------------------------------------------------
diff --git 
a/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/LazyLoadingPage.html
 
b/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/LazyLoadingPage.html
index 821833d..576b194 100644
--- 
a/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/LazyLoadingPage.html
+++ 
b/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/LazyLoadingPage.html
@@ -1,12 +1,27 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 <wicket:extend xmlns:wicket="http://wicket.apache.org";>
 
+<p>
 This example demonstrates the AjaxLazyLoadPanel
 It will lazy load a panel after the page is first fully rendered.
 So panels that can take a while too create can be lazy created
 by an ajax call after the page is rendered.
-  
-<br/><br/>
+</p>
+
+<div wicket:id="nonblocking">
+       <h2>Non-blocking lazy panels</h2>
+
+       <p><a href="#" wicket:id="start">Start non-blocking panels</a> (<a 
href="#" wicket:id="startAjax">via Ajax</a>)</p>
+
+       <div wicket:id="repeater"></div>
+</div>
+
+<div wicket:id="blocking">
+       <h2>Blocking lazy panels</h2>
+       
+       <p><a href="#" wicket:id="start">Start blocking panels</a> (<a href="#" 
wicket:id="startAjax">via Ajax</a>)</p>
+
+       <div wicket:id="repeater"></div>
+</div>
 
-<div wicket:id="lazy"></div>
 </wicket:extend>

http://git-wip-us.apache.org/repos/asf/wicket/blob/cfb75dd6/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/LazyLoadingPage.java
----------------------------------------------------------------------
diff --git 
a/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/LazyLoadingPage.java
 
b/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/LazyLoadingPage.java
index 23b4403..ddf1de6 100644
--- 
a/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/LazyLoadingPage.java
+++ 
b/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/LazyLoadingPage.java
@@ -16,38 +16,139 @@
  */
 package org.apache.wicket.examples.ajax.builtin;
 
-import org.apache.wicket.Component;
+import java.util.Random;
+
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
 import org.apache.wicket.extensions.ajax.markup.html.AjaxLazyLoadPanel;
+import org.apache.wicket.markup.html.WebMarkupContainer;
 import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.repeater.RepeatingView;
+import org.apache.wicket.util.time.Duration;
 
-/**
- * @author jcompagner
- */
+@SuppressWarnings({ "javadoc", "serial" })
 public class LazyLoadingPage extends BasePage
 {
-       /**
-        * Construct.
-        */
+       private Random r = new Random();
+       private WebMarkupContainer nonblocking;
+       private WebMarkupContainer blocking;
+       private RepeatingView blockingRepeater;
+       private RepeatingView nonBlockingRepeater;
+
        public LazyLoadingPage()
        {
-               add(new AjaxLazyLoadPanel("lazy")
+               nonblocking = new WebMarkupContainer("nonblocking");
+               nonblocking.setOutputMarkupId(true);
+               add(nonblocking);
+               
+               nonblocking.add(new Link<Void>("start")
+               {
+                       @Override
+                       public void onClick()
+                       {
+                               addNonBlockingPanels();
+                       }
+               });
+               nonblocking.add(new AjaxLink<Void>("startAjax")
+               {
+                       @Override
+                       public void onClick(AjaxRequestTarget target)
+                       {
+                               addNonBlockingPanels();
+                       }
+               });
+               
+               nonBlockingRepeater = new RepeatingView("repeater");
+               nonblocking.add(nonBlockingRepeater);
+               
+               blocking = new WebMarkupContainer("blocking");
+               blocking.setOutputMarkupId(true);
+               add(blocking);
+               
+               blocking.add(new Link<Void>("start")
                {
-
                        @Override
-                       public Component getLazyLoadComponent(String id)
+                       public void onClick()
                        {
-                               // sleep for 5 seconds to show the behavior
-                               try
+                               addBlockingPanels();
+                       }
+               });
+               blocking.add(new AjaxLink<Void>("startAjax")
+               {
+                       @Override
+                       public void onClick(AjaxRequestTarget target)
+                       {
+                               addBlockingPanels();
+                       }
+               });
+
+               blockingRepeater = new RepeatingView("repeater");
+               blocking.add(blockingRepeater);
+       }
+
+       private void addNonBlockingPanels()
+       {
+               nonBlockingRepeater.removeAll();
+
+               for (int i = 0; i < 10; i++)
+                       nonBlockingRepeater.add(new 
AjaxLazyLoadPanel<Label>(nonBlockingRepeater.newChildId())
+                       {
+                               private static final long serialVersionUID = 1L;
+
+                               private long startTime = 
System.currentTimeMillis();
+
+                               private int seconds = r.nextInt(10);
+
+                               @Override
+                               protected boolean isContentReady()
                                {
-                                       Thread.sleep(5000);
+                                       return 
Duration.milliseconds(System.currentTimeMillis() - startTime)
+                                               .seconds() > seconds;
                                }
-                               catch (InterruptedException e)
+                               
+                               @Override
+                               protected Duration getUpdateInterval()
                                {
-                                       throw new RuntimeException(e);
+                                       return Duration.milliseconds(seconds * 
1000 / 10);
                                }
-                               return new Label(id, "Lazy Loaded after 5 
seconds");
-                       }
 
-               });
+                               @Override
+                               public Label createContentComponent(String id)
+                               {
+                                       return new Label(id, "Lazy Loaded after 
" + seconds + " seconds");
+                               }
+                       });
+               
+               getRequestCycle().find(AjaxRequestTarget.class).ifPresent(t -> 
t.add(nonblocking));
+       }
+
+       private void addBlockingPanels()
+       {
+               blockingRepeater.removeAll();
+
+               for (int i = 0; i < 5; i++)
+                       blockingRepeater.add(new 
AjaxLazyLoadPanel<Label>(blockingRepeater.newChildId())
+                       {
+                               private static final long serialVersionUID = 1L;
+
+                               private int seconds = r.nextInt(5);
+
+                               @Override
+                               public Label createContentComponent(String 
markupId)
+                               {
+                                       try
+                                       {
+                                               Thread.sleep(seconds * 1000);
+                                       }
+                                       catch (InterruptedException e)
+                                       {
+                                       }
+                                       return new Label(markupId,
+                                               "Lazy loaded after blocking the 
Wicket thread for " + seconds + " seconds");
+                               }
+                       });
+               
+               getRequestCycle().find(AjaxRequestTarget.class).ifPresent(t -> 
t.add(blocking));
        }
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/cfb75dd6/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxLazyLoadPanel.java
----------------------------------------------------------------------
diff --git 
a/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxLazyLoadPanel.java
 
b/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxLazyLoadPanel.java
index ce473ad..01cef17 100644
--- 
a/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxLazyLoadPanel.java
+++ 
b/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxLazyLoadPanel.java
@@ -16,42 +16,48 @@
  */
 package org.apache.wicket.extensions.ajax.markup.html;
 
+import java.util.List;
+import java.util.Optional;
+
 import org.apache.wicket.Component;
+import org.apache.wicket.ajax.AbstractAjaxTimerBehavior;
 import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
 import org.apache.wicket.ajax.AjaxRequestTarget;
-import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
-import org.apache.wicket.markup.head.IHeaderResponse;
-import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
 import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.request.IRequestHandler;
 import org.apache.wicket.request.cycle.RequestCycle;
 import 
org.apache.wicket.request.handler.resource.ResourceReferenceRequestHandler;
+import org.apache.wicket.util.time.Duration;
+import org.apache.wicket.util.visit.IVisit;
+import org.apache.wicket.util.visit.IVisitor;
 
 /**
- * A panel where you can lazy load another panel. This can be used if you have 
a panel/component
- * that is pretty heavy in creation and you first want to show the user the 
page and then replace
- * the panel when it is ready.
- * 
- * @author jcompagner
+ * A panel which load lazily a single content component. This can be used if 
you have a
+ * component that is pretty heavy in creation and you first want to show the 
user the page and
+ * then replace the panel when it is ready.
+ * <p>
+ * This panel will wait with adding the content until {@link 
#isContentReady()} returns
+ * {@code true}. It will poll using an AJAX timer behavior that is installed 
on the page. When the
+ * component is replaced, the timer stops. When you have multiple {@code 
AjaxLazyLoadPanel}s on the
+ * same page, only one timer is used and all panels piggyback on this single 
timer.
+ * <p> 
+ * This component will also replace the contents when a normal request comes 
through and the
+ * content is ready.
  * 
  * @since 1.3
  */
-public abstract class AjaxLazyLoadPanel extends Panel
+public abstract class AjaxLazyLoadPanel<T extends Component> extends Panel
 {
        private static final long serialVersionUID = 1L;
 
        /**
         * The component id which will be used to load the lazily loaded 
component.
         */
-       public static final String LAZY_LOAD_COMPONENT_ID = "content";
+       private static final String CONTENT_ID = "content";
 
-       // state,
-       // 0:add loading component
-       // 1:loading component added, waiting for ajax replace
-       // 2:ajax replacement completed
-       private byte state = 0;
+       private boolean loaded;
 
        /**
         * Constructor
@@ -74,121 +80,173 @@ public abstract class AjaxLazyLoadPanel extends Panel
                super(id, model);
 
                setOutputMarkupId(true);
-
-               add(new AbstractDefaultAjaxBehavior()
-               {
-                       private static final long serialVersionUID = 1L;
-
-                       @Override
-                       protected void respond(final AjaxRequestTarget target)
-                       {
-                               if (state < 2)
-                               {
-                                       Component component = 
getLazyLoadComponent(LAZY_LOAD_COMPONENT_ID);
-                                       
AjaxLazyLoadPanel.this.replace(component);
-                                       setState((byte) 2);
-                                       
AjaxLazyLoadPanel.this.onComponentLoaded(component, target);
-                               }
-                               target.add(AjaxLazyLoadPanel.this);
-
-                       }
-
-                       @Override
-                       protected void 
updateAjaxAttributes(AjaxRequestAttributes attributes)
-                       {
-                               super.updateAjaxAttributes(attributes);
-                               
AjaxLazyLoadPanel.this.updateAjaxAttributes(attributes);
-                       }
-
-                       @Override
-                       public void renderHead(final Component component, final 
IHeaderResponse response)
-                       {
-                               super.renderHead(component, response);
-                               if (state < 2)
-                               {
-                                       CharSequence js = 
getCallbackScript(component);
-                                       handleCallbackScript(response, js, 
component);
-                               }
-                       }
-               });
-       }
-
-       protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
-       {
        }
 
        /**
-        * Allows subclasses to change the callback script if needed.
+        * Determines that the content we're waiting for is ready, typically 
used in polling background
+        * threads for their result. Override this to implement your own check.
+        * <p>
+        * This default implementation returns {@code true}, i.e. assuming the 
content is ready immediately.
         * 
-        * @param response
-        *      the current response that writes to the header
-        * @param callbackScript
-        *      the JavaScript to write in the header
-        * @param component
-        *      the component which produced the callback script
-        */
-       protected void handleCallbackScript(final IHeaderResponse response,
-               final CharSequence callbackScript, final Component component)
-       {
-               response.render(OnDomReadyHeaderItem.forScript(callbackScript));
-       }
-
-       /**
-        * @see org.apache.wicket.Component#onBeforeRender()
+        * @return whether the actual content is ready
         */
-       @Override
-       protected void onBeforeRender()
+       protected boolean isContentReady()
        {
-               if (state == 0)
-               {
-                       add(getLoadingComponent(LAZY_LOAD_COMPONENT_ID));
-                       setState((byte)1);
-               }
-               super.onBeforeRender();
+               return true;
        }
 
        /**
+        * Create a loading component shown instead of the actual content until 
it is {@link #isContentReady()}.
         * 
-        * @param state
+        * @param markupId
+        *            The components markupid.
+        * @return The component to show while the real content isn't ready yet
         */
-       private void setState(final byte state)
+       protected Component createLoadingComponent(final String markupId)
        {
-               this.state = state;
-               getPage().dirty();
+               IRequestHandler handler = new ResourceReferenceRequestHandler(
+                       AbstractDefaultAjaxBehavior.INDICATOR);
+               return new Label(markupId,
+                       "<img alt=\"Loading...\" src=\"" + 
RequestCycle.get().urlFor(handler) + "\"/>")
+                               .setEscapeModelStrings(false);
        }
 
        /**
+        * Factory method for creating the lazily loaded content that replaces 
the loading component after
+        * {@link #isContentReady()} returns {@code true}. You may call 
setRenderBodyOnly(true)
+        * on this component if you need the body only.
         * 
         * @param markupId
         *            The components markupid.
-        * @return The component that must be lazy created. You may call 
setRenderBodyOnly(true) on this
-        *         component if you need the body only.
+        * @return the content to show after {@link #isContentReady()}
         */
-       public abstract Component getLazyLoadComponent(String markupId);
+       protected abstract T createContentComponent(String markupId);
 
        /**
-        * Called when the placeholder component is replaced with the lazy 
loaded one.
+        * Called after the loading component was replaced with the lazy loaded 
content.
+        * <p>
+        * This default implementation does nothing.
         *
         * @param component
-        *      The lazy loaded component
+        *            The lazy loaded content
         * @param target
-        *      The Ajax request handler
+        *            optional Ajax request handler
         */
-       protected void onComponentLoaded(Component component, AjaxRequestTarget 
target)
+       protected void onContentLoaded(T component, Optional<AjaxRequestTarget> 
target)
        {
        }
 
+       @Override
+       protected void onInitialize()
+       {
+               super.onInitialize();
+
+               AjaxRequestTarget target = 
getRequestCycle().find(AjaxRequestTarget.class).orElse(null);
+               
+               AjaxLazyLoadTimer timer;
+               // when the timer is not yet installed add it
+               List<AjaxLazyLoadTimer> behaviors = 
getPage().getBehaviors(AjaxLazyLoadTimer.class);
+               if (behaviors.isEmpty()) {
+                       timer = new AjaxLazyLoadTimer();
+                       getPage().add(timer);
+                       if (target != null) {
+                               // the timer will not be rendered, so stop it 
first
+                               // and restart it immediately on the Ajax 
request
+                               timer.stop(null);
+                               timer.restart(target);
+                       }
+               }
+       }
+       
+       @Override
+       protected void onConfigure()
+       {
+               super.onConfigure();
+
+               if (get(CONTENT_ID) == null) {
+                       add(createLoadingComponent(CONTENT_ID));
+               } else {
+                       isLoaded();
+               }
+       }
+
        /**
-        * @param markupId
-        *            The components markupid.
-        * @return The component to show while the real component is being 
created.
+        * Get the preferred interval for updates.
+        * <p>
+        * Since all LazyLoadingPanels on a page share the same Ajax timer, its 
update interval
+        * is derived from the minimum of all panel's update intervals.
+        * 
+        * @return update interval
         */
-       public Component getLoadingComponent(final String markupId)
-       {
-               IRequestHandler handler = new ResourceReferenceRequestHandler(
-                       AbstractDefaultAjaxBehavior.INDICATOR);
-               return new Label(markupId, "<img alt=\"Loading...\" src=\"" +
-                       RequestCycle.get().urlFor(handler) + 
"\"/>").setEscapeModelStrings(false);
+       protected Duration getUpdateInterval() {
+               return Duration.seconds(1);
        }
 
+       private boolean isLoaded() {
+               if (loaded == false)
+               {
+                       if (isContentReady())
+                       {
+                               loaded = true;
+
+                               // create the lazy load component
+                               T content = createContentComponent(CONTENT_ID);
+
+                               // replace the spinner with the new component
+                               AjaxLazyLoadPanel.this.replace(content);
+
+                               Optional<AjaxRequestTarget> target = 
getRequestCycle().find(AjaxRequestTarget.class);
+
+                               // notify our subclasses of the updated 
component
+                               onContentLoaded(content, target);
+
+                               // repaint our selves if there's an AJAX 
request in play, otherwise let the page
+                               // redraw itself
+                               target.ifPresent(t -> 
t.add(AjaxLazyLoadPanel.this));
+                       }
+               }
+               
+               return loaded;
+       }
+
+       /**
+        * The AJAX timer for updating the AjaxLazyLoadPanel. Is designed to be 
a page-local singleton
+        * running as long as LazyLoadPanels are still loading.
+        * 
+        * @see AjaxLazyLoadPanel#isLoaded()
+        */
+       private static class AjaxLazyLoadTimer extends AbstractAjaxTimerBehavior
+       {
+               private static final long serialVersionUID = 1L;
+
+               public AjaxLazyLoadTimer()
+               {
+                       super(Duration.ONE_SECOND);
+               }
+
+               @Override
+               protected void onTimer(AjaxRequestTarget target)
+               {
+                       setUpdateInterval(Duration.MAXIMUM);
+                       
+                       
getComponent().getPage().visitChildren(AjaxLazyLoadPanel.class, new 
IVisitor<AjaxLazyLoadPanel<?>, Void>()
+                       {
+                               @Override
+                               public void component(AjaxLazyLoadPanel<?> 
panel, IVisit<Void> visit)
+                               {
+                                       if (panel.isLoaded() == false) {
+                                               
setUpdateInterval(Duration.min(getUpdateInterval(), panel.getUpdateInterval()));
+                                       }                                       
        
+                               }
+                       });
+
+                       // all panels have completed their replacements, we can 
stop the timer
+                       if (Duration.MAXIMUM.equals(getUpdateInterval()))
+                       {
+                               stop(target);
+                               
+                               getComponent().remove(this);
+                       }
+               }
+       }
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/cfb75dd6/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxLazyLoadPanelTester.java
----------------------------------------------------------------------
diff --git 
a/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxLazyLoadPanelTester.java
 
b/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxLazyLoadPanelTester.java
index a141108..81f0224 100644
--- 
a/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxLazyLoadPanelTester.java
+++ 
b/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxLazyLoadPanelTester.java
@@ -19,9 +19,9 @@ package org.apache.wicket.extensions.ajax.markup.html;
 import java.util.List;
 
 import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.ajax.AbstractAjaxTimerBehavior;
 import org.apache.wicket.ajax.AjaxSelfUpdatingTimerBehavior;
 import org.apache.wicket.behavior.AbstractAjaxBehavior;
-import org.apache.wicket.behavior.Behavior;
 import org.apache.wicket.util.tester.BaseWicketTester;
 import org.apache.wicket.util.visit.IVisit;
 import org.apache.wicket.util.visit.IVisitor;
@@ -35,7 +35,6 @@ import org.slf4j.LoggerFactory;
  */
 public class AjaxLazyLoadPanelTester
 {
-
        private static final Logger logger = 
LoggerFactory.getLogger(AjaxLazyLoadPanelTester.class);
 
        /**
@@ -59,12 +58,13 @@ public class AjaxLazyLoadPanelTester
                        {
                                // get the AbstractAjaxBehaviour which is 
responsible for
                                // getting the contents of the lazy panel
-                               List<AbstractAjaxBehavior> behaviors = 
component.getBehaviors(AbstractAjaxBehavior.class);
+                               List<AbstractAjaxTimerBehavior> behaviors = 
component.getPage()
+                                       
.getBehaviors(AbstractAjaxTimerBehavior.class);
                                if (behaviors.size() == 0)
                                {
                                        logger.warn("AjaxLazyLoadPanel child 
found, but no attached AbstractAjaxBehaviors found. A curious situation...");
                                }
-                               for (Behavior b : behaviors)
+                               for (AbstractAjaxTimerBehavior b : behaviors)
                                {
                                        if (!(b instanceof 
AjaxSelfUpdatingTimerBehavior))
                                        {
@@ -78,6 +78,4 @@ public class AjaxLazyLoadPanelTester
                        }
                });
        }
-
-
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/cfb75dd6/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/AjaxLazyLoadPanelTesterTest.java
----------------------------------------------------------------------
diff --git 
a/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/AjaxLazyLoadPanelTesterTest.java
 
b/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/AjaxLazyLoadPanelTesterTest.java
index 5ee746a..5cfa13a 100644
--- 
a/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/AjaxLazyLoadPanelTesterTest.java
+++ 
b/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/AjaxLazyLoadPanelTesterTest.java
@@ -43,7 +43,7 @@ public class AjaxLazyLoadPanelTesterTest extends 
WicketTestCase
                        private static final long serialVersionUID = 1L;
 
                        @Override
-                       public Component getLazyLoadComponent(final String 
markupId)
+                       public Component createContentComponent(final String 
markupId)
                        {
                                return new Label(markupId, "lazy panel 
test").setRenderBodyOnly(true);
                        }

http://git-wip-us.apache.org/repos/asf/wicket/blob/cfb75dd6/wicket-util/src/main/java/org/apache/wicket/util/value/LongValue.java
----------------------------------------------------------------------
diff --git 
a/wicket-util/src/main/java/org/apache/wicket/util/value/LongValue.java 
b/wicket-util/src/main/java/org/apache/wicket/util/value/LongValue.java
index 8c96060..3e5e4bc 100755
--- a/wicket-util/src/main/java/org/apache/wicket/util/value/LongValue.java
+++ b/wicket-util/src/main/java/org/apache/wicket/util/value/LongValue.java
@@ -218,6 +218,27 @@ public class LongValue implements Comparable<LongValue>, 
Serializable
        }
 
        /**
+        * Returns the min of the two long values.
+        * 
+        * @param <T>
+        * @param lhs
+        * @param rhs
+        * @throws IllegalArgumentException
+        *             if either argument is {@code null}
+        * @return min value
+        */
+       public static <T extends LongValue> T min(final T lhs, final T rhs)
+       {
+               Args.notNull(lhs, "lhs");
+               Args.notNull(rhs, "rhs");
+               if (lhs.compareTo(rhs) < 0)
+               {
+                       return lhs;
+               }
+               return rhs;
+       }
+
+       /**
         * Returns the max of the two long values.
         * 
         * @param <T>

Reply via email to