1 29 30 package nextapp.echo2.webcontainer; 31 32 import java.util.HashSet ; 33 import java.util.Set ; 34 35 import org.w3c.dom.Document ; 36 import org.w3c.dom.Element ; 37 38 import nextapp.echo2.app.ApplicationInstance; 39 import nextapp.echo2.app.Command; 40 import nextapp.echo2.app.Component; 41 import nextapp.echo2.app.Window; 42 import nextapp.echo2.app.update.PropertyUpdate; 43 import nextapp.echo2.app.update.ServerComponentUpdate; 44 import nextapp.echo2.app.update.ServerUpdateManager; 45 import nextapp.echo2.app.update.UpdateManager; 46 import nextapp.echo2.webcontainer.syncpeer.WindowPeer; 47 import nextapp.echo2.webrender.Connection; 48 import nextapp.echo2.webrender.ServerMessage; 49 import nextapp.echo2.webrender.Service; 50 import nextapp.echo2.webrender.UserInstance; 51 import nextapp.echo2.webrender.WebRenderServlet; 52 import nextapp.echo2.webrender.servermessage.WindowUpdate; 53 import nextapp.echo2.webrender.service.JavaScriptService; 54 import nextapp.echo2.webrender.service.SynchronizeService; 55 import nextapp.echo2.webrender.util.DomUtil; 56 57 71 public class ContainerSynchronizeService extends SynchronizeService { 72 73 76 public static final Service WEB_CONTAINER_SERVICE = JavaScriptService.forResource("Echo.WebContainer", 77 "/nextapp/echo2/webcontainer/resource/js/WebContainer.js"); 78 79 static { 80 WebRenderServlet.getServiceRegistry().add(WEB_CONTAINER_SERVICE); 81 } 82 83 86 public static final ContainerSynchronizeService INSTANCE = new ContainerSynchronizeService(); 87 88 98 private static boolean isAncestor(Set potentialAncestors, Component component) { 99 component = component.getParent(); 100 while (component != null) { 101 if (potentialAncestors.contains(component)) { 102 return true; 103 } 104 component = component.getParent(); 105 } 106 return false; 107 } 108 109 113 private ClientMessagePartProcessor propertyUpdateProcessor = new ClientMessagePartProcessor() { 114 115 118 public String getName() { 119 return "EchoPropertyUpdate"; 120 } 121 122 126 public void process(UserInstance userInstance, Element messagePartElement) { 127 ContainerInstance ci = (ContainerInstance) userInstance; 128 Element [] propertyElements = DomUtil.getChildElementsByTagName(messagePartElement, "property"); 129 for (int i = 0; i < propertyElements.length; ++i) { 130 String componentId = propertyElements[i].getAttribute("component-id"); 131 Component component = ci.getComponentByElementId(componentId); 132 if (component == null) { 133 continue; 138 } 139 ComponentSynchronizePeer syncPeer = SynchronizePeerFactory.getPeerForComponent(component.getClass()); 140 if (!(syncPeer instanceof PropertyUpdateProcessor)) { 141 throw new IllegalStateException ("Target peer is not an PropertyUpdateProcessor."); 142 } 143 ((PropertyUpdateProcessor) syncPeer).processPropertyUpdate(ci, component, propertyElements[i]); 144 } 145 } 146 }; 147 148 152 private ClientMessagePartProcessor actionProcessor = new ClientMessagePartProcessor() { 153 154 157 public String getName() { 158 return "EchoAction"; 159 } 160 161 165 public void process(UserInstance userInstance, Element messagePartElement) { 166 ContainerInstance ci = (ContainerInstance) userInstance; 167 Element actionElement = DomUtil.getChildElementByTagName(messagePartElement, "action"); 168 String componentId = actionElement.getAttribute("component-id"); 169 Component component = ci.getComponentByElementId(componentId); 170 if (component == null) { 171 return; 176 } 177 ComponentSynchronizePeer syncPeer = SynchronizePeerFactory.getPeerForComponent(component.getClass()); 178 if (!(syncPeer instanceof ActionProcessor)) { 179 throw new IllegalStateException ("Target peer is not an ActionProcessor."); 180 } 181 ((ActionProcessor) syncPeer).processAction(ci, component, actionElement); 182 } 183 }; 184 185 189 private ContainerSynchronizeService() { 190 super(); 191 registerClientMessagePartProcessor(propertyUpdateProcessor); 192 registerClientMessagePartProcessor(actionProcessor); 193 } 194 195 208 private void disposeComponents(RenderContext rc, ServerComponentUpdate componentUpdate, 209 Component[] disposedComponents) { 210 ContainerInstance ci = rc.getContainerInstance(); 211 for (int i = 0; i < disposedComponents.length; ++i) { 212 ComponentSynchronizePeer disposedSyncPeer = SynchronizePeerFactory.getPeerForComponent( 213 disposedComponents[i].getClass()); 214 disposedSyncPeer.renderDispose(rc, componentUpdate, disposedComponents[i]); 215 ci.removeRenderState(disposedComponents[i]); 216 } 217 } 218 219 231 private void disposeReplacedDescendants(RenderContext rc, ServerComponentUpdate update, Component parent) { 232 Component[] replacedComponents = parent.getVisibleComponents(); 233 boolean isRoot = parent == update.getParent(); 234 for (int i = 0; i < replacedComponents.length; ++i) { 235 if (isRoot && update.hasAddedChild(replacedComponents[i])) { 237 continue; 240 } 241 242 disposeReplacedDescendants(rc, update, replacedComponents[i]); 244 245 ComponentSynchronizePeer syncPeer = SynchronizePeerFactory.getPeerForComponent(replacedComponents[i].getClass()); 247 syncPeer.renderDispose(rc, update, replacedComponents[i]); 248 } 249 } 250 251 262 private boolean isRendered(ContainerInstance ci, Component component) { 263 Component parent = component.getParent(); 264 if (parent == null) { 265 return true; 266 } 267 ComponentSynchronizePeer syncPeer = SynchronizePeerFactory.getPeerForComponent(parent.getClass()); 268 if (syncPeer instanceof LazyRenderContainer) { 269 boolean rendered = ((LazyRenderContainer) syncPeer).isRendered(ci, parent, component); 270 if (!rendered) { 271 return false; 272 } 273 } 274 return isRendered(ci, parent); 275 } 276 277 286 private void processClientFocusedComponent(RenderContext rc, Document clientMessageDocument) { 287 if (clientMessageDocument.getDocumentElement().hasAttribute("focus")) { 288 String focusedComponentId = clientMessageDocument.getDocumentElement().getAttribute("focus"); 289 Component component = null; 290 if (focusedComponentId.length() > 2) { 291 component = rc.getContainerInstance().getComponentByElementId(focusedComponentId); 293 } 294 ApplicationInstance applicationInstance = rc.getContainerInstance().getApplicationInstance(); 295 applicationInstance.getUpdateManager().getClientUpdateManager().setApplicationProperty( 296 ApplicationInstance.FOCUSED_COMPONENT_CHANGED_PROPERTY, component); 297 } 298 } 299 300 306 private void processInvalidTransaction(RenderContext rc) { 307 WindowUpdate.renderReload(rc.getServerMessage()); 308 } 309 310 315 private void processQueuedCommands(RenderContext rc) { 316 ServerUpdateManager serverUpdateManager = rc.getContainerInstance().getUpdateManager().getServerUpdateManager(); 317 Command[] commands = serverUpdateManager.getCommands(); 318 for (int i = 0; i < commands.length; i++) { 319 CommandSynchronizePeer peer = SynchronizePeerFactory.getPeerForCommand(commands[i].getClass()); 320 peer.render(rc, commands[i]); 321 } 322 } 323 324 330 private void processServerUpdates(RenderContext rc) { 331 ContainerInstance ci = rc.getContainerInstance(); 332 UpdateManager updateManager = ci.getUpdateManager(); 333 ServerUpdateManager serverUpdateManager = updateManager.getServerUpdateManager(); 334 ServerComponentUpdate[] componentUpdates = updateManager.getServerUpdateManager().getComponentUpdates(); 335 336 if (serverUpdateManager.isFullRefreshRequired()) { 337 Window window = rc.getContainerInstance().getApplicationInstance().getDefaultWindow(); 338 ServerComponentUpdate fullRefreshUpdate = componentUpdates[0]; 339 340 Component[] removedDescendants = fullRefreshUpdate.getRemovedDescendants(); 342 disposeComponents(rc, fullRefreshUpdate, removedDescendants); 343 344 RootSynchronizePeer rootSyncPeer 346 = (RootSynchronizePeer) SynchronizePeerFactory.getPeerForComponent(window.getClass()); 347 rootSyncPeer.renderRefresh(rc, fullRefreshUpdate, window); 348 349 setRootLayoutDirection(rc); 350 } else { 351 for (int i = 0; i < componentUpdates.length; ++i) { 354 if (!isRendered(ci, componentUpdates[i].getParent())) { 355 componentUpdates[i] = null; 356 } 357 } 358 359 Set fullyReplacedHierarchies = new HashSet (); 362 363 for (int i = 0; i < componentUpdates.length; ++i) { 364 if (componentUpdates[i] == null) { 365 continue; 367 } 368 369 Component[] removedChildren = componentUpdates[i].getRemovedChildren(); 371 disposeComponents(rc, componentUpdates[i], removedChildren); 372 373 Component[] removedDescendants = componentUpdates[i].getRemovedDescendants(); 375 disposeComponents(rc, componentUpdates[i], removedDescendants); 376 377 Component parentComponent = componentUpdates[i].getParent(); 379 if (!isAncestor(fullyReplacedHierarchies, parentComponent)) { 380 ComponentSynchronizePeer syncPeer = SynchronizePeerFactory.getPeerForComponent(parentComponent.getClass()); 383 String targetId; 384 if (parentComponent.getParent() == null) { 385 targetId = null; 386 } else { 387 ComponentSynchronizePeer parentSyncPeer 388 = SynchronizePeerFactory.getPeerForComponent(parentComponent.getParent().getClass()); 389 targetId = parentSyncPeer.getContainerId(parentComponent); 390 } 391 boolean fullReplacement = syncPeer.renderUpdate(rc, componentUpdates[i], targetId); 392 if (fullReplacement) { 393 disposeReplacedDescendants(rc, componentUpdates[i], parentComponent); 396 fullyReplacedHierarchies.add(parentComponent); 397 } 398 } 399 } 400 } 401 } 402 403 407 protected ServerMessage renderInit(Connection conn, Document clientMessageDocument) { 408 ServerMessage serverMessage = new ServerMessage(); 409 RenderContext rc = new RenderContextImpl(conn, serverMessage); 410 ContainerInstance containerInstance = rc.getContainerInstance(); 411 try { 412 serverMessage.addLibrary(WEB_CONTAINER_SERVICE.getId()); 413 414 processClientMessage(conn, clientMessageDocument); 415 416 if (!containerInstance.isInitialized()) { 417 containerInstance.init(conn); 418 } 419 420 ApplicationInstance applicationInstance = rc.getContainerInstance().getApplicationInstance(); 421 ApplicationInstance.setActive(applicationInstance); 422 423 Window window = applicationInstance.getDefaultWindow(); 424 425 ServerComponentUpdate componentUpdate = new ServerComponentUpdate(window); 426 ComponentSynchronizePeer syncPeer = SynchronizePeerFactory.getPeerForComponent(window.getClass()); 427 ((WindowPeer) syncPeer).renderRefresh(rc, componentUpdate, window); 428 429 setAsynchronousMonitorInterval(rc); 431 setFocus(rc, true); 432 setModalContextRootId(rc); 433 setRootLayoutDirection(rc); 434 435 processQueuedCommands(rc); 436 437 applicationInstance.getUpdateManager().purge(); 438 439 return serverMessage; 440 } finally { 441 ApplicationInstance.setActive(null); 442 } 443 } 444 445 449 protected ServerMessage renderUpdate(Connection conn, Document clientMessageDocument) { 450 ServerMessage serverMessage = new ServerMessage(); 451 RenderContext rc = new RenderContextImpl(conn, serverMessage); 452 453 ContainerInstance ci = rc.getContainerInstance(); 454 ApplicationInstance applicationInstance = ci.getApplicationInstance(); 455 456 try { 457 if (!validateTransactionId(ci, clientMessageDocument)) { 458 processInvalidTransaction(rc); 459 return serverMessage; 460 } 461 462 ApplicationInstance.setActive(applicationInstance); 464 465 UpdateManager updateManager = applicationInstance.getUpdateManager(); 466 467 processClientFocusedComponent(rc, clientMessageDocument); 468 469 processClientMessage(conn, clientMessageDocument); 471 472 updateManager.processClientUpdates(); 473 474 processServerUpdates(rc); 476 477 setAsynchronousMonitorInterval(rc); 478 setFocus(rc, false); 479 setModalContextRootId(rc); 480 481 processQueuedCommands(rc); 482 483 updateManager.purge(); 484 485 return serverMessage; 486 } finally { 487 ApplicationInstance.setActive(null); 489 } 490 } 491 492 497 private void setAsynchronousMonitorInterval(RenderContext rc) { 498 boolean hasTaskQueues = rc.getContainerInstance().getApplicationInstance().hasTaskQueues(); 499 if (hasTaskQueues) { 500 int interval = rc.getContainerInstance().getCallbackInterval(); 501 rc.getServerMessage().setAsynchronousMonitorInterval(interval); 502 } else { 503 rc.getServerMessage().setAsynchronousMonitorInterval(-1); 504 } 505 } 506 507 516 private void setFocus(RenderContext rc, boolean initial) { 517 ApplicationInstance applicationInstance = rc.getContainerInstance().getApplicationInstance(); 518 Component focusedComponent = null; 519 if (initial) { 520 focusedComponent = applicationInstance.getFocusedComponent(); 521 } else { 522 ServerUpdateManager serverUpdateManager = applicationInstance.getUpdateManager().getServerUpdateManager(); 523 PropertyUpdate focusUpdate = 524 serverUpdateManager.getApplicationPropertyUpdate(ApplicationInstance.FOCUSED_COMPONENT_CHANGED_PROPERTY); 525 if (focusUpdate != null) { 526 focusedComponent = (Component) focusUpdate.getNewValue(); 527 } 528 } 529 530 if (focusedComponent != null) { 531 ComponentSynchronizePeer componentSyncPeer 532 = SynchronizePeerFactory.getPeerForComponent(focusedComponent.getClass()); 533 if (componentSyncPeer instanceof FocusSupport) { 534 ((FocusSupport) componentSyncPeer).renderSetFocus(rc, focusedComponent); 535 } 536 } 537 } 538 539 545 private void setModalContextRootId(RenderContext rc) { 546 ApplicationInstance applicationInstance = rc.getContainerInstance().getApplicationInstance(); 547 Component modalContextRoot = applicationInstance.getModalContextRoot(); 548 if (modalContextRoot == null) { 549 rc.getServerMessage().setModalContextRootId(null); 550 } else { 551 rc.getServerMessage().setModalContextRootId(ContainerInstance.getElementId(modalContextRoot)); 552 } 553 } 554 555 561 private void setRootLayoutDirection(RenderContext rc) { 562 ApplicationInstance applicationInstance = rc.getContainerInstance().getApplicationInstance(); 563 rc.getServerMessage().setRootLayoutDirection(applicationInstance.getLayoutDirection().isLeftToRight() 564 ? ServerMessage.LEFT_TO_RIGHT : ServerMessage.RIGHT_TO_LEFT); 565 } 566 567 574 private boolean validateTransactionId(ContainerInstance containerInstance, Document clientMessageDocument) { 575 try { 576 long clientTransactionId = Long.parseLong(clientMessageDocument.getDocumentElement().getAttribute("trans-id")); 577 return containerInstance.getCurrentTransactionId() == clientTransactionId; 578 } catch (NumberFormatException ex) { 579 return true; 582 } 583 } 584 } 585 | Popular Tags |