You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by sv...@apache.org on 2017/11/19 18:04:29 UTC
wicket git commit: WICKET-6055 non-blocking lazy loading
Repository: wicket
Updated Branches:
refs/heads/master b230793ba -> 11877422b
WICKET-6055 non-blocking lazy loading
this closes #151 and closes #240
Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/11877422
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/11877422
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/11877422
Branch: refs/heads/master
Commit: 11877422bc2f5a934d8bc9c3080ffc108e4d4314
Parents: b230793
Author: Sven Meier <sv...@apache.org>
Authored: Fri Oct 20 14:25:15 2017 +0200
Committer: Sven Meier <sv...@apache.org>
Committed: Sun Nov 19 19:01:11 2017 +0100
----------------------------------------------------------------------
.../wicket/ajax/AbstractAjaxTimerBehavior.java | 18 +-
.../examples/ajax/builtin/LazyLoadingPage.html | 21 +-
.../examples/ajax/builtin/LazyLoadingPage.java | 137 +++++++--
.../ajax/markup/html/AjaxLazyLoadPanel.java | 305 +++++++++++++------
.../markup/html/AjaxLazyLoadPanelTester.java | 93 +++---
.../html/AjaxLazyLoadPanelTesterTest.java | 4 +-
.../org/apache/wicket/util/value/LongValue.java | 21 ++
7 files changed, 437 insertions(+), 162 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/wicket/blob/11877422/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..7fd3606 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,10 @@ public abstract class AbstractAjaxTimerBehavior extends AbstractDefaultAjaxBehav
@Override
protected final void respond(final AjaxRequestTarget target)
{
+ // onTimer might remove this behavior, so keep the component
+ // so the timeout can be cleared later on
+ Component component = getComponent();
+
if (shouldTrigger())
{
onTimer(target);
@@ -124,7 +128,7 @@ public abstract class AbstractAjaxTimerBehavior extends AbstractDefaultAjaxBehav
}
}
- clearTimeout(target.getHeaderResponse());
+ clearTimeout(component, target.getHeaderResponse());
}
/**
@@ -181,9 +185,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 +204,7 @@ public abstract class AbstractAjaxTimerBehavior extends AbstractDefaultAjaxBehav
if (target != null)
{
- clearTimeout(target.getHeaderResponse());
+ clearTimeout(getComponent(), target.getHeaderResponse());
}
}
}
@@ -208,13 +212,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/11877422/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/11877422/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..ba89084 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 getLazyLoadComponent(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 getLazyLoadComponent(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/11877422/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..783b64d 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,56 @@
*/
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 {@link AbstractAjaxTimerBehavior} 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";
+
+ /**
+ * @deprecated will be removed in Wicket 9
+ */
+ @Deprecated
+ public static final String LAZY_LOAD_COMPONENT_ID = CONTENT_ID;
- // 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 +88,228 @@ 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)
+ /**
+ * 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.
+ *
+ * @return whether the actual content is ready
+ */
+ protected boolean isContentReady()
{
+ return true;
}
/**
- * Allows subclasses to change the callback script if needed.
- *
- * @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)
+ * @deprecated this method is not called, and will be removed in Wicket 9
+ */
+ protected final void updateAjaxAttributes(AjaxRequestAttributes attributes)
{
- response.render(OnDomReadyHeaderItem.forScript(callbackScript));
}
/**
- * @see org.apache.wicket.Component#onBeforeRender()
+ * @deprecated this method is not called, and will be removed in Wicket 9
*/
- @Override
- protected void onBeforeRender()
+ @Deprecated
+ protected final void handleCallbackScript(final IHeaderResponse response,
+ final CharSequence callbackScript, final Component component)
{
- if (state == 0)
- {
- add(getLoadingComponent(LAZY_LOAD_COMPONENT_ID));
- setState((byte)1);
- }
- super.onBeforeRender();
+
}
/**
+ * 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)
+ public Component getLoadingComponent(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);
+ public abstract T getLazyLoadComponent(String markupId);
/**
- * Called when the placeholder component is replaced with the lazy loaded one.
+ * @deprecated override {@link #onContentLoaded(Component, Optional)} instead - will be removed in Wicket 9
+ */
+ @Deprecated
+ protected final void onComponentLoaded(Component component, AjaxRequestTarget target)
+ {
+ }
+
+ /**
+ * Called after the loading component was replaced with the lazy loaded content.
+ * <p>
+ * This default implementation does nothing.
*
- * @param component
- * The lazy loaded component
+ * @param content
+ * 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 content, Optional<AjaxRequestTarget> target)
{
}
/**
- * @param markupId
- * The components markupid.
- * @return The component to show while the real component is being created.
+ * Installs a page-global timer if not already present.
*/
- public Component getLoadingComponent(final String markupId)
+ @Override
+ protected void onInitialize()
{
- IRequestHandler handler = new ResourceReferenceRequestHandler(
- AbstractDefaultAjaxBehavior.INDICATOR);
- return new Label(markupId, "<img alt=\"Loading...\" src=\"" +
- RequestCycle.get().urlFor(handler) + "\"/>").setEscapeModelStrings(false);
+ super.onInitialize();
+
+ initTimer();
}
+ /**
+ * Initialize a timer - default implementation installs an {@link AbstractAjaxTimerBehavior} on the page,
+ * if it is not already present.
+ */
+ protected void initTimer()
+ {
+ // when the timer is not yet installed add it
+ List<AjaxLazyLoadTimer> behaviors = getPage().getBehaviors(AjaxLazyLoadTimer.class);
+ if (behaviors.isEmpty()) {
+ AbstractAjaxTimerBehavior timer = new AjaxLazyLoadTimer();
+ getPage().add(timer);
+
+ getRequestCycle().find(AjaxRequestTarget.class).ifPresent(target -> {
+ // 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(getLoadingComponent(CONTENT_ID));
+ } else {
+ isLoaded();
+ }
+ }
+
+ /**
+ * 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, must not be {@value null}
+ */
+ protected Duration getUpdateInterval() {
+ return Duration.seconds(1);
+ }
+
+ /**
+ * Check whether the content is loaded.
+ * <p>
+ * If not loaded already and the content is ready, replaces the lazy loading component with
+ * the lazily loaded content.
+ *
+ * @return {@code true} if content is loaded
+ *
+ * @see #isContentReady()
+ */
+ protected final boolean isLoaded() {
+ if (loaded == false)
+ {
+ if (isContentReady())
+ {
+ loaded = true;
+
+ // create the lazy load component
+ T content = getLazyLoadComponent(CONTENT_ID);
+
+ // replace the loading component 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()
+ */
+ static class AjaxLazyLoadTimer extends AbstractAjaxTimerBehavior
+ {
+ private static final long serialVersionUID = 1L;
+
+ public AjaxLazyLoadTimer()
+ {
+ super(Duration.ONE_SECOND);
+ }
+
+ @Override
+ protected void onTimer(AjaxRequestTarget target)
+ {
+ load(target);
+ }
+
+ public void load(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) {
+ Duration updateInterval = panel.getUpdateInterval();
+ if (getUpdateInterval() == null) {
+ throw new IllegalArgumentException("update interval must not ben null");
+ }
+
+ setUpdateInterval(Duration.min(getUpdateInterval(), updateInterval));
+ }
+ }
+ });
+
+ // 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/11877422/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..13a65b9 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
@@ -18,13 +18,10 @@ package org.apache.wicket.extensions.ajax.markup.html;
import java.util.List;
-import org.apache.wicket.MarkupContainer;
-import org.apache.wicket.ajax.AjaxSelfUpdatingTimerBehavior;
-import org.apache.wicket.behavior.AbstractAjaxBehavior;
-import org.apache.wicket.behavior.Behavior;
+import org.apache.wicket.Page;
+import org.apache.wicket.extensions.ajax.markup.html.AjaxLazyLoadPanel.AjaxLazyLoadTimer;
import org.apache.wicket.util.tester.BaseWicketTester;
-import org.apache.wicket.util.visit.IVisit;
-import org.apache.wicket.util.visit.IVisitor;
+import org.apache.wicket.util.time.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -35,49 +32,63 @@ import org.slf4j.LoggerFactory;
*/
public class AjaxLazyLoadPanelTester
{
-
private static final Logger logger = LoggerFactory.getLogger(AjaxLazyLoadPanelTester.class);
/**
- * Searches the {@link MarkupContainer}, looking for and triggering {@link AjaxLazyLoadPanel}s
- * to fetch their contents. Very useful for testing pages / panels that use
- * {@link AjaxLazyLoadPanel}s.
+ * Triggers loading of all {@link AjaxLazyLoadPanel}'s content in the last rendered page.
*
* @param wt
- * the {@link BaseWicketTester} to execute the behaviour (
- * {@link BaseWicketTester#executeBehavior} ).
- * @param container
- * contains the {@link AjaxLazyLoadPanel} to trigger
+ * the tester
*/
- public static void executeAjaxLazyLoadPanel(final BaseWicketTester wt,
- final MarkupContainer container)
+ public static void executeAjaxLazyLoadPanel(final BaseWicketTester wt)
{
- container.visitChildren(AjaxLazyLoadPanel.class, new IVisitor<AjaxLazyLoadPanel, Void>()
- {
- @Override
- public void component(final AjaxLazyLoadPanel component, final IVisit<Void> visit)
- {
- // get the AbstractAjaxBehaviour which is responsible for
- // getting the contents of the lazy panel
- List<AbstractAjaxBehavior> behaviors = component.getBehaviors(AbstractAjaxBehavior.class);
- if (behaviors.size() == 0)
- {
- logger.warn("AjaxLazyLoadPanel child found, but no attached AbstractAjaxBehaviors found. A curious situation...");
- }
- for (Behavior b : behaviors)
- {
- if (!(b instanceof AjaxSelfUpdatingTimerBehavior))
- {
- // tell wicket tester to execute it :)
- logger.debug("Triggering lazy panel: " + component.getClassRelativePath());
- AbstractAjaxBehavior abstractAjaxBehaviour = (AbstractAjaxBehavior)b;
- wt.executeBehavior(abstractAjaxBehaviour);
- }
- }
- // continue looking for other AjazLazyLoadPanel
- }
- });
+ executeAjaxLazyLoadPanel(wt, wt.getLastRenderedPage());
}
+ /**
+ * Triggers loading of all {@link AjaxLazyLoadPanel}'s content in a page.
+ *
+ * @param wt
+ * the tester
+ * @param page
+ * contains the {@link AjaxLazyLoadPanel}s to trigger
+ */
+ public static void executeAjaxLazyLoadPanel(final BaseWicketTester wt, final Page page)
+ {
+ // get the AbstractAjaxBehaviour which is responsible for
+ // getting the contents of the lazy panel
+ List<AjaxLazyLoadTimer> behaviors = page.getBehaviors(AjaxLazyLoadTimer.class);
+ if (behaviors.size() == 0)
+ {
+ logger.warn("No timer behavior for AjaxLazyLoadPanel found. A curious situation...");
+ }
+ else if (behaviors.size() > 1)
+ {
+ logger.warn(
+ "Multiple timer behavior for AjaxLazyLoadPanel found. A curious situation...");
+ }
+ wt.executeBehavior(behaviors.get(0));
+ }
+
+ /**
+ * Triggers loading of a single {@link AjaxLazyLoadPanel}.
+ *
+ * @param wt
+ * the tester
+ * @param panel
+ * the panel
+ * @return update duration or {@value null} of already loadedO
+ */
+ public static Duration loadAjaxLazyLoadPanel(final BaseWicketTester wt, final AjaxLazyLoadPanel<?> panel)
+ {
+ if (panel.isLoaded())
+ {
+ return null;
+ }
+ else
+ {
+ return panel.getUpdateInterval();
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/wicket/blob/11877422/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..4ea40b8 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
@@ -38,7 +38,7 @@ public class AjaxLazyLoadPanelTesterTest extends WicketTestCase
@Test
public void test()
{
- AjaxLazyLoadPanel panel = new AjaxLazyLoadPanel("panel")
+ AjaxLazyLoadPanel<Component> panel = new AjaxLazyLoadPanel<Component>("panel")
{
private static final long serialVersionUID = 1L;
@@ -52,7 +52,7 @@ public class AjaxLazyLoadPanelTesterTest extends WicketTestCase
tester.assertLabel(
"panel:content",
"<img alt=\"Loading...\" src=\"./resource/org.apache.wicket.ajax.AbstractDefaultAjaxBehavior/indicator.gif\"/>");
- AjaxLazyLoadPanelTester.executeAjaxLazyLoadPanel(tester, panel.getParent());
+ AjaxLazyLoadPanelTester.executeAjaxLazyLoadPanel(tester);
tester.debugComponentTrees();
tester.assertLabel("panel:content", "lazy panel test");
String doc = tester.getLastResponseAsString();
http://git-wip-us.apache.org/repos/asf/wicket/blob/11877422/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>