KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > nextapp > echo2 > webrender > ServerMessage


1 /*
2  * This file is part of the Echo Web Application Framework (hereinafter "Echo").
3  * Copyright (C) 2002-2005 NextApp, Inc.
4  *
5  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * Alternatively, the contents of this file may be used under the terms of
18  * either the GNU General Public License Version 2 or later (the "GPL"), or
19  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
20  * in which case the provisions of the GPL or the LGPL are applicable instead
21  * of those above. If you wish to allow use of your version of this file only
22  * under the terms of either the GPL or the LGPL, and not to allow others to
23  * use your version of this file under the terms of the MPL, indicate your
24  * decision by deleting the provisions above and replace them with the notice
25  * and other provisions required by the GPL or the LGPL. If you do not delete
26  * the provisions above, a recipient may use your version of this file under
27  * the terms of any one of the MPL, the GPL or the LGPL.
28  */

29
30 package nextapp.echo2.webrender;
31
32 import java.util.HashMap JavaDoc;
33 import java.util.HashSet JavaDoc;
34 import java.util.Map JavaDoc;
35 import java.util.Set JavaDoc;
36
37 import org.w3c.dom.Document JavaDoc;
38 import org.w3c.dom.Element JavaDoc;
39 import org.w3c.dom.NodeList JavaDoc;
40
41 import nextapp.echo2.webrender.output.XmlDocument;
42
43 /**
44  * The outgoing XML message which synchronizes the state of the client to that
45  * of the server.
46  */

47 public class ServerMessage extends XmlDocument {
48     
49     /**
50      * Constant for the use with <code>setRootLayoutDirection()</code>
51      * indicating a left-to-right layout direction.
52      */

53     public static final int LEFT_TO_RIGHT = 0;
54
55     /**
56      * Constant for the use with <code>setRootLayoutDirection()</code>
57      * indicating a right-to-left layout direction.
58      */

59     public static final int RIGHT_TO_LEFT = 1;
60
61     /**
62      * A hash table associating <code>ItemizedDirectiveLookupKey</code>s to
63      * corresponding <code>Element</code>s in the message.
64      */

65     private Map JavaDoc itemizedDirectivesMap = new HashMap JavaDoc();
66
67     /**
68      * Representation of the information required to look up a suitable Itemized
69      * Directive <code>Element</code>. Instances are used as keys in the
70      * <code>itemizedDirectivesMap</code>. This class provides a
71      * <code>getHashCode()</code> implementation for efficient lookups.
72      */

73     private class ItemizedDirectiveLookupKey {
74
75         String JavaDoc groupId;
76         String JavaDoc processor;
77         String JavaDoc directiveName;
78         String JavaDoc[] keyAttributeNames;
79         String JavaDoc[] keyAttributeValues;
80         int hashCode;
81
82         /**
83          * Creates an <code>ItemizedDirectiveLookupKey</code> based on the
84          * provided description.
85          *
86          * @param groupId the identifier of the target message part group
87          * @param processor the name of the client-side processor object which
88          * will process the message part containing the directive, e.g.,
89          * "EchoEventUpdate", or "EchoDomUpdate"
90          * @param directiveName the name of the directive, e.g., "event-add" or
91          * "dom-remove".
92          * @param keyAttributeNames
93          * @param keyAttributeValues
94          */

95         private ItemizedDirectiveLookupKey(String JavaDoc groupId, String JavaDoc processor, String JavaDoc directiveName, String JavaDoc[] keyAttributeNames,
96                 String JavaDoc[] keyAttributeValues) {
97             super();
98             this.groupId = groupId;
99             this.processor = processor;
100             this.directiveName = directiveName;
101             this.keyAttributeNames = keyAttributeNames;
102             this.keyAttributeValues = keyAttributeValues;
103             this.hashCode = groupId.hashCode() ^ processor.hashCode() ^ directiveName.hashCode();
104             for (int i = 0; i < keyAttributeNames.length; ++i) {
105                 this.hashCode ^= keyAttributeNames[i].hashCode() ^ keyAttributeValues[i].hashCode();
106             }
107         }
108
109         /**
110          * @see java.lang.Object#equals(java.lang.Object)
111          */

112         public boolean equals(Object JavaDoc o) {
113             if (!(o instanceof ItemizedDirectiveLookupKey)) {
114                 return false;
115             }
116             ItemizedDirectiveLookupKey that = (ItemizedDirectiveLookupKey) o;
117
118             if (!this.groupId.equals(that.groupId)) {
119                 return false;
120             }
121             if (!this.processor.equals(that.processor)) {
122                 return false;
123             }
124             if (!this.directiveName.equals(that.directiveName)) {
125                 return false;
126             }
127             if (this.keyAttributeNames.length != that.keyAttributeNames.length) {
128                 return false;
129             }
130             for (int i = 0; i < keyAttributeValues.length; ++i) {
131                 if (!(this.keyAttributeValues[i].equals(that.keyAttributeValues[i]))) {
132                     return false;
133                 }
134             }
135             for (int i = 0; i < keyAttributeNames.length; ++i) {
136                 if (!(this.keyAttributeNames[i].equals(that.keyAttributeNames[i]))) {
137                     return false;
138                 }
139             }
140
141             return true;
142         }
143
144         /**
145          * @see java.lang.Object#hashCode()
146          */

147         public int hashCode() {
148             return hashCode;
149         }
150     }
151
152     /**
153      * Constant for the "init" message part group. Message parts in this group are
154      * processed before the "preremove", "remove" "update", and "postupdate"
155      * groups.
156      */

157     public static final String JavaDoc GROUP_ID_INIT = "init";
158
159     /**
160      * Constant for the "preremove" message part group. Message parts in this group
161      * are processed after the "init" group. Message parts in this group are
162      * processed before the "remove", "update" and "postupdate" groups.
163      */

164     public static final String JavaDoc GROUP_ID_PREREMOVE = "preremove";
165
166     /**
167      * Constant for the "remove" message part group. Message parts in this group
168      * are processed after the "init" and "preremove" groups. Message parts in
169      * this group are processed before the "update" and "postupdate" groups.
170      * This group is used for removing elements from the DOM.
171      */

172     public static final String JavaDoc GROUP_ID_REMOVE = "remove";
173
174     /**
175      * Constant for the "update" message part group. Message parts in this group
176      * are processed after the "init", "preremove" and "remove" groups.
177      * Message parts in this group are processed before the "postupdate" group.
178      * This group is used for adding elements to the DOM.
179      */

180     public static final String JavaDoc GROUP_ID_UPDATE = "update";
181
182     /**
183      * Constant for the "postupdate" message part group. Message parts in this
184      * group are processed after the "init", "preremove", "remove" and "update"
185      * groups.
186      */

187     public static final String JavaDoc GROUP_ID_POSTUPDATE = "postupdate";
188
189     /** Set of added script libraries. */
190     private Set JavaDoc addedLibraries;
191
192     /**
193      * DOM <code>libraries</code> Element to which <code>library</code>
194      * elements are added to represent individual dynamically loaded JavaScript
195      * libraries.
196      */

197     private Element JavaDoc librariesElement;
198
199     /** Root DOM <code>server-message</code> element. */
200     private Element JavaDoc serverMessageElement;
201
202     /**
203      * Creates a new <code>ServerMessage</code>.
204      */

205     public ServerMessage() {
206         super("server-message", null, null, "http://www.nextapp.com/products/echo2/svrmsg/servermessage");
207         Document JavaDoc document = getDocument();
208         serverMessageElement = document.getDocumentElement();
209         librariesElement = document.createElement("libraries");
210         serverMessageElement.appendChild(librariesElement);
211
212         // Add basic part groups.
213
addPartGroup(GROUP_ID_INIT);
214         addPartGroup(GROUP_ID_PREREMOVE);
215         addPartGroup(GROUP_ID_REMOVE);
216         addPartGroup(GROUP_ID_UPDATE);
217         addPartGroup(GROUP_ID_POSTUPDATE);
218     }
219
220     /**
221      * Adds a JavaScript library service to be dynamically loaded.
222      *
223      * @param serviceId the id of the service to load (the service must return
224      * JavaScript code with content-type "text/javascript")
225      */

226     public void addLibrary(String JavaDoc serviceId) {
227         if (addedLibraries == null) {
228             addedLibraries = new HashSet JavaDoc();
229         }
230         if (addedLibraries.contains(serviceId)) {
231             return;
232         }
233         Element JavaDoc libraryElement = getDocument().createElement("library");
234         libraryElement.setAttribute("service-id", serviceId);
235         librariesElement.appendChild(libraryElement);
236         addedLibraries.add(serviceId);
237     }
238
239     /**
240      * Adds a "group" to the document. Part groups enable certain groups of
241      * operations, e.g., remove operations, to be performed before others, e.g.,
242      * add operations.
243      *
244      * @param groupId the identifier of the group
245      * @return the created "message-part-group" element.
246      */

247     public Element JavaDoc addPartGroup(String JavaDoc groupId) {
248         Element JavaDoc messagePartGroupElement = getDocument().createElement("message-part-group");
249         messagePartGroupElement.setAttribute("id", groupId);
250         serverMessageElement.appendChild(messagePartGroupElement);
251         return messagePartGroupElement;
252     }
253
254     /**
255      * Retrieves the "message-part-group" element pertaining to a specific group.
256      *
257      * @param groupId the id of the group
258      * @return the "message-part-group" element
259      */

260     public Element JavaDoc getPartGroup(String JavaDoc groupId) {
261         NodeList JavaDoc groupList = serverMessageElement.getElementsByTagName("message-part-group");
262         int length = groupList.getLength();
263         for (int i = 0; i < length; ++i) {
264             Element JavaDoc groupElement = (Element JavaDoc) groupList.item(i);
265             if (groupId.equals(groupElement.getAttribute("id"))) {
266                 return groupElement;
267             }
268         }
269         return null;
270     }
271
272     /**
273      * Adds a "message-part" to the document that will be processed by the
274      * specified client-side processor object.
275      *
276      * @param groupId the id of the group to which the "message-part" element
277      * should be added
278      * @param processor the name of the client-side processor object which will
279      * process the message part, e.g., "EchoEventUpdate", or
280      * "EchoDomUpdate"
281      * @return the created "message-part" element
282      */

283     public Element JavaDoc addPart(String JavaDoc groupId, String JavaDoc processor) {
284         Element JavaDoc messagePartGroupElement = getPartGroup(groupId);
285         Element JavaDoc messagePartElement = getDocument().createElement("message-part");
286         messagePartElement.setAttribute("processor", processor);
287         messagePartGroupElement.appendChild(messagePartElement);
288         return messagePartElement;
289     }
290
291     /**
292      * Creates and appends a directive element beneath to a message part.
293      * Attempts to append the directive to an existing message part if the last
294      * message part in the specified group happens to have the same processor as
295      * is specified by the <code>processor</code> argument. If this is not
296      * possible, a new "message-part" element is created and the directive is
297      * added to it.
298      *
299      * @param groupId
300      * @param processor the name of the client-side processor object which will
301      * process the message part, e.g., "EchoEventUpdate", or
302      * "EchoDomUpdate"
303      * @param directiveName the name of the directive, e.g., "event-add" or
304      * "dom-remove".
305      * @return the directive element
306      */

307     public Element JavaDoc appendPartDirective(String JavaDoc groupId, String JavaDoc processor, String JavaDoc directiveName) {
308         Element JavaDoc messagePartElement = null;
309         Element JavaDoc groupElement = getPartGroup(groupId);
310
311         Element JavaDoc lastChild = (Element JavaDoc) groupElement.getLastChild();
312         if (lastChild != null && processor.equals(lastChild.getAttribute("processor"))) {
313             messagePartElement = lastChild;
314         } else {
315             messagePartElement = addPart(groupId, processor);
316         }
317         
318         Element JavaDoc directiveElement = getDocument().createElement(directiveName);
319         messagePartElement.appendChild(directiveElement);
320         return directiveElement;
321     }
322
323     /**
324      * Creates or retrieves a suitable "Itemized Directive" element. Itemized
325      * Directives may be used to create more bandwidth-efficient ServerMessage
326      * output in cases where a particular operation may need to be performed on
327      * a significant number of targets. In the case that the directive must be
328      * created, it will be added to the message. Repeated invocations of this
329      * method with equivalent values of all parameters will result in the same
330      * directive being returned each time.
331      *
332      * This method should only be used for adding directives to the
333      * <code>GROUP_ID_PREREMOVE</code> and <code>GROUP_ID_POSTUPDATE</code>
334      * groups as itemized directives will not be executed in-order, which
335      * will cause problems if they are used for to manipulate the DOM.
336      *
337      * @param groupId the identifier of the target message part group,
338      * either <code>GROUP_ID_PREREMOVE</code> or
339      * <code>GROUP_ID_POSTUPDATE</code>
340      * @param processor the name of the client-side processor object which will
341      * process the message part containing the directive, e.g.,
342      * "EchoEventUpdate", or "EchoDomUpdate"
343      * @param directiveName the name of the directive, e.g., "event-add" or
344      * "dom-remove"
345      * @param keyAttributeNames the names of the key attributes
346      * @param keyAttributeValues the values of the key attributes
347      * @return the created/retrieved directive element
348      */

349     public Element JavaDoc getItemizedDirective(String JavaDoc groupId, String JavaDoc processor, String JavaDoc directiveName, String JavaDoc[] keyAttributeNames,
350             String JavaDoc[] keyAttributeValues) {
351         ItemizedDirectiveLookupKey itemizedDirectiveLookupKey = new ItemizedDirectiveLookupKey(groupId, processor, directiveName,
352                 keyAttributeNames, keyAttributeValues);
353         Element JavaDoc element = (Element JavaDoc) itemizedDirectivesMap.get(itemizedDirectiveLookupKey);
354         if (element == null) {
355             element = appendPartDirective(groupId, processor, directiveName);
356             for (int i = 0; i < keyAttributeNames.length; ++i) {
357                 element.setAttribute(keyAttributeNames[i], keyAttributeValues[i]);
358             }
359             itemizedDirectivesMap.put(itemizedDirectiveLookupKey, element);
360         }
361         return element;
362     }
363     
364     /**
365      * Sets the interval between asynchronous requests to the server to check
366      * for server-pushed updates.
367      *
368      * @param newValue the new interval in milliseconds (a negative value will
369      * disable asynchronous requests)
370      */

371     public void setAsynchronousMonitorInterval(int newValue) {
372         if (newValue < 0) {
373             serverMessageElement.setAttribute("async-interval", "disable");
374         } else {
375             serverMessageElement.setAttribute("async-interval", Integer.toString(newValue));
376         }
377     }
378
379     /**
380      * Sets the element id of the root of the modal context. Only elements
381      * within the modal context will be enabled. A <code>id</code> value of
382      * null will disable the modal context, thus allowing ALL elements to be
383      * enabled.
384      *
385      * @param id the root element id of the modal context
386      */

387     public void setModalContextRootId(String JavaDoc id) {
388         if (id == null) {
389             serverMessageElement.setAttribute("modal-id", "");
390         } else {
391             serverMessageElement.setAttribute("modal-id", id);
392         }
393     }
394
395     /**
396      * Sets the root layout direction of the application, i.e., either
397      * <code>LEFT_TO_RIGHT</code> or <code>RIGHT_TO_LEFT</code>.
398      *
399      * @param layoutDirection the new layout direction
400      */

401     public void setRootLayoutDirection(int layoutDirection) {
402         switch (layoutDirection) {
403         case LEFT_TO_RIGHT:
404             serverMessageElement.setAttribute("root-layout-direction", "ltr");
405             break;
406         case RIGHT_TO_LEFT:
407             serverMessageElement.setAttribute("root-layout-direction", "rtl");
408             break;
409         default:
410             throw new IllegalArgumentException JavaDoc("Illegal layout direction.");
411         }
412     }
413     
414     /**
415      * Sets the numeric identifier for this transaction, which will be returned
416      * in next client message.
417      *
418      * @param transactionId the transaction identifier
419      */

420     public void setTransactionId(long transactionId) {
421         serverMessageElement.setAttribute("trans-id", Long.toString(transactionId));
422     }
423 }
Popular Tags