de.jwic.controls.AsyncRenderContainer Maven / Gradle / Ivy
/*******************************************************************************
* Copyright 2015 xWic group (http://www.xwic.de)
*
* Licensed 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.
*
*******************************************************************************/
/*
* de.jwic.controls.AsyncRenderContainer
*/
package de.jwic.controls;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONException;
import org.json.JSONWriter;
import de.jwic.base.Control;
import de.jwic.base.ControlContainer;
import de.jwic.base.Dimension;
import de.jwic.base.IControlContainer;
import de.jwic.base.IResourceControl;
import de.jwic.base.ImageRef;
import de.jwic.base.JWicException;
import de.jwic.base.JavaScriptSupport;
import de.jwic.base.RenderContext;
import de.jwic.web.ContentRenderer;
/**
* Renders the controls within the container asynchronously without blocking
* the main thread. This can be useful if either the creation of child controls or
* the rendering itself is slow. By performing the initialization and rendering
* after the control has been placed into the UI, the user can continue using the
* application while a wait image/message is displayed until the rendering is completed
* and the child controls are displayed.
*
* Controls may either be added right away or be initialized only at the first rendering
* attempt. For this, a LazyInitializationHandler must be registered, which is invoked
* the first time the control is rendered.
*
* @author lippisch
*
*/
@JavaScriptSupport
public class AsyncRenderContainer extends ControlContainer implements IResourceControl {
private ControlContainer container;
private LazyInitializationHandler lazyInitializationHandler = null;
private boolean initialized = false;
private boolean notifySuccess = false;
private long seqNum = 0;
private String waitImageCss = "loadingIconAsync";
private Dimension waitBlockDimension = null;
private String waitText = null;
private Throwable error;
/**
* Constructor.
* @param parent
*/
public AsyncRenderContainer(IControlContainer parent) {
super(parent);
internalInit();
}
/**
* @param container
* @param name
*/
public AsyncRenderContainer(IControlContainer parent, String name) {
super(parent, name);
internalInit();
}
/**
* Initialize the control itself.
*/
private void internalInit() {
this.container = new ControlContainer(this, "content");
}
/**
* @return the lazyInitializationHandler
*/
public LazyInitializationHandler getLazyInitializationHandler() {
return lazyInitializationHandler;
}
/**
* @param lazyInitializationHandler the lazyInitializationHandler to set
*/
public void setLazyInitializationHandler(LazyInitializationHandler lazyInitializationHandler) {
this.lazyInitializationHandler = lazyInitializationHandler;
}
/**
* Returns the container to be used for childs.
*/
public IControlContainer getContainer() {
return container;
}
/* (non-Javadoc)
* @see de.jwic.base.ControlContainer#registerControl(de.jwic.base.Control, java.lang.String)
*/
@Override
public void registerControl(Control control, String name) throws JWicException {
if (container == null) {
// until the container is created, add all controls as childs. This is most likely only
// the container itself.
super.registerControl(control, name);
} else {
container.registerControl(control, name);
}
}
/* (non-Javadoc)
* @see de.jwic.base.ControlContainer#getControls()
*/
@Override
public Iterator getControls() {
if(this.container!=null){
return this.container.getControls();
}
return super.getControls();
}
/* (non-Javadoc)
* @see de.jwic.base.IResourceControl#attachResource(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
public void attachResource(HttpServletRequest req, HttpServletResponse res) throws IOException {
res.setContentType("text/json; charset=UTF-8");
PrintWriter pw;
try {
pw = res.getWriter();
} catch (Exception e) {
log.error("Error getting writer!");
return;
}
JSONWriter jsonOut = new JSONWriter(pw);
// Initialize the content when the control is rendered the first time.
if (!initialized && lazyInitializationHandler != null) {
synchronized (this) {
if (!initialized) {
try{
lazyInitializationHandler.initialize(getContainer());
}catch(Throwable t){
Iterator it = this.getControls();
while(it.hasNext()){
Control c = it.next();
this.removeControl(c.getName());
try{
c.destroy();
}catch(Throwable t2){
log.error("Cannot destroy control.", t2);
}//remove and try to destroy all the control to allow for recreation with same name
}
try {
jsonOut.object().key("success").value(false).key("fail").value(true).endObject();//let the ui know about the grave problem with nifty little booleans
} catch (JSONException e) {
res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.toString());
log.error("Error generating JSON response", e);
}
pw.flush();
pw.close();
this.error = t;
return;
}
initialized = true;
}
}
}
try {
// render child control
ByteArrayOutputStream out = new ByteArrayOutputStream();
PrintWriter buffer = new PrintWriter(out);
RenderContext context = new RenderContext(req, res, buffer);
ContentRenderer cr = new ContentRenderer(container, context);
try {
cr.render();
} catch (Throwable t) {
log.error("Error rendering embedded container", t);
pw.print("Error rendering control: " + t.toString());
}
buffer.flush();
jsonOut.object()
.key("seqNum")
.value(req.getParameter("seqNum"))
.key("controlId")
.value(getControlID())
.key("html")
.value(out.toString());
if (context.getScripts() != null) {
if (context.getScripts() != null && context.getScripts().size() > 0) {
jsonOut.key("scripts")
.array();
for (Map.Entry entry : context.getScripts().entrySet()) {
jsonOut.object();
jsonOut.key("controlId");
jsonOut.value(entry.getKey());
jsonOut.key("script");
jsonOut.value(entry.getValue());
jsonOut.endObject();
}
jsonOut.endArray();
}
}
jsonOut.key("success").value(true);
jsonOut.key("fail").value(false);
jsonOut.endObject();
} catch (JSONException e) {
res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.toString());
log.error("Error generating JSON response", e);
}
pw.close();
this.requireRedraw();
}
/**
* @return the seqNum
*/
public long nextSeqNum() {
seqNum++;
return seqNum;
}
/**
* @return the waitImageCss
*/
public String getWaitImageCss() {
return waitImageCss;
}
/**
* @param waitImageCss the waitImageCss to set
*/
public void setWaitImageCss(String waitImageCss) {
this.waitImageCss = waitImageCss;
}
/**
* @return the waitBlockDimension
*/
public Dimension getWaitBlockDimension() {
return waitBlockDimension;
}
/**
* @param waitBlockDimension the waitBlockDimension to set
*/
public void setWaitBlockDimension(Dimension waitBlockDimension) {
this.waitBlockDimension = waitBlockDimension;
}
/**
* @return the waitText
*/
public String getWaitText() {
return waitText;
}
/**
* @param waitText the waitText to set
*/
public void setWaitText(String waitText) {
this.waitText = waitText;
}
/**
* @return the notifySuccess
*/
public boolean isNotifySuccess() {
return notifySuccess;
}
/**
* @param notifySuccess the notifySuccess to set
*/
public void setNotifySuccess(boolean notifySuccess) {
this.notifySuccess = notifySuccess;
}
public final void actionOnFail(){
if(this.lazyInitializationHandler!=null){
this.setRequireRedraw(false);
this.lazyInitializationHandler.failure(error);
}
}
public final void actionOnSuccess(){
if(this.lazyInitializationHandler != null){
this.setRequireRedraw(false);
this.lazyInitializationHandler.success();
}
}
@Override
public void requireRedraw() {
if(this.container == null){
super.requireRedraw();
}else{
this.container.requireRedraw();
}
}
@Override
public void setRequireRedraw(boolean requireRedraw) {
if (this.container != null)
this.container.setRequireRedraw(requireRedraw);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy