Github user martin-g commented on a diff in the pull request:

    https://github.com/apache/wicket/pull/249#discussion_r155464694
  
    --- Diff: 
wicket-core/src/main/java/org/apache/wicket/core/util/string/ComponentRenderer.java
 ---
    @@ -16,35 +16,321 @@
      */
     package org.apache.wicket.core.util.string;
     
    +import java.io.Serializable;
    +import java.util.List;
    +import java.util.Set;
    +import java.util.function.Supplier;
    +
     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;
     
     /**
      * 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(() -> {
    +                           application.setServletContext(new 
MockServletContext(application, null));
    +                           application.setName(
    +                                   "ComponentRenderer[" + 
System.identityHashCode(ComponentRenderer.this) + "]");
    +                           application.initApplication();
    +                   });
    +           }
    +   }
    +
    +   /**
    +    * Destroy this renderer.
    +    */
    +   public void destroy()
    +   {
    +           inThreadContext(() -> {
    +                   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 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(() -> {
    +                   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}!
    --- End diff --
    
    What does it mean "a thread processing an application" ?
    Processing a request is clear, but application is not.


---

Reply via email to