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/12/07 08:24:34 UTC

wicket git commit: render independently from web or tester

Repository: wicket
Updated Branches:
  refs/heads/sandbox/component-renderer [created] 6e6c273fd


render independently from web or tester


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

Branch: refs/heads/sandbox/component-renderer
Commit: 6e6c273fd32325a447cc32c751d5ce0c083e7ed1
Parents: 693dad3
Author: Sven Meier <sv...@apache.org>
Authored: Thu Dec 7 09:24:12 2017 +0100
Committer: Sven Meier <sv...@apache.org>
Committed: Thu Dec 7 09:24:12 2017 +0100

----------------------------------------------------------------------
 .../core/util/string/ComponentRenderer.java     | 324 ++++++++++++++++++-
 .../ComponentRendererInstanceTest.java          |  52 +++
 2 files changed, 369 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/6e6c273f/wicket-core/src/main/java/org/apache/wicket/core/util/string/ComponentRenderer.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/core/util/string/ComponentRenderer.java b/wicket-core/src/main/java/org/apache/wicket/core/util/string/ComponentRenderer.java
index 0cf63bf..e971bc2 100644
--- a/wicket-core/src/main/java/org/apache/wicket/core/util/string/ComponentRenderer.java
+++ b/wicket-core/src/main/java/org/apache/wicket/core/util/string/ComponentRenderer.java
@@ -16,35 +16,341 @@
  */
 package org.apache.wicket.core.util.string;
 
+import java.io.Serializable;
+import java.util.List;
+import java.util.Set;
+
 import org.apache.wicket.Application;
 import org.apache.wicket.Component;
 import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.Page;
+import org.apache.wicket.RuntimeConfigurationType;
+import org.apache.wicket.Session;
 import org.apache.wicket.ThreadContext;
 import org.apache.wicket.core.request.handler.PageProvider;
 import org.apache.wicket.markup.IMarkupCacheKeyProvider;
 import org.apache.wicket.markup.IMarkupResourceStreamProvider;
 import org.apache.wicket.markup.MarkupNotFoundException;
 import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.mock.MockApplication;
+import org.apache.wicket.mock.MockWebRequest;
 import org.apache.wicket.protocol.http.BufferedWebResponse;
+import org.apache.wicket.protocol.http.WebApplication;
+import org.apache.wicket.protocol.http.mock.MockServletContext;
+import org.apache.wicket.request.Request;
 import org.apache.wicket.request.Response;
+import org.apache.wicket.request.Url;
 import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.http.WebRequest;
+import org.apache.wicket.serialize.ISerializer;
+import org.apache.wicket.session.ISessionStore;
 import org.apache.wicket.util.resource.IResourceStream;
 import org.apache.wicket.util.resource.StringResourceStream;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Supplier;
