package nextapp.echo2.testapp.interactive.testscreen;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import nextapp.echo2.app.Button;
import nextapp.echo2.app.Column;
import nextapp.echo2.app.Component;
import nextapp.echo2.app.Insets;
import nextapp.echo2.app.event.ActionEvent;
import nextapp.echo2.app.event.ActionListener;
import nextapp.echo2.app.layout.SplitPaneLayoutData;
import nextapp.echo2.app.update.ServerComponentUpdate;
import nextapp.echo2.app.util.DomUtil;
import nextapp.echo2.webcontainer.ComponentSynchronizePeer;
import nextapp.echo2.webcontainer.ContainerInstance;
import nextapp.echo2.webcontainer.DomUpdateSupport;
import nextapp.echo2.webcontainer.RenderContext;
import nextapp.echo2.webrender.ServerMessage;
import nextapp.echo2.webrender.Service;
import nextapp.echo2.webrender.WebRenderServlet;
import nextapp.echo2.webrender.servermessage.DomUpdate;
import nextapp.echo2.webrender.service.JavaScriptService;
/**
* A test to examine failure behavior with client script exceptions.
*/
public class ClientExceptionTest extends Column {
/**
* Component that can be configured to throw JavaScript
* exception on client/server sync.
*/
public static class ExComponent extends Component {
public static final int MODE_WORKING = 0;
public static final int MODE_FAIL_ON_RENDER_ONCE = 1;
public static final int MODE_FAIL_ON_RENDER_EVERY_TIME = 2;
public static final int MODE_LOAD_BROKEN_JS_ONCE = 3;
public static final int MODE_LOAD_BROKEN_JS_EVERY_TIME = 4;
private int mode;
public ExComponent(int mode) {
super();
this.mode = mode;
}
public int getMode() {
return mode;
}
public void setMode(int mode) {
this.mode = mode;
}
}
/**
* Peer class for <code>ExComponent</code> that will throw a JavaScript
* error depending on component state.
*/
public static class ExPeer implements ComponentSynchronizePeer, DomUpdateSupport {
/**
* Service to provide supporting JavaScript library.
*/
private static final Service EXCOMPONENT_SERVICE = JavaScriptService.forResource("EchoTestApp.ExComponent",
"/nextapp/echo2/testapp/interactive/resource/js/ExComponent.js");
/**
* Service to provide supporting JavaScript library.
*/
private static final Service EXCOMPONENT_BROKEN_SERVICE = JavaScriptService.forResource("EchoTestApp.ExComponentBroken",
"/nextapp/echo2/testapp/interactive/resource/js/ExComponentBroken.js");
static {
WebRenderServlet.getServiceRegistry().add(EXCOMPONENT_SERVICE);
WebRenderServlet.getServiceRegistry().add(EXCOMPONENT_BROKEN_SERVICE);
}
/**
* @see nextapp.echo2.webcontainer.ComponentSynchronizePeer#getContainerId(nextapp.echo2.app.Component)
*/
public String getContainerId(Component child) {
throw new UnsupportedOperationException("Component does not support children.");
}
/**
* @see nextapp.echo2.webcontainer.ComponentSynchronizePeer#renderAdd(nextapp.echo2.webcontainer.RenderContext,
* nextapp.echo2.app.update.ServerComponentUpdate, java.lang.String, nextapp.echo2.app.Component)
*/
public void renderAdd(RenderContext rc, ServerComponentUpdate update, String targetId, Component component) {
Element domAddElement = DomUpdate.renderElementAdd(rc.getServerMessage());
DocumentFragment htmlFragment = rc.getServerMessage().getDocument().createDocumentFragment();
renderHtml(rc, update, htmlFragment, component);
DomUpdate.renderElementAddContent(rc.getServerMessage(), domAddElement, targetId, htmlFragment);
}
/**
* Renders a directive to dynamically load a broken script module.
*
* @param rc the relevant <code>RenderContext</code>
*/
private void renderBrokenScriptModule(RenderContext rc) {
rc.getServerMessage().addLibrary(EXCOMPONENT_BROKEN_SERVICE.getId());
}
/**
* @see nextapp.echo2.webcontainer.ComponentSynchronizePeer#renderDispose(
* nextapp.echo2.webcontainer.RenderContext, nextapp.echo2.app.update.ServerComponentUpdate,
* nextapp.echo2.app.Component)
*/
public void renderDispose(RenderContext rc, ServerComponentUpdate update, Component component) { }
/**
* Renders a directive that will fail during processing.
*
* @param rc the relevant <code>RenderContext</code>
*/
private void renderFailDirective(RenderContext rc) {
rc.getServerMessage().addLibrary(EXCOMPONENT_SERVICE.getId());
rc.getServerMessage().appendPartDirective(ServerMessage.GROUP_ID_POSTUPDATE, "ExComponent.MessageProcessor", "fail");
}
/**
* @see nextapp.echo2.webcontainer.DomUpdateSupport#renderHtml(nextapp.echo2.webcontainer.RenderContext,
* nextapp.echo2.app.update.ServerComponentUpdate,
* org.w3c.dom.Node, nextapp.echo2.app.Component)
*/
public void renderHtml(RenderContext rc, ServerComponentUpdate update, Node parentNode, Component component) {
ExComponent exComponent = (ExComponent) component;
Document document = rc.getServerMessage().getDocument();
Element spanElement = document.createElement("span");
spanElement.setAttribute("id", ContainerInstance.getElementId(component));
parentNode.appendChild(spanElement);
switch (exComponent.getMode()) {
case ExComponent.MODE_FAIL_ON_RENDER_ONCE:
DomUtil.setElementText(spanElement, "[fail on render once]");
renderFailDirective(rc);
exComponent.setMode(ExComponent.MODE_WORKING);
break;
case ExComponent.MODE_FAIL_ON_RENDER_EVERY_TIME:
DomUtil.setElementText(spanElement, "[fail on render every time]");
renderFailDirective(rc);
break;
case ExComponent.MODE_LOAD_BROKEN_JS_ONCE:
DomUtil.setElementText(spanElement, "[load broken script module]");
renderBrokenScriptModule(rc);
exComponent.setMode(ExComponent.MODE_WORKING);
break;
case ExComponent.MODE_LOAD_BROKEN_JS_EVERY_TIME:
DomUtil.setElementText(spanElement, "[load broken script module]");
renderBrokenScriptModule(rc);
break;
default:
DomUtil.setElementText(spanElement, "[non-broken]");
}
}
/**
* @see nextapp.echo2.webcontainer.ComponentSynchronizePeer#renderUpdate(
* nextapp.echo2.webcontainer.RenderContext, nextapp.echo2.app.update.ServerComponentUpdate,
* java.lang.String)
*/
public boolean renderUpdate(RenderContext rc, ServerComponentUpdate update, String targetId) {
String parentId = ContainerInstance.getElementId(update.getParent());
DomUpdate.renderElementRemove(rc.getServerMessage(), parentId);
renderAdd(rc, update, targetId, update.getParent());
return true;
}
}
/**
* Creates a new <code>ClientExceptionTest</code>.
*/
public ClientExceptionTest() {
super();
SplitPaneLayoutData splitPaneLayoutData = new SplitPaneLayoutData();
splitPaneLayoutData.setInsets(new Insets(10));
setLayoutData(splitPaneLayoutData);
Button button;
button = new Button("Add working component (Control Case)");
button.setStyleName("Default");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
add(new ExComponent(ExComponent.MODE_WORKING));
}
});
add(button);
button = new Button("Add broken component that fails to render (ONCE).");
button.setStyleName("Default");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
add(new ExComponent(ExComponent.MODE_FAIL_ON_RENDER_ONCE));
}
});
add(button);
button = new Button("Add broken component that will dynamically load broken JavaScript module (ONCE).");
button.setStyleName("Default");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
add(new ExComponent(ExComponent.MODE_LOAD_BROKEN_JS_ONCE));
}
});
add(button);
button = new Button("Add broken component that fails to render (EVERY TIME).");
button.setStyleName("Default");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
add(new ExComponent(ExComponent.MODE_FAIL_ON_RENDER_EVERY_TIME));
}
});
add(button);
button = new Button("Add broken component that will dynamically load broken JavaScript module (EVERY TIME).");
button.setStyleName("Default");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
add(new ExComponent(ExComponent.MODE_LOAD_BROKEN_JS_EVERY_TIME));
}
});
add(button);
}
}