Logo

 

 

 

 

 

ItsNat

Reference Manual

v1.4

Doc. version 1.0

Sept. 16, 2015

 

 

 

 

 

 

 

 

© 2007-Present  Jose María Arranz Santamaría

(Innowhere Software)

  

 


 

Table of contents

LEGAL.. 8

1. INTRODUCTION.. 10

1.1      THE AJAX ERA: REVOLUTION AND NIGTHMARE.. 10

1.2      WHY ANOTHER (AJAX) FRAMEWORK? CURRENT SCENARIO.. 10

1.2.1       JavaScript centric. 10

1.2.2       Server centric fully based in custom tags with JavaScript/HTML generation. 11

1.2.3       View code and view control code tightly coupled. 11

1.2.4       Too much XML and XML-Java bindings, too much declarative programming. 12

1.2.5       No API reuse, all is new again and again. 12

1.2.6       AJAX introduced artificially. 13

1.3      ITSNAT: RETURNING TO THE ROOTS IN THE AJAX ERA.. 13

1.3.1       AJAX from scratch. 13

1.3.2       Pure W3C DOM.. 14

1.3.3       The view: no JSP, no XML, no custom tags, only pure HTML with no logic. 14

1.3.4       Event system: pure W3C DOM Events through AJAX/SCRIPT. 14

1.3.5       Multiple remote views! 15

1.3.6       No XML, no declarative programming, only pure Java and Java IoC.. 15

1.3.7       Custom JavaScript coded in the server. 16

1.3.8       “Smart” DOM memory caching and disconnected nodes to save memory. 16

1.3.9       Test the view in the server! 16

1.3.10    Pattern based view manipulation using DOM utilities. 17

1.3.11    Layering versus replacing. Minimalist API 20

1.3.12    COMET without special servers. 20

1.3.13    A non-intrusive component system.. 20

1.3.14    Component system reusing Swing when possible. 22

1.3.15    User defined components, a child’s game ….. 22

1.3.16    HTML 5 support 22

1.3.17    Beyond (X)HTML: SVG and XUL and embedding options. 22

1.3.18    Beyond X/HTML: XML. 23

1.3.19    Disabled Events and Disabled JavaScript modes. 23

1.3.20    Remote Templates. 24

1.3.21    Extreme mashups. 24

1.3.22    One Web: AJAX everywhere including in your mobile browser. 24

1.3.23    Single Page Interface Stateless Mode!!! 24

1.3.24    Single Page Interface SEO compatible!! 24

1.3.25    Why “ItsNat” name? And what ItsNat is not 25

2. CONSIDERATIONS. 27

2.1      DOCUMENT SCOPE.. 27

2.2      DOCUMENT CONVENTIONS. 27

2.3      LICENSE.. 27

2.4      COPYRIGHTS. 27

2.5      REQUIRED DEVELOPER TECHNICAL SKILLS. 27

2.6      TECHNICAL REQUIREMENTS, LIMITATIONS AND DEPENDENCIES. 28

2.6.1       Browsers supported. 28

2.6.2       External dependencies. 29

2.6.3       Session management (stateful applications) 30

2.6.4       Google Application Engine support 32

3. INSTALLATION.. 35

3.1      ITSNAT DISTRIBUTION.. 35

3.2      WHAT DOES ANY NEW JAVA WEB APPLICATION NEED?. 36

4. ITSNAT ARCHITECTURE.. 38

4.1      PURE INTERFACE/IMPLEMENTATION PATTERN.. 38

4.2      LAYERED ARCHITECTURE.. 38

4.3      COMPONENT SYSTEM “INSPIRED” IN SWING.. 38

4.4      MODULES/PACKAGES. 39

4.4.1       Core. 39

4.4.2       Components. 40

4.5      SECURITY AND PRIVACY.. 40

4.5.1       Security is inherent in The Browser Is The Server approach. 40

4.5.2       Security and client identification. 41

4.5.3       Privacy. 41

4.6      PRODUCTIVITY WITH CLASS AUTORELOADING BUILT-IN.. 41

4.6.1       What type of code can be reloaded?. 42

4.6.2       Configuration example. 43

5. DEVELOPMENT LIFECYCLE.. 47

5.1      A CORE BASED WEB APPLICATION.. 47

5.1.1       Create a new servlet 47

5.1.2       Configuring global behavior (global options/configuration) 48

5.1.3       Designing the page template. 54

5.1.4       Registering the page template. 55

5.1.5       Testing the template with a link or URL. 55

5.1.6       Adding behavior. 56

5.2      A COMPONENT BASED WEB APPLICATION.. 59

5.2.1       Designing the template. 60

5.2.2       Registering the template. 60

6. CORE MODULE FEATURES. 65

6.1      DHTML ON THE SERVER.. 65

6.1.1       Text nodes. 65

6.2      DOM EVENT LISTENERS. 65

6.2.1       Communication modes for events. 66

6.2.2       Extra parameters. 67

6.2.3       Custom pre-send JavaScript code. 68

6.2.4       Event timeout 69

6.2.5       Load and unload events. 69

6.2.6       Key events. 69

6.2.7       Global event listeners. 70

6.2.8       Chain control of event listeners. 71

6.2.9       Detection of session or page lost with global event listeners. 72

6.3      REMOTE VS INTERNAL DOM NODE.. 73

6.4      REMOTE DOM MUTATION EVENT LISTENERS. 74

6.5      CROSS-PLATFORM CLIENT TO SERVER SYNCHRONIZATION.. 76

6.5.1       Attribute synchronization. 77

6.5.2       Node inner synchronization. 78

6.5.3       Complete node synchronization. 79

6.5.4       Property synchronization. 79

6.6      REMOTE CONTINUE EVENT LISTENERS. 80

6.7      REMOTE USER DEFINED EVENT LISTENERS. 81

6.8      TIMERS. 82

6.9      REMOTE ASYNCHRONOUS TASKS. 83

6.10        COMET.. 84

6.11        STRING TO DOM CONVERSION.. 87

6.12        MARKUP FRAGMENTS. 87

6.12.1    HTML/XHTML fragments. 87

6.12.2    SVG and XUL fragments. 88

6.12.3    XML fragments. 88

6.12.4    Static includes. 89

6.12.5    Dynamic include. 90

6.13        DOM UTILITIES TO TRAVERSE AND CREATE DOM ELEMENTS. 91

6.14        FREE ELEMENT LISTS. 92

6.15        FREE ELEMENT TABLES. 94

6.16        DOM RENDERERS. 95

6.17        PATTERN BASED ELEMENT LABELS. 98

6.18        PATTERN BASED ELEMENT LISTS. 99

6.18.1    Using custom renderers. 101

6.18.2    Using custom structures. 102

6.19        PATTERN BASED ELEMENT TABLES. 104

6.19.1    Using custom renderers. 105

6.19.2    Using custom structures. 106

6.19.3    Tables without <table> (free tables) 108

6.19.4    Tables and “UsePatternMarkupToRender” feature. 109

6.20        PATTERN BASED ELEMENT TREES. 109

6.20.1    Trees with non-removable root 113

6.20.2    Rootless. 113

6.20.3    Using custom renderer and structure. 114

6.20.4    Tree-Tables. 115

6.20.5    Trees and “UsePatternMarkupToRender” feature. 117

6.21        VARIABLE RESOLVER.. 117

6.21.1    Variables and cache. 121

6.21.2    Using variable resolvers and UsePatternMarkupToRender feature. 121

6.22        W3C ELEMENTCSSINLINESTYLE IMPLEMENTATION.. 122

6.23        SAVING SERVER MEMORY: DISCONNECTED NODES. 124

6.23.1    When to disconnect nodes. 125

6.23.2    Drawbacks of disconnected nodes feature. 125

6.24        REMOTE VIEW/CONTROL (A.K.A. ATTACHED CLIENT). 126

6.24.1    More about the request phase and how to ask permission to user. 131

6.24.2    Controlling other users/sessions. 132

6.24.3    Comet limitations. 134

6.24.4    Document not found detection. 134

6.24.5    Session expired or web application reload detection. 135

6.24.6    Implications of full remote control 136

6.25        EXTREME MASHUPS (A.K.A. ATTACHED SERVER). 137

6.25.1    Pages served with XHTML MIME, SVG and XUL. 141

6.25.2    Security concerns. 142

6.25.3    Session Replication Capable and Google App Engine support 142

6.26        REMOTE TEMPLATES. 142

6.27        JAVASCRIPT GENERATION UTILITIES. 147

6.28        EVENT MONITORS IN CLIENT.. 148

6.29        EVENTS FIRED BY THE SERVER (SERVER-SENT EVENTS). 150

6.29.1    Events sent to the browser simulating user actions. 150

6.29.2    Events directly dispatched to the server DOM tree. 153

6.29.3    More about testing. 154

6.29.4    Bookmarking and search engines. 154

6.30        FAST AND SLOW LOADING MODES. 155

6.30.1    Fast mode. 155

6.30.2    Slow mode. 156

6.30.3    How to select the most appropriated mode. 156

6.30.4    Single Page Interface, Fast mode and SEO Compatibility. 156

6.31        GLOBAL LOAD REQUEST PROCESSING.. 156

6.31.1    Detection of template not found with the specified document name. 157

6.31.2    Not standard page loading (custom requests) 158

6.31.3    Pretty URLs. 158

6.32        THREADING.. 159

6.33        REFERRERS. 160

6.33.1    Referrer “pull”. 160

6.33.2    Referrer “push”. 161

6.34        DISABLED EVENTS MODE.. 162

6.35        DISABLED JAVASCRIPT MODE.. 162

6.36        EXCEPTIONS. 162

6.37        SVG, XUL AND NON-XHTML NAMESPACES. 162

6.37.1    SVG support in browsers. 163

6.37.2    SVG support in Internet Explorer 8. 163

6.37.3    SVG embedded in X/HTML using iframe, object and embed. 164

6.37.4    SVG embedded inline in X/HTML and browsers with native support 165

6.37.5    SVG embedded inline in X/HTML, Internet Explorer 8 and Adobe SVG.. 166

6.37.6    SVG embedded inline in X/HTML processed by SVGWeb (MSIE 8) 170

6.37.7    SVG documents loaded by the ItsNat Batik applet 177

6.37.8    Pure XUL. 179

6.37.9    Embedding inline XHTML in SVG and XUL. 179

6.37.10      Non-XHTML markup in X/HTML and text/html MIME. 180

6.38        IFRAME/OBJECT/EMBED/APPLET AUTO-BINDING.. 180

6.38.1    The case of <embed> elements. 182

6.38.2    The case of <applet> elements. 182

6.38.3    Example. 183

6.38.4    Dynamic insertion and URL change. 188

6.38.5    Auto-binding in SVG and XUL documents. 189

6.38.6    Auto-binding and Remote View/Control 189

6.39        XML GENERATION.. 189

6.39.1    XML fragments. 191

6.40        BROWSER ISSUES. 192

6.40.1    Unload events are not ever fired. 192

6.40.2    Pages are not reloaded from server using back and forward buttons. 193

6.40.3    Form auto-fill and user actions while the page is loading. 194

6.40.4    XMLHttpRequest only asynchronous in some browsers. 194

6.40.5    Old modes and Quirks Mode in Internet Explorer v9. 194

6.40.6    Other issues. 195

6.41        EXTERNAL JAVASCRIPT LIBRARIES AND BROWSER EXTENSIONS. 195

6.41.1    Tolerance to DOM modifications only in client in some locations. 195

6.41.2    Tolerance to DOM modifications only in client in other locations. 196

6.41.3    Tolerance to modifications of attributes. 197

6.41.4    Conditional comments in MSIE. 197

7. COMPONENTS. 198

7.1      OVERVIEW... 198

7.2      CLASSIFICATIONS. 199

7.2.1       By data model 199

7.2.2       By fixed based or free DOM elements. 199

7.3      NAME CONVENTIONS. 199

7.3.1       HTML components. 199

7.3.2       Free components. 200

7.3.3       Non-HTML and non-Free base interfaces. 200

7.3.4       Other. 200

7.4      LIFE CYCLE.. 201

7.4.1       Creation. 201

7.4.2       Destruction. 202

7.5      DOM EVENTS. 203

7.6      BUTTONS. 203

7.6.1       Normal Buttons. 204

7.6.2       Toggle Buttons. 206

7.6.3       Buttons with Label 210

7.7      TEXT BASED COMPONENTS. 210

7.7.1       Input File component 212

7.7.2       Input Hidden component 212

7.7.3       Use of keyup and keydown events. 212

7.7.4       Use of keypress events. 213

7.7.5       Input Text Formatted component 213

7.7.6       Text Area components. 216

7.8      LABELS. 216

7.8.1       User defined editors. 218

7.8.2       User defined renderers. 223

7.8.3       Labels with non-HTML elements. 224

7.9      LISTS. 224

7.9.1       Combo Boxes. 224

7.9.2       Lists with multiple selected items. 228

7.9.3       Free lists. 230

7.9.4       User defined renderers and editors. 232

7.9.5       User defined structures. 233

7.9.6       Free lists and combos with non-HTML elements. 234

7.10        TABLES. 234

7.10.1    Table header support 238

7.10.2    Free tables. 238

7.10.3    User defined renderers and editors. 239

7.10.4    User defined structures. 241

7.10.5    Free tables with non-HTML elements. 241

7.11        TREES. 242

7.11.1    Trees with <table> based nodes. 247

7.11.2    Rootless. 248

7.11.3    Tree-Tables. 249

7.11.4    User defined renderers and editors. 250

7.11.5    User defined structures. 251

7.11.6    Direct factory method. 252

7.11.7    Free trees with non-HTML elements. 252

7.12        FORMS. 252

7.13        INCLUDES. 253

7.14        IFRAMES FOR FILE UPLOADING.. 255

7.15        MODAL LAYERS. 258

7.15.1    Browser issues. 260

7.15.2    Detection of unexpected events received by hidden elements. 261

7.15.3    Modal layers in SVG.. 262

7.15.4    Modal Layers in XUL. 262

7.15.5    Clean Below mode (Clean Layers) 262

7.15.6    Artifacts and attributes. 263

7.16        USER DEFINED COMPONENTS. 264

7.16.1    A simple login component 264

7.16.2    The same login component based on simple custom tags and isolated on a jar. 267

7.17        AUTOMATIC COMPONENT BUILD.. 268

7.17.1    HTML form elements. 269

7.17.2    HTML elements with a default associated component 270

7.17.3    Free elements. 270

7.17.4    Specifying a user defined structure using markup and artifacts. 270

7.17.5    Other configuration parameters defined in markup or as artifacts. 271

7.17.6    Removing and disposing components automatically. 271

7.17.7    Excluding nodes of automatic component creation. 271

7.17.8    Fully automatic component creation (template level configuration) 272

7.18        MARKUP DRIVEN MODE IN FORM BASED NODES. 272

7.18.1    Overview.. 272

7.18.2    Components with markup driven mode feature. 273

7.18.3    Setting up components in markup driven mode. 273

7.19        DISABLED EVENTS MODE AND COMPONENTES. 274

7.20        DISABLED JAVASCRIPT MODE AND COMPONENTES. 274

7.21        XML AND COMPONENTS. 275

7.22        COMPONENTS IN MOBILE DEVICES/BROWSERS. 275

7.22.1    Selection uses keyboard mode. 275

7.22.2    Joystick mode. 276

8. STATELESS MODE.. 277

8.1      INTRODUCTION.. 277

8.2      DEVELOPMENT LIFECYCLE AND EXAMPLE.. 277

8.2.1       Development lifecycle. 277

8.2.2       Stateless example. 278

8.2.3       The global ItsNatServletRequestListener and the second opportunity. 286

8.2.4       The global EventListener and the custom stateless events. 288

8.2.5       Conclusion. 289

 

LEGAL

Copyright 2007-2013 Innowhere Software a professional service of Jose María Arranz Santamaría

Author: Jose María Arranz Santamaría

 

NOTICE: This Document is protected by copyright. Except as provided under the following license, no part of the Document may be reproduced in any form by any means without the prior written authorization of Innowhere Software ("Innowhere"). Any use of the Document and the information described therein will be governed by the terms and conditions of this Agreement. Subject to the terms and conditions of this license, Innowhere hereby grants you a fully-paid, non-exclusive, non-transferable, limited license (without the right to sublicense) under Innowhere's intellectual property rights to review the Document only for the purposes of evaluation or legal use of ItsNat. This license includes the right to discuss the Document (including the right to provide limited excerpts of text to the extent relevant to the point[s] under discussion) with other licensees (under this or a substantially similar version of this Agreement) of the Document. Other than this limited license, you acquire no right, title or interest in or to the Document or any other Innowhere intellectual property, and the Document may only be used in accordance with the license terms set forth herein. This license will expire on the finish of the acquired ItsNat product license. In addition, this license will terminate immediately without notice from Innowhere if you fail to comply with any provision of this license. Upon termination, you must cease use of or destroy the Document.

 

TRADEMARKS: No right, title, or interest in or to any trademarks, service marks, or trade names of Innowhere, Innowhere's licensors or Document author is granted hereunder.

 

DISCLAIMER OF WARRANTIES: THE DOCUMENT IS PROVIDED "AS IS" AND MAY CONTAIN DEFECTS OR DEFICIENCIES WHICH CANNOT OR WILL NOT BE CORRECTED BY Innowhere. Innowhere MAKES NO REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT THAT THE CONTENTS OF THE DOCUMENT ARE SUITABLE FOR ANY PURPOSE OR THAT ANY PRACTICE OR IMPLEMENTATION OF SUCH CONTENTS WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADE SECRETS OR OTHER RIGHTS.

 

THE DOCUMENT COULD INCLUDE TECHNICAL INACCURACIES OR TYPOGRAPHICAL ERRORS. CHANGES ARE PERIODICALLY ADDED TO THE INFORMATION THEREIN; THESE CHANGES WILL BE INCORPORATED INTO NEW VERSIONS OF THE DOCUMENT, IF ANY. Innowhere MAY MAKE IMPROVEMENTS AND/OR CHANGES TO THE PRODUCT(S) AND/OR THE PROGRAM(S) DESCRIBED IN THE DOCUMENT AT ANY TIME. ANY USE OF SUCH CHANGES IN THE DOCUMENT WILL BE GOVERNED BY THE THEN-CURRENT LICENSE FOR THE APPLICABLE VERSION OF THE DOCUMENT.

 

LIMITATION OF LIABILITY: TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT WILL

Innowhere OR ITS LICENSORS BE LIABLE FOR ANY DAMAGES, INCLUDING WITHOUT LIMITATION, LOST REVENUE, PROFITS OR DATA, OR FOR SPECIAL, INDIRECT, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF OR RELATED TO ANY FURNISHING, PRACTICING, MODIFYING OR ANY USE OF THE DOCUMENTATION, EVEN IF Innowhere AND/OR ITS LICENSORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

 

You will hold Innowhere (and its licensors) harmless from any claims based on your use of the Document for any purposes other than the limited right of evaluation or legal use as described above, and from any claims that later versions or releases of any Documentation furnished to you are incompatible with the Documentation provided to you under this license.

 

 

REPORT: You may wish to report any ambiguities, inconsistencies or inaccuracies you may find in connection with your of evaluation or legal use of the Document ("Feedback"). To the extent that you provide Innowhere with any Feedback, you hereby: (i) agree that such Feedback is provided on a non-proprietary and non-confidential basis, and (ii) grant Innowhere a perpetual, nonexclusive, worldwide, fully paid-up, irrevocable license, with the right to sublicense through multiple levels of sublicensees, to incorporate, disclose, and use without limitation the Feedback for any purpose related to the Document and future versions, implementations, and test suites thereof.

 

GENERAL TERMS: Any action related to this Agreement will be governed by the Spanish law and international copyright and intellectual property laws and that unauthorized use may subject you to civil and criminal liability. The Document is subject to Spanish export control laws and may be subject to export or import regulations in other countries. Licensee agrees to comply strictly with all such laws and regulations and acknowledges that it has the responsibility to obtain such licenses to export, re-export or import as may be required after delivery to Licensee. Neither party may assign or otherwise transfer any of its rights or obligations under this Agreement, without the prior written consent of the other party, except that Innowhere may assign this Agreement to an affiliated company. This Agreement is the parties' entire agreement relating to its subject matter. It supersedes all prior or contemporaneous oral or written communications, proposals, conditions, representations and warranties and prevails over any conflicting or additional terms of any quote, order, acknowledgment, or other communication between the parties relating to its subject matter during the term of this Agreement. No modification to this Agreement will be binding, unless in writing and signed by an authorized representative of each party.

 

1. INTRODUCTION

1.1      THE AJAX ERA: REVOLUTION AND NIGTHMARE

We are living in the AJAX (Asynchronous JavaScript And XML) era, there is no doubt, the AJAX approach has revitalized the old DHTML stuff, DHTML is not new of course but today is a real option, the times of Navigator 4.x and Internet Explorer 4.x were definitively back, these browsers hurt seriously the DHTML (Dynamic HTML) promise of highly interactive web sites with almost no reload. Fortunately current browsers like Firefox and WebKit browser (Safari, Chrome, modern Opera...) are highly W3C compliant, Internet Explorer 6/7/8 are "good enough" for AJAX  (fortunately MSIE 9+ are better) and today mobile browsers have the same capabilities as desktop counterparts. DHTML and the XMLHttpRequest approach to communicate with the server, have introduced the web programming world in the AJAX era, the core technology of Web 2.0, achieving the web RIA (Rich Internet Applications) utopia.

But any “new” paradigm ever drives to “real” FUD: Fear Uncertainty Doubt.

Too many new AJAX frameworks are out there, ajaxpatterns.org lists[1] 38 Java AJAX frameworks at the time of writing!

When a senior Java developer tries to enter in the new AJAX world, fear, uncertainty and doubt are perhaps the first feelings. Of course this document is not done to propagate FUD against AJAX, AJAX has come to stay. ItsNat main objective is to combat the reasonably FUD about AJAX: “AJAX without FUD”.

1.2      WHY ANOTHER (AJAX) FRAMEWORK? CURRENT SCENARIO

This is the question (approximately) that Jonathan Locke, the main author of the famous Wicket framework, said to the world[2] some time ago, Jonathan, a “hard core” Swing contributor, was shocked with the Java web frameworks out there, the wheel was not developed as a circle (we may call this The Jonathan Locke Syndrome). ItsNat is the result of similar feelings, ok we already have Wicket, Wicket is nice … but there is another way to build the Java based web… another Java web is possible … another wheel more circular.

