All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.jwic.controls.AsyncRenderContainer Maven / Gradle / Ivy

There is a newer version: 5.3.43
Show newest version
/*******************************************************************************
 * 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