+
 /**
  * A helper class for rendering components and pages.
- *
- * <p><strong>Note</strong>: {@link #renderComponent(Component)} does <strong>not</strong>
- * support rendering {@link org.apache.wicket.markup.html.panel.Fragment} instances!</p>
+ * <p>
+ * With the static methods of this class components and pages can be rendered
+ * on a thread already processing an {@link Application}.
+ * <p>
+ * If you want to render independently from any web request processing (e.g. generating an email
+ * body on a worker thread), you can create an instance of this class.<br/>
+ * You may use an existing application, create a fresh one or just use the defaults of
+ * {@link #ComponentRenderer()} for a mocked application with sensible defaults.
+ * <p>
+ * Note: For performance instances can and should be reused, be sure to call {@link #destroy()}
+ * when they are no longer needed.
  */
 public class ComponentRenderer
 {
 	private static final Logger LOGGER = LoggerFactory.getLogger(ComponentRenderer.class);
 
+	private WebApplication application;
+
+	/**
+	 * A renderer using a default mocked application, which
+	 * <ul>
+	 * <li>never shares anything in a session</li>
+	 * <li>never serializes anything</li>
+	 * </ul>
+	 */
+	public ComponentRenderer()
+	{
+		this(new MockApplication()
+		{
+			@Override
+			public RuntimeConfigurationType getConfigurationType()
+			{
+				return RuntimeConfigurationType.DEPLOYMENT;
+			}
+
+			@Override
+			protected void init()
+			{
+				super.init();
+
+				setSessionStoreProvider(() -> new NeverSessionStore());
+				getFrameworkSettings().setSerializer(new NeverSerializer());
+			}
+		});
+	}
+
+	/**
+	 * A renderer using the given application.
+	 * <p>
+	 * If the application was not yet initialized - e.g. it is not reused from an already running web
+	 * container - it will be initialized.
+	 */
+	public ComponentRenderer(WebApplication application)
+	{
+		this.application = application;
+
+		if (application.getName() == null) {
+			// not yet initialized
+			
+			inThreadContext(new Runnable()
+			{
+				@Override
+				public void run()
+				{
+					application.setServletContext(new MockServletContext(application, null));
+					application.setName("ComponentRenderer[" + System.identityHashCode(ComponentRenderer.this) + "]");
+					application.initApplication();
+				}
+			});
+		}
+	}
+
+	/**
+	 * Destroy this renderer.
+	 */
+	public void destroy()
+	{
+		inThreadContext(new Runnable()
+		{
+			@Override
+			public void run()
+			{
+				application.internalDestroy();
+			}
+		});
+	}
+
+	/**
+	 * 
+	 * Collects the html generated by the rendering a component.
+	 * 
+	 * @param component
+	 *            supplier of the component
+	 * @return the html rendered by the panel
+	 */
+	public CharSequence renderComponent(final Supplier<Component> component)
+	{
+		return renderPage(new Supplier<Page>()
+		{
+			@Override
+			public Page get()
+			{
+				return new RenderPage(component.get());
+			}
+		});
+	}
+
+	/**
+	 * Collects the html generated by the rendered a component.
+	 *
+	 * @param page
+	 *            supplier of the page
+	 * @return the html rendered by the panel
+	 */
+	public CharSequence renderPage(final Supplier<? extends Page> page)
+	{
+		return inThreadContext(new Supplier<CharSequence>()
+		{
+			@Override
+			public CharSequence get()
+			{
+				WebRequest request = newWebRequest();
+
+				BufferedWebResponse response = new BufferedWebResponse(null);
+
+				RequestCycle cycle = application.createRequestCycle(request, response);
+
+				ThreadContext.setRequestCycle(cycle);
+
+				page.get().renderPage();
+
+				return response.getText();
+			}
+		});
+	}
+
+	/**
+	 * Run the given runnable inside a valid {@link ThreadContext}.
+	 * 
+	 * @param runnable
+	 *            runnable
+	 */
+	private void inThreadContext(Runnable runnable) {
+		inThreadContext(() -> {
+			runnable.run();
+			return null;
+		});
+	}
+	
+	/**
+	 * Get the result from the given supplier inside a valid {@link ThreadContext}.
+	 * 
+	 * @param supplier
+	 *            supplier
+	 * @return result of {@link Supplier#get()}
+	 */
+	private <T> T inThreadContext(Supplier<T> supplier)
+	{
+		ThreadContext oldContext = ThreadContext.detach();
+
+		try
+		{
+			ThreadContext.setApplication(application);
+
+			return supplier.get();
+		}
+		finally
+		{
+
+			ThreadContext.restore(oldContext);
+		}
+	}
+
+	/**
+	 * Create a new request, by default a {@link MockWebRequest}.
+	 */
+	protected WebRequest newWebRequest()
+	{
+		return new MockWebRequest(Url.parse("/"));
+	}
+
+	/**
+	 * Never serialize.
+	 */
+	private static final class NeverSerializer implements ISerializer
+	{
+		@Override
+		public byte[] serialize(Object object)
+		{
+			return null;
+		}
+
+		@Override
+		public Object deserialize(byte[] data)
+		{
+			return null;
+		}
+	}
+
+	/**
+	 * Never share anything.
+	 */
+	private static class NeverSessionStore implements ISessionStore
+	{
+
+		@Override
+		public Serializable getAttribute(Request request, String name)
+		{
+			return null;
+		}
+
+		@Override
+		public List<String> getAttributeNames(Request request)
+		{
+			return null;
+		}
+
+		@Override
+		public void setAttribute(Request request, String name, Serializable value)
+		{
+		}
+
+		@Override
+		public void removeAttribute(Request request, String name)
+		{
+		}
+
+		@Override
+		public void invalidate(Request request)
+		{
+		}
+
+		@Override
+		public String getSessionId(Request request, boolean create)
+		{
+			return null;
+		}
+
+		@Override
+		public Session lookup(Request request)
+		{
+			return null;
+		}
+
+		@Override
+		public void bind(Request request, Session newSession)
+		{
+		}
+
+		@Override
+		public void flushSession(Request request, Session session)
+		{
+		}
+
+		@Override
+		public void destroy()
+		{
+		}
+
+		@Override
+		public void registerUnboundListener(UnboundListener listener)
+		{
+		}
+
+		@Override
+		public void unregisterUnboundListener(UnboundListener listener)
+		{
+		}
+
+		@Override
+		public Set<UnboundListener> getUnboundListener()
+		{
+			return null;
+		}
+
+		@Override
+		public void registerBindListener(BindListener listener)
+		{
+		}
+
+		@Override
+		public void unregisterBindListener(BindListener listener)
+		{
+		}
+
+
+		@Override
+
+		public Set<BindListener> getBindListeners()
+		{
+			return null;
+		}
+	}
+	
 	/**
 	 * Collects the html generated by the rendering of a page.
+	 * <p>
+	 * Important note: Must be called on a thread already processing a {@link WebApplication}!
 	 *
 	 * @param pageProvider
 	 *            the provider of the page class/instance and its parameters
@@ -75,12 +381,16 @@ public class ComponentRenderer
 
 	/**
 	 * Collects the html generated by the rendering of a component.
-	 *
 	 * <p>
-	 * NOTE: this method is meant to render fresh component instances that are disposed after the
+	 * Important notes:
+	 * <ul>
+	 * <li>this method is meant to render fresh component instances that are disposed after the
 	 * html has been generate. To avoid unwanted side effects do not use it with components that 
-	 * are from an existing hierarchy.
-	 * </p>
+	 * are from an existing hierarchy.</li>
+	 * <li>does <strong>not</strong> support rendering
+	 * {@link org.apache.wicket.markup.html.panel.Fragment} instances</li>
+	 * <li>must be called on a thread already processing a {@link WebApplication}!</li>
+	 * </ul>
 	 *
 	 * @param component
 	 *            the component to render.

http://git-wip-us.apache.org/repos/asf/wicket/blob/6e6c273f/wicket-core/src/test/java/org/apache/wicket/core/util/string/componentrenderer/ComponentRendererInstanceTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/core/util/string/componentrenderer/ComponentRendererInstanceTest.java b/wicket-core/src/test/java/org/apache/wicket/core/util/string/componentrenderer/ComponentRendererInstanceTest.java
new file mode 100644
index 0000000..4aa6dfa
--- /dev/null
+++ b/wicket-core/src/test/java/org/apache/wicket/core/util/string/componentrenderer/ComponentRendererInstanceTest.java
@@ -0,0 +1,52 @@
+/*
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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
+ *
+ *      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.apache.wicket.core.util.string.componentrenderer;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.wicket.core.util.string.ComponentRenderer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests for {@link ComponentRenderer}
+ */
+public class ComponentRendererInstanceTest
+{
+	private ComponentRenderer renderer;
+
+	@Before
+	public void setup() {
+		renderer = new ComponentRenderer();
+	}
+	
+	@After
+	public void destroy() {
+		renderer.destroy();
+	}
+	
+	@Test
+	public void render()
+	{
+		CharSequence html = renderer.renderComponent(() -> new Label("id", "Hello renderer"));
+		
+		assertEquals("Hello renderer", html.toString());
+	}
+}
\ No newline at end of file


Re: wicket git commit: render independently from web or tester

Posted by Sven Meier <sv...@meiers.net>.
Wow, you're fast :P

Sven


Am 07.12.2017 um 09:29 schrieb Maxim Solodovnik:
> Hello Sven,
>
> Is this correct import?
> import com.google.common.base.Supplier;
>
> On Thu, Dec 7, 2017 at 3:24 PM,  <sv...@apache.org> wrote:
>> Repository: wicket
>> Updated Branches:
>>    refs/heads/sandbox/component-renderer [created] 6e6c273fd
>>
>>
>> render independently from web or tester
>>
>>
>> Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
>> Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/6e6c273f
>> Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/6e6c273f
>> Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/6e6c273f
>>
>> Branch: refs/heads/sandbox/component-renderer
>> Commit: 6e6c273fd32325a447cc32c751d5ce0c083e7ed1
>> Parents: 693dad3
>> Author: Sven Meier <sv...@apache.org>
>> Authored: Thu Dec 7 09:24:12 2017 +0100
>> Committer: Sven Meier <sv...@apache.org>
>> Committed: Thu Dec 7 09:24:12 2017 +0100
>>
>> ----------------------------------------------------------------------
>>   .../core/util/string/ComponentRenderer.java     | 324 ++++++++++++++++++-
>>   .../ComponentRendererInstanceTest.java          |  52 +++
>>   2 files changed, 369 insertions(+), 7 deletions(-)
>> ----------------------------------------------------------------------
>>
>>
>> http://git-wip-us.apache.org/repos/asf/wicket/blob/6e6c273f/wicket-core/src/main/java/org/apache/wicket/core/util/string/ComponentRenderer.java
>> ----------------------------------------------------------------------
>> diff --git a/wicket-core/src/main/java/org/apache/wicket/core/util/string/ComponentRenderer.java b/wicket-core/src/main/java/org/apache/wicket/core/util/string/ComponentRenderer.java
>> index 0cf63bf..e971bc2 100644
>> --- a/wicket-core/src/main/java/org/apache/wicket/core/util/string/ComponentRenderer.java
>> +++ b/wicket-core/src/main/java/org/apache/wicket/core/util/string/ComponentRenderer.java
>> @@ -16,35 +16,341 @@
>>    */
>>   package org.apache.wicket.core.util.string;
>>
>> +import java.io.Serializable;
>> +import java.util.List;
>> +import java.util.Set;
>> +
>>   import org.apache.wicket.Application;
>>   import org.apache.wicket.Component;
>>   import org.apache.wicket.MarkupContainer;
>> +import org.apache.wicket.Page;
>> +import org.apache.wicket.RuntimeConfigurationType;
>> +import org.apache.wicket.Session;
>>   import org.apache.wicket.ThreadContext;
>>   import org.apache.wicket.core.request.handler.PageProvider;
>>   import org.apache.wicket.markup.IMarkupCacheKeyProvider;
>>   import org.apache.wicket.markup.IMarkupResourceStreamProvider;
>>   import org.apache.wicket.markup.MarkupNotFoundException;
>>   import org.apache.wicket.markup.html.WebPage;
>> +import org.apache.wicket.mock.MockApplication;
>> +import org.apache.wicket.mock.MockWebRequest;
>>   import org.apache.wicket.protocol.http.BufferedWebResponse;
>> +import org.apache.wicket.protocol.http.WebApplication;
>> +import org.apache.wicket.protocol.http.mock.MockServletContext;
>> +import org.apache.wicket.request.Request;
>>   import org.apache.wicket.request.Response;
>> +import org.apache.wicket.request.Url;
>>   import org.apache.wicket.request.cycle.RequestCycle;
>> +import org.apache.wicket.request.http.WebRequest;
>> +import org.apache.wicket.serialize.ISerializer;
>> +import org.apache.wicket.session.ISessionStore;
>>   import org.apache.wicket.util.resource.IResourceStream;
>>   import org.apache.wicket.util.resource.StringResourceStream;
>>   import org.slf4j.Logger;
>>   import org.slf4j.LoggerFactory;
>>
>> +import com.google.common.base.Supplier;
>> +
>>   /**
>>    * A helper class for rendering components and pages.
>> - *
>> - * <p><strong>Note</strong>: {@link #renderComponent(Component)} does <strong>not</strong>
>> - * support rendering {@link org.apache.wicket.markup.html.panel.Fragment} instances!</p>
>> + * <p>
>> + * With the static methods of this class components and pages can be rendered
>> + * on a thread already processing an {@link Application}.
>> + * <p>
>> + * If you want to render independently from any web request processing (e.g. generating an email
>> + * body on a worker thread), you can create an instance of this class.<br/>
>> + * You may use an existing application, create a fresh one or just use the defaults of
>> + * {@link #ComponentRenderer()} for a mocked application with sensible defaults.
>> + * <p>
>> + * Note: For performance instances can and should be reused, be sure to call {@link #destroy()}
>> + * when they are no longer needed.
>>    */
>>   public class ComponentRenderer
>>   {
>>          private static final Logger LOGGER = LoggerFactory.getLogger(ComponentRenderer.class);
>>
>> +       private WebApplication application;
>> +
>> +       /**
>> +        * A renderer using a default mocked application, which
>> +        * <ul>
>> +        * <li>never shares anything in a session</li>
>> +        * <li>never serializes anything</li>
>> +        * </ul>
>> +        */
>> +       public ComponentRenderer()
>> +       {
>> +               this(new MockApplication()
>> +               {
>> +                       @Override
>> +                       public RuntimeConfigurationType getConfigurationType()
>> +                       {
>> +                               return RuntimeConfigurationType.DEPLOYMENT;
>> +                       }
>> +
>> +                       @Override
>> +                       protected void init()
>> +                       {
>> +                               super.init();
>> +
>> +                               setSessionStoreProvider(() -> new NeverSessionStore());
>> +                               getFrameworkSettings().setSerializer(new NeverSerializer());
>> +                       }
>> +               });
>> +       }
>> +
>> +       /**
>> +        * A renderer using the given application.
>> +        * <p>
>> +        * If the application was not yet initialized - e.g. it is not reused from an already running web
>> +        * container - it will be initialized.
>> +        */
>> +       public ComponentRenderer(WebApplication application)
>> +       {
>> +               this.application = application;
>> +
>> +               if (application.getName() == null) {
>> +                       // not yet initialized
>> +
>> +                       inThreadContext(new Runnable()
>> +                       {
>> +                               @Override
>> +                               public void run()
>> +                               {
>> +                                       application.setServletContext(new MockServletContext(application, null));
>> +                                       application.setName("ComponentRenderer[" + System.identityHashCode(ComponentRenderer.this) + "]");
>> +                                       application.initApplication();
>> +                               }
>> +                       });
>> +               }
>> +       }
>> +
>> +       /**
>> +        * Destroy this renderer.
>> +        */
>> +       public void destroy()
>> +       {
>> +               inThreadContext(new Runnable()
>> +               {
>> +                       @Override
>> +                       public void run()
>> +                       {
>> +                               application.internalDestroy();
>> +                       }
>> +               });
>> +       }
>> +
>> +       /**
>> +        *
>> +        * Collects the html generated by the rendering a component.
>> +        *
>> +        * @param component
>> +        *            supplier of the component
>> +        * @return the html rendered by the panel
>> +        */
>> +       public CharSequence renderComponent(final Supplier<Component> component)
>> +       {
>> +               return renderPage(new Supplier<Page>()
>> +               {
>> +                       @Override
>> +                       public Page get()
>> +                       {
>> +                               return new RenderPage(component.get());
>> +                       }
>> +               });
>> +       }
>> +
>> +       /**
>> +        * Collects the html generated by the rendered a component.
>> +        *
>> +        * @param page
>> +        *            supplier of the page
>> +        * @return the html rendered by the panel
>> +        */
>> +       public CharSequence renderPage(final Supplier<? extends Page> page)
>> +       {
>> +               return inThreadContext(new Supplier<CharSequence>()
>> +               {
>> +                       @Override
>> +                       public CharSequence get()
>> +                       {
>> +                               WebRequest request = newWebRequest();
>> +
>> +                               BufferedWebResponse response = new BufferedWebResponse(null);
>> +
>> +                               RequestCycle cycle = application.createRequestCycle(request, response);
>> +
>> +                               ThreadContext.setRequestCycle(cycle);
>> +
>> +                               page.get().renderPage();
>> +
>> +                               return response.getText();
>> +                       }
>> +               });
>> +       }
>> +
>> +       /**
>> +        * Run the given runnable inside a valid {@link ThreadContext}.
>> +        *
>> +        * @param runnable
>> +        *            runnable
>> +        */
>> +       private void inThreadContext(Runnable runnable) {
>> +               inThreadContext(() -> {
>> +                       runnable.run();
>> +                       return null;
>> +               });
>> +       }
>> +
>> +       /**
>> +        * Get the result from the given supplier inside a valid {@link ThreadContext}.
>> +        *
>> +        * @param supplier
>> +        *            supplier
>> +        * @return result of {@link Supplier#get()}
>> +        */
>> +       private <T> T inThreadContext(Supplier<T> supplier)
>> +       {
>> +               ThreadContext oldContext = ThreadContext.detach();
>> +
>> +               try
>> +               {
>> +                       ThreadContext.setApplication(application);
>> +
>> +                       return supplier.get();
>> +               }
>> +               finally
>> +               {
>> +
>> +                       ThreadContext.restore(oldContext);
>> +               }
>> +       }
>> +
>> +       /**
>> +        * Create a new request, by default a {@link MockWebRequest}.
>> +        */
>> +       protected WebRequest newWebRequest()
>> +       {
>> +               return new MockWebRequest(Url.parse("/"));
>> +       }
>> +
>> +       /**
>> +        * Never serialize.
>> +        */
>> +       private static final class NeverSerializer implements ISerializer
>> +       {
>> +               @Override
>> +               public byte[] serialize(Object object)
>> +               {
>> +                       return null;
>> +               }
>> +
>> +               @Override
>> +               public Object deserialize(byte[] data)
>> +               {
>> +                       return null;
>> +               }
>> +       }
>> +
>> +       /**
>> +        * Never share anything.
>> +        */
>> +       private static class NeverSessionStore implements ISessionStore
>> +       {
>> +
>> +               @Override
>> +               public Serializable getAttribute(Request request, String name)
>> +               {
>> +                       return null;
>> +               }
>> +
>> +               @Override
>> +               public List<String> getAttributeNames(Request request)
>> +               {
>> +                       return null;
>> +               }
>> +
>> +               @Override
>> +               public void setAttribute(Request request, String name, Serializable value)
>> +               {
>> +               }
>> +
>> +               @Override
>> +               public void removeAttribute(Request request, String name)
>> +               {
>> +               }
>> +
>> +               @Override
>> +               public void invalidate(Request request)
>> +               {
>> +               }
>> +
>> +               @Override
>> +               public String getSessionId(Request request, boolean create)
>> +               {
>> +                       return null;
>> +               }
>> +
>> +               @Override
>> +               public Session lookup(Request request)
>> +               {
>> +                       return null;
>> +               }
>> +
>> +               @Override
>> +               public void bind(Request request, Session newSession)
>> +               {
>> +               }
>> +
>> +               @Override
>> +               public void flushSession(Request request, Session session)
>> +               {
>> +               }
>> +
>> +               @Override
>> +               public void destroy()
>> +               {
>> +               }
>> +
>> +               @Override
>> +               public void registerUnboundListener(UnboundListener listener)
>> +               {
>> +               }
>> +
>> +               @Override
>> +               public void unregisterUnboundListener(UnboundListener listener)
>> +               {
>> +               }
>> +
>> +               @Override
>> +               public Set<UnboundListener> getUnboundListener()
>> +               {
>> +                       return null;
>> +               }
>> +
>> +               @Override
>> +               public void registerBindListener(BindListener listener)
>> +               {
>> +               }
>> +
>> +               @Override
>> +               public void unregisterBindListener(BindListener listener)
>> +               {
>> +               }
>> +
>> +
>> +               @Override
>> +
>> +               public Set<BindListener> getBindListeners()
>> +               {
>> +                       return null;
>> +               }
>> +       }
>> +
>>          /**
>>           * Collects the html generated by the rendering of a page.
>> +        * <p>
>> +        * Important note: Must be called on a thread already processing a {@link WebApplication}!
>>           *
>>           * @param pageProvider
>>           *            the provider of the page class/instance and its parameters
>> @@ -75,12 +381,16 @@ public class ComponentRenderer
>>
>>          /**
>>           * Collects the html generated by the rendering of a component.
>> -        *
>>           * <p>
>> -        * NOTE: this method is meant to render fresh component instances that are disposed after the
>> +        * Important notes:
>> +        * <ul>
>> +        * <li>this method is meant to render fresh component instances that are disposed after the
>>           * html has been generate. To avoid unwanted side effects do not use it with components that
>> -        * are from an existing hierarchy.
>> -        * </p>
>> +        * are from an existing hierarchy.</li>
>> +        * <li>does <strong>not</strong> support rendering
>> +        * {@link org.apache.wicket.markup.html.panel.Fragment} instances</li>
>> +        * <li>must be called on a thread already processing a {@link WebApplication}!</li>
>> +        * </ul>
>>           *
>>           * @param component
>>           *            the component to render.
>>
>> http://git-wip-us.apache.org/repos/asf/wicket/blob/6e6c273f/wicket-core/src/test/java/org/apache/wicket/core/util/string/componentrenderer/ComponentRendererInstanceTest.java
>> ----------------------------------------------------------------------
>> diff --git a/wicket-core/src/test/java/org/apache/wicket/core/util/string/componentrenderer/ComponentRendererInstanceTest.java b/wicket-core/src/test/java/org/apache/wicket/core/util/string/componentrenderer/ComponentRendererInstanceTest.java
>> new file mode 100644
>> index 0000000..4aa6dfa
>> --- /dev/null
>> +++ b/wicket-core/src/test/java/org/apache/wicket/core/util/string/componentrenderer/ComponentRendererInstanceTest.java
>> @@ -0,0 +1,52 @@
>> +/*
>> +/*
>> + * Licensed to the Apache Software Foundation (ASF) under one or more
>> + * contributor license agreements.  See the NOTICE file distributed with
>> + * this work for additional information regarding copyright ownership.
>> + * The ASF 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
>> + *
>> + *      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.apache.wicket.core.util.string.componentrenderer;
>> +
>> +import static org.junit.Assert.assertEquals;
>> +
>> +import org.apache.wicket.core.util.string.ComponentRenderer;
>> +import org.apache.wicket.markup.html.basic.Label;
>> +import org.junit.After;
>> +import org.junit.Before;
>> +import org.junit.Test;
>> +
>> +/**
>> + * Tests for {@link ComponentRenderer}
>> + */
>> +public class ComponentRendererInstanceTest
>> +{
>> +       private ComponentRenderer renderer;
>> +
>> +       @Before
>> +       public void setup() {
>> +               renderer = new ComponentRenderer();
>> +       }
>> +
>> +       @After
>> +       public void destroy() {
>> +               renderer.destroy();
>> +       }
>> +
>> +       @Test
>> +       public void render()
>> +       {
>> +               CharSequence html = renderer.renderComponent(() -> new Label("id", "Hello renderer"));
>> +
>> +               assertEquals("Hello renderer", html.toString());
>> +       }
>> +}
>> \ No newline at end of file
>>
>
>


Re: wicket git commit: render independently from web or tester

Posted by Maxim Solodovnik <so...@gmail.com>.
Hello Sven,

Is this correct import?
import com.google.common.base.Supplier;

On Thu, Dec 7, 2017 at 3:24 PM,  <sv...@apache.org> wrote:
> Repository: wicket
> Updated Branches:
>   refs/heads/sandbox/component-renderer [created] 6e6c273fd
>
>
> render independently from web or tester
>
>
> Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
> Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/6e6c273f
> Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/6e6c273f
> Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/6e6c273f
>
> Branch: refs/heads/sandbox/component-renderer
> Commit: 6e6c273fd32325a447cc32c751d5ce0c083e7ed1
> Parents: 693dad3
> Author: Sven Meier <sv...@apache.org>
> Authored: Thu Dec 7 09:24:12 2017 +0100
> Committer: Sven Meier <sv...@apache.org>
> Committed: Thu Dec 7 09:24:12 2017 +0100
>
> ----------------------------------------------------------------------
>  .../core/util/string/ComponentRenderer.java     | 324 ++++++++++++++++++-
>  .../ComponentRendererInstanceTest.java          |  52 +++
>  2 files changed, 369 insertions(+), 7 deletions(-)
> ----------------------------------------------------------------------
>
>
> http://git-wip-us.apache.org/repos/asf/wicket/blob/6e6c273f/wicket-core/src/main/java/org/apache/wicket/core/util/string/ComponentRenderer.java
> ----------------------------------------------------------------------
> diff --git a/wicket-core/src/main/java/org/apache/wicket/core/util/string/ComponentRenderer.java b/wicket-core/src/main/java/org/apache/wicket/core/util/string/ComponentRenderer.java
> index 0cf63bf..e971bc2 100644
> --- a/wicket-core/src/main/java/org/apache/wicket/core/util/string/ComponentRenderer.java
> +++ b/wicket-core/src/main/java/org/apache/wicket/core/util/string/ComponentRenderer.java
> @@ -16,35 +16,341 @@
>   */
>  package org.apache.wicket.core.util.string;
>
> +import java.io.Serializable;
> +import java.util.List;
> +import java.util.Set;
> +
>  import org.apache.wicket.Application;
>  import org.apache.wicket.Component;
>  import org.apache.wicket.MarkupContainer;
> +import org.apache.wicket.Page;
> +import org.apache.wicket.RuntimeConfigurationType;
> +import org.apache.wicket.Session;
>  import org.apache.wicket.ThreadContext;
>  import org.apache.wicket.core.request.handler.PageProvider;
>  import org.apache.wicket.markup.IMarkupCacheKeyProvider;
>  import org.apache.wicket.markup.IMarkupResourceStreamProvider;
>  import org.apache.wicket.markup.MarkupNotFoundException;
>  import org.apache.wicket.markup.html.WebPage;
> +import org.apache.wicket.mock.MockApplication;
> +import org.apache.wicket.mock.MockWebRequest;
>  import org.apache.wicket.protocol.http.BufferedWebResponse;
> +import org.apache.wicket.protocol.http.WebApplication;
> +import org.apache.wicket.protocol.http.mock.MockServletContext;
> +import org.apache.wicket.request.Request;
>  import org.apache.wicket.request.Response;
> +import org.apache.wicket.request.Url;
>  import org.apache.wicket.request.cycle.RequestCycle;
> +import org.apache.wicket.request.http.WebRequest;
> +import org.apache.wicket.serialize.ISerializer;
> +import org.apache.wicket.session.ISessionStore;
>  import org.apache.wicket.util.resource.IResourceStream;
>  import org.apache.wicket.util.resource.StringResourceStream;
>  import org.slf4j.Logger;
>  import org.slf4j.LoggerFactory;
>
> +import com.google.common.base.Supplier;
> +
>  /**
>   * A helper class for rendering components and pages.
> - *
> - * <p><strong>Note</strong>: {@link #renderComponent(Component)} does <strong>not</strong>
> - * support rendering {@link org.apache.wicket.markup.html.panel.Fragment} instances!</p>
> + * <p>
> + * With the static methods of this class components and pages can be rendered
> + * on a thread already processing an {@link Application}.
> + * <p>
> + * If you want to render independently from any web request processing (e.g. generating an email
> + * body on a worker thread), you can create an instance of this class.<br/>
> + * You may use an existing application, create a fresh one or just use the defaults of
> + * {@link #ComponentRenderer()} for a mocked application with sensible defaults.
> + * <p>
> + * Note: For performance instances can and should be reused, be sure to call {@link #destroy()}
> + * when they are no longer needed.
>   */
>  public class ComponentRenderer
>  {
>         private static final Logger LOGGER = LoggerFactory.getLogger(ComponentRenderer.class);
>
> +       private WebApplication application;
> +
> +       /**
> +        * A renderer using a default mocked application, which
> +        * <ul>
> +        * <li>never shares anything in a session</li>
> +        * <li>never serializes anything</li>
> +        * </ul>
> +        */
> +       public ComponentRenderer()
> +       {
> +               this(new MockApplication()
> +               {
> +                       @Override
> +                       public RuntimeConfigurationType getConfigurationType()
> +                       {
> +                               return RuntimeConfigurationType.DEPLOYMENT;
> +                       }
> +
> +                       @Override
> +                       protected void init()
> +                       {
> +                               super.init();
> +
> +                               setSessionStoreProvider(() -> new NeverSessionStore());
> +                               getFrameworkSettings().setSerializer(new NeverSerializer());
> +                       }
> +               });
> +       }
> +
> +       /**
> +        * A renderer using the given application.
> +        * <p>
> +        * If the application was not yet initialized - e.g. it is not reused from an already running web
> +        * container - it will be initialized.
> +        */
> +       public ComponentRenderer(WebApplication application)
> +       {
> +               this.application = application;
> +
> +               if (application.getName() == null) {
> +                       // not yet initialized
> +
> +                       inThreadContext(new Runnable()
> +                       {
> +                               @Override
> +                               public void run()
> +                               {
> +                                       application.setServletContext(new MockServletContext(application, null));
> +                                       application.setName("ComponentRenderer[" + System.identityHashCode(ComponentRenderer.this) + "]");
> +                                       application.initApplication();
> +                               }
> +                       });
> +               }
> +       }
> +
> +       /**
> +        * Destroy this renderer.
> +        */
> +       public void destroy()
> +       {
> +               inThreadContext(new Runnable()
> +               {
> +                       @Override
> +                       public void run()
> +                       {
> +                               application.internalDestroy();
> +                       }
> +               });
> +       }
> +
> +       /**
> +        *
> +        * Collects the html generated by the rendering a component.
> +        *
> +        * @param component
> +        *            supplier of the component
> +        * @return the html rendered by the panel
> +        */
> +       public CharSequence renderComponent(final Supplier<Component> component)
> +       {
> +               return renderPage(new Supplier<Page>()
> +               {
> +                       @Override
> +                       public Page get()
> +                       {
> +                               return new RenderPage(component.get());
> +                       }
> +               });
> +       }
> +
> +       /**
> +        * Collects the html generated by the rendered a component.
> +        *
> +        * @param page
> +        *            supplier of the page
> +        * @return the html rendered by the panel
> +        */
> +       public CharSequence renderPage(final Supplier<? extends Page> page)
> +       {
> +               return inThreadContext(new Supplier<CharSequence>()
> +               {
> +                       @Override
> +                       public CharSequence get()
> +                       {
> +                               WebRequest request = newWebRequest();
> +
> +                               BufferedWebResponse response = new BufferedWebResponse(null);
> +
> +                               RequestCycle cycle = application.createRequestCycle(request, response);
> +
> +                               ThreadContext.setRequestCycle(cycle);
> +
> +                               page.get().renderPage();
> +
> +                               return response.getText();
> +                       }
> +               });
> +       }
> +
> +       /**
> +        * Run the given runnable inside a valid {@link ThreadContext}.
> +        *
> +        * @param runnable
> +        *            runnable
> +        */
> +       private void inThreadContext(Runnable runnable) {
> +               inThreadContext(() -> {
> +                       runnable.run();
> +                       return null;
> +               });
> +       }
> +
> +       /**
> +        * Get the result from the given supplier inside a valid {@link ThreadContext}.
> +        *
> +        * @param supplier
> +        *            supplier
> +        * @return result of {@link Supplier#get()}
> +        */
> +       private <T> T inThreadContext(Supplier<T> supplier)
> +       {
> +               ThreadContext oldContext = ThreadContext.detach();
> +
> +               try
> +               {
> +                       ThreadContext.setApplication(application);
> +
> +                       return supplier.get();
> +               }
> +               finally
> +               {
> +
> +                       ThreadContext.restore(oldContext);
> +               }
> +       }
> +
> +       /**
> +        * Create a new request, by default a {@link MockWebRequest}.
> +        */
> +       protected WebRequest newWebRequest()
> +       {
> +               return new MockWebRequest(Url.parse("/"));
> +       }
> +
> +       /**
> +        * Never serialize.
> +        */
> +       private static final class NeverSerializer implements ISerializer
> +       {
> +               @Override
> +               public byte[] serialize(Object object)
> +               {
> +                       return null;
> +               }
> +
> +               @Override
> +               public Object deserialize(byte[] data)
> +               {
> +                       return null;
> +               }
> +       }
> +
> +       /**
> +        * Never share anything.
> +        */
> +       private static class NeverSessionStore implements ISessionStore
> +       {
> +
> +               @Override
> +               public Serializable getAttribute(Request request, String name)
> +               {
> +                       return null;
> +               }
> +
> +               @Override
> +               public List<String> getAttributeNames(Request request)
> +               {
> +                       return null;
> +               }
> +
> +               @Override
> +               public void setAttribute(Request request, String name, Serializable value)
> +               {
> +               }
> +
> +               @Override
> +               public void removeAttribute(Request request, String name)
> +               {
> +               }
> +
> +               @Override
> +               public void invalidate(Request request)
> +               {
> +               }
> +
> +               @Override
> +               public String getSessionId(Request request, boolean create)
> +               {
> +                       return null;
> +               }
> +
> +               @Override
> +               public Session lookup(Request request)
> +               {
> +                       return null;
> +               }
> +
> +               @Override
> +               public void bind(Request request, Session newSession)
> +               {
> +               }
> +
> +               @Override
> +               public void flushSession(Request request, Session session)
> +               {
> +               }
> +
> +               @Override
> +               public void destroy()
> +               {
> +               }
> +
> +               @Override
> +               public void registerUnboundListener(UnboundListener listener)
> +               {
> +               }
> +
> +               @Override
> +               public void unregisterUnboundListener(UnboundListener listener)
> +               {
> +               }
> +
> +               @Override
> +               public Set<UnboundListener> getUnboundListener()
> +               {
> +                       return null;
> +               }
> +
> +               @Override
> +               public void registerBindListener(BindListener listener)
> +               {
> +               }
> +
> +               @Override
> +               public void unregisterBindListener(BindListener listener)
> +               {
> +               }
> +
> +
> +               @Override
> +
> +               public Set<BindListener> getBindListeners()
> +               {
> +                       return null;
> +               }
> +       }
> +
>         /**
>          * Collects the html generated by the rendering of a page.
> +        * <p>
> +        * Important note: Must be called on a thread already processing a {@link WebApplication}!
>          *
>          * @param pageProvider
>          *            the provider of the page class/instance and its parameters
> @@ -75,12 +381,16 @@ public class ComponentRenderer
>
>         /**
>          * Collects the html generated by the rendering of a component.
> -        *
>          * <p>
> -        * NOTE: this method is meant to render fresh component instances that are disposed after the
> +        * Important notes:
> +        * <ul>
> +        * <li>this method is meant to render fresh component instances that are disposed after the
>          * html has been generate. To avoid unwanted side effects do not use it with components that
> -        * are from an existing hierarchy.
> -        * </p>
> +        * are from an existing hierarchy.</li>
> +        * <li>does <strong>not</strong> support rendering
> +        * {@link org.apache.wicket.markup.html.panel.Fragment} instances</li>
> +        * <li>must be called on a thread already processing a {@link WebApplication}!</li>
> +        * </ul>
>          *
>          * @param component
>          *            the component to render.
>
> http://git-wip-us.apache.org/repos/asf/wicket/blob/6e6c273f/wicket-core/src/test/java/org/apache/wicket/core/util/string/componentrenderer/ComponentRendererInstanceTest.java
> ----------------------------------------------------------------------
> diff --git a/wicket-core/src/test/java/org/apache/wicket/core/util/string/componentrenderer/ComponentRendererInstanceTest.java b/wicket-core/src/test/java/org/apache/wicket/core/util/string/componentrenderer/ComponentRendererInstanceTest.java
> new file mode 100644
> index 0000000..4aa6dfa
> --- /dev/null
> +++ b/wicket-core/src/test/java/org/apache/wicket/core/util/string/componentrenderer/ComponentRendererInstanceTest.java
> @@ -0,0 +1,52 @@
> +/*
> +/*
> + * Licensed to the Apache Software Foundation (ASF) under one or more
> + * contributor license agreements.  See the NOTICE file distributed with
> + * this work for additional information regarding copyright ownership.
> + * The ASF 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
> + *
> + *      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.apache.wicket.core.util.string.componentrenderer;
> +
> +import static org.junit.Assert.assertEquals;
> +
> +import org.apache.wicket.core.util.string.ComponentRenderer;
> +import org.apache.wicket.markup.html.basic.Label;
> +import org.junit.After;
> +import org.junit.Before;
> +import org.junit.Test;
> +
> +/**
> + * Tests for {@link ComponentRenderer}
> + */
> +public class ComponentRendererInstanceTest
> +{
> +       private ComponentRenderer renderer;
> +
> +       @Before
> +       public void setup() {
> +               renderer = new ComponentRenderer();
> +       }
> +
> +       @After
> +       public void destroy() {
> +               renderer.destroy();
> +       }
> +
> +       @Test
> +       public void render()
> +       {
> +               CharSequence html = renderer.renderComponent(() -> new Label("id", "Hello renderer"));
> +
> +               assertEquals("Hello renderer", html.toString());
> +       }
> +}
> \ No newline at end of file
>



-- 
WBR
Maxim aka solomax