Most of the current AJAX Java web frameworks share these characteristics (all characteristics are not applied to every framework of course):

1.2.1       JavaScript centric

The revitalized DHTML technology invites to create new cutting-edge JavaScript libraries, plenty of cool and sophisticated widgets.

This approach has problems like: JavaScript is a weak language, hard to code, test, manage and debug, error prone (no errors are detected in a compilation phase), with a poor and strange object orientation, slow, no explicit types, no refactoring tools, too many browser differences, too much code sent to the client, defensive programming on the server (no confidence in the client side), security issues (the user controls the browser)… In the worst case the JavaScript library generates the HTML (HTML code goes out of developer control and design control).

Many hard core Java web programmers find the JavaScript centric programming a risk and a nightmare.

1.2.2       Server centric fully based in custom tags with JavaScript/HTML generation

A typical server centric approach is to generate the JavaScript code to perform the DHTML behavior, but generating the HTML and JavaScript code too usually using custom tags. JavaScript and HTML are fully managed and controlled by the framework and very hard to customize. This extreme is usually seen in frameworks trying to mimic a desktop application, they are so sophisticated that they do not seem web applications (this may be a compliment and a criticism too).

Many frameworks are competing in this area, competing to offer “filthy rich GUIs”[3] in the web space:

·       The winner => the user experience, “wow is cool”.

·       The loser => the developer, abandoning almost absolutely the control to the framework.

·       Unsolved problem => customization. Most of these amazing widgets/GUIs are very hard to customize beyond the predefined layout. If layout and behavior match your needs ok, if not you have a serious and perhaps unsurpassed problem.

·       The definitive loser => the customer and his “Oh cool, but please change this thing…”, the developer answer “I’m sorry I can’t do it my framework doesn’t do that”. Cool != does the job.

A desktop application appearance can be fully customized because is pixel based but usually is a hard work, this is not necessary because a typical CRUD desktop application has not very much “special effects”.

The web space is fully different, web developers love to fully control the layout and appearance of their web pages; fully control of the HTML code beyond the color change, and fortunately HTML language (and CSS) is not very hard and we have visual tools. Furthermore, advanced web developers like to add some cool visual effects with JavaScript (and CSS). If the HTML/JavaScript pair is not controlled by the developer is very hard to do this stuff.

Conclusion: a <tree> tag may be a dream and a nightmare: too intrusive, too legacy, too closed, too vendor lock in.

1.2.3       View code and view control code tightly coupled

There are tons of template processors including of course JSP, they all share the same idea: special instructions mixed with HTML code: <c:if…> <%if…> #if … different flavours but they are basically the same.

What is the problem? Some kind of view control is unavoidable, isn’t it? Yes of course, but there is no reuse, if the view changes, the view logic must be repeated:

Example (JSTL):

    <c:forEach var="item" items="${sessionScope.cart.items}">

        <td align="right" bgcolor="#ffffff">

            ${item.quantity}

        </td>

    </c:forEach>

 

    ...

 

    <c:forEach var="item" items="${sessionScope.cart.items}">

      <p>

        <b>Quantity:</b> ${item.quantity}

      </p>

    </c:forEach>

What is unnecessarily repeated? Answer: the <c:forEach var=”item”…> statement.

With this approach there is no much “generic view programming”, a clean separation between view code and algorithms applied to the view.

1.2.4       Too much XML and XML-Java bindings, too much declarative programming

XML metaprogramming is a modern trend and perhaps overused, may be valid with page based web sites because the navigation is relatively simple, but in the AJAX world there is no classic (page based) navigation inside the same page[4]. XML metaprogramming is used too to bind view component events to Java handlers and many other types of bindings and commands. This approach is not very productive, makes hard any reuse and is difficult to maintain (no refactoring, no compile time checking). In fact most of typical web frameworks are banishing developers of Object Oriented Programming, because most of the web logic is being coded in XML files and in the form of framework tags and expression languages.

XML based declarative programming is a nice feature for frameworks oriented to tools because Java code has not a fixed structure, but declarative programming is not oriented to developers because is verbose, does not provide reuse (no OOP, too many duplication) and easy “batch configuration” (to apply the same configuration pattern to many elements, only the different element needs a specific configuration).

ItsNat is not oriented to tools like other web frameworks like JSF or Struts, you only need a decent Java editor and optionally a visual HTML editor.

1.2.5       No API reuse, all is new again and again

Usually Java web frameworks reinvent all again and again, developers must learn a new API, and there is no very much reuse between a desktop and a web application sharing the same data model. Some Java web frameworks mimics the Swing API, this may work with quick ports of Swing applications, but most of the Swing API is tightly bound to the desktop programming style, based in pixels. But the web is different, the pixel based approach is wrong or unnecessarily forced and the HTML layout control is completely lost to simulate desktop components.

But in the Swing API there are classes and interfaces not bound to the desktop view/screen: data and selection models and related listeners… almost no Java web framework reuses this API except Swing mimic web frameworks (there is some exception like Wicket trees). May be these Swing models are not perfect, but they are a mature standard and improves the integration with the desktop. ItsNat uses Swing data and selection models to build the typical components.

1.2.6       AJAX introduced artificially

Most of well established component based frameworks were designed in the pre-AJAX era; they have been leveraged to AJAX artificially with hacks and as an extension.

1.3      ITSNAT: RETURNING TO THE ROOTS IN THE AJAX ERA

ItsNat is an AJAX, Component Based, Java Web Application Framework. No news.

One phrase summarizes the ItsNat approach: “The Browser Is The Server” (TBITS). The Java server code deals with the browser as if the browser object model was on the server memory, like a “W3C Java browser”.

The principle behind ItsNat is very simple, the HTML DOM tree is replicated at the server side, exactly is the opposite, the pure W3C HTML DOM tree in server side is replicated in the client browser.

This technique is not fully new, old frameworks like Cocoon and Barracuda used DOM in some way before with no very much success… but we live in the AJAX time, everything has changed.

The incremental page modification fits perfectly well with the “DOM in the server” technique, if the server DOM changes the change is propagated to the client.

In summary: ItsNat simulates a Universal W3C Java Browser in the server. ItsNat can be seen as a Firefox or WebKit in the server using the client browser as the GUI.

1.3.1       AJAX from scratch

AJAX is changing how the web is developed. Classic frameworks are designed around the page navigation. ItsNat is designed with AJAX from scratch, furthermore it does not have very much page navigation facilities because they are going to be outdated or over engineered[5]. An AJAX centric web may be like a desktop application, typical desktop applications have only one frame; in the same way your web application may have only one page! The “Feature Showcase” included on ItsNat distribution is an example of this approach.

Client and server communication is done through AJAX based events, auxiliary SCRIPT elements can be an alternative to AJAX, your application can select the required communication method with a simple configuration option.

1.3.2       Pure W3C DOM

ItsNat maintains a Java W3C DOM document in the server matching the browser DOM document, any change performed on the server DOM is propagated to the client as JavaScript DOM instructions thanks to W3C DOM Mutation Events. JavaScript generated by the framework is adapted to the usual inconsistencies between the specific browser and the W3C standard. If the DOM modification is a response of an AJAX event the generated JavaScript code is small if the DOM modification is small.

Client DOM and server will be in sync driven this synchronization by the server. This synchronization is mandatory for the “dynamic parts” (DOM subtrees willing to be changed on the server), static subtrees (in a server point of view) may change in the client with no problem allowing any kind of DHTML effects (including client DOM modifications) used only in the client. These static and dynamic HTML zones need to be declared.

No strange programming artifacts, only pure Java W3C DOM!

1.3.3       The view: no JSP, no XML, no custom tags, only pure HTML with no logic

Of course an ItsNat generated web page is NOT fully coded with Java DOM. Any page starts with a pure normal HTML page, the template. This page has no custom tags (only a few custom optional attributes and two custom optional tags, comment and include, processed and removed in the server). This page works as a template, where some parts are static and other parts will be changed by the developer using the Java DOM API in the server. Of course this pure HTML file can be designed with your favorite HTML WYSIWYG editor.

When a user invokes an ItsNat page, the framework loads a template and is converted to DOM, and then the developer has the opportunity to adapt the original page to the desired HTML output using Java W3C APIs. The final DOM tree is serialized and sent to the browser as a normal HTML/XHTML page in this load phase. When writing “HTML” we mean any HTML version including HTML 5. Also you can code XHTML using HTML 5 tags and interpret it as HTML X<5 or HTML 5 because text/html MIME is used to send to client.

In summary ItsNat templates contain pure view information, this is a radical (extreme) separation of view and logic (view logic), because developers change the initial view using DOM in Java and this Java code is absolutely separated from the view. These changes are “pushed” to the view with the desired order instead of the typical “pull” and top/down execution model of most of web based frameworks, because templates are “executable” files and work like “imperative programming languages” (JSP as the prominent example)[6].

1.3.4       Event system: pure W3C DOM Events through AJAX/SCRIPT

User events are sent to the server using AJAX (XMLHttpRequest) or auxiliary SCRIPT elements and received as W3C DOM Events[7].

The developer can bind an org.w3c.dom.events.EventListener Java object to any server Java DOM element calling org.w3c.dom.events.EventTarget.addEventListener( String,EventListener,boolean)[8], or ItsNatDocument.addEventListener(…) methods, in fact one of these methods  is called by EventTarget.addEventListener(…) behind the scenes. This listener is registered as a remote listener, ready to receive events from the browser. For instance: if an event listener is registered as a mouse “click” listener of a specific Java DOM element, when the symmetric element in the browser is clicked, the browser event is sent to the server as a W3C DOM Event object, with the currentTarget property set as the Java DOM element “listened”. The approach is similar to W3C Rex specification[9] but no XML is used (a big performance penalty) and using a custom XPath technique. Again the browser events are perceived as “in the server” like a real Java browser. ItsNat provides org.w3c.dom.events.EventTarget.removeEventListener(String,EventListener,boolean)[10] , or ItsNatDocument.removeEventListener(…) methods to unregister remote event listeners.

ItsNat uses an internal and custom XPath (is not a real XPath implementation) to bind browser and server DOM elements. To increase performance (path resolution takes time), two automatic DOM element registries (caches), in the server and in the client, are used behind the scenes where any explicitly used element has a unique (internally generated) id.

1.3.5       Multiple remote views!

If the original DOM tree is on the server, the browser DOM is basically a “clone” of the server tree and if browser events are processed on the server and DOM modifications are sent to the client again… nothing prevents having more than one browser window representing the same server DOM document/page!

In ItsNat a new browser window can be bound to an existing DOM document (page) in server working as a remote viewer of the page of another window/browser/user; the new window loads the current DOM server state.

Of course ItsNat provides a security system to control who access this kind of “spyware” by default the remote view/control feature is not active and authorization is granted per “remote view” request.

ItsNat implementation has two modes:

1)    Read only remote views, when attached clients cannot send events to the server. In this mode ItsNat offers some kind of remote control: remote viewer refreshing is controlled by an optional server listener; this Java listener can do anything including changing the server DOM tree.

2)    Full remote control: attached clients can send events to the server interacting with the same document in server.

Applications… remote supervision, help desk, cooperative applications, “legal” spying, monitoring suspicious behavior, teaching, web based distributed shows etc.

1.3.6       No XML, no declarative programming, only pure Java and Java IoC

ItsNat configuration is fully based in Java, of course some configuration parameters can be put in a user defined XML, or using Spring etc. In fact old Java .properties configuration files are used in ItsNat examples to bind the physical HTML template file paths with logical names used by ItsNat, of course this technique is an example and is optional, ItsNat does not mandate to use any configuration file.

ItsNat uses the IoC (Inversion Of Control) paradigm frequently with the old fashion style: programmatic registering of Java object listeners, the framework calls these listeners when appropriate (when loading a page, when receiving an client event, when a component is created…). In fact there is no logging system, is user election when log and how log, the framework listeners are the join points with the well defined lifecycles of the framework. 

1.3.7       Custom JavaScript coded in the server

When user code changes the DOM tree, this change is automatically converted to JavaScript and sent to the client at the end of the event cycle (and in the load cycle if the page load mode is set as “slow”). Developers can add custom JavaScript code in server code in any time of the server cycle to be sent to client, for instance, to do some animation effect.

1.3.8       “Smart” DOM memory caching and disconnected nodes to save memory

The DOM approach is memory intensive, this is the main complaint about this technique (memory is cheaper and bigger than before but this complaint is valid anyway).

ItsNat uses an automatic customizable DOM caching technique: ItsNat detects if a DOM subtree is not going to change, then the subtree is serialized as text and removed from the tree and registered the text in a cache registry; a text mark is leaved in the tree to remind the removed/cached subtree position. When this part is going to be sent to the client the mark is replaced with the cached text (on load time with the serialized document or into an innerHTML string). Cached subtrees saved as text are saved once per HTML template, all user pages share the same cached serialized subtrees. Of course a developer can declare a markup zone as no cacheable if ItsNat thinks it is static and is not with a special attribute.

ItsNat has a feature called HTML/XML fragments; a fragment is piece of markup to be included in a page/document, a fragment is registered and managed much like a normal page. ItsNat automatically caches fragment subtrees, if a fragment is inserted in a document the cached subtrees are shared (fragment subtrees cached are in memory as text once).

Conclusion: big (static) parts of HTML pages can be cached in memory as text in a per template basis, the memory consumed is not different to any other template based framework including JSP (HTML template code is in memory as string literals).

Another technique to save memory in server is “disconnected nodes”, you can explicitly remove nodes and server but not in client when these server nodes are no longer to be used in server.

Both techniques allow server-centric Single Page Interface and web sites mainly stateless!

1.3.9       Test the view in the server!

As the DOM tree is in the server you can test your markup in the server with Java code.

ItsNat can fire W3C DOM Events and send them to the browser simulating user actions, this technique is called “server-sent events”[11]. These user actions usually are processed by the server again, the test code can check whether the desired behavior is accomplished checking the server DOM tree (testing the view in the server) or new/removed/updated data.

Furthermore W3C DOM Events can be sent optionally to the server DOM directly with no browser interaction!

1.3.10    Pattern based view manipulation using DOM utilities

A joke is a good way to explain this feature; a psychologist interviews us with a “HTML Rorschach’s test”:

Q) What do you see in this HTML fragment?

    <div>

        <p><b>Tiger</b></p>

        <p><b>Lion</b></p>

        <p><b>Giraffe</b></p>

    </div>

A) A list of animals

Q) Good. How would you add a new animal like “Zebra”

A) Very easy:

             …

        <p><b>Zebra</b></p>

    </div>

Q) Fine. What do you see in this fragment?

    <select>

        <option>Tiger</option>

        <option>Lion</option>

        <option>Giraffe</option>

    </select>

A) Again the same list of animals, using a standard <select> based list.

Q) OK. And how to add “Zebra”?

A) Obvious:

             …

        <option>Zebra</option>

    </select>

Q) What is shared?

A) Both are two lists of animals (data model), both are two ways to show the same list, both share the same structure or pattern:

    <parentList>

        <listItem><optElem1>…<optElemN>Item Content

                  </optElemN>…</optElem1></listItem>

        ...

    </parentList>

Q) What are the differences?

A) Tag names are different, one list uses <b> as a decorator or you can see <p><b> as the elements used as the item pattern, in <select> only the <option> element is the pattern. 

Q) Construct the same list with the following structure/pattern:

    <ul>

        <li><b><i>Content</i></b></li>

    </ul>

A) Simple

    <ul>

        <li><b><i>Tiger</i></b></li>

        <li><b><i>Lion</i></b></li>

        <li><b><i>Giraffe</i></b></li>    

        <li><b><i>Zebra</i></b></li>        

    </ul>

 

Q) More difficult, what is this?

 

    <div>

        <span>Root</span>

        <ul>

            <li>

                <span>Child 1</span>

                <ul>

                    <li>

                        <span>Child 1.1</span>

                        <ul/>

                    </li>

                </ul>

            </li>

            <li>

                <span>Child 2</span>

                <ul />

            </li>

        </ul>

    </div>

A) Course: a tree

Q) Add the “Child 1.2” new node

A) A child’s game:

                         …

                <ul>

                    <li>

                        <span>Child 1.1</span>

                        <ul/>

                    </li>

                    <li>

                        <span>Child 1.2</span>

                        <ul/>

                    </li>                   

                </ul>

                         …

Q) More difficult again, what is this?

 

    <div>

        <span>Root</span>

        <table style="margin-left:10px">

            <tbody>

                <tr>

                    <td>

                        <span>Child 1</span>

                        <table style="margin-left:10px">

                            <tbody>

                                <tr>

                                    <td>

                                        <span>Child 1.1</span>

                                        <table style="margin-left:10px">

                                              <tbody/>

                                        </table>

                                    </td>                                   

                                </tr>

                            </tbody>

                        </table>

                    </td>

                </tr>

                <tr>

                    <td>

                        <span>Child 2</span>

                        <table style="margin-left:10px"><tbody/></table>

                    </td> 

                </tr>

            </tbody>

        </table>

    </div>

A) The same tree (same content) with a different layout. I’m boring.

Q) Finally add “Child 1.2”

 

A) Here it is. I’m sleeping, something more?

                               ...

                                <tr>

                                    <td>

                                        <span>Child 1.1</span>

                                        <table style="margin-left:10px">

                                              <tbody/>

                                        </table>

                                    </td>                                   

                                </tr>

                                <tr>

                                    <td>

                                        <span>Child 1.2</span>

                                        <table style="margin-left:10px">

                                              <tbody/>

                                        </table>

                                    </td>                                   

                                </tr>

                               ...

 

Q) No. You showed me you know to distinguish that the concrete view is orthogonal to the concrete data model and several views can share the same structure and can be manipulated using the same pattern based technique.

This is how ItsNat utilities work; ItsNat has pattern based element lists, tables and trees, these utilities (classes) are agnostic with the concrete DOM elements declared in the markup using the pattern based technique (a list must contain an item as pattern, a table a cell, a tree a tree node).  

For instance:

    ItsNatDocument itsNatDoc = ...;

    Document doc = itsNatDoc.getDocument();

    Element parentElem = doc.getElementById("listParentId");

    ElementGroupManager factory = itsNatDoc.getElementGroupManager();

    ElementList elemList = factory.createElementList(parentElem,true);

    elemList.addElement("Tiger");

    elemList.addElement("Lion");

    ...

       

Where listParentId is the id attribute of the parent element of the list, any previous list is valid (<div>, <select>, <ul>…). The ElementList implementation uses a default renderer, this renderer writes the string into the deepest element of the item list pattern (below <b> and <i> if both exists).

1.3.11    Layering versus replacing. Minimalist API

ItsNat is constructed over the old Servlet Specification, over the W3C DOM Level 2 standard, over HTML 4.x/XHTML 1.x/XML 1.x, SVG 1.x or XUL (every standard supported by NekoHTML and Xerces parsers). ItsNat uses layering to extend the functionality when necessary but there is no full replacement, every need already covered by a well established API/standard is not rewritten. For instance ItsNat covers with layers the Servlet infrastructure (e.g. ItsNatServlet, ItsNatServletRequest…), but the original objects can be got when needed, for instance to get the parameters sent to an ItsNat page.

Only very small bunch ItsNat interfaces and W3C DOM APIs are needed to develop complex Single Page Interface web sites fully based on AJAX. Most of ItsNat APIs (DOM utilities, components etc) are optional.

1.3.12    COMET without special servers

ItsNat provides an amazingly simple but powerful COMET[12] solution to push code from server to client without an explicit client request using server push, a kind of “Reverse AJAX”. ItsNat COMET implementation works with any servlet engine.

1.3.13    A non-intrusive component system

ItsNat has two levels: Core and Component levels; the Component level is constructed over the Core but Core has no dependency with Components, in fact developers can construct ItsNat based applications without components.

ItsNat components are the “typical” classes encapsulating and managing the state of a visual element alongside a data model (and usually a selection model) and processing user events.

But the ItsNat approach deeply differs of the typical approach. Again, another “ItsNat-Rorschach’s test”:

Q) What do you see in this HTML fragment?

    <input type="button" value="Click me!" />

A) A button

Q) And this?

    <p>Click me!</p>

A) A button again!

Q) Really?

A) Yes, only changes the appearance

Q) And this fragment?

    Select the color:

     <input type="radio" name="colors" value="Red" />

     <input type="radio" name="colors" value="Green" />   

     <input type="radio" name="colors" value="Blue" />   

A) Three radio buttons to select a color

Q) And this?

    Select the color:

     <p>Red</p>

     <p>Green</p>   

     <p>Blue</p>   

A) The same radio buttons to select a color

Q) Really?

A) Yes, only changes the appearance!

Q) And this fragment?

    <select>

        <option>Option 1</option>

        <option>Option 2</option>

    </select>

A) A single selection list box

Q) And this?

    <div>

        <p>Option 1</p>

        <p>Option 2</p>

    </div> 

A) Of course the same list box! May be with single selection, is unspecified. Something more?

Q) No, it’s absolutely clear for me, you have an ItsNat mind!!

ItsNat components go far beyond the typical form control-Java component: every markup element can be a component!!

ItsNat has buttons, lists, tables and trees, more components will be added, any developer can add new components to the framework as plug-ins.

ItsNat components bind the HTML view with an event model, a data model and a selection model (lists, tables and trees). The framework component system uses the view pattern approach; the developer is free to design the component markup how he or she likes (using the pattern technique), and the concrete data model. ItsNat syncs data model and selection model changes with the view automatically, routes client events to the registered component event listener in the server and syncs form control changes (text introduced in a text box etc) with matched components and related server side DOM elements (for instance, the text box component automatically updates the value attribute of the HTMLInputElement server object when the browser <input type=”text”> control changes).

Furthermore some components associated to form controls can be configured as “markup driven”, in this mode form controls can be fully controlled by DOM, the component API is not needed.

ItsNat has a pluggable user defined structure (layout) system when the used user’s markup structure is not supported by default by the framework (remember, structure != concrete tag names). Developer freedom is one key feature behind ItsNat architecture.

1.3.14    Component system reusing Swing when possible

Why reinvent the wheel if the wheel is already circular, standard, mature and popular? Swing has many classes/interfaces independent of the desktop UI, like data models, selection models and related listeners; furthermore CellEditor and CellEditorListener are UI independent! and of course used by ItsNat.

ItsNat is strongly inspired in the component architecture of Swing, for instance there is an ItsNatTree and an ItsNatTreeUI (and of course uses the Swing’s tree data and selection models including event listeners). But ItsNat does NOT try to fit the web UI (based in markup with built-in layout rules) with the desktop UI (based in pixels), no ItsNat method gets/sets the (x,y) pixel position of a component!

