001: /*
002: * Copyright 2005 Joe Walker
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.directwebremoting.extend;
017:
018: import java.io.IOException;
019:
020: import org.apache.commons.logging.LogFactory;
021: import org.apache.commons.logging.Log;
022: import org.directwebremoting.ScriptBuffer;
023: import org.directwebremoting.ScriptSession;
024: import org.directwebremoting.dwrp.ProtocolConstants;
025: import org.directwebremoting.impl.DefaultRemoter;
026: import org.directwebremoting.proxy.ScriptProxy;
027: import org.directwebremoting.util.JavascriptUtil;
028:
029: /**
030: * An abstraction of the DWREngine Javascript class for use by
031: * {@link org.directwebremoting.dwrp.BaseCallMarshaller},
032: * {@link org.directwebremoting.dwrp.PollHandler} and a few others that need
033: * to call internal functions in engine.js
034: * @author Joe Walker [joe at getahead dot ltd dot uk]
035: */
036: public class EnginePrivate extends ScriptProxy {
037: /**
038: * Call the dwr.engine.remote.handleResponse() in the browser
039: * @param conduit The browser pipe to write to
040: * @param batchId The identifier of the batch that we are handling a response for
041: * @param callId The identifier of the call that we are handling a response for
042: * @param data The data to pass to the callback function
043: * @throws IOException If writing fails.
044: * @throws MarshallException If objects in the script can not be marshalled
045: */
046: public static void remoteHandleCallback(ScriptConduit conduit,
047: String batchId, String callId, Object data)
048: throws IOException, MarshallException {
049: ScriptBuffer script = new ScriptBuffer();
050: script.appendCall("dwr.engine.remote.handleCallback", batchId,
051: callId, data);
052: conduit.addScript(script);
053: }
054:
055: /**
056: * Call dwr.engine.remote.handleException() in the browser
057: * @param conduit The browser pipe to write to
058: * @param batchId The identifier of the batch that we are handling a response for
059: * @param callId The id of the call we are replying to
060: * @param ex The exception to throw on the remote end
061: * @throws IOException If writing fails.
062: */
063: public static void remoteHandleException(ScriptConduit conduit,
064: String batchId, String callId, Throwable ex)
065: throws IOException {
066: try {
067: ScriptBuffer script = new ScriptBuffer();
068: script.appendCall("dwr.engine.remote.handleException",
069: batchId, callId, ex);
070: conduit.addScript(script);
071: } catch (MarshallException mex) {
072: log.warn("This exception can't happen. Really.", ex);
073: }
074: }
075:
076: /**
077: * Call dwr.engine.remote.handleNewScriptSession() in the browser
078: * @param session The browser page to write to
079: * @param newSessionId The new script session id for the browser to reuse
080: */
081: public static void remoteHandleNewScriptSession(
082: ScriptSession session, String newSessionId) {
083: ScriptBuffer script = new ScriptBuffer();
084: script.appendCall("dwr.engine.remote.handleNewScriptSession",
085: newSessionId);
086: session.addScript(script);
087: }
088:
089: /**
090: * Call dwr.engine.remote.handleNewWindowName() in the browser
091: * @param session The browser page to write to
092: * @param windowName The new window name for the page
093: */
094: public static void remoteHandleNewWindowName(ScriptSession session,
095: String windowName) {
096: ScriptBuffer script = new ScriptBuffer();
097: script.appendCall("dwr.engine.remote.handleNewWindowName",
098: windowName);
099: session.addScript(script);
100: }
101:
102: /**
103: * Call the dwr.engine.remote.handleServerException() in the browser
104: * @param batchId The identifier of the batch that we are handling a response for
105: * @param ex The exception from which we make a reply
106: * @return The script to send to the browser
107: */
108: public static String getRemoteHandleBatchExceptionScript(
109: String batchId, Exception ex) {
110: StringBuffer reply = new StringBuffer();
111:
112: String output = JavascriptUtil
113: .escapeJavaScript(ex.getMessage());
114: String params = "{ name:'" + ex.getClass().getName()
115: + "', message:'" + output + "' }";
116: if (batchId != null) {
117: params += ", '" + batchId + "'";
118: }
119:
120: reply.append(ProtocolConstants.SCRIPT_CALL_REPLY)
121: .append("\r\n");
122: reply
123: .append(
124: "if (window.dwr) dwr.engine.remote.handleBatchException(")
125: .append(params).append(");\r\n");
126: reply
127: .append(
128: "else if (window.parent.dwr) window.parent.dwr.engine.remote.handleBatchException(")
129: .append(params).append(");\r\n");
130:
131: return reply.toString();
132: }
133:
134: /**
135: * Call the dwr.engine.remote.pollCometDisabled() in the browser
136: * @param batchId The identifier of the batch that we are handling a response for
137: * @return The script to send to the browser
138: */
139: public static String getRemotePollCometDisabledScript(String batchId) {
140: StringBuffer reply = new StringBuffer();
141:
142: String params = "{ name:'dwr.engine.pollAndCometDisabled', message:'Polling and Comet are disabled. See the server logs.' }";
143: if (batchId != null) {
144: params += ", '" + batchId + "'";
145: }
146:
147: reply.append(ProtocolConstants.SCRIPT_CALL_REPLY)
148: .append("\r\n");
149: reply.append(
150: "if (window.dwr) dwr.engine.remote.pollCometDisabled(")
151: .append(params).append(");\r\n");
152: reply
153: .append(
154: "else if (window.parent.dwr) window.parent.dwr.engine.remote.pollCometDisabled(")
155: .append(params).append(");\r\n");
156:
157: return reply.toString();
158: }
159:
160: /**
161: * Take an XML string, and convert it into some Javascript that when
162: * executed will return a DOM object that represents the same XML object
163: * @param xml The XML string to convert
164: * @return The Javascript
165: */
166: public static String xmlStringToJavascriptDom(String xml) {
167: String xmlout = JavascriptUtil.escapeJavaScript(xml);
168: return "dwr.engine.serialize.toDom(\"" + xmlout + "\")";
169: }
170:
171: /**
172: * Get a string which will initialize a dwr.engine object
173: * @return A dwr.engine init script
174: */
175: public static String getEngineInitScript() {
176: return "// Provide a default path to dwr.engine\n"
177: + "if (typeof this['dwr'] == 'undefined') this.dwr = {};\n"
178: + "if (typeof dwr['engine'] == 'undefined') dwr.engine = {};\n"
179: + '\n';
180: }
181:
182: /**
183: * {@link DefaultRemoter} needs to know the name of the execute function
184: * @return The execute function name
185: */
186: public static String getExecuteFunctionName() {
187: return "dwr.engine._execute";
188: }
189:
190: /**
191: * A script to send at the beginning of an iframe response
192: * @param batchId The id of the current batch
193: * @param useWindowParent Will the exec happen from a child iframe which is
194: * the case for normal iframe based calls, or from the main window, which is
195: * the case for iframe streamed polling.
196: * @return A script to init the environment
197: */
198: public static String remoteBeginIFrameResponse(String batchId,
199: boolean useWindowParent) {
200: String script = "dwr.engine.transport.iframe.remote.beginIFrameResponse(this.frameElement"
201: + (batchId == null ? "" : ", '" + batchId + "'") + ");";
202: if (useWindowParent) {
203: script = addWindowParent(script);
204: }
205:
206: return script;
207: }
208:
209: /**
210: * A script to send at the end of an iframe response
211: * @param batchId The id of the current batch
212: * @param useWindowParent Will the exec happen from a child iframe which is
213: * the case for normal iframe based calls, or from the main window, which is
214: * the case for iframe streamed polling.
215: * @return A script to tidy up the environment
216: */
217: public static String remoteEndIFrameResponse(String batchId,
218: boolean useWindowParent) {
219: String script = "dwr.engine.transport.iframe.remote.endIFrameResponse("
220: + (batchId == null ? "" : "'" + batchId + "'") + ");";
221: if (useWindowParent) {
222: script = addWindowParent(script);
223: }
224:
225: return script;
226: }
227:
228: /**
229: * Prepare a script for execution in an iframe environment
230: * @param script The script to modify
231: * @return The modified script
232: */
233: public static String remoteEval(String script) {
234: String script2 = "dwr.engine._eval(\""
235: + JavascriptUtil.escapeJavaScript(script) + "\");";
236: return addWindowParent(script2);
237: }
238:
239: /**
240: * Evade the 2 connection limit by sending scripts to the wrong window and
241: * having that use window.name to push it to the right window
242: * @param original The script that we wish to be proxied
243: * @param windowName The window to which we wish the window to be proxied
244: * @return A script to send to a different window to cause proxying
245: */
246: public static ScriptBuffer createForeignWindowProxy(
247: String windowName, ScriptBuffer original) {
248: String proxy = JavascriptUtil.escapeJavaScript(original
249: .toString());
250:
251: ScriptBuffer reply = new ScriptBuffer();
252: reply.appendCall("dwr.engine.remote.handleForeign", windowName,
253: proxy);
254: reply.appendData(proxy);
255: return reply;
256: }
257:
258: /**
259: * A Utility to add a try/catch block to get rid of the infamous IE
260: * "Can't execute code from a freed script" errors
261: * @param script The script to wrap in a try/catch
262: * @return The wrapped script
263: */
264: private static String addWindowParent(String script) {
265: return "try { window.parent."
266: + script
267: + " } catch(ex) { if (!(ex.number && ex.number == -2146823277)) { throw ex; }}";
268: }
269:
270: /**
271: * The log stream
272: */
273: private static final Log log = LogFactory
274: .getLog(EnginePrivate.class);
275: }
|