001: package org.wings.resource;
002:
003: import java.io.IOException;
004: import java.util.Iterator;
005: import java.util.List;
006:
007: import org.apache.commons.logging.Log;
008: import org.apache.commons.logging.LogFactory;
009: import org.wings.ReloadManager;
010: import org.wings.SFrame;
011: import org.wings.plaf.Update;
012: import org.wings.plaf.css.Utils;
013: import org.wings.io.Device;
014: import org.wings.script.ScriptListener;
015: import org.wings.session.ScriptManager;
016: import org.wings.session.SessionManager;
017:
018: /**
019: * This resource is responsible for incremental page updates using AJAX. While requests sent to the
020: * {@link ReloadResource} always entail a full rewrite of the frame's complete component hierarchy,
021: * requests received by the {@link UpdateResource} will result in preferably small data chunks being
022: * sent back to the client. These so called "incremental updates" encapsulate all informations the
023: * client needs in order to synchronize its page with the server's state. Because this resource is
024: * typically requested from an XMLHttpRequest object, it returns a well-formed XML document with MIME
025: * type "text/xml". The updates in this document will be processed by according JavaScript functions.
026: *
027: * The XML structure looks as follows:
028: *
029: * <pre>
030: * <?xml version="1.0" encoding="[encoding]" standalone="yes"?>
031: * <updates>
032: * <update><![CDATA[ my1stClientSideHandler(...) ]]></update>
033: * <update><![CDATA[ my2ndClientSideHandler(...) ]]></update>
034: * <update><![CDATA[ my3rdClientSideHandler(...) ]]></update>
035: * ...
036: * </updates>
037: * </pre>
038: *
039: * @author Stephan Schuster
040: */
041: public class UpdateResource extends DynamicResource {
042:
043: private static final transient Log log = LogFactory
044: .getLog(UpdateResource.class);
045:
046: public UpdateResource(final SFrame f) {
047: super (f);
048: this .extension = "xml";
049: this .mimeType = "text/xml; charset="
050: + SessionManager.getSession().getCharacterEncoding();
051: }
052:
053: public void write(Device out) throws IOException {
054: try {
055: final SFrame frame = getFrame();
056: final ReloadManager reloadManager = frame.getSession()
057: .getReloadManager();
058: final ScriptManager scriptManager = frame.getSession()
059: .getScriptManager();
060:
061: writeHeader(out);
062: if (reloadManager.isReloadRequired(frame)) {
063: writeUpdate(out, "wingS.request.reloadFrame()");
064: } else {
065: // update components
066: for (Iterator i = reloadManager.getUpdates().iterator(); i
067: .hasNext();) {
068: writeUpdate(out, (Update) i.next());
069: }
070:
071: // update scripts
072: ScriptListener[] scriptListeners = scriptManager
073: .getScriptListeners();
074: for (int i = 0; i < scriptListeners.length; ++i) {
075: if (scriptListeners[i].getScript() != null) {
076: writeUpdate(out, scriptListeners[i].getScript());
077: }
078: }
079: scriptManager.clearScriptListeners();
080: }
081: writeFooter(out);
082:
083: } catch (IOException e) {
084: throw e;
085: } catch (Exception e) {
086: log.fatal("resource: " + getId(), e);
087: throw new IOException(e.getMessage());
088: }
089: }
090:
091: public static void writeHeader(Device out) throws IOException {
092: String encoding = SessionManager.getSession()
093: .getCharacterEncoding();
094: out.print("<?xml version=\"1.0\" encoding=\"" + encoding
095: + "\" standalone=\"yes\"?>");
096: out.print("\n<updates>");
097:
098: if (log.isDebugEnabled()) {
099: SFrame frame = SessionManager.getSession().getRootFrame();
100: log.debug("Request: "
101: + (frame != null ? frame.getEventEpoch() : "x"));
102: }
103: }
104:
105: public static void writeFooter(Device out) throws IOException {
106: out.print("\n</updates>");
107: }
108:
109: public static void writeUpdate(Device out, Update update)
110: throws IOException {
111: Update.Handler handler = update.getHandler();
112:
113: writePrefix(out);
114: out.print(handler.getName()).print('(');
115: Iterator parameters = handler.getParameters();
116: boolean isFirst = true;
117: while (parameters.hasNext()) {
118: if (!isFirst)
119: out.print(',');
120: Utils.encodeJS(out, parameters.next());
121: isFirst = false;
122: }
123: out.print(')');
124: writePostfix(out);
125:
126: if (log.isDebugEnabled()) {
127: log.debug(update.getClass().getName() + ":");
128: StringBuilder builder = new StringBuilder();
129: builder.append(handler.getName()).append("(");
130: parameters = handler.getParameters();
131: if (parameters.hasNext())
132: builder.append(parameters.next());
133: while (parameters.hasNext())
134: builder.append(",").append(parameters.next());
135: builder.append(")");
136: log.debug(builder.toString());
137: }
138: }
139:
140: public static void writeUpdate(Device out, String update)
141: throws IOException {
142: writePrefix(out);
143: out.print(update);
144: writePostfix(out);
145: }
146:
147: private static void writePrefix(Device out) throws IOException {
148: out.print("\n <update><![CDATA[");
149: }
150:
151: private static void writePostfix(Device out) throws IOException {
152: out.print("]]></update>");
153: }
154: }
|