1.3.15    User defined components, a child’s game …

Creating a custom component is so easy as to implement ItsNatComponent and optionally register a CreateItsNatComponentListener listener.

Furthermore, what is a component? In ItsNat a component is an object binding markup with a data model with some kind of behavior depending on events. But if we remove the “data model” part, an even listener bound to a concrete DOM element could be considered a “component” (not in ItsNat sense), so there is no “panel” component in ItsNat, every DOM element can be considered a panel.

1.3.16    HTML 5 support

ItsNat parser and renderer recognize the HTML 5 DOCTYPE declaration (<!DOCTYPE html>) and HTML 5 new tags.

1.3.17    Beyond (X)HTML: SVG and XUL and embedding options

1.3.17.1       SVG support

Maybe you now that FireFox 1.5+, modern WebKit browsers (Safari 3+, Chrome 1.0+,  iPhone 2.1+, BlackBerry JDE 5.0+), Opera (Presto and WebKit) and Internet Explorer 9+ support pure SVG documents and SVG inline into HTML/XHTML. Internet Explorer 8 also supports pure SVG through Adobe SVG Viewer or Savarese Ssrc plugins and a special Applet based on Batik provided by ItsNat, also in Internet Explorer v8 SVG can be inline inside HTML/XHTML pages by using Adobe SVG Viewer and SVGWeb built in ItsNat.

As previously stated ItsNat makes a big effort of supporting SVG in Microsoft Explorer v8.

The most interesting thing is that SVG in any browser support Single Page, that is, it includes AJAX (can emit and receive events) can be attached to components and so on as any other X/HTML element!

ItsNat treats SVG documents as first class citizens with the same features as X/HTML documents. SVG documents have server state, can receive events, have fragments, referrers, COMET, timers, remote control… and components! For instance: a circle list, a pie chart seen as a list, tables and trees with graphic elements… of course they all include data models, selection models, custom structures, renderers…

1.3.17.2       XUL support

XUL[13] is a web based component system included in Gecko browsers like FireFox and Internet Explorer with Savarese Ssrc SVG/XUL plugin (this plugin is basically is FireFox registered as plugin in MSIE). ItsNat supports remote XUL applications in the same way as SVG is supported.

1.3.17.3       Embedding XHTML in SVG and XUL

Embedding XHTML elements in SVG documents[14] is a cutting edge feature of modern browsers; it is very interesting because SVG standard lacks of visual controls like text boxes, selection lists etc.

XUL allows XHTML elements embedded; in this case XHTML is not very useful because XUL can be seen as a richer alternative to XHTML, anyway it works.

ItsNat supports, in a server point of view, embedding XHTML in SVG and XUL documents, furthermore, HTML components can be created and attached to embedded XHTML elements.

1.3.18    Beyond X/HTML: XML

ItsNat can generate XML documents (for instance RDF) with no server state (the server processes the document only in the load phase). ItsNat DOM utilities like lists, tables and trees can be used to create the resulting XML using pattern based techniques, simplifying very much the typical DOM manipulation. XML templates can be used too including node caching (an XML template can have “static” parts). XML documents do not have scripting nor AJAX events but it does not prevent that components can be also used!

1.3.19    Disabled Events and Disabled JavaScript modes

ItsNat is very strongly based on AJAX (or SCRIPT elements) for events, anyway we are conscious AJAX is a relatively new technology and many developers, companies, clients, users etc are not ready to enter in this new era. Notwithstanding direct DOM manipulation at the server, smart cache to gain memory size, DOM cache for quick node path resolution, DOM utilities (renderers, lists, tables, trees) and Swing-like components[15] are worth enough to work with ItsNat in spite of AJAX is missing.

Furthermore, JavaScript can be fully disabled, this is the lowest downgraded mode of ItsNat. This mode is basically the same as disabled events mode but no JavaScript code is sent to the client, this feature allows ItsNat to serve pages to clients with JavaScript disabled. 

1.3.20    Remote Templates

Because templating is based on pure X/HTML, SVG, XUL, XML files, any markup based file may be an ItsNat template. ItsNat supports remote templates, that is, the template may be any remote file pointed by a URL, furthermore, ItsNat provides a user defined way to load the template source, user code can freely load templates from any source and refresh them in a per-request basis, by this way (in extreme) ItsNat can be used as a front end/filter/proxy of any web application.

1.3.21    Extreme mashups

With a simple script located in the end of any web page, this alive page can be attached to an ItsNat server to be fully controlled by an ItsNat based application. Extreme mashups can be used, to enrich any web application for instance to add state and events to old applications.

1.3.22    One Web: AJAX everywhere including in your mobile browser

ItsNat supports only browsers with AJAX, desktop or mobile.

1.3.23    Single Page Interface Stateless Mode!!!

ItsNat normal mode is stateful making use of server memory (and optionally session) to storing in server the browser state, when using multiple symmetric servers sticky sessions are required (unless session replication is enabled).

Since v1.3 ItsNat provides a new mode of working, the “stateless” mode, in stateless mode current browser state can be reconstructed in server and modificated, modifications are sent to the browser as JavaScript as DOM operations as usual, but the “page” loaded in server is not stored in server nor in session, by this way multiple symmetric servers can work together with no need of session replication (anyway user code can make use of session for storing custom data as any conventional web application).

1.3.24    Single Page Interface SEO compatible!!

Thanks to the “fast-load mode” of ItsNat, the same DOM tree is converted to markup in load time and to JavaScript as the result of an AJAX event, by this way a concrete “state” can be the initial page on load time ready to be crawled by web crawlers like Google Search.

Single Page Interface SEO compatibility is possible in stateful and stateless modes of ItsNat!!

1.3.25    Why “ItsNat” name? And what ItsNat is not

ItsNat means “It’s Natural”, because it is a natural way to develop Java web applications: Java centric, pure HTML, pure W3C DOM APIs, nodes and events, non intrusive, HTML layout highly controlled by the developer, Swing inspired/reused, no new templating language, no strange artifacts like custom tags… It’s Natural because basically ItsNat simulates the behavior of a web browser in server, in few words, ItsNat is DHTML on the Server[16].

ItsNat “natural” approach does not try to replace the Java developer work and HTML developer art; ItsNat is a “conservative” technology because it tries not to limit your imagination[17]. Current implementation does not provide obscure, sophisticated, overloaded, black boxed, absolute position based and highly intrusive UI controls. For instance do your mission critical applications need resizable cells in tables? Most of them do not. These features are cool but they usually require tons of JavaScript code and behavior is not usually the same cross-browser.

Bad news, ItsNat is not for newcomers, is not for developers looking for a drag & drop framework tied to GUI tools, some serious previous knowledge is necessary like W3C DOM and Swing basics if components are used, and of course the framework itself has a learning curve. ItsNat has many interfaces because is highly structured and highly customizable and fully oriented to Java developers not to declarative oriented GUI tools.

The good news: the learning curve is very very flat because only some basic ItsNat interfaces and the W3C DOM Core API are enough to develop complex Single Page Interface AJAX applications.

ItsNat components like buttons, editable labels, text boxes, lists, tables and trees can be used “out of the box” and easily bound to your markup code, but some work is up to you, for instance how to decorate a selected element (to change background color, position, resize…), how to expand/collapse a tree node (display or not display) etc. Most of the time this code will be in the server using pure Java and DOM and when you find your own “style” this code can be reused again and again because is pure Java, pure DOM usually “tag agnostic”. Do not worry about this, ItsNat provides “already made” examples like the “Feature showcase”; you can reuse and modify these examples with no limitation.

ItsNat is a highly customizable framework, we can call it like a meta-framework: any minor piece of markup can be modified, components are open and customizable with custom layouts, custom data and selection models (by default ItsNat uses Swing default models), custom renderers, custom layout structures and so on. In fact a hook allows plugging new user defined components. Furthermore, the framework can be fully extended or replaced because ItsNat architecture is based on interfaces extensively (in fact, ItsNat class is almost the unique public class, and this class is abstract[18]).

ItsNat is focused to developers who want extensive use of AJAX and in the same time do not want to lose control of their work.

 

2. CONSIDERATIONS

2.1      DOCUMENT SCOPE

This manual makes an extensive documentation of ItsNat features but must be complemented with the API documentation in javadoc format.

2.2      DOCUMENT CONVENTIONS

A Verdana font is used to describe the ItsNat architecture.

A Courier New font is used for source code (Java and markup code).

2.3      LICENSE

ItsNat is Lesser General Public License Version 3 licensed to third parties (LGPL v3). LGPL v3 license allows commercial closed source derivatives based on ItsNat. Any change done to ItsNat itself must be released as source code under LGPL v3 to end users.

If LGPL v3 is not for you alternative commercial licensing exists.

2.4      COPYRIGHTS

Jose María Arranz Santamaría is the author of ItsNat source code, documentation and examples. ItsNat intellectual property and exploitation rights are owned by Jose María Arranz Santamaría. Innowhere Software, a professional service of Jose María Arranz (former Innowhere Software Services S.L.), grants third party licenses of ItsNat.

The “Feature Showcase” source code (not including the source code of the ItsNat framework provided) and any example in this manual can be used including derivatives without any restriction or fee except you can not claim the original code is owned by you.

2.5      REQUIRED DEVELOPER TECHNICAL SKILLS

ItsNat is based on Java 1.6, W3C DOM Level 2 Core[19]/HTML[20]/Events[21], and Servlet 2.5. A medium knowledge of these API is supposed, especially DOM and Swing. Swing knowledge is optional if ItsNat components are not used.

2.6      TECHNICAL REQUIREMENTS, LIMITATIONS AND DEPENDENCIES

ItsNat is based on Java Standard Edition (Java SE) 1.6 as the minimum configuration (source and binaries), and may compile and run with any upper version without problem.

ItsNat is based on the Servlet specification, no advanced API is used, virtually any Servlet container compatible with Java 1.6 may be valid. ItsNat has been tested with the following servlet containers: Tomcat 6 and 7 and Google App Engine (powered by a custom version of Jetty).

2.6.1       Browsers supported

ItsNat only supports browsers with AJAX support.

ItsNat supports and has been tested with the following desktop browsers:

·       Google Chrome

·       Firefox

·       Microsoft Internet Explorer 8[22] is the only old version still supported

·       Microsoft Internet Explorer 9+ (supported as a W3C browser) including Edge (v12)

·       Opera 12.12+ (WebKit based only)

·       Safari 6.0.5+

Previous versions may work but unsupported.

When Firefox is cited we mean any Gecko based (the web engine of Firefox) browser for instance Mozilla family browsers. Firefox, Safari, Chrome and Opera (Presto and WebKit) and most of mobile browsers are considered “W3C browsers”, MSIE 8 is not a “W3C browser” (their support is poor, for instance, DOM events, namespaces, XHTML etc, MSIE 8 is barely W3C DOM level 2 compliant but not including W3C DOM events), MSIE 9 is very different to previous versions and ItsNat considers internally this browser as a legitimate W3C browser.

Mobile browsers supported (minimum version, previous versions may work):

·       Android 4.0.3+

·       iPhone/iPad/iPod iOS 7.1+

·       Opera Mini (still based on Presto in Opera servers)

·       Opera Mobile (now based on WebKit)

SVG plug-ins (including AJAX) for SVG support in Internet Explorer 8:

·       Adobe SVG Viewer v3[23]

·       Savarese Ssrc[24]. This plugin also provides XUL for MSIE.

·       SVGWeb[25] 2010-02-03 “Lurker Above”

·       Batik Applet[26] v1.7. Batik is packaged as an applet working like a SVG browser specially tuned for ItsNat and is included into the ItsNat.

Previous versions may work but not tested. Of course mobile browsers have some limitations and some ItsNat features are not supported (all browsers listed support AJAX).

Unknown browsers (user agents unknown) are treated as bots and AJAX is automatically disabled. This saves memory because AJAX is used to destroy the document in the server when the page is closed (documents are lost too when the session ends and old documents associated to the same session are automatically closed when a configured number is surpassed).

Web browsers can be classified in two categories:

1.    Support of standards: MSIE 8[27] and W3C based (the rest).

2.    Device type: desktop and mobile.

2.6.2       External dependencies

·         Batik 1.7: Batik is used in ItsNat as the DOM provider. It depends on Xalan 2.6 (and this requires Xerces 2.6).

·         NekoHTML 1.9.12[28]. It depends on Xerces 2.8.1 for markup parsing. Xerces 2.8.1 must be used instead of 2.6.

·         ItsNat Batik Applet. This applet created for ItsNat and based on Batik is optional for rendering SVG in browsers with lack of SVG support like Internet Explorer 8. It includes core-renderer-minimal.jar, this jar is optional and provides some support (minimal) of XHTML embedded in SVG (through <foreignObject>) and is part of the Flying Saucer[29] project version R8.

These external products are open source and have compatible licenses. Previous versions may work but not tested.

Further we will show how to make a Maven POM to resolve dependencies required by ItsNat.

In previous versions ItsNat used Xerces DOM for DOM management in server. Xerces DOM implementation has very serious threading problems including when using one thread per DOM document, this is not a problem for Batik DOM, which is thread safe if only one thread accesses a DOM document. In spite of Batik has some dependencies with Xerces (for instance Batik may use XPath) and Xerces parsers and serializers are used in ItsNat, there is no problem with threading. Batik DOM Core is extended by ItsNat to provide an almost complete W3C DOM HTML Level 2 implementation.

2.6.3       Session management (stateful applications)

There are two modes of session management in servlet containers: sticky sessions and session replication.

In sticky sessions mode any client request is ever transported to the same node and web application instance. Because there is no data transport between nodes/server instances, session data may be not serializable[30].

With session replication any data registered in the session is serialized and shared between nodes, the servlet engine takes care of serialization and the cloud environment takes care of node coordination. Usually serialization happens after any web request is completed if the container detects some change in session attributes. This is how Google App Engine (GAE) works, at this time GAE does not support sticky sessions.

ItsNat preferred mode is sticky sessions because ItsNat is server centric and focused on Single Page Interface[31] applications keeping client state in server, if session data is shared between nodes this client state must be copied to servers and some special features like remote view/control only work fine in web applications running in a single node or using sticky sessions. In spite of this session replication is a first class citizen in ItsNat and with some techniques, such as disconnected nodes, node caching provided by templates and session compression, session data transported can be reduced to minimum.

2.6.3.1   Sticky Sessions Mode

If ItsNatServletContext.setSessionReplicationCapable(boolean) is set to false (the default mode) no session attribute is used by ItsNat to store ItsNat session data, hence no serialization happens to user code. In this mode servlet sessions are mainly used by ItsNat to identify the client[32]. ItsNat session ids are only valid and unique in the concrete application instance. This is the preferred mode, and highly recommended in Single Page Interface applications.

In this mode, native servlet sessions are almost only used for client identification purposes, that is, the session cookie value (session id) is the base of the ItsNat security model, this does not necessarily imply using session attributes, furthermore, in a Single Page Interface application session attributes can be fully avoided by the user. In brief, ItsNat provides ItsNat specific session objects, implementing ItsNatServletSession, in some way these ItsNat session objects are bound to the native session objects, with 1-1 relationship. This 1-1 relationship does not imply session attributes are being used.

ItsNat generates alternative and simple session ids, these ids may be public to identify the client to other clients (this is the main reason), the kind of things other clients can do with this session id is controlled by ItsNat (native session ids must not be public to other users because they grant full control of the monitored client outside ItsNat control). Never client identification of requests is based on these ItsNat generated ids.

Do not confuse sticky sessions and the stateless mode of ItsNat (explained later), in sticky session mode, sessions are still used to client identification purposes, sessions help to keep the server document (stateful). In stateless mode, sessions are not used in any way.

2.6.3.2   Session Replication Capable Mode

If the method ItsNatServletContext.setSessionReplicationCapable(boolean) is called with true, ItsNat session wrapper ItsNatServletSession is bound to the native session calling HttpSession.setAttribute(String,Object) after any request is completed to notify some change in the server state of the session in the concrete node/instance. This mode is recommended if the servlet engine is doing session replication between nodes or some kind of failover. ItsNat by default does not serialize, only setAttribute is called, is responsibility of servlet container serialize the ItsNatServletSession object.

If serialization happens user code must be serializable, otherwise an IO exception is thrown by the servlet engine. If there is one only one application instance (one node or servlet container instance) or servlet container is not doing session sharing between nodes (sticky sessions) then there is no essential functional difference between both ItsNat modes (sticky and session replication capable) in spite of session replication is enabled.

In session replication capable mode, ItsNat session public ids are SHA-1 generated values from the native session ids. Because SHA-1 is a one way algorithm the reverse process to obtain the native session id is extremely painful (brute force), and because the native session id is unique and SHA-1 generated value is also unique, the generated public session id is also unique between nodes.

In session replication some ItsNat features do no work because they were designed for single node or sticky sessions, usually they are thread-based features:

·       Comet: use timers instead.

·       Server-sent events using browser: this feature is heavily based on local threads.

·       Asynchronous tasks: again it uses threads.

·       Iframe/object/embed/applet child document auto-binding.

·       Remote view/control: remote view/control usually involves several sessions.

·       SVGWeb: automatic handling of dynamically inserted nodes does not work, use a SVGLoad listener instead.

·       ItsNatDocument or related ItsNat objects cannot be explicitly serialized calling HttpSession.setAttribute(String,Object)

In session replication mode this configuration method is interesting:

ItsNatServletContext.setSessionSerializeCompressed(boolean)

When is set to true (by default is false) ItsNat compresses (using GZIP) the final serialized data of the ItsNat session when this session is being serialized (ItsNat first serializes the session as a byte buffer then writes this buffer to the stream). This action significantly reduces the amount of bytes being transported between nodes in the cloud and may provide a significative gain in performance.

Because developers most of the time develop in single instances, ItsNat provides a complementary configuration flag for testing session serialization:

ItsNatServletContext.setSessionExplicitSerialize(boolean)

If this method is called with a true value (by default is false), ItsNat explicitly serializes the ItsNatServletSession object and saves the serialized byte array in session when any request is completed. In addition, when a new request arrives to the server, the ItsNatServletSession object is ever obtained again de-serializing the byte buffer saved in the session, by this way a new fresh session object (and dependent objects like documents bound to the session) is used in every request simulating the behavior of a cloud environment using replicated sessions like GAE. This method is independent of ItsNatServletContext.setSessionSerializeCompressed(boolean) and both can be combined, that is, sessions can be explicitly serialized and serialized data can be compressed before calling HttpSession.setAttribute.

2.6.4       Google Application Engine support

2.6.4.1   Stateful mode

ItsNat works in Google App Engine (GAE) with the limitations explained before due to session replication, the only valid mode in GAE for stateful applications, there are more specific restrictions:

·       Most of components do not work because of most of them reuse Swing classes, and Swing packages are not white listed in GAE.

This problem is not critical because the “core” level API of ItsNat offers DOM utilities similar to components and utilities to transport data from client to server alongside AJAX events (for instance to transport the textual data of a text control).

·       Features which create new threads do not work, for instance Comet (use timers instead).

·       Stack size is relatively small, StackOverflowError errors can happen when internally serializing DOM nodes.

To deploy an ItsNat and GAE based application you must provide an appengine-web.xml file like this:

 

<?xml version="1.0" encoding="utf-8"?>

<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">

    <application>yourappname</application>

    <version>1</version>

    <sessions-enabled>true</sessions-enabled>

    <threadsafe>true</threadsafe>

</appengine-web-app>

 

Another requirement is you must remove the original Batik DOM jar used in ItsNat, batik-dom-1.7.jar, and replace it with a custom version, batik-dom-1.7-gae.jar, this file included in ItsNat distribution is located in /gae/lib

The file batik-dom-1.7-gae.jar is basically the same as the original, the only difference is the class org.apache.batik.dom.AbstractDocument, this class has been modified removing some problematic XPath dependencies. Google App Engine does not support org.w3c.dom.xpath.* classes because org.w3c.* content is controlled by GAE and org.w3c.dom.xpath.* classes are not white listed. W3C DOM XPath classes can be used in Batik DOM included in ItsNat but internally are not used and they are not loaded (unless you use them explicitly), however GAE accidentally tries to load some XPath class when document DOM objects are being serialized and this action causes an exception.

In GAE most of your code must be serializable, serialization is problematic because it introduces the problem of versioning. When you upload a new version of your application to GAE, GAE does not free the current persistent sessions (GAE saves sessions in both datastore and memcached) and tries to reload old saved sessions in the new version of your application. If the schema has changed and the saved data is not compatible a java.io.IOException would be thrown. Fortunately ItsNat is tolerant to schema changes, ItsNat detects when de-serialization fails and discards the session and no explicit session cleaning is needed.

Anyway if you need to manually remove one or all sessions, use ”Delete” action in “Datastore Viewer” of your GAE administration account. However this action is not enough, because session data is also saved in memcached, removing the session cookie of your browser gets rid of the session definitely. Of course the last is not practical to end users, another option is the GAE servlet for session cleanup[33].

To detect when your application is running on GAE there are two known techniques[34].

Finally GAE do not ensure your requests are dispatched to the same node, furthermore if no request is received during several minutes GAE can automatically dispatch new requests to a new node, because the application must be loaded in the new node (only the first time) you may suffer a significative delay, this has nothing to do with session size. Sometimes if the current node being used is very busy, application loading may fail because GAE imposes a timeout per request of 30 second… the solution is to try again.

The method  ItsNatServletContext.setSessionSerializeCompressed(boolean) set to true is interesting in GAE to reduce the size of data being transported between nodes. This can also help to avoid the limit of session data size imposed by GAE.

The method ItsNatServletContext.setSessionExplicitSerialize(boolean) set to true is interesting to simulate on local and single instance the behavior of GAE regarding to session replication and is also useful when session serialization takes too much time, because serialization is executed by ItsNat before calling ItsNatSession.setAttribute.

2.6.4.2   Stateless mode

If your ItsNat documents are going to be stateless you are lucky, you may disable session replication if you want, ItsNat makes no use of sessions.

3. INSTALLATION

3.1      ITSNAT DISTRIBUTION

Decompress the ItsNat distribution .zip file. ItsNat distribution includes a NetBeans web project based on Maven, this web application is the “Feature Showcase”, an ItsNat based web application with source code showing main features and components of ItsNat.

The “Feature Showcase” is a NetBeans Java 1.6 web application, because based on Maven can be easily ported to other IDEs.

To quickest way to execute (run or debug) the “Feature Showcase” example with NetBeans, is through the file run.html as shown in the figure (this file is just a quick launcher for NetBeans):

Or start your application server and load the index page with this URL (port may be different):

http://localhost:8080/itsnat_featshow

This web application is very useful to show how a complex ItsNat application can be developed. All of examples include the source code, this is the reason Java source code of this web application is below WEB-INF, because you can see the source code of examples through the application UI shown to the user as documentation. Of course this is not a usual location of source code (Java source code is not usually included in a web application .war file), other ItsNat examples in ItsNat repositories are more conventional.

The itsnat_featshow/pom.xml is an example of the required dependencies to run a ItsNat based web application.

The folder itsnat_featshow/target/itsnat_featshow-1.0-SNAPSHOT/WEB-INF/lib contains the libraries required (resolved by Maven).

If you want to execute the “Feature Showcase” example as a “production ready” Java web application, pick the itsnat_featshow/target/itsnat_featshow-1.0-SNAPSHOT.war archive and deploy into your application server.

3.2      WHAT DOES ANY NEW JAVA WEB APPLICATION NEED?

Create your standard web application using your preferred IDE, use a JDK 1.6+. This is the list of dependencies you must have in your Maven POM:

<dependencies>

     

        <dependency>

            <groupId>org.itsnat</groupId>

            <artifactId>itsnat_server</artifactId>

            <version>1.4</version>

        </dependency>

 

        <dependency>

            <groupId>com.innowhere</groupId>

            <artifactId>relproxy</artifactId>

            <version>0.8.6</version>

            <type>jar</type>

        </dependency>

 

        <dependency>

            <groupId>org.apache.xmlgraphics</groupId>

            <artifactId>batik-dom</artifactId>

            <version>1.7</version>

        </dependency>

 

        <dependency>

            <groupId>org.apache.xmlgraphics</groupId>

            <artifactId>batik-xml</artifactId>

            <version>1.7</version>

        </dependency>

 

        <dependency>

            <groupId>org.apache.xmlgraphics</groupId>

            <artifactId>batik-util</artifactId>

            <version>1.7</version>

        </dependency>

 

        <dependency>

            <groupId>net.sourceforge.nekohtml</groupId>

            <artifactId>nekohtml</artifactId>

            <version>1.9.12</version>

        </dependency>

 

        <dependency>

            <groupId>xalan</groupId>

            <artifactId>serializer</artifactId>

            <version>2.7.1</version>

        </dependency>

     

     

     

        <dependency>

          <groupId>javax.servlet</groupId>

          <artifactId>servlet-api</artifactId>

          <version>2.5</version>

          <scope>provided</scope>

        </dependency>

   

        <dependency>

          <groupId>javax.servlet.jsp</groupId>

          <artifactId>jsp-api</artifactId>

          <version>2.1</version>

          <scope>provided</scope>

        </dependency>

   

</dependencies>

RelProxy and javax.servlet versions can be changed to upper versions, similar can be said for other dependencies but they are not tested.

The folder itsnat_featshow/target/itsnat_featshow-1.0-SNAPSHOT/WEB-INF/lib of the ItsNat distribution contains the jar libraries required (resolved by Maven).

 

4. ITSNAT ARCHITECTURE

4.1      PURE INTERFACE/IMPLEMENTATION PATTERN

ItsNat public API is based on interfaces, only very few classes are public, the root class is ItsNatBoot, this class is abstract (fully implemented by ItsNat internally) and defined to get the singleton object implementing the interface ItsNat calling the static method ItsNatBoot.get(). The singleton object returned works as a factory: ItsNat based objects implementing public interfaces like ItsNatServletContext and ItsNatServlet can be created, these objects are used as factory of other objects and so on.

A pure interface/implementation technique allows to program “by contract”, where the interface is the contract, only the interfaces are documented. This technique avoids the framework to publish internal methods and classes, the user finds a “clean”, solid and stable interface to deal with the implementation, and framework developers can hide internal and “ever changing” implementation artifacts easily. By using only interfaces the internal implementation can be changed “behind the scenes” automatically without external code modification, in fact the ItsNat implementation can be fully switched.

An interface based architecture avoids class inheritance as a way of extension of the framework, instead of inheritance ItsNat provides many hooks and listeners as the standard way to extend the framework, and finally the developer can optionally re-implement any default implementation of ItsNat implementing the required interface.

4.2      LAYERED ARCHITECTURE

ItsNat is constructed on top of the Servlet classes/interfaces using a layer & composition approach. An example: an ItsNatServlet object contains a field to the real “covered” Servlet object (1->1), ItsNatServlet interface has a method, ItsNatServlet.getServlet(), to return the “real” servlet object if the user need it. In this manner ItsNat extends the Servlet architecture not fully replacing it, the user can and must use the “old stuff” when ItsNat does not offer something new following the DRY[35] principle.

ItsNat is built upon Java W3C DOM too, for instance, an ItsNatDocument wraps an org.w3c.dom.Document object (and of course the covered Document can be got through ItsNatDocument). The “ItsNat” prefix is used to easily distinguish the ItsNat layer and the original data type, most of the ItsNat API starts with “ItsNat” sometimes because the interface wraps a class with the same name and sometimes because of “viral” symmetry/dependencies (for instance ItsNatDocumentTemplate).

4.3       COMPONENT SYSTEM “INSPIRED” IN SWING

The architecture of ItsNat classes/interfaces (only the interfaces are public) is very similar to Swing. An example:

Swing

ItsNat interface

JTable

ItsNatTable

TableCellEditor

ItsNatTableCellEditor

TableCellRenderer

ItsNatTableCellRenderer

TableUI

ItsNatTableUI

The “ItsNat” prefix is used to distinguish ItsNat components from Swing counterparts.

ItsNat components use as possible UI agnostic Swing elements like data models, listener models and related listeners.

4.4      MODULES/PACKAGES

ItsNat is divided in two main modules/packages[36]

·         Core (org.itsnat.core)

Is the “core” part of the framework, offers the basic infrastructure to develop event (AJAX or SCRIPT) based Java web applications.

·         Components (org.itsnat.comp)

Contains the optional component system, it relies on the “core” part, but “core” has (almost) no dependency with “components”.

4.4.1       Core

The core package contains the fundamental interfaces, this package provides utilities to wrap the servlet system, to register page templates, to control the page lifecycle, to create event listeners etc.

Sub packages:

·         org.itsnat.core.event: defines event and listener classes and interfaces associated to the page lifecycle and AJAX/SCRIPT events.

·         org.itsnat.core.html: interfaces related to HTML documents and fragments.

·         org.itsnat.core.http: interfaces related to HTTP servlets.

·         org.itsnat.core.script: contains utilities to generate JavaScript code to send from server (Java) to client.

·         org.itsnat.core.domutil: contains utilities to manipulate DOM elements using the pattern approach (lists, tables and trees).

4.4.2       Components

org.itsnat.comp package contains generic interfaces of components, they may be applied to HTML, XHTML, SVG, XUL or XML components.  Inside this package they are sub packages usually grouping components per component type:

·       buttons (org.itsnat.comp.button),

·       labels (org.itsnat.comp.label),

·       lists (org.itsnat.comp.list),

·       tables (org.itsnat.comp.table),

·       trees (org.itsnat.comp.tree)

·       etc.

4.5      SECURITY AND PRIVACY

ItsNat is a server centric framework, any server centric framework is by nature securer than client centric approaches (any client centric approach needs to check any access to the server in some way security, validations etc must be replicated in server).

4.5.1       Security is inherent in The Browser Is The Server approach

In the case of ItsNat the browser is managed as a sophisticated UI terminal of the server, all the business logic and view logic is executed in the server[37]; view logic is executed in the server mainly in the form of DOM tree mutations and automatically replicated in the client.

Because the client state is accurately represented in the server (in fact is the opposite) following the approach “The Browser Is The Server”, the opportunities of spoofing are very few. For instance event listeners are registered in the server, any event received by the server with no server listener listening is ignored; listeners may be seen as a gate to enter into the server, if no listener is registered in server associated to a concrete DOM node and event type, no event will be processed.

Because the view is based on a W3C DOM tree, some built-in security features are present, for instance, if a malicious user fills an input box with some JavaScript code containing an script like “<script>some code</script>” and this code is sent to the server, this user text is usually managed as raw text and text data is usually shown in the DOM as the content of text nodes, by default the DOM renderer “escapes” this text as “&lt;script&gt;some code&lt;/script&gt;”, this code cannot be constructed as DOM including inside an innerHTML assignation[38].  

4.5.2       Security and client identification

Client identity is based on the session identification of the servlet container (based on a very long cookie), in spite of ItsNat generates and uses a very simple id for sessions (or SHA-1 generated ids), ItsNat does not rely on this id to identify the client browser in the first instance. Of course this ItsNat generated id is used to identify a concrete user to other users but this id is used once the user request has been correctly identified by the servlet container using the servlet container session id. Access to other clients by using ItsNat public session ids is managed by ItsNat, controlling what the other user can do.

In ItsNat ids are not reused in the lifecycle of the web application, this applies to id sessions too. In the case of sessions ItsNat goes beyond trying to avoid reusing of ids including when the application or the servlet container is relaunched and session replication is disabled. In this case servlet containers do not ensure the session id is not reused so an additional internal number randomly generated by ItsNat is used, and is saved in server and client, if this number in the client casually matches the number of the random number in server of the newly created session, this is not a real threat because this new session was created by the user sending an event from a lost document of a lost session. 

In “session replication capable” mode public session ids are SHA-1 generated from native session ids. SHA-1 is a one way algorithm and generated ids are unique because the original session id is unique between clusters. 

Any other identification number (for instance document ids) is not absolute, for instance the document “cd_1” has no sense without the ItsNat session id and as said before, this session id is not the number used to identify first the user session in server.

4.5.3       Privacy

In Single Page Interface (SPI) applications there is no page navigation, only the URL used to enter into the application is saved in the browser page history, and AJAX/SCRIPT events do not generate history entries.

ItsNat use ever HTTP POST to send in AJAX events, this mode is more “secure” and “private” than GET method.

In ItsNat and SPI applications cookies are not needed, that is, cookie support is optional and can be disabled in the browser settings. In this case when the initial page of the SPI web application is loaded, ItsNat automatically adds the session id to the path used for AJAX events.

4.6      PRODUCTIVITY WITH CLASS AUTORELOADING BUILT-IN

The Java servlet technology have some built-in productivity techniques like JSP automatic reloading (thanks to the servlet reloading capability) and context reloading when some .class is changed in runtime, the later feature is usually aligned to auto-deploy of modern IDEs.

JSP is no longer the preferred technology for templating, many Java web frameworks use other techniques and context reloading is no longer useful when the web application becomes big, in this case and development time, with auto-deploy in your IDE enabled, every file save implies an application context reloading and soon the PermGen exception arises.

The tool RelProxy[39] is the result to provide better and lighter hot reload capabilities to ItsNat. RelProxy is an standalone toolkit with no ItsNat dependency, but initially it was conceived exclusively for ItsNat and was created by the original author of ItsNat.

As of ItsNat v1.4, RelProxy is built-in on ItsNat, its use is optional, in fact, there is no performance impact when is not configurated and enabled.

RelProxy supports Java (JProxy) and Groovy (GProxy) class reloading, only Java class reloading capability is built-in, in RelProxy Manual you can find some example of how to use Groovy with ItsNat including hot code reloading using RelProxy externally.

4.6.1       What type of code can be reloaded?

RelProxy 0.8.6 or upper is supposed.

4.6.1.1   Registered ItsNatServletRequestListener in document templates

In this example the class CoreExampleLoadListener and dependent classes maybe reloadable if they are part of the reloadable sources:

 
String pathPrefix = ...;
ItsNatHttpServlet itsNatServlet = ...;
ItsNatDocumentTemplate docTemplate =         itsNatServlet.registerItsNatDocumentTemplate("manual.core.example",
               "text/html", pathPrefix + "core_example.html"); docTemplate.addItsNatServletRequestListener(new CoreExampleLoadListener());
 

Because a ItsNatServletRequestListener in this context is executed when loading the page template associated, after changing the class you can check the changes just reloading the page based on this template.

4.6.1.2   Registered org.w3c.dom.events.EventListener

In this example the code of this inner class is changed it may be reloaded when received the next user event if the container class is part of the reloadable sources, no need of page reload, a single click may be enough:

EventListener listener = new EventListener()

{

   public void handleEvent(Event evt) {

    ...

   }

};

itsNatDoc.addUserEventListener(null,"rem_ctrl_request",listener);

 

Most of EventListener registry options are detected for reloading like in the document (previous example), DOM elements, components...:

Element element = ...;        

EventListener listener = new EventListener()

{

    @Override

    public void handleEvent(Event evt) {

        ...

    }

};

((EventTarget)element).addEventListener("click",listener,false);

 

ItsNatHTMLInputButton input = ...;

input.addEventListener("click",new EventListener() {

    @Override

    public void handleEvent(Event evt) {

       //...         

    }

});

4.6.2       Configuration example

RelProxy is focused to provide hot reloading in two scenarios:

1. To be able of source code changes and hot class reloading avoid context reload in development time.

2. To be able of some source code change in production (similar to JSP changing but more powerful).

In both cases there is no need of session serialization, RelProxy do not support serialization, you do not need serialization in development time and in production with a single instance with source code reloadable, serialization is mainly useful for clusters of application servers (all symmetric).

The following code is a configuration example on using RelProxy in development time, you must register this ServletContextListener in your web.xml. Read the RelProxy manual to understand everything. There is some code related to Google App Engine (GAE), ignore it if you do not use GAE.

package test.shared;

 

import com.innowhere.relproxy.RelProxyOnReloadListener;

import com.innowhere.relproxy.jproxy.JProxy;

import com.innowhere.relproxy.jproxy.JProxyCompilerListener;

import com.innowhere.relproxy.jproxy.JProxyConfig;

import com.innowhere.relproxy.jproxy.JProxyDiagnosticsListener;

import com.innowhere.relproxy.jproxy.JProxyInputSourceFileExcludedListener;

import com.innowhere.relproxy.jproxy.JProxyScriptEngine;

import java.io.File;

import java.lang.reflect.Method;

import java.util.Arrays;

import java.util.List;

import javax.servlet.ServletContext;

import javax.servlet.ServletContextEvent;

import javax.servlet.ServletContextListener;

import javax.tools.Diagnostic;

import javax.tools.DiagnosticCollector;

import javax.tools.JavaFileObject;

import org.itsnat.core.ItsNat;

import org.itsnat.core.ItsNatBoot;

import org.itsnat.core.ItsNatServletContext;

import test.AnyThingServlet;

import test.ItsNatDroidServletExample;

import test.ItsNatDroidServletNoItsNat;

import test.ItsNatServletExample;

 

/**

 *

 * @author jmarranz

 */

public class CustomServletContextListener implements ServletContextListener

{

  @Override

  public void contextInitialized(ServletContextEvent sce)

  {

    System.out.println("CustomServletContextListener contextInitialized");

 

    ItsNat itsNat = ItsNatBoot.get();

    ServletContext context = sce.getServletContext();

 

    SharedInitContextConf.init(context,itsNat);

 

    // Use example of RelProxy in development time:

    String realPath = context.getRealPath("/"); // NetBeans Maven: /target/itsnat-dev-1.0-SNAPSHOT/ dir

    String inputPath = realPath + "../../src/main/java/";

 

    boolean gaeEnabled = context.getServerInfo().startsWith("Google App Engine");

    if (gaeEnabled)

    {

      // In GAE we can't call to new File(inputPath).exists() if inputPath is a parent directory of the web app

          

      System.out.println("RelProxy disabled, production mode (Google App Engine) detected");            

      return;

    }

 

    ItsNatServletContext itsNatCtx = itsNat.getItsNatServletContext(context);       

    if (itsNatCtx.isSessionReplicationCapable())

    {

      System.out.println("RelProxy disabled, serialization is enabled (not compatible with RelProxy)");           

      return;

    }

       

    if (new File(inputPath).exists())

    {

      System.out.println("RelProxy to be enabled, development mode detected");

    }

    else

    {

      System.out.println("RelProxy disabled, production mode detected");

      return;

    }

 

    JProxyInputSourceFileExcludedListener excludedListener =

      new JProxyInputSourceFileExcludedListener()

      {

        @Override

        public boolean isExcluded(File file, File rootFolderOfSources)

        {

          String absPath = file.getAbsolutePath();

          if (file.isDirectory())

          {

            return absPath.endsWith(File.separatorChar + "manual") ||

                   absPath.endsWith(File.separatorChar + "test" + File.separatorChar + "shared");

          }

          else

          {

            return absPath.endsWith(File.separatorChar +

                          AnyThingServlet.class.getSimpleName() + ".java") ||

                   absPath.endsWith(File.separatorChar +

                          ItsNatDroidServletExample.class.getSimpleName() + ".java") ||

                   absPath.endsWith(File.separatorChar +

                          ItsNatDroidServletNoItsNat.class.getSimpleName() + ".java") ||

                   absPath.endsWith(File.separatorChar +

                          ItsNatServletExample.class.getSimpleName() + ".java");

          }

        }

      };

 

 

    String classFolder = null; // Optional: context.getRealPath("/") + "/WEB-INF/classes";

    Iterable<String> compilationOptions = Arrays.asList(

                 new String[]{"-source","1.6","-target","1.6"});

    long scanPeriod = 1000;

 

    RelProxyOnReloadListener proxyListener = new RelProxyOnReloadListener() {

      @Override

      public void onReload(Object objOld, Object objNew, Object proxy, Method method,

                          Object[] args) {

        System.out.println("Reloaded " + objNew + " Calling method: " + method);

      }

    };

 

    JProxyCompilerListener compilerListener = new JProxyCompilerListener(){

      @Override

      public void beforeCompile(File file)

      {

        System.out.println("Before compile: " + file);

      }

 

      @Override

      public void afterCompile(File file)

      {

        System.out.println("After compile: " + file);

      }

    };

 

    JProxyDiagnosticsListener diagnosticsListener = new JProxyDiagnosticsListener()

    {

      @Override

      public void onDiagnostics(DiagnosticCollector<JavaFileObject> diagnostics)

      {

        List<Diagnostic<? extends JavaFileObject>> diagList =

                 diagnostics.getDiagnostics();

        int i = 1;

        for (Diagnostic diagnostic : diagList)

        {

          System.err.println("Diagnostic " + i);

          System.err.println("  code: " + diagnostic.getCode());

          System.err.println("  kind: " + diagnostic.getKind());

          System.err.println("  line number: " + diagnostic.getLineNumber());

          System.err.println("  column number: " + diagnostic.getColumnNumber());

          System.err.println("  start position: " + diagnostic.getStartPosition());

          System.err.println("  position: " + diagnostic.getPosition());

          System.err.println("  end position: " + diagnostic.getEndPosition());

          System.err.println("  source: " + diagnostic.getSource());

          System.err.println("  message: " + diagnostic.getMessage(null));

          i++;

        }

            }

        };

 

    JProxyScriptEngine engine = ItsNatBoot.get().getJProxyScriptEngine();

 

    JProxyConfig jpConfig = JProxy.createJProxyConfig();

    jpConfig.setEnabled(true)

            .setRelProxyOnReloadListener(proxyListener)

            .setInputPath(inputPath)

            .setJProxyInputSourceFileExcludedListener(excludedListener)

            .setScanPeriod(scanPeriod)

            .setClassFolder(classFolder)

            .setCompilationOptions(compilationOptions)

            .setJProxyCompilerListener(compilerListener)

            .setJProxyDiagnosticsListener(diagnosticsListener);

 

    engine.init(jpConfig);

  }

 

  @Override

  public void contextDestroyed(ServletContextEvent sce)

  {

    System.out.println("CustomServletContextListener contextDestroyed");

    JProxy.stop();

  }

}

 

5. DEVELOPMENT LIFECYCLE

5.1      A CORE BASED WEB APPLICATION

We are going to create a simple AJAX based web application using the “core” part of the framework (without components).

5.1.1       Create a new servlet

ItsNat does not provide a framework servlet, the main reason is because the init(ServletConfig) method must be used to setup the ItsNatHttpServlet object and register used templates. ItsNat provides an abstract servlet: HttpServletWrapper, the source code is very simple and useful to understand how the layering starts:    

 

public class HttpServletWrapper extends HttpServlet

{

    protected ItsNatHttpServlet itsNatServlet;

   

    /**

     * Creates a new instance of HttpServletWrapper

     */

    public HttpServletWrapper()

    {

    }

   

    public ItsNatHttpServlet getItsNatHttpServlet()

    {

        return itsNatServlet;

    }

           

    /**

     * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.

     *

     * @param request itsNatServlet request

     * @param response itsNatServlet response

     */

    protected void processRequest(HttpServletRequest request,

                       HttpServletResponse response)

        throws ServletException, IOException

    {

        itsNatServlet.processRequest(request,response);

    }

   

    public void init(ServletConfig config) throws ServletException

    {

        super.init(config);

 

        this.itsNatServlet =

                      (ItsNatHttpServlet)ItsNatBoot.get().createItsNatServlet(this);       

    }   

   

    // Other typical servlet methods (doGet, doPost,getServletInfo) go here

   ...

 

}

When the servlet is first loaded an ItsNatHttpServlet layer object is created wrapping the real servlet object.

As you can see in the line:

 

        itsNatServlet.processRequest(request,response);

 

Any request received by this servlet is redirected to ItsNat servlet layer.

The easiest way to create an ItsNat based servlet is to inherit from HttpServletWrapper

 

public class servlet extends HttpServletWrapper

{

    public void init(ServletConfig config) throws ServletException

    {

        super.init(config);

       ...

 

No special configuration is required in the web.xml archive to register the servlet (use the typical default code generated by your IDE).

A typical ItsNat application only needs one servlet, anyway multiple ItsNat based servlets may be deployed and they may cooperate because the same ItsNatSession and ItsNatServletContext objects are automatically shared.

5.1.2       Configuring global behavior (global options/configuration)

The init() method is the appropriate place to setup global behavior:

 

    public void init(ServletConfig config) throws ServletException

    {

        super.init(config);

 

        ItsNatHttpServlet itsNatServlet = getItsNatHttpServlet();

        ItsNatServletConfig itsNatConfig =

               itsNatServlet.getItsNatServletConfig();

 

        ItsNatServletContext itsNatCtx = itsNatConfig.getItsNatServletContext();

        itsNatCtx.setMaxOpenDocumentsBySession(10);

        itsNatCtx.setSessionSerializeCompressed(false);

        itsNatCtx.setSessionExplicitSerialize(false);

 

        String serverInfo = getServletContext().getServerInfo();

        boolean gaeEnabled = serverInfo.startsWith("Google App Engine");

        itsNatCtx.setSessionReplicationCapable(gaeEnabled);

 

        itsNatConfig.setDebugMode(true);

        itsNatConfig.setClientErrorMode(

                       ClientErrorMode.SHOW_SERVER_AND_CLIENT_ERRORS);

        itsNatConfig.setLoadScriptInline(true);

        itsNatConfig.setFastLoadMode(true);

        itsNatConfig.setCommMode(CommMode.XHR_ASYNC_HOLD);

        itsNatConfig.setEventTimeout(-1);

        itsNatConfig.setOnLoadCacheStaticNodes("text/html",true);

        itsNatConfig.setOnLoadCacheStaticNodes("text/xml",false);

        itsNatConfig.setNodeCacheEnabled(true);

        itsNatConfig.setDefaultEncoding("UTF-8");

        itsNatConfig.setUseGZip(UseGZip.SCRIPT);

        itsNatConfig.setDefaultDateFormat(DateFormat.getDateInstance(

               DateFormat.DEFAULT,Locale.US));

        itsNatConfig.setDefaultNumberFormat(

               NumberFormat.getInstance(Locale.US));

        itsNatConfig.setEventDispatcherMaxWait(0);

        itsNatConfig.setEventsEnabled(true);

        itsNatConfig.setScriptingEnabled(true);

        itsNatConfig.setUsePatternMarkupToRender(false);

        itsNatConfig.setAutoCleanEventListeners(true);

        itsNatConfig.setUseXHRSyncOnUnloadEvent(true);

        itsNatConfig.setMaxOpenClientsByDocument(5);

 

Most of these options can be avoided because the default values are the same, but they are included to show very important ItsNat features. All of these features can be declared per page (template) and many of them per document too.

The ItsNatServletContext object is used global configuration shared between ItsNat servlets, in this case we have only one servlet, if you need several ItsNat servlets in the same application, use ItsNatServletContext a custom ServletContextListener, you can obtain this object in this context by calling ItsNatBoot.get().getItsNatServletContext(ServletContext).

5.1.2.1   Max Open Documents By Session

 

        ItsNatServletContext itsNatCtx = itsNatConfig.getItsNatServletContext();

        itsNatCtx.setMaxOpenDocumentsBySession(10);

 

Defines the max number of open documents can hold a user server session. This feature is very useful to limit the server memory used by web bots (crawlers) with session support identified as legitimated browsers, browsers with JavaScript disabled traversing pages/documents designed for AJAX and abusive users. By default unknown browsers are treated as bots and events are automatically disabled, the document in the server is automatically destroyed after the page is loaded.

Because child ItsNat documents included by iframe, object and embed elements also count, this number must be greater than the max number of child documents +1 (the container page).

A negative value is the default and means no limit.

Note this configuration value is set in the servlet/application context level and not in the servlet configuration level because only one ItsNat session instance is shared by all ItsNat servlets of the same web application.

5.1.2.2   Session Replication Capable Mode

 

        itsNatCtx.setSessionReplicationCapable(gaeEnabled);

 

Configures ItsNat to work in clusters using session replication like Google App Engine (if set to true) or to work in single nodes or clusters using sticky sessions. Anyway in a single node/instance there is no significative difference between both modes.

By default ItsNatServletContext.isSessionReplicationCapable(boolean) returns false (sticky).

5.1.2.3   Session Data is Compressed When is Serialized

 

        itsNatCtx.setSessionSerializeCompressed(false);

 

This method when called with a true parameter, configures ItsNat to compress the serialized data when the user’s session is serialized to be shared between nodes of the cloud (or saved in some kind of persistent store for failover) to reduce the amount of transported data. This configuration option set to true only has sense if session replication is enabled and when the servlet container serializes the session.

By default ItsNatServletContext.isSessionSerializeCompressed() returns false (not compressed).

5.1.2.4   Session Data is Compressed When is Serialized

 

        itsNatCtx.setSessionExplicitSerialize(false);

 

This method when called with a true parameter, configures ItsNat to explicitly serialize the user’s session saving the serialized data to the native session calling HttpSession.setAttribute(String,Object) when any web request ends. When any request arrives to the server, the user’s session is explicitly de-serialized from the servlet creating new fresh objects, useful to simulate how cloud environments with session replication works and to avoid serialization time limits imposed by the cloud (for instance Google App Engine). This configuration option set to true only does something if session replication is enabled.

By default ItsNatServletContext.isSessionExplicitSerialize() returns false (no explicit serialization).

5.1.2.5   Debug mode

 

        itsNatConfig.setDebugMode(true);     

 

Sets the debug mode as true (default value), in debug mode the framework makes more checks to ensure is correctly used. A value of true is highly recommended in development and production because in current version the performance impact is negligible.

5.1.2.6   Client error mode

 

        itsNatConfig.setClientErrorMode(

                       ClientErrorMode.SHOW_SERVER_AND_CLIENT_ERRORS);   

                             

Specifies the browser catches and shows server (server exceptions) and client (JavaScript) errors to the user (using an alert).  By default is SHOW_SERVER_AND_CLIENT_ERRORS.

5.1.2.7   Initial script inline/loaded

        itsNatConfig.setLoadScriptInline(true);

When the document/page is first served to the browser initial JavaScript generated code can be sent “inline” into a <script> element of can be loaded with a special URL. If this feature is set to true the code is sent “inline”, this mode is useful to see the initial JavaScript code easily.

5.1.2.8   Fast/slow load mode

 

        itsNatConfig.setFastLoadMode(true);

 

Sets the load mode as “fast” (is the default value), this is the recommended value. Only in special scenarios this setting must be set to false. “Fast” and “slow” modes will be discussed further.

5.1.2.9   Default communication mode for events

 

        itsNatConfig.setCommMode(CommMode.XHR_ASYNC_HOLD);  

 

Sets the default communication mode for events as “AJAX asynchronous-hold” (this is the default value), in this mode AJAX events are automatically queued as a FIFO list and sent sequentially and asynchronously to the server, and when the last event sent returns the next event is sent. This mode provides an almost synchronous event system without blocking the browser. ItsNat also supports events transported by request using SCRIPT elements including a “hold” mode.

5.1.2.10       Default timeout of asynchronous events

 

        itsNatConfig.setEventTimeout(-1);

 

Sets the default timeout of asynchronous AJAX or SCRIPT events. This is the time an asynchronous request will wait before abort. In AJAX synchronous mode this flag is ignored (a synchronous XMLHttpRequest request cannot be aborted). A negative value means no timeout. By default is -1.

5.1.2.11       On load static (X)HTML caching to save memory size

 

        itsNatConfig.setOnLoadCacheStaticNodes("text/html", true);

 

Enables the “memory cache” in X/HTML pages, this is the default value. When the X/HTML template page is first loaded, static DOM subtrees are serialized as text and replaced with a special text mark to save memory. By default is true in text/html, application/xhtml+xml, image/svg+xml and application/vnd.mozilla.xul+xml MIMEs.

5.1.2.12       On load static XML caching to save memory size

 

        itsNatConfig.setOnLoadCacheStaticNodes("text/xml", false);

 

Disables the “memory cache” to any XML page served with the text/xml MIME (the default value). XML generated pages are usually “content based”, and fully generated with no static parts. 

5.1.2.13       Node cache for speed

 

        itsNatConfig.setNodeCacheEnabled(true);       

 

Enables the “speed cache” (default value). When the speed cache is enabled, DOM elements are saved in a server and client registry when suitable using a global ID per element, this ID is used to communicate the DOM element identity between server and browser replacing the time consuming task of resolving localization paths in the DOM tree.    

5.1.2.14       Default encoding

 

        itsNatConfig.setDefaultEncoding("UTF-8");

 

Defines the default encoding (UTF-8 is the default value).

5.1.2.15       Use GZIP encoding if available

 

        itsNatConfig.setUseGZip(UseGZip.SCRIPT );       

 

If the browser accepts gzip encoding then JavaScript code (sent as response of an AJAX/SCRIPT event) is automatically compressed. Markup may be compressed to:

 

        itsNatConfig.setUseGZip(UseGZip.SCRIPT | UseGZip.MARKUP);       

 

By default ItsNat uses gzip to compress JavaScript if the browser accepts this encoding.

5.1.2.16       Default date format

 

        itsNatConfig.setDefaultDateFormat(

                       DateFormat.getDateInstance(DateFormat.DEFAULT,Locale.US));        

 

Defines the default date format, this format is used in components like ItsNatFormattedTextField when dealing with dates. The default date format uses the platform locale.

5.1.2.17       Default number format

 

        itsNatConfig.setDefaultNumberFormat(NumberFormat.getInstance(Locale.US));       

 

Defines the default number format, this format is used in components like ItsNatFormattedTextField when dealing with numbers. The default number format uses the platform locale.

5.1.2.18       Default dispatched max wait

 

        itsNatConfig.setEventDispatcherMaxWait(0);

 

Defines the max wait an “event dispatcher” thread will wait until a server fired event is processed. An event dispatcher thread is launched using the method ItsNatDocument.startEventDispatcherThread(Runnable). By default is 0 (unlimited).

5.1.2.19       Use events

 

        itsNatConfig.setEventsEnabled(true);

 

Defines whether events (transported with AJAX or SCRIPT) are enabled. By default is true.

5.1.2.20       Use JavaScript

 

        itsNatConfig.setScriptingEnabled(true);

 

Defines whether JavaScript is enabled (ItsNat sends JavaScript code to clients on load time and as answer of AJAX/SCRIPT events). By default is true.

5.1.2.21       Use the original markup (pattern) to render

 

        itsNatConfig. setUsePatternMarkupToRender(false);

 

If set to true the original markup of a component (the pattern) is ever used to render a new value, for instance a list item. By default is false.

5.1.2.22       Auto Clean Event Listeners

 

        itsNatConfig.setAutoCleanEventListeners(true);

 

If set to true the framework automatically removes all event listeners (DOM and User event types) associated to a DOM element and child nodes when this element is removed from the tree. This feature is a kind of “garbage collector” of removed DOM nodes and helps to avoid server and client memory leaks. With this feature set to true components with internal event listeners can be garbage collected when the associated element is removed without calling ItsNatComponent.dispose(). The default value is true.

When a DOM node is removed from the tree on the server any event listener still defined is not valid because ItsNat only synchronizes client and server nodes in the tree, if the same server DOM element is again inserted in the tree the client node counterpart inserted is a new node. When a server DOM node is removed from the tree the client counterpart is “lost” by the framework.

Manual removing of event listeners can be done calling EventTarget.removeEventListener(…) (in non-internal event mode),   ItsNatDocument.removeEventListener(…) and ItsNatDocument.removeUserEventListener(…) methods. These methods remove listeners associated to DOM nodes currently in the DOM tree, the listeners are automatically removed in the client too.

5.1.2.23       Communication mode of internal unload events

 

        itsNatConfig.setUseXHRSyncOnUnloadEvent (true);

 

When end user leaves a (stateful) page, ItsNat automatically sends an unload event to the server to notify the page is no longer loaded in client, ItsNat automatically remove the corresponding document in server freeing resources. If the default communication mode is AJAX (XMLHttpRequest or XHR) this event is sent synchronously (true by default) to ensure the unload event is sent to the server stopping the unload processing of the browser, in some browsers the unload event is not send if the AJAX request is sent asynchronously.

In some concrete circumstances (usually using COMET) and some browsers with a very limited number of open sockets per page (MSIE 6-7) this synchronous communication may hang the browser when end user leaves the page. By setting to false an asynchronous AJAX request is used. Do not worry about “orphan” documents in server, ItsNat has an aging criteria to get rid of them.

This configuration mode in no way affects to user defined event listeners registered for unload events.

5.1.2.24       Max Open Clients By Document

 

        ItsNatServletContext itsNatCtx = itsNatConfig.getItsNatServletContext();

        itsNatCtx.setMaxOpenClientsByDocument(5);

 

Defines the max number of clients attached to a document in server. This feature is very useful to limit the number of clients attached to a document in remote view/control.

A negative value is the default and means no limit.

5.1.3       Designing the page template

ItsNat supports HTML and XHTML files, in our example we are developing a XHTML file like the following:

 

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">

    <head>

        <title>ItsNat Core Example</title>

    </head>

    <body>

        <h3>ItsNat Core Example</h3>

       

        <div itsnat:nocache="true" xmlns:itsnat="http://itsnat.org/itsnat">           

            <div id="clickableId1">Clickable Elem 1</div>

            <br />

            <div id="clickableId2">Clickable Elem 2</div>           

        </div>       

    </body>

</html>

 

We could add the standard XML header (<?xml…?>), it is optional and may be interesting when DOCTYPE is XHTML.

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

 

Note the isnat:nocache attribute (and the XML mandatory itsnat namespace declaration), this attribute, set to true, tells the framework to avoid caching the <div> content. <head> and <h3> elements will be cached automatically, for instance, in the server DOM, <head> contains a text node with a cache mark as the only child node, <h3> is not touched actually because the framework detects there is no saving (only contains and very small text). The nocache attribute is needed because this page is cached by default to save memory, cached DOM fragments are shared between pages in form of serialized text.

This file will work as a template, and usually is not directly accessible with a public URL, so it will be saved below the standard WEB-INF folder, for instance:

<WebAppRoot>/WEB-INF/pages/manual/core_example.html

5.1.4       Registering the page template

Now we need to bind the template with ItsNat with the following instructions (again inside init() method):

    String pathPrefix = getServletContext().getRealPath("/");

    pathPrefix += "/WEB-INF/pages/manual/";

 

    ItsNatHttpServlet itsNatServlet = getItsNatHttpServlet();

    ItsNatDocumentTemplate docTemplate;

    docTemplate = itsNatServlet.registerItsNatDocumentTemplate("manual.core.example",

               "text/html",pathPrefix + "core_example.html");

 

ItsNat identifies the template with the specified name, manual.core.example, this name uses a Java-like format; this format is not mandatory but is recommended.

In this example no special configuration technique or framework is used and a hard coded file name is used in the code, if you think this approach is not elegant use the configuration technique you like more (.properties, custom XML, Spring …), the easiest way is to use .properties archives using the template names as keys and the relative file path as value.

Why a XHTML file is registered with text/html MIME? Most of supported browsers accept application/xhtml+xml header but Microsoft Internet Explorer (MSIE) 6-8 does not, this is the most compatible declaration and is the main reason why the MIME type must be explicitly declared when registering.

5.1.5       Testing the template with a link or URL

Inside any static html, JSP etc add the following relative link:

        <a href="servlet?itsnat_doc_name=manual.core.example">Core Example</a>

or type the following in your browser:

http://<host>:<port>/<yourapp>/servlet?itsnat_doc_name=manual.core.example

A page like this will be loaded in your browser:

This page is the template page with no “user defined” processing. If you inspect the source code the page is not exactly the original template, some non-intrusive JavaScript code was added automatically at the end of the page, this JavaScript, mostly the “unload” event listener, controls the page lifecycle notifying when the page is unloaded.

Page templates can be modified while running and modifications are shown when the page is reloaded, this is very useful to change the layout when nothing functional changes without redeploying the application. For instance try to change the page title and reload again.

5.1.6       Adding behavior

We need to intercept any request to the manual.core.example page, to achieve this we need to register a “load listener” to the ItsNatDocumentTemplate object of the page:

 

        docTemplate.addItsNatServletRequestListener(new CoreExampleLoadListener());

 

The CoreExampleLoadListener source code:

package org.itsnat.manual;

 

import org.itsnat.core.html.ItsNatHTMLDocument;

import org.itsnat.core.ItsNatServletRequest;

import org.itsnat.core.ItsNatServletRequestListener;

import org.itsnat.core.ItsNatServletResponse;

 

public class CoreExampleLoadListener implements ItsNatServletRequestListener

{

    public CoreExampleLoadListener()

    {

    }

 

    public void processRequest(ItsNatServletRequest request,

                               ItsNatServletResponse response)

    {

        ItsNatHTMLDocument itsNatDoc =

               (ItsNatHTMLDocument)request.getItsNatDocument();

        new CoreExampleDocument(itsNatDoc);

    }   

}

The processRequest method mimics HttpServlet.doGet/doPost methods, but using ItsNat object layers (in fact request and response are ItsNatHttpServletRequest and ItsNatHttpServletResponse objects). This method is called every time the page is requested to load by the client; the same page can be loaded several times and several browser windows can load the same page.

The ItsNatHTMLDocument object is the ItsNat object layer covering the DOM HTMLDocument object. The HTMLDocument instance is a template clone; every loaded page has a different ItsNatHTMLDocument/HTMLDocument object pair, then any modification made on an HTMLDocument while loading only affects to the concrete page loading.

An ItsNatHTMLDocument/HTMLDocument object pair lives during the lifecycle of the page and by default ItsNat keeps the page state in server, any subsequent AJAX/SCRIPT based event is targeted to the concrete document object in the server.

ItsNatHttpServletRequest and ItsNatHttpServletResponse are unique per request and must not be saved beyond the request (load or event request) like the standard servlet request/response counterparts wrapped by these ItsNat objects.

To isolate the document load processing and save any desired per loaded page state, a CoreExampleDocument auxiliary object is created; this object does not need to be saved (registered etc).

 

package org.itsnat.manual;

 

import org.itsnat.core.html.ItsNatHTMLDocument;

import org.w3c.dom.Element;

import org.w3c.dom.Text;

import org.w3c.dom.html.HTMLDocument;

 

public class CoreExampleDocument

{

    protected ItsNatHTMLDocument itsNatDoc;

    protected Element clickElem1;

    protected Element clickElem2;   

   

    public CoreExampleDocument(ItsNatHTMLDocument itsNatDoc)

    {

        this.itsNatDoc = itsNatDoc;

        load();

    }

 

    public void load()

    {

        HTMLDocument doc = itsNatDoc.getHTMLDocument();

        this.clickElem1 = doc.getElementById("clickableId1");

        this.clickElem2 = doc.getElementById("clickableId2");       

       

        clickElem1.setAttribute("style","color:red;");

        Text text1 = (Text)clickElem1.getFirstChild();

        text1.setData("Click Me!");

       

        Text text2 = (Text)clickElem2.getFirstChild();

        text2.setData("Cannot be clicked");

 

        Element noteElem = doc.createElement("p");

        noteElem.appendChild(doc.createTextNode("Ready to receive clicks..."));

        doc.getBody().appendChild(noteElem);

    }

}

 

The load method modifies the document changing text nodes and adding a final element, using pure Java DOM because the page DOM tree page is in the server as a Java W3C DOM tree. Any change to the original template is sent to the client.

Redeploying and reloading:

If you click the “Click Me!” text nothing occurs, we must register a DOM event listener:

 

package org.itsnat.manual;

 

import org.itsnat.core.ItsNatDocument;

import org.itsnat.core.ItsNatServletRequest;

import org.itsnat.core.event.ItsNatEvent;

import org.itsnat.core.html.ItsNatHTMLDocument;

import org.w3c.dom.Element;

import org.w3c.dom.Text;

import org.w3c.dom.events.Event;

import org.w3c.dom.events.EventListener;

import org.w3c.dom.events.EventTarget;

import org.w3c.dom.html.HTMLDocument;

 

public class CoreExampleDocument implements EventListener

{

    ...

    public void load()

    {

        ...       

        ((EventTarget)clickElem1).addEventListener("click",this,false);

    }

 

    public void handleEvent(Event evt)

    {

        EventTarget currTarget = evt.getCurrentTarget();

        if (currTarget == clickElem1)

        {

            removeClickable(clickElem1);

            setAsClickable(clickElem2);

        }

        else

        {

            setAsClickable(clickElem1);

            removeClickable(clickElem2);

        }           

       

        ItsNatEvent itsNatEvt = (ItsNatEvent)evt;

        ItsNatServletRequest itsNatReq = itsNatEvt.getItsNatServletRequest();

        ItsNatDocument itsNatDoc = itsNatReq.getItsNatDocument();

        HTMLDocument doc = (HTMLDocument)itsNatDoc.getDocument();

        Element noteElem = doc.createElement("p");

        noteElem.appendChild(doc.createTextNode("Clicked " +

               ((Element)currTarget).getAttribute("id")));

        doc.getBody().appendChild(noteElem);       

    }

   

    public void setAsClickable(Element elem)

    {

        elem.setAttribute("style","color:red;");

        Text text = (Text)elem.getFirstChild();

        text.setData("Click Me!");

        ((EventTarget)elem).addEventListener("click",this,false);       

    }

   

    public void removeClickable(Element elem)

    {

        elem.removeAttribute("style");

        Text text = (Text)elem.getFirstChild();

        text.setData("Cannot be clicked");

        ((EventTarget)elem).removeEventListener("click",this,false); 

    }

}

Redeploying and reloading again our web page now receives clicks and sends client events to the server using AJAX (because AJAX asynchronous-hold mode is the declared mode by default). Now both DOM elements are enabled/disabled to receive events every time the appropriate element is clicked.

The code fragment:

 

        ItsNatEvent itsNatEvt = (ItsNatEvent)evt;

        ItsNatServletRequest itsNatReq = itsNatEvt.getItsNatServletRequest();

        ItsNatDocument itsNatDoc = itsNatReq.getItsNatDocument();

        HTMLDocument doc = (HTMLDocument)itsNatDoc.getDocument();

 

Is used to show how the DOM Event object is implemented by ItsNat and can be used to obtain the ItsNatServletRequest object (ItsNatHttpServletRequest actually). Of course the returned ItsNatDocument is the same object as the itsNatDoc field.

We have finished our first ItsNat AJAX based web application!

5.2      A COMPONENT BASED WEB APPLICATION

Now we develop an ItsNat application using components. In this example an <input type=”text”> element will be bound to a component at the server.

The development lifecycle is basically the same as the previous example.

5.2.1       Designing the template

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">

    <head>

        <title>ItsNat Components Example</title>

    </head>

    <body>

        <h3>ItsNat Components Example</h3>

       

        <div>

            <input type="text" id="inputId" value="" size="40" />                      

        </div>       

    </body>

</html>

 

We can see a “big” difference with the previous “core” example: itsnat:nocache is not needed. Why? Because ItsNat detects there is an element “dynamic” by nature, the <input> element; ItsNat automatically prevents the <div> element to be cached (to avoid the <input> removal). 

This file will be saved as:

<WebAppRoot>/WEB-INF/pages/manual/comp_example.html

5.2.2       Registering the template

Method init(ServletConfig):

 

    docTemplate = itsNatServlet.registerItsNatDocumentTemplate("manual.comp.example",

                       "text/html", pathPrefix + "comp_example.html");

    docTemplate.addItsNatServletRequestListener(new CompExampleLoadListener()); 

     

Now the template is registered and a CompExampleLoadListener object and ready to process load request:

. . .

public class CompExampleLoadListener implements ItsNatServletRequestListener

{

    public CompExampleLoadListener()

    {

    }

 

    public void processRequest(ItsNatServletRequest request,

                               ItsNatServletResponse response)

    {

        ItsNatHTMLDocument itsNatDoc =

                               (ItsNatHTMLDocument)request.getItsNatDocument();

        new CompExampleDocument(itsNatDoc);

    }   

}

 

The load listener delegates to CompExampleDocument, this is a first draft:

 

package org.itsnat.manual;

 

import org.itsnat.comp.ItsNatComponentManager;

import org.itsnat.comp.text.ItsNatHTMLInputText;

import org.itsnat.core.html.ItsNatHTMLDocument;

import org.w3c.dom.html.HTMLDocument;

 

public class CompExampleDocument

{

    protected ItsNatHTMLDocument itsNatDoc;

    protected ItsNatHTMLInputText inputComp; 

   

    public CompExampleDocument(ItsNatHTMLDocument itsNatDoc)

    {

        this.itsNatDoc = itsNatDoc;

        load();

    }

 

    public void load()

    {

        ItsNatComponentManager componentMgr =

                                      itsNatDoc.getItsNatComponentManager();       

        this.inputComp =

               (ItsNatHTMLInputText)componentMgr.addItsNatComponentById("inputId");       

        inputComp.setText("Change this text and lost the focus");       

 

        inputComp.focus();       

        inputComp.select();           

    }

}

The ItsNatComponentManager object works like a page component registry/factory, the addItsNatComponentById call obtains the <input> element calling ItsNatDocument.getElementById, and returns a new ItsNatHTMLInputText component, this type is the appropriate to the <input type=”text”> control. The component is registered in the component manager registry too, the same component/object is returned with a call like:

      componentMgr.findItsNatComponentById("inputId");

The ItsNatHTMLInputText component has several missions:

1.    Wraps the associated DOM HTMLInputElement object.

2.    Works as a UI coordinator: modifies the DOM object when appropriate (delegating to the ItsNatTextFieldUI object).

3.    Synchronizes a javax.swing.text.Document data model object with the server DOM element (if the data model is changed the DOM server object is changed automatically).

4.    Receives the “change” browser DOM event, updating the data model and DOM server element with the new text.

Returning to the example, the line:

      inputComp.setText("Change this text and lost the focus");

Changes the data model (a javax.swing.text.PlainDocument by default) with the new text, this change can be performed using the javax.swing.text.Document object directly. When a data model is bound to the component (a default data model is ever bound by default) the component registers an internal DocumentListener, this listener changes the DOM server HTMLInputElement element; if the server element is changed an mutation event is fired and processed by ItsNat generating JavaScript to send to the browser to change the client element too when the server process returns.

The followings lines:

        inputComp.focus();       

        inputComp.select();

 

Sends JavaScript code to the browser to call focus() and select() in the <input> DOM element. These method calls do the same as HTMLInputElement.focus() and select() methods in non-internal mode (ItsNatNode.isInternalMode() returns false).

This is the link to execute the example:

 

    <a href="servlet?itsnat_doc_name=manual.comp.example">Component Example</a>

 

And the visual result:

If the text is changed (and the focus is lost) the component data model is automatically updated.

To detect user changes we can add listeners: a “change” DOM event listener and a javax.swing.event.DocumentListener. In this example any text change is logged, but of course many serious tasks can be done as updating a database (as a response of a javax.swing.event.DocumentEvent).

The complete CompExampleDocument source code:

 

package org.itsnat.manual;

 

import javax.swing.event.DocumentEvent;

import javax.swing.event.DocumentListener;

import javax.swing.text.BadLocationException;

import javax.swing.text.PlainDocument;

import org.itsnat.comp.ItsNatComponentManager;

import org.itsnat.comp.text.ItsNatHTMLInputText;

import org.itsnat.core.html.ItsNatHTMLDocument;

import org.w3c.dom.Element;

import org.w3c.dom.events.Event;

import org.w3c.dom.events.EventListener;

import org.w3c.dom.html.HTMLDocument;

 

public class CompExampleDocument implements EventListener,DocumentListener

{

    protected ItsNatHTMLDocument itsNatDoc;

    protected ItsNatHTMLInputText inputComp; 

   

    public CompExampleDocument(ItsNatHTMLDocument itsNatDoc)

    {

        this.itsNatDoc = itsNatDoc;

        load();

    }

 

    public void load()

    {

        ItsNatComponentManager componentMgr =

               itsNatDoc.getItsNatComponentManager();

       

        this.inputComp =                (ItsNatHTMLInputText)componentMgr.addItsNatComponentById("inputId");         

        inputComp.setText("Change this text and lost the focus");       

 

        inputComp.addEventListener("change",this);

       

        PlainDocument dataModel = (PlainDocument)inputComp.getDocument();

        dataModel.addDocumentListener(this);

 

        inputComp.focus();       

        inputComp.select();           

    }

 

    public void handleEvent(Event evt)

    {

        log("Text has been changed");            

    }

 

    public void insertUpdate(DocumentEvent e)

    {

        javax.swing.text.Document docModel = e.getDocument();

        int offset = e.getOffset();           

        int len = e.getLength();

       

        try

        {

            log("Text inserted: " + offset + "-" + len + " chars,\"" +

               docModel.getText(offset,len) + "\"");

        }

        catch(BadLocationException ex)

        {

            throw new RuntimeException(ex);

        }

    }

 

    public void removeUpdate(DocumentEvent e)

    {

        int offset = e.getOffset();           

        int len = e.getLength();

 

        log("Text removed: " + offset + "-" + len + " chars");     

    }

 

    public void changedUpdate(DocumentEvent e)

    {

        // A PlainDocument has no attributes

    }

   

    public void log(String msg)

    {

        HTMLDocument doc = itsNatDoc.getHTMLDocument();       

        Element noteElem = doc.createElement("p");

        noteElem.appendChild(doc.createTextNode(msg));

        doc.getBody().appendChild(noteElem);       

    }

}

And finally the screenshot:

 

6. CORE MODULE FEATURES

6.1      DHTML ON THE SERVER

This is the most important feature of ItsNat, any change performed in the server DOM using normal Java W3C DOM methods automatically generates custom JavaScript to automatically change the client DOM too.

6.1.1       Text nodes

Text nodes are problematic in DOM because text nodes can be filtered and contiguous nodes can be automatically joined (normalized) by clients. For instance some browsers filter text nodes with spaces when the page is first loaded from markup. W3C DOM standard recommends text nodes must be normalized, that is, contiguous text nodes should be joined and this is the preferred mode of ItsNat. Before you insert a new text node be sure there is no other sibling text node, if present avoid this insertion and change the text value (calling setData(String)) of this already inserted text node accordingly.

Contiguous text nodes or text nodes with spaces are not an insurmountable problem for ItsNat because internal paths used to locate nodes in server and in client are calculated ignoring text nodes. The only case text nodes are used to calculate paths is when a text node is itself targeted (for instance a text node being removed or text content updated). 

6.2      DOM EVENT LISTENERS

Because ItsNat simulates the behavior of a W3C browser in the server, this applies to DOM events, in ItsNat you can register W3C DOM event listeners associated to DOM nodes in the server, these listeners are remote listeners, that is, automatically JavaScript code is generated behind the scenes to add a proxy listener in the client associated to the mirror DOM node in the client, this proxy listener forwards any client event received by this node and matching the event type, to the server using AJAX or auxiliary SCRIPT elements as transport technique. The Java DOM event listener in the server is dispatched receiving a W3C DOM Event as having been “fired” in the server[40]. Only browser events with some event listener associated in server are sent to the server.

A DOM event listener is an org.w3c.dom.events.EventListener object associated to a Java DOM element and a specific event type (for instance click) in the server side, ready to be executed when the browser fires this event associated with the symmetric DOM element in client side.

Java server DOM event listeners are registered calling org.w3c.dom.events.EventTarget.addEventListener(String,EventListener,boolean)[41] or ItsNatDocument.addEventListener(…) methods, ItsNatDocument versions include more optional parameters.

Of course symmetric methods can be used to unregister these event listeners: org.w3c.dom.events.EventTarget.remoteEventListener(String,EventListener,boolean) or ItsNatDocument.removeEventListener(…). Only DOM nodes into the document tree can receive remote DOM events.

ItsNat does a strong effort to provide a complete W3C DOM Events support (server point of view) in browsers with a poor support of this standard, for instance, ItsNat provides capturing (useCapture parameter as defined in W3C DOM Level 2 Events[42] standard) in browsers like Internet Explorer.

In Internet Explorer (a non-W3C browser) W3C DOM Events standard is simulated from a server point of view:

1.    Listeners are executed (dispatched) in the same order they were registered in the node. This is the correct mode of W3C and is not the way as IE works.

2.    Event capturing is simulated: this simulation fully works with ItsNat based event listeners in server because user defined inline handlers in client (e.g. onclick="...") are executed before capturing listeners defined in ancestor nodes (and this is not correct).

As Internet Explorer automatically bubbles, this browser is almost W3C DOM Events compliant from a server point of view.

In Internet Explorer Mobile 6 (WM 6) and capturing and bubbling are simulated too.

The remote event system can be tuned with optional parameters: communication modes, extra parameters and custom pre-send JavaScript code can be associated too. These parameters are optional and can be used when registering a listener with addEventListener.

6.2.1       Communication modes for events

When the browser fires an event and some registered server side listener was registered for this event, ItsNat uses an XMLHttpRequest object or an auxiliary SCRIPT element to send the event data and receive the JavaScript code. As everybody knows, AJAX request can be executed synchronously and asynchronously, SCRIPT transport is essentially asynchronous.

6.2.1.1   AJAX synchronous mode

The AJAX synchronous mode is the most secure and reliable, because the application has full control of the lifecycle, this is the most similar approach to the typical one-thread event dispatcher of desktop applications; the obvious problem is the browser freezes during event processing, this is not a problem in a desktop application but is not usual in a web application.

AJAX synchronous mode can be specified using the constant:

org.itsnat.core.CommMode.XHR_SYNC

as the value of the commMode parameter registering an event listener.

6.2.1.2   Asynchronous modes

AJAX asynchronous or SCRIPT communication modes are more user friendly because there is no browser blocking but they are insecure from the “application point of view”. ItsNat has two asynchronous modes, pure and hold.

The asynchronous pure modes are almost synchronous in ItsNat, because the framework automatically locks (synchronizes) the ItsNatDocument target; only one thread can (should) modify the ItsNatDocument and dependent objects like the DOM tree and components. ItsNat synchronizes web request threads requesting access to the same ItsNatDocument object (usually events transported by AJAX or SCRIPT), only one thread per ItsNatDocument is allowed to be processed, by this way an ItsNat application can be considered thread-safe. The pure AJAX or SCRIPT asynchronous mode do not prevent that the second event fired by the browser arrives first to the server and gains control of the ItsNatDocument object before the first event. 

Pure asynchronous modes can be specified using the constants:

org.itsnat.core.CommMode.XHR_ASYNC

org.itsnat.core.CommMode.SCRIPT

as the commMode parameter registering an event listener.

6.2.1.3   Asynchronous-Hold modes

ItsNat offers a third type mode of communication valid for AJAX and SCRIPT: the asynchronous-hold mode. In this mode there is no browser freeze (communication with server is asynchronous) and pending events are queued in arrival order (like a FIFO list) in the browser, waiting to the current event to be fully processed.  This mode offers the best of both worlds.

The only main caveat is: queued events cannot be cancelled because the browser considers these events as processed, neither server side org.w3c.dom.events.Event methods like stopPropagation() and preventDefault() should be called nor reading/writing native JavaScript properties[43] of event objects.

Asynchronous-Hold modes can be specified using the constants:

org.itsnat.core.CommMode.XHR_ASYNC_HOLD

org.itsnat.core.CommMode.SCRIPT_HOLD

as the commMode parameter registering an event listener.

CommMode.SCRIPT_HOLD is highly recommended instead of CommMode.SCRIPT mode because requests performed by SCRIPT elements are really asynchronous.

6.2.2       Extra parameters

By default any received org.w3c.dom.events.Event object carries the standard W3C-DOM event properties (current target and target nodes, mouse x and y positions and so on). Sometimes we need to get specific info from client, to achieve this any browser event can carry user defined extra parameters.

For instance if we need the current document title we can add a listener ready to receive events with this information:

 

    ItsNatDocument itsNatDoc = ...;

    Element anElem = ...; 

    EventListener anListener = new EventListener()

    {

        public void handleEvent(Event evt)

        {

            ItsNatEvent itsNatEvt = (ItsNatEvent)evt;

            String title = (String)itsNatEvt.getExtraParam("title");

            System.out.println("Page title: " + title);

        }

    };

    CustomParamTransport extraParam =

               new CustomParamTransport ("title","document.title");

    itsNatDoc.addEventListener((EventTarget)anElem,"click",anListener,false,

        new ParamTransport[]{ extraParam });

 

The ClientParam object specifies a name and a JavaScript code to execute when the event is fired, this class is a specialization of the abstract class ParamTransport used to transport client to server data. In this example the name “title” is the extra parameter name, is used only to identify the parameter, and “document.title” is the JavaScript code used to get the parameter value, executed in the browser when the event is fired. CustomParamTransport inherits from ParamTransport, this class is the base of the classes oriented to transport data from the client.

6.2.3       Custom pre-send JavaScript code

Custom user-defined JavaScript code can be executed every time an event is fired (parameter preSendCode).

Example:

 

    ItsNatDocument itsNatDoc = ...;

    EventTarget anElem = ...; 

    EventListener anListener = ...;

    String code = "   alert('Fired a ' + event.getNativeEvent().type + ' event');\n";

    itsNatDoc.addEventListener(anElem,"click",anListener,false,code);       

 

This is a fragment of the JavaScript code generated[44]:

 

    var func = function (event)

    {

       alert('Fired a ' + event.getNativeEvent().type + ' event');

    };

 

This JavaScript function is called when a click event is dispatched to the specified target element. The event parameter is a wrapper of the native event object, this native event can be obtained calling event.getNativeEvent().

Another public JavaScript method of event object wrapper is setMustBeSent(boolean). If the parameter is false this event is not sent to the server (by default is true, event is sent). This method is interesting because remote event listeners can be used to add/remove cross-platform event listeners executed only in client. Must be reminded ItsNat adds support of capture events to Internet Explorer 6+ (desktop and mobile), bubbling is already supported.

6.2.4       Event timeout

The timeout of asynchronous AJAX/SCRIPT events can be specified when registering a listener for instance as the last parameter in:

    public void addEventListener(EventTarget target,String type,

        EventListener listener, boolean useCapture,int commMode,

        ParamTransport[] extraParams,String preSendCode,long eventTimeout);

 

If not specified the default value of the document is used.

Use this feature with care (by default there is no timeout), an aborted request may stop a COMET process, a timer, a remote view/control process etc, and the worst thing, the client may remain unsynchronized.

6.2.5       Load and unload events

Java DOM elements (org.w3c.dom.Element) and org.w3c.dom.Document objects can be targets of remote event listeners. Load and unload event types are special because in the window object is the target. To emulate this behavior, ItsNat implements a fake window object implementing the official W3C AbstractView interface, this object implements Node (most of the methods are invalid) and EventTarget interfaces too; this window object can be obtained using the Document object because it implements DocumentView.

The following example shows how the “load” and “unload” events can be listened:

 

    ItsNatDocument itsNatDoc = ...;

    Document doc = itsNatDoc.getDocument();

    AbstractView view = ((DocumentView)doc).getDefaultView();

    EventListener listener = new EventListener()

    {

        public void handleEvent(Event evt)

        {

            System.out.println(evt.getType()); // outs load/unload

        }           

    };

    ((EventTarget)view).addEventListener("load",listener,false);        

    ((EventTarget)view).addEventListener("unload",listener,false);

 

6.2.6       Key events

The W3C DOM Events Level 2 does not define a key event standard API, at the time of writing W3C DOM Events Level 3 is still a draft, this standard defines key events but the specification have been evolving.

 

This is the current state (desktop):

 

·       Internet Explorer +6: has the traditional proprietary key event API, in fact MSIE has only one type of event[45].

 

·       Gecko browsers (Mozilla, FireFox): key event API is based on an early W3C DOM 2 draft[46], this API was removed on the final Recommendation.

 

·       Safari 3 (Webkit browsers in general): is compliant with an old W3C DOM 3 draft[47], this API is not the current.

 

·       Opera (Presto): key event API is a mix of W3C and MSIE, with properties like keyCode, altKey, shiftKey and ctrlKey. Key events can be created programmatically in Opera with the standard call DocumentEvent.createEvent(String) with “Events” as the type, initialized with the Event.initEvent and “manually” adding the properties keyCode, altKey, shiftKey and ctrlKey. As MSIE the property keyCode is the char code on “keypress” events.

 

In ItsNat Firefox is considered the facto W3C standard implementation, ItsNat defines an interface, org.itsnat.core.event.ItsNatKeyEvent, to provide a standard key event API, this interface is basically the key event interface used by Gecko browsers[48]. Any client key event is converted on the server to this event API, the behaviour of a Firefox key event is simulated too if the client is not a Gecko browser. Key events can be created programmatically on the server calling DocumentEvent.createEvent(String) (ItsNatNode.isInternalMode() must return false, the default value) or ItsNatDocument.createEvent(String) with “KeyEvents” or “KeyEvent” type as parameter, then use ItsNatKeyEvent.initKeyEvent method to initialize this object.

 

6.2.7       Global event listeners

DOM event listeners are registered per target, event type and capture mode, when a listener is registered in the server, custom JavaScript code is send to the client to register a client stub to forward client events targeting the same triad to the server.

ItsNat provides DOM global event listeners, a global event listener is an org.w3c.dom.EventListener object registered with the following methods:

1.    ItsNatServer.addEventListener(EventListener): per servlet registry.

2.    ItsNatDocumentTemplate.addEventListener(EventListener): per template registry.

3.    ItsNatDocument.addEventListener(EventListener): per document registry.

A global listener is called when any DOM client event is received by a document in the server which matches the condition of the registry (global listener was registered in this document, or target document is associated to the specified document template or servlet used in the registry).

A global listener is passive, that is when registered no JavaScript code is generated to send to the client and is designed for monitoring events received by “normal” DOM listeners because global listeners are dispatched before normal listeners.

For instance, global listeners may be used to monitor (and may be modify) the state of the markup and data model of an ItsNat component before an event is dispatched to the component, because some events automatically modify the markup and state of components as the normal behaviour. Methods like Event.getType() and Event.getCurrentTarget() may be used to identify the target and type of action.

6.2.8       Chain control of event listeners

ItsNat sends an event from client to server per listener registered, that is to say one server listener is dispatched per request.

This is not applied to global listeners registered in servlet, template or document; these listeners are executed before normal listeners in the same request/event processing.

Event listener chain control can be used by global listeners to control how following listeners are executed. The object used to control this flow implements ItsNatEventListenerChain, and is obtained calling ItsNatEvent.getItsNatEventListenerChain(). For instance, if ItsNatEventListenerChain.continueChain() is called, listener dispatching flow will follow this path, that is to say, next listeners will be executed before returning this method. This feature can be used to catch exceptions, to open and commit transactions etc.

The method ItsNatEventListenerChain.stop() is used to stop the normal dispatching flow, listeners following (including global) are not executed.

The following example shows how to register a global listener to automatically reload the page when some error occurs processing AJAX/SCRIPT events (usually a user defined or internal component event listener threw an exception).

 

final ItsNatDocument itsNatDoc = ...;

EventListener global = new EventListener()

{

    public void handleEvent(Event evt)

    {

        ItsNatEventListenerChain chain =

               ((ItsNatEvent)evt).getItsNatEventListenerChain();

        try

        {

            chain.continueChain();

        }

        catch(Exception ex)

        {

            itsNatDoc.addCodeToSend("alert('Unexpected Error! The page will

               reload.');");

      itsNatDoc.addCodeToSend("window.location.reload(true);");

 

            itsNatDoc.setInvalid();

            chain.stop();

        }

   }

};

itsNatDoc.addEventListener(global);

 

This example avoids the default error processing (exception stack shown to the user)[49].

One more complicated example is found in the “Feature Showcase” demo.

DOM event listeners in components registered calling ItsNatComponent.addEventListener(…) can be used to control the listener dispatching flow, because these listeners are dispatched sharing the same AJAX/SCRIPT request (event) and in registration order. Usually ItsNat components have a default behavior associated to a event type, a user event listener can be registered to be executed before/after the execution of the default behavior.

Event listener chain control is available on remote view/control events (ItsNatAttachedClientEvent) too.

6.2.9       Detection of session or page lost with global event listeners

In an ItsNat based application using events the browser page is in sync with “a page” (an ItsNatDocument) in server. In the following scenarios the server page associated to the page in browser is lost:

 

  1. Servlet container or web application context was reloaded.
  2. Session has expired.
  3. Server page/document was invalidated explicitly in server (for instance when they are too many open pages).
  4. The user has returned to the page using back/forward in a browser caching pages. ItsNat tries to disable page caching automatically reloading the page, in some browsers is not possible (usually some mobile browsers).

 

When the user tries to use the web page as usual (for instance clicking something) an AJAX/SCRIPT event is sent to the server, ItsNat detects there is no target document in server (there is no matching ItsNatDocument and ClientDocument).  

 

ItsNat gives an opportunity to user code to manage this scenario dispatching this DOM event to the global event listeners registered on the ItsNatServlet object calling ItsNatServlet.addEventListener(EventListener).

 

This DOM event is special, most of the methods are useless and throw an exception if called and the most important characteristic, ItsNatEvent.getItsNatDocument() returns null (this is the way to detect a lost user page sending events). Only “unload” and “beforeunload” events are excluded and not dispatched to global listeners in servlet, because these events are sent when the user is leaving or closing the web page, in these cases ItsNat does nothing.

 

If there is no global listener registered in ItsNatServlet, ItsNat by default sends the following JavaScript instruction, window.location.reload(true) as the event response.

 

The following example shows how to detect and manage a DOM event with no server page associated. This global listener must be registered the first because the call itsNatEvt.getItsNatEventListenerChain().stop() tries to avoid next global listeners are executed.

 

ItsNatHttpServlet itsNatServlet = ...;       

EventListener listener = new EventListener()

{

    public void handleEvent(Event evt)

    {

        ItsNatEvent itsNatEvt = (ItsNatEvent)evt;

        if (itsNatEvt.getItsNatDocument() == null)

        {

           ItsNatServletResponse response =

               itsNatEvt.getItsNatServletResponse();

           response.addCodeToSend(

                 "alert('Session or page was lost. Reloading...');");

     response.addCodeToSend("window.location.reload(true);");

           itsNatEvt.getItsNatEventListenerChain().stop();

        }

    }  

};

itsNatServlet.addEventListener(listener);

6.3      REMOTE VS INTERNAL DOM NODE

ItsNat extends Batik DOM to provide a transparent “The Browser Is The Server” experience to the developer using W3C DOM methods as much as possible. By default the DOM tree works in “remote” mode, that is, any action usually modifies the client state in some way:

A.    Any structural change in the document tree is reflected in the client DOM.

B.    The following methods work in “remote” mode:

1.    Any event listener registered calling org.dom.events.EventTarget.addEventListener(…) and unregistered calling org.dom.events.EventTarget.removeEventListener(…) is registered/unregistered in the client too:

2.    DocumentEvent.createEvent(String)[50] creates a “remote” event, the method EventTarget.dispatchEvent(Event) detects if the event submitted is remote, if so the call is redirected to ItsNatDocument.createEvent(String).

3.    Methods like HTMLInputElement.focus() generate and send JavaScript code to do the same action in the client.

This is the default and recommended behavior, however sometimes we need non-remote behavior:

A.    To avoid automatic synchronization in the client of DOM structural changes, ItsNat provides two methods: ItsNatDocument.disableSendCode() and ClientDocument.disableSendCode(), these methods avoid sending JavaScript code to the client. Use them with extreme care because the client can result unsynchronized (in fact this is the use case).

B.    Any DOM node implements ItsNatNode, this interface is used to extend the standard DOM API. If the node is set as “internal” calling ItsNatNode.setInternalMode(boolean) with a parameter true (ItsNatNode.isInternalMode() will return true, the default is false). This flag affects the behavior of DOM methods as following:

a.    EventTarget.addEventListener(…) and EventTarget.removeEventListener(…) register/unregister event listeners using the internal registry of Batik. Monitoring DOM tree changes using mutation listeners is almost the only one use case, the following example is the recommended way to do this:

 

    Element elem = ...;

    EventListener listener = ...;

    boolean old = ((ItsNatNode)elem).isInternalMode();

    ((ItsNatNode)elem).setInternalMode(true);

    try

    {

      ((EventTarget)elem).addEventListener("DOMNodeInserted",

                                listener,false);

    }

    finally

    {

        ((ItsNatNode)elem).setInternalMode(old);

    }

b.    DocumentEvent.createEvent(String) now creates an internal event, the method EventTarget.dispatchEvent(Event) dispatches this event to the internal event listeners (event listeners registered in internal mode). There is no known use case.

c.    Methods like HTMLInputElement.focus() do nothing in internal mode.

6.4      REMOTE DOM MUTATION EVENT LISTENERS

W3C DOM Events Level 2 defines mutation events, mutation events are fired when a DOM node is changed in some way (a node or attribute was inserted, removed or updated). Currently, only W3C browsers (FireFox, Chrome, Safari[51], Opera Presto and WebKit etc) support mutation events.

ItsNat is designed as a server centric tool, the browser is automatically updated when the server DOM tree changes, there is no “out of the box” support to update the server DOM tree when the browser DOM tree changes[52].

This scenario is a bit different with W3C browsers, ItsNat has a special support of “remote” mutation events, offering the tools to automatically update the server when the client DOM changes. Mutation events can be received using normal listeners registered with EventTarget.addEventListener(…) or ItsNatDocument.addEventListener(…) methods but the event info is not enough to synchronize the server DOM with the client changes.

ItsNat defines the method ItsNatDocument.addMutationEventListener, this method internally uses a special “remote parameter” object, NodeMutationTransport; this class has a similar mission to the CustomParamTransport class and tells to ItsNat to transport the necessary mutation data from client to server.

When a mutation event is fired in the client, all needed information is collected and sent to the mutation listener, this object synchronizes the client change with the server. The addMutationEventListener method registers the listener to track and synchronize any change performed in the submitted element and children (subtree) in the client, receiving any DOMNodeInserted, DOMNodeRemoved, DOMAttrModified or DOMCharacterDataModified event fired in the subtree.

Current ItsNatDocument.addMutationEventListener implementation does the following:

 

    public void addMutationEventListener(EventTarget target,

        EventListener listener,boolean useCapture,int commMode,String preSendCode)

    {

        ParamTransport[] params =

               new ParamTransport[]{new NodeMutationTransport()};

        addEventListener(target,"DOMAttrModified",listener,useCapture,

               commMode,params,preSendCode);

        addEventListener(target,"DOMNodeInserted",listener,useCapture,

               commMode,params,preSendCode);

        addEventListener(target,"DOMNodeRemoved",listener,useCapture,

               commMode,params,preSendCode);             addEventListener(target,"DOMCharacterDataModified",listener,

               useCapture,commMode,params,preSendCode);       

    }   

 

An example:

 

    ItsNatDocument itsNatDoc = ...;

    Document doc = itsNatDoc.getDocument();

 

    EventListener listener = new EventListener()

    {

        public void handleEvent(Event evt)

        {

            MutationEvent mutEvent = (MutationEvent)evt;

 

            String type = mutEvent.getType();

            if (type.equals("DOMNodeInserted"))

            {

                Element parent = (Element)mutEvent.getRelatedNode();

                Node newNode = (Node)mutEvent.getTarget();

                System.out.println("DOMNodeInserted " + newNode + " " +

                       newNode.getNextSibling());

            }

            else if (type.equals("DOMNodeRemoved"))

            {

                Element parent = (Element)mutEvent.getRelatedNode();

                Node removedNode = (Node)mutEvent.getTarget();  

                System.out.println("DOMNodeRemoved " + removedNode + " " +

                       parent);

            }

            else if (type.equals("DOMAttrModified"))

            {

                Attr attr = (Attr)mutEvent.getRelatedNode();           

                Element elem = (Element)mutEvent.getTarget();            

                String attrValue = elem.getAttribute(mutEvent.getAttrName());

                String changeName = null;           

                int changeType = mutEvent.getAttrChange();

                switch(changeType)

                {

                    case MutationEvent.ADDITION:

                        changeName = "addition";

                        break;

                    case MutationEvent.MODIFICATION:

                        changeName = "modification";                   

                        break;

                    case MutationEvent.REMOVAL:

                        changeName = "removal";                   

                        break;   

                }

                System.out.println("DOMAttrModified (" + changeName + ") " +

                       mutEvent.getAttrName() + " " + attrValue + " " + elem);

            }

            else if (type.equals("DOMCharacterDataModified"))

            {

                CharacterData charNode = (CharacterData)mutEvent.getTarget();

                System.out.println("DOMCharacterDataModified " +

                       mutEvent.getNewValue());

            }                       

        }

    };

 

    itsNatDoc.addMutationEventListener((EventTarget)doc,listener,false);

   

In this example a custom listener object is registered to listen document changes as mutation events fired by the browser, this listener is called after the server was automatically synchronized with client changes. The Document object is used as target, therefore any client change realized in the DOM client tree is automatically synchronized at the server DOM tree.

6.5      CROSS-PLATFORM CLIENT TO SERVER SYNCHRONIZATION

ItsNat offers some portable support to easily update the server DOM tree when a client change occurs.

 

ItsNat provides several event driven techniques to automatically synchronize a client DOM element changed with the server counterpart:

 

 

6.5.1       Attribute synchronization

The objective is to transport the current values of the required attributes to the server when an event occurs in the specified client element. This is a specialization of the “Extra parameters” feature and again a specialized ParamTransport is used: NodeAttributeTransport, this class specifies the attribute name to transport and synchronize.

Example:

 

    ItsNatDocument itsNatDoc = ...;

    EventTarget anElem = ...; 

 

    EventListener listener = new EventListener()

    {

        public void handleEvent(Event evt)

        {

            Element elem = (Element)evt.getCurrentTarget();

            System.out.println(elem.getAttribute("style"));

        }

    };       

 

    itsNatDoc.addEventListener(anElem,"click",listener,false,

        new NodeAttributeTransport("style") );

   

In this example a custom listener is registered listening click events on the specified element. The NodeAttributeTransport object commands ItsNat to automatically update the current client style attribute at the server element. The listener is called after this synchronization.

To transport the attribute with no synchronization, use the two parameter constructor with sync parameter set to false. Use the ItsNatEvent.getExtraParam(String) to get the transported attribute. For instance:

 

    new NodeAttributeTransport("style",false);

 

6.5.1.1   Transporting all attributes

This feature works well with concrete attributes, the method allows a NodeAttributeTransport array, but how can ItsNat synchronize any attribute change? Answer: using a NodeAllAttribTransport object. This object mandates ItsNat to carry and synchronize all current attributes of the specified client element:

 

    itsNatDoc.addEventListener(anElem,"click",listener,false,

        new NodeAllAttribTransport () );

 

ItsNat sends to the server all declared element attributes (names and values) from the client. This technique can detect and sync added or removed attributes in the client.

To transport the attributes with no synchronization, use the one parameter constructor with sync parameter set to false. Use the ItsNatEvent.getExtraParam(String) to get the transported attribute. For instance:

 

    new NodeAllAttribTransport(false);

 

6.5.2       Node inner synchronization

The objective is to transport the current content of the specified client node to the server when an event occurs in this node. A specialized ParamTransport is used: NodeInnerTransport.

Example:

 

    <a href="javascript:void(0);" id="clickableId"

        onclick="addNode(this);">Click to add a new child node</a>

 

    <script type="text/javascript">

    function addNode(link)

    {

        var newElem = document.createElement("b");

        newElem.appendChild(

               document.createTextNode(" New Node " + link.childNodes.length));

        link.appendChild(newElem);            

    }

    </script>

 

Java code:

 

    ItsNatDocument itsNatDoc = ...;

    Document doc = itsNatDoc.getDocument();

    Element anElem = doc.getElementById("clickableId");       

 

    EventListener listener = new EventListener()

    {       

        public void handleEvent(Event evt)

        {

            Element currTarget = (Element)evt.getCurrentTarget();

            Node newNode = currTarget.getLastChild();

            Text text = (Text)newNode.getFirstChild();

            System.out.println("New node : " + newNode + " " + text.getData());           

        }   

    };

 

    itsNatDoc.addEventListener((EventTarget)anElem,"click",listener,false,

               new NodeInnerTransport());       

 

In this example a new child node is added in the client when the user clicks the specified link. The NodeInnerTransport transports the node content and automatically updates the server content of the link.

 

6.5.3       Complete node synchronization

This case is the sum of the behaviour of NodeAllAttribTransport and NodeInnerTransport. The class NodeCompleteTransport is used.

6.5.4       Property synchronization

Browser DOM elements have properties, a property is not the same as an attribute though some attributes become properties like value in a <input> element, because the property can have a different value from the attribute. These properties are almost ever reflected as attributes in the server DOM, though Java W3C DOM API have get/set based methods to get/set properties, Java DOM implementation uses attributes behind the scenes. A user interface action can change an element property like the value property of an <input> element; this property change is not manifested as an attribute change, then we can not use the ItsNat “attribute synchronization” technique to update the server.

ItsNat provides a technique very similar to attribute synchronization, in this case is “property synchronization”.

Like in attribute synchronization a specialized ParamTransport descriptor object is used: NodePropertyTransport, this class specifies the property name to transport and synchronize as an attribute:

Example:

 

    ItsNatDocument itsNatDoc = ...;

    HTMLInputElement anElem = ...; 

 

    EventListener listener = new EventListener()

    {

        public void handleEvent(Event evt)

        {

            HTMLInputElement elem = (HTMLInputElement)evt.getCurrentTarget();

            System.out.println(elem.getValue());

        }

    };       

 

    itsNatDoc.addEventListener((EventTarget)anElem,"change",listener,false,

        new NodePropertyTransport("value"));

   

In this example a listener object is registered listening change events over the specified server HTMLInputElement element (e.g. a text box). The NodePropertyTransport object commands to ItsNat to transport the value property and synchronizes as the value attribute. The listener is called after synchronization.

An alternative NodePropertyTransport constructor may be used to synchronize using Java reflection:

 

    // Alternative

    itsNatDoc.addEventListener((EventTarget)anElem,"change",listener,false,

        new NodePropertyTransport("value",String.class));       

 

With this mode the current client value property is synchronized at the server element calling HTMLInputElement.setValue(String) using Java reflection following the Java Beans method name pattern and data type (String) known through the specified NodePropertyTransport object.

To transport the property with no synchronization, use the any constructor with the sync parameter set to false. Use the ItsNatEvent.getExtraParam(String) to get the transported property. For instance:

    new NodePropertyTransport("value",false);

6.6      REMOTE CONTINUE EVENT LISTENERS

Client and server are two different programming scenarios; server code is executed when a client event occurs, server code usually sends JavaScript code to modify the client state and the event lifecycle finally ends. Sometimes when processing an event we need to change the client state and continue again in the server, the typical example is when the server needs some value from the client and this value is not present in the event object. ItsNat provides a new event/listener type: continue.

A continue listener is a Java object implementing the DOM interface org.w3c.dom.events.EventListener, this listener is ready to receive ItsNatContinueEvent events, this interface inherits from org.w3c.dom.events.Event because is defined by ItsNat as new DOM event type (a DOM extension). This listener must be registered with the method ClientDocument.addContinueEventListener, this action tells to ItsNat to generate and send JavaScript code to the client to call again the server firing an ItsNatContinueEvent; this event is received by the registered EventListener object. When the ItsNatContinueEvent event is received and processed the listener is automatically unregistered and a new call to addContinueEventListener is needed to start a new cycle.

When registering a listener, we have the option to specify with a CustomParamTransport object the custom JavaScript code what we need to transport data from the client. The addContinueEventListener method admits an optional EventTarget parameter; this parameter is useful if used along with ParamTransport objects.

Example:

public void handleEvent(Event evt)

{

    ItsNatEvent itsNatEvent = (ItsNatEvent)evt;

    ClientDocument clientDoc = itsNatEvent.getClientDocument();

 

    // We need the page title in this context:                

 

    EventListener listener = new EventListener()

    {

        public void handleEvent(Event evt)           

        {

            ItsNatContinueEvent contEvt = (ItsNatContinueEvent)evt;

            String title = (String)contEvt.getExtraParam("title");

            System.out.println("This is the title: " + title);

        }

    };

 

    ParamTransport[] extraParams =

          new ParamTransport[]{new CustomParamTransport("title","document.title")};

    clientDoc.addContinueEventListener(null,listener,itsNatEvent.getCommMode(),

        extraParams,null,-1);       

}

 

In this example a continue request gets the page title from the client.

6.7      REMOTE USER DEFINED EVENT LISTENERS

Usually events are fired by the browser as a result of a user action over a specific markup element (a mouse click, text changed etc). User defined events allow to call the server from the client in a programmatic manner calling a JavaScript function. This event/listener type is very useful to full control when the server is called.

Another useful scenario is when ItsNat is integrated with a well established JavaScript library (usually a DHTML library); usually JavaScript libraries generate HTML code, this HTML code of course is not controlled by ItsNat and can be very hard to bind ItsNat DOM listeners to this markup. Notwithstanding these JavaScript libraries usually provide hooks to register user defined JavaScript based listeners, these listeners are the right place to call user defined ItsNat event listeners.

A user defined listener is a Java object implementing the interface org.w3c.dom.events.EventListener, this listener is ready to receive ItsNatUserEvent events, this interface inherits from org.w3c.dom.events.Event because is defined by ItsNat as new DOM event type (a DOM extension). This listener must be registered with the method ItsNatDocument.addUserEventListener, using a target node and an event name, both parameters, target node and name, are necessary to call the listener (target node may be null). Then the listener is ready to receive ItsNatUserEvent events. If several listeners were registered with the same pair node-name, they all will be called at the same time.

To fire an ItsNatUserEvent use the following methods from JavaScript:

document.getItsNatDoc().createUserEvent(name)

 

document.getItsNatDoc().dispatchUserEvent(targetNode,evt)

The first method creates a user event object with the specified name (this name is used to locate associated listeners). This JavaScript object may be used to transport optional parameters calling the object method: setExtraParam(name,value) (an example is shown later); this optional parameter is obtained in the server as usual. The second one dispatches the specified user event to the listeners associated to the specified target node and event name.

A third method is available:

document.getItsNatDoc().fireUserEvent(targetNode,name)

This method is equal to:

document.getItsNatDoc().dispatchUserEvent(targetNode,

        document.getItsNatDoc().createUserEvent(name))

Example:

    ItsNatDocument itsNatDoc = ...;       

    Document doc = itsNatDoc.getDocument();          

 

    Element buttonElem = doc.getElementById("buttonId");            

 

    EventListener listener = new EventListener()

    {

        public void handleEvent(Event evt)           

        {

            ItsNatUserEvent userEvt = (ItsNatUserEvent)evt;

            String title = (String)userEvt.getExtraParam("title");

            System.out.println("Page title: " + title);

            String url = (String)userEvt.getExtraParam("url");

            System.out.println("URL: " + url); 

            Object[] both = userEvt. getExtraParamMultiple("both");

            System.out.println("Page title/URL: " + both[0] + "/" + both[1]);

        }

    };      

   

    itsNatDoc.addUserEventListener((EventTarget)buttonElem,"myUserAction",listener);

 

    String code = "";

    code += "var itsNatDoc = document.getItsNatDoc();";

    code += "var evt = itsNatDoc.createUserEvent('myUserAction');";

    code += "evt.setExtraParam('title',document.title);";

    code += "evt.setExtraParam('url',document.location);"

    code += "evt.setExtraParam('both',[document.title,document.location]);"

    code += "itsNatDoc.dispatchUserEvent(this,evt);";

    buttonElem.setAttribute("onclick",code);

 

This example registers a listener ready to receive the page title and URL, the listener name is used to construct the onclick JavaScript handler of an element. When this element is clicked the user event is fired transporting the document title and URL, both values are received as “extra” parameters.

ParamTransport objects can be used too to transport data from client to server.

6.8      TIMERS

ItsNat provides a time based event/listener system. The architecture is very similar to java.util.Timer adapted of course to the web. Similar to java.util.Timer, ItsNat defines a utility object implementing the ItsNatTimer interface and can be created with ItsNatDocument.

The ItsNatTimer provides all schedule* methods introduced in java.util.Timer (same functionality with different signatures). The approach is different:

·         There is no server thread controlling the scheduled tasks.

·         Any registered task is scheduled using the JavaScript setTimeout method on the client (a repetitive task will call setTimeout several times).

·         The concrete task, an object implementing org.w3c.dom.events.EventListener in the server, is called when the task is scheduled receiving an ItsNatTimerEvent event object. An ItsNatTimerEvent inherits from org.w3c.dom.events.Event because is defined by ItsNat as a DOM extension.

·         An ItsNatTimerHandle object is returned when a new task is scheduled, and represents the “task scheduled” (the same EventListener object can be shared between several scheduled tasks). A scheduled task can be cancelled with a call to ItsNatTimerHandle.cancel().

When a scheduled task is fully completed (there is no future scheduled execution) is automatically unscheduled.

schedule* methods admit an optional EventTarget parameter; this parameter is useful if used along with ParamTransport parameters.

Timers (scheduled tasks) are useful to refresh the client with a fixed time interval, animations controlled by the server etc.

Code example:

 

    ItsNatDocument itsNatDoc = ...;   

    ClientDocument clientDoc = itsNatDoc.getClientDocumentOwner();

 

    EventListener listener = new EventListener()

    {

        public void handleEvent(Event evt)            

        {

            ItsNatTimerEvent timerEvt = (ItsNatTimerEvent)evt;

            ItsNatTimerHandle handle = timerEvt.getItsNatTimerHandle();

            long firstTime = handle.getFirstTime();

            if ((new Date().getTime() - firstTime) > 10000)

            {

                handle.cancel();

                System.out.println("Timer canceled");            

            }

            else System.out.println("Tick, next execution: " +

               new Date(handle.scheduledExecutionTime()));                 

        }

    };              

 

    ItsNatTimer timer = clientDoc.createItsNatTimer();

    ItsNatTimerHandle handle = timer.schedule(null,listener,1000,2000);

 

    System.out.println("Timer started, first time: " +

                                         new Date(handle.getFirstTime()) + " period: " + handle.getPeriod());

6.9      REMOTE ASYNCHRONOUS TASKS

A remote asynchronous task was developed with this scenario in mind:

1.    A server task takes very much time

2.    This task is asynchronous by nature (other tasks could be executed at the same time)

3.    The ItsNatDocument should not be locked (the long task could be executed asynchronously)

4.    The client need to be notified when the long task finishes or the long task modifies the client in same way

A Remote Asynchronous Task (RAT) satisfies these requisites. A RAT is a Runnable object registered with the method ClientDocument.addAsynchronousTask(Runnable,EventListener), this method starts a new thread executing the Runnable object in this thread; then immediately generates JavaScript code to fire an (asynchronous by default) event when is executed in the client. This event is caught internally by the framework and the execution does not return to client until the user task ends, this ensures any modification performed at the DOM tree or in general any JavaScript code scheduled to send is sent to the client as the event response. Optionally an EventListener can be registered and dispatched when the event (implementing ItsNatAsyncTaskEvent) is going to notify the client.

An alternative addAsynchronousTask method has a lockDoc parameter, this parameter tells ItsNat to lock (synchronize) the ItsNatDocument while executing the task. If set to false (the typical and recommended scenario if the task is long) the user code in the asynchronous task must not use the ItsNatDocument or related objects without synchronization, because ItsNatDocument and dependent objects are not thread safe.

The following example shows a correct use of a RAT, while executing a RAT any other event can be processed by the document.

 

    final ItsNatDocument itsNatDoc = ...;

    ClientDocument clientDoc = itsNatDoc.getClientDocumentOwner();

    Runnable task = new Runnable()

    {

        public void run()

        {

            try

            {

                Thread.sleep(2000);

            }

            catch(InterruptedException ex) { }

 

            synchronized(itsNatDoc) // MANDATORY, lock is false !!

            {

                itsNatDoc.addCodeToSend(

                       "alert('Asynchronous task finished!');");

            }

        }

    };

 

    EventListener listener = new EventListener()

    {

        public void handleEvent(Event evt)

        {

            itsNatDoc.addCodeToSend("alert('Finished really!');");

        }

    };

    clientDoc.addAsynchronousTask(task,listener);

        // by default lockDoc is false!! 

 

    itsNatDoc.addCodeToSend("alert('An asynchronous task has started');");

6.10  COMET

ItsNat provides some COMET support without relying on special servers. The ItsNat COMET approach is based on AJAX or SCRIPT events: the client is ever waiting for an AJAX/SCRIPT pure asynchronous (hold modes are not allowed) event locked in server; when new JavaScript code with changes in server must be sent to the client, this event returns and updates the client and automatically a new AJAX/SCRIPT asynchronous request is sent to the server waiting for new asynchronous server changes. This technique is called “long polling”[53].

This solution requires one server thread per comet notifier, and a HTTP client to server connection blocked. This may sound a limitation for scaling to many concurrent COMET connections but is important to take into account that these threads are stalled (sleeping) when no asynchronous server changes occur, and modern operating systems can handle thousand of threads with no very much problem[54]. This technique (synchronous long polling) is the most standard and no specific NIO or Servlet 3.0 servlet container is required (for instance a NIO based like GlassFish), in fact recent studies are trying to debunk the popular belief that non-blocking IO (NIO) is more scalable than classic blocking IO[55] (this belief was true before Linux NPTL).

The HTTP client/server connection blocked is the worst problem because HTTP 1.1 standard only specifies two live connections per browser with the same host; some browsers like MSIE 6 and 7 and Firefox <=v2 obey this limitation, other browsers like Chrome, Safari 3, Firefox 3 and Opera (Presto) have a higher number of concurrent connections per host. Anyway use only one comet notifier to avoid your browser freezes!

ItsNat COMET support is based on the interface/default implementation of CometNotifier, a COMET notifier object is created with the method ClientDocument.createCometNotifier(). To notify the client about a server change call CometNotifier.notifyClient() in any time.

The following code is a simple but complete example of how to update the client using CometNotifier when a background server thread makes this change. A link is used to start the background task and COMET notifier:

 

    final ItsNatDocument itsNatDoc = null;

 

    final CometNotifier notifier =

               itsNatDoc.getClientDocumentOwner().createCometNotifier();

    EventListener listener = new EventListener()

    {

        public void handleEvent(Event evt)

        {

            itsNatDoc.addCodeToSend("alert('Tick From Event');");

        }

    };

    notifier.addEventListener(listener);

 

    Thread backgroundThr = new Thread()

    {

        public void run()

        {

            System.out.println("Background server task started");               

            long t1 = System.currentTimeMillis();

            long t2 = t1;

            do

            {

                try

                {

                    Thread.sleep(2000);

                }

                catch(InterruptedException ex) { }

 

                if (!notifier.isStopped())

                {

                    synchronized(itsNatDoc)

                    {

                        itsNatDoc.addCodeToSend("alert('Tick From Thread');");

                    }

                    notifier.notifyClient();

                }

                t2 = System.currentTimeMillis();

            }

            while( (t2 - t1) < 10*60*1000 ); // Max 10 minutes

 

            notifier.stop();

 

            System.out.println("Background server task finished");

        }

    };

 

    backgroundThr.start();

   

There are two ways to modify the document:

1.    In any time synchronizing the document

 

                    synchronized(itsNatDoc)

                    {

                        itsNatDoc.addCodeToSend("alert('Tick From Thread');");

                    }

                    notifier.notifyClient();

 

Synchronization is absolutely necessary because the background thread is going to use the ItsNatDocument (or dependent objects) and this object is not synchronized (ItsNat automatically synchronizes the document in a normal request). The notifyClient() call does not need to be synchronized (in spite of it is document dependent); this call tells to ItsNat to send this new code immediately as the result of an, already pending, asynchronous AJAX/SCRIPT event, and a new asynchronous AJAX/SCRIPT request is automatically sent to wait new changes. The method CometNotifier.stop() ends the COMET based listener.

2.    Using an event listener registered on the CometNotifier.

    EventListener listener = new EventListener()

    {

        public void handleEvent(Event evt)

        {

            itsNatDoc.addCodeToSend("alert('Tick From Event');");

        }

    };

    notifier.addEventListener(listener);

 

When the client is going to be notified (a web request is going to return to the browser with any pending modification) an especial DOM event (implementing ItsNatCometEvent) is dispatched to the registered listeners, in this context the document is synchronized. Most of methods of this especial DOM event are useless. 

6.11  STRING TO DOM CONVERSION

ItsNat provides a very simple way to convert a string with serialized markup to DOM using ItsNatDocument.toDOM(String). This method returns a DocumentFragment object ready to be inserted into the document using DOM methods. Use this method with small pieces of markup because source code is ever parsed from scratch and there is no caching, use instead markup fragments (see “MARKUP FRAGMENTS” chapter).

Example:

    ItsNatDocument itsNatDoc = ...;        

    Element refElem = ...;

 

    String code = "<b>New Markup Inserted</b><br />";       

    DocumentFragment docFrag = itsNatDoc.toDOM(code); 

    refElem.getParentNode().insertBefore(docFrag, refElem);

Be careful with the security using this method when the string is constructed containing user data. For instance, a malicious user can add unexpected elements like <script>, <link> or <object>. This is not the recommended approach, insert user provided data using DOM APIs after calling this method.

6.12  MARKUP FRAGMENTS

Any typical templating system has some type of include mechanism. ItsNat has an include mechanism of course, before describing how to include a markup fragment, we need to know how ItsNat manages them.

A markup fragment must be registered in the ItsNat servlet very much as a normal HTML/XML file, in fact, markup fragments support caching too: static parts of markup fragments are automatically cached to save memory, a cached subtree is saved as text once in memory and is not included as DOM in the target document saving memory. The same as page templates, markup fragments can be changed on runtime, the new markup is shown next time the fragment is included.

6.12.1    HTML/XHTML fragments

An HTML/XHTML fragment is a normal HTML/XHTML file, for instance:

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">

    <head>

        <title>What is Lorem Ipsum?</title>

    </head>

    <body>

        <h4>What is Lorem Ipsum?</h4>       

        <p>Lorem Ipsum is simply dummy text of the printing and typesetting

           industry.

        </p>

    </body>

</html>

 

ItsNat automatically recognize two fragments: the <head> content and the <body> content, these parts are “the fragments” (<head> and <body> elements are not included).

To register an HTML file as a fragment (init(ServletConfig) servlet method):

 

    String pathPrefix = getServletContext().getRealPath("/");

    pathPrefix += "/WEB-INF/pages/manual/core/";

 

    ItsNatHttpServlet itsNatServlet = getItsNatHttpServlet();

 

    ItsNatDocFragmentTemplate fragTemplate;

    fragTemplate = itsNatServlet.registerItsNatDocFragmentTemplate(

               "manual.core.htmlFragExample","text/html",

               pathPrefix + "fragment_example.html");   

 

Registers the fragment (pair of fragments) with the name manual.core.htmlFragExample.

6.12.2    SVG and XUL fragments

Creating an SVG fragment is similar to HTML:

 

<?xml version="1.0" standalone="no"?>

 

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"

    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

 

<svg version="1.1" xmlns="http://www.w3.org/2000/svg">

    <text x="25" y="150" font-family="Verdana" font-size="20" fill="green" >

    Text Included via Fragment

    </text>

</svg>

 

The fragment is the <svg> content, the <svg> element is not included itself.

To register the XML file as a fragment (continues the previous example):

    fragTemplate = itsNatServlet.registerItsNatDocFragment(

                       "manual.core.svgFragExample","image/svg+xml",

                       pathPrefix + "svg_fragment_example.xml");   

 

Registers the SVG fragment with the name manual.core.svgFragExample.

 

Similar to SVG you can insert XUL fragments, in this case use the MIME type application/vnd.mozilla.xul+xml. The Feature Showcase includes some examples using XUL.

6.12.3    XML fragments

An XML fragment (not HTML/XHTML, SVG or XUL) is very similar to SVG or XUL:

 

<?xml version='1.0' encoding='UTF-8' ?>

<root>

    <title>CD List</title>

    <subtitle>in XML</subtitle>  

</root>

The fragment is the <root> content, the <root> element is not included itself, in fact the “root” name is not mandatory, use the root element you like more.

To register the XML file as a fragment (continues the previous example):

    fragTemplate = itsNatServlet.registerItsNatDocFragment(

                       "manual.core.xmlFragExample","text/xml",

                       pathPrefix + "xml_fragment_example.xml");   

 

Registers the XML fragment with the name manual.core.xmlFragExample.

6.12.4    Static includes

ItsNat has two include mechanisms: static and dynamic.

Static include uses a special ItsNat-prefixed tag, <include>, this tag is resolved and replaced with the specified fragment when the template container is first loaded.

Example:

 

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml"

      xmlns:itsnat="http://itsnat.org/itsnat">

    <head>

        <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />       

        <itsnat:include name="manual.core.htmlFragExample" />

    </head>

    <body>

        <h3>This pages includes a dummy text</h3>

        <itsnat:include name="manual.core.htmlFragExample" />

    </body>

</html>

This template is resolved on memory as:

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml"

      xmlns:itsnat="http://itsnat.org/itsnat">

    <head>

        <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />       

        <title>What is Lorem Ipsum?</title>

    </head>

    <body>

        <h3>This pages includes a dummy text</h3>

        <h4>What is Lorem Ipsum?</h4>       

        <p>Lorem Ipsum is simply dummy text of the printing and typesetting

           industry.

        </p>

    </body>

</html>

 

ItsNat detects automatically if the <include> tag is inside <head> or <body> and includes the appropriate sub fragment.

In XML is very much the same, in this case there is no “sub fragments” because there is no head or body recognized.

To avoid problems with HTML editors there are an alternative to <include> not so intrusive, using an attribute: itsnat:include=”fragment name”:

 

    <span itsnat:include="manual.core.htmlFragExample" />   

 

This element is fully replaced by the specified fragment.

Another alternative is itsnat:includeInside=”fragment name”:

 

    <div itsnat:includeInside="manual.core.htmlFragExample" />   

 

In this case the container element is not replaced, the fragment is inserted inside the container node.

6.12.4.1       Comments

ItsNat only has two custom tags <include> and <comment>. Both are replaced or removed on load time. The <comment> element can be used to add text (and markup) to templates, this element and content is removed when the template is first loaded. For instance:

 

    <itsnat:comment><![CDATA[ Comment example

        with <tag> as text

    ]]></itsnat:comment>

 

    <itsnat:comment>Comment example with tags

        <p>A paragraph</p>

    </itsnat:comment>

  

Another alternative not so intrusive is the attribute version: itsnat:comment=”a comment”. This attribute is removed when the template is first loaded.

 

 <div itsnat:comment="this is a comment" />   

 

6.12.5    Dynamic include

ItsNat supports including fragments programmatically, the standard way to add a fragment to a W3C DOM tree is using org.w3c.dom.DocumentFragment objects.

For instance:

    ItsNatDocument itsNatDoc = ...;        

    Element includeParentElem = ...;

 

    ItsNatServlet servlet = itsNatDoc.getItsNatDocumentTemplate().getItsNatServlet();

 

    ItsNatHTMLDocFragmentTemplate fragTemplate =

        (ItsNatHTMLDocFragmentTemplate)servlet.getItsNatDocFragmentTemplate(

               "manual.core.htmlFragExample");

    DocumentFragment docFrag = fragTemplate.loadDocumentFragmentBody(itsNatDoc);

 

    includeParentElem.appendChild(docFrag); // docFrag is empty now       

 

The method ItsNatServlet.getItsNatDocFragmentTemplate(String) returns the specified fragment template and ItsNatHTMLDocFragmentTemplate.loadDocumentFragmentBody(ItsNatDocument) creates a new DocumentFragment using the original fragment as a template and the current ItsNatDocument. In a XML document use ItsNatDocFragmentTemplate.loadDocumentFragment(ItsNatDocument).

6.13  DOM UTILITIES TO TRAVERSE AND CREATE DOM ELEMENTS

The W3C DOM is a very powerful API but sometimes is not practical, for instance, typical DOM tree navigation only uses elements filtering text nodes and comments and built-in DOM methods deals with any type of node. W3C DOM Traversal and Range Specification[56] provide two iterator interfaces, almost unknown[57]: NodeIterator and TreeWalker, they are very useful but both interfaces have an unnecessary state (“current node”) and the most useful interface, TreeWalker, has an annoying behavior.

For instance, we want to walk through the child elements of a given root element:

 

    Document doc = ...;

    Element root = ...;       

 

    // Using TreeWalker       

    DocumentTraversal travDoc = (DocumentTraversal)doc;

    TreeWalker walker =

               travDoc.createTreeWalker(root,NodeFilter.SHOW_ELEMENT,null,true);

    Element child = (Element)walker.firstChild();

    while(child != null)

    {

        // Do something with child ...

        child = (Element)walker.nextSibling();

    }

What is wrong with this code? Nothing, but if the root element is empty (no child elements, firstChild returns null) the walker object retains the root as the “current node”; if root is not empty the walker is set finally with the last child as the current node; this is a problem if walker is going to be reused.

To avoid this annoying behavior:

    Element child = (Element)walker.firstChild();

    if (child != null)

    {

        while(child != null)

        {

            // Do something with child ...

            child = (Element)walker.nextSibling();

        }

        walker.parentNode();

    }

In this case walker remains root as the current node ever.

Using the ItsNatTreeWalker class:

    Element child = ItsNatTreeWalker.getFirstChildElement(root);

    while(child != null)

    {

        // Do something with child ...

        child = ItsNatTreeWalker.getNextSiblingElement(child);           

    }

No object creation, no filter declaration, no state. ItsNatTreeWalker rewrites TreeWalker methods with no state and with methods to traverse elements. There are several DOM node types: elements, comments, text nodes, CDATA etc, but the king is the element, ItsNat DOM utilities are oriented to manage DOM elements.

The ItsNatDOMUtil class offers some utility methods like methods to get/set text content of an element:

    Element elem = ...; // <elem>Some Text</elem>

    ItsNatDOMUtil.setTextContent(elem,

        ItsNatDOMUtil.getTextContent(elem) + "(updated)");

 

Another useful method is ItsNatDOMUtil.createElement(String,String,Document), this method creates a new DOM element with the specified text as the only child node. For instance:

 

    Document doc = ...;

    Element h1 = ItsNatDOMUtil.createElement("h1","Home Page",doc);   

6.14  FREE ELEMENT LISTS

Most of the time we need to deal with consecutive elements: iterate, add, search, and remove one or several elements of an element list. The typical element list is several consecutive elements separated by text nodes with blanks, tabulators or carriage returns, they all share the same parent element; this kind of structure is the typical of XML documents and some HTML constructs. For instance:

 

    <select>

        <option>Car</option>

        <option>Airplane</option>       

        <option>Ship</option>         

    </select>   

 

Other HTML examples: rows or columns of a table.

ItsNat provides some utilities to deal with element lists to avoid the typical and verbose DOM manipulation. The first one is the ElementListFree interface implemented by ItsNat, this interface represents an element list as an integer indexed list ignoring non-element nodes like text nodes. Elements may have different tag names (the meaning of “free”).

ElementListFree has the usual methods to search, add, insert and remove elements, but it goes beyond, ElementListFree inherits from org.w3c.dom.NodeList and java.util.List and supports java.util.Iterator and java.util.ListIterator.

An ElementListFree object is created using ElementGroupManager obtained from   ItsNatDocument:

 

    <div id="elementListId" />

 

 

    ItsNatDocument itsNatDoc = ...;       

    Document doc = itsNatDoc.getDocument();

    Element parent = doc.getElementById("elementListId");

    ElementGroupManager factory = itsNatDoc.getElementGroupManager();

    ElementListFree elemList = factory.createElementListFree(parent,true);

      

The previous createElementListFree call submits a parameter as true: master. If master is true the ElementListFree object is created in “master” mode, in this mode this ElementListFree object must be used to add, remove or replace child elements avoiding direct DOM manipulation, this is the fastest mode. If master is false, elements can be added or removed using normal DOM methods (Node.appendChild, Node.removeChild etc) too, in this mode ElementListFre is more flexible but slower.

Use examples:

    Element elem;

 

    elem = ItsNatDOMUtil.createElement("p","Item 1",doc);

    elemList.addElement(elem);

 

    elem = ItsNatDOMUtil.createElement("p","Item 2",doc);

    elemList.addElement(elem);       

 

These sentences add two <p>Item X</p> elements below the list parent (<div>). They both may be obtained using a zero-based index (<div> element was initially empty):

 

    elem = elemList.getElementAt(1);

    System.out.println(ItsNatDOMUtil.getTextContent(elem)); // "Item 2"

 

And replaced:

 

    elem = ItsNatDOMUtil.createElement("h1","Tittle",doc);               

    elemList.setElementAt(0,elem); // Replaces <p>Item 1</p> => <h1>Tittle</h1>

 

Finally as an ElementListFree inherits from java.util.List, DOM elements can be iterated using standard iterator interfaces:

 

    List<Element> list = elemList;

    for(ListIterator<Element> it = list.listIterator(); it.hasNext(); )

    {

        Element curElem = it.next();

        System.out.println(it.nextIndex() + ":" +

               ItsNatDOMUtil.getTextContent(curElem));

        it.remove();

    }

 

The starting point of previous examples was an empty list, this is not a requisite, when the ElementListFree is just created is synchronized automatically with the “real” DOM element list to represent the current state. This works in master mode too (initial synchronization). For instance:

    <select>

        <option>Car</option>

        <option>Airplane</option>       

        <option>Ship</option>         

    </select>   

If an ElementListFree is created to manage this already existing list, a call to the method getLength() will return 3, and getElementAt(2) will return the third DOM element (containing “Ship”).

6.15  FREE ELEMENT TABLES

Free element tables are very similar to free element lists, the main different is that elements form a table. For instance (this example consciously avoids the typical <table> based example):

    <div>

        <div>

            <span>Car</span><span>Road</span><span>Ford</span>

        </div>

        <div>

            <span>Airplane</span><span>Air</span><span>Boeing</span>

        </div>       

        <div>

            <span>Ship</span><span>Sea</span><span>Ferry</span>

        </div>

    </div>  

 

ItsNat provides the ElementTableFree interface implemented by ItsNat too; this interface represents an element table as an integer indexed row list (and a column list per row) ignoring non-element nodes like text nodes. Elements may have different tag names (the meaning of “free”).

ElementTableFree has methods to search, add and insert rows, columns and individual cells. ElementTableFree inherits from ElementListFree, list methods see the table as a row list: every item is a row DOM Element, for instance, an Iterator or ListIterator can be used to iterate/modify the table rows. The method ElementTableFree.getCellElementListOfRow(int row) can be used to manage the cells of a row as an ElementListFree.

An ElementTableFree object is created using ItsNatDocument and ElementGroupManager:

 

    <div id="elementTableId" />

 

 

    ItsNatDocument itsNatDoc = ...;       

    Document doc = itsNatDoc.getDocument();

    Element tableParent = doc.getElementById("elementTableId");

    ElementGroupManager factory = itsNatDoc.getElementGroupManager();

    ElementTableFree table = factory.createElementTableFree(tableParent,true);   

      

The previous createElementTableFree call submits a parameter as true: master. If master is true the ElementTableFree object is created in “master” mode, as in ElementListFree in this mode this object must be used to add, remove or replace rows and cells avoiding direct DOM manipulation, this is the fastest mode.

Use examples:

 

    Element rowElem;

    Element cellElem;

 

    rowElem = doc.createElement("div");       

 

        cellElem = doc.createElement("span");       

        cellElem.appendChild(doc.createTextNode("Cell 0,0"));

        rowElem.appendChild(cellElem);       

 

        cellElem = doc.createElement("span");       

        cellElem.appendChild(doc.createTextNode("Cell 0,1"));

        rowElem.appendChild(cellElem);            

 

    table.addRow(rowElem);           

 

    rowElem = doc.createElement("div");            

 

        cellElem = doc.createElement("span");       

        cellElem.appendChild(doc.createTextNode("Cell 1,0"));

        rowElem.appendChild(cellElem);       

 

        cellElem = doc.createElement("span");       

        cellElem.appendChild(doc.createTextNode("Cell 1,1"));

        rowElem.appendChild(cellElem);       

 

    table.addRow(rowElem);       

 

These sentences create the following table (the parent <div> element is initially empty and spaces are included to beautify the markup):

 

    <div id="elementTableId">

        <div>

            <span>Cell 0,0</span>

            <span>Cell 0,1</span>

        </div>

        <div>

            <span>Cell 1,0</span>

            <span>Cell 1,1</span>

        </div>

    </div>   

 

The starting point of previous examples was an empty table, this is not a requisite, when the ElementTableFree is just created is synchronized automatically with the “real” DOM element table to represent the current state. This works in master mode too (initial synchronization).

6.16  DOM RENDERERS

DOM renderers are objects implementing the interfaces ElementRenderer, ElementLabelRenderer, ElementTableRenderer and ElementTreeNodeRenderer. They are used to convert an object value to markup (usually as a text node) using a markup pattern. ItsNat defines default renderers, they all are based on the default ElementRenderer, this renderer replaces the first and deepest text node with some text (not only spaces, tabs or line feeds) of the pattern with the value converted to string with Object.toString(). This default ElementRenderer renderer is used by the “DOM element group managers” like labels, lists, tables, trees and by some ItsNat components when no other custom renderer is defined.

For instance:

    <div id="elementId"><b><i><img src="image.png" />Text Pattern<img src="image.png" /></i></b></div>     

   

Processed with:

 

    ItsNatDocument itsNatDoc = ...;

    Document doc = itsNatDoc.getDocument();

 

    Date value = new Date();

 

    ElementGroupManager factory = itsNatDoc.getElementGroupManager();

    ElementRenderer renderer = factory.createDefaultElementRenderer();

    renderer.render(null,value,doc.getElementById("elementId"), true);        

 

Renders:

    <div id="elementId"><b><i><img src="image.png"/>Fri Jun 08 18:43:30 CEST 2007<img src="image.png"/></i></b></div>    

   

The default renderer supports many structures enclosing a text node (basically rep