]> source.dussan.org Git - vaadin-framework.git/commitdiff
now from app/UIDL feeds JSON
authorMatti Tahvonen <matti.tahvonen@itmill.com>
Tue, 5 Jun 2007 11:38:41 +0000 (11:38 +0000)
committerMatti Tahvonen <matti.tahvonen@itmill.com>
Tue, 5 Jun 2007 11:38:41 +0000 (11:38 +0000)
svn changeset:1582/svn branch:trunk

src/com/itmill/toolkit/terminal/web/AjaxApplicationManager.java
src/com/itmill/toolkit/terminal/web/AjaxJsonPaintTarget.java [new file with mode: 0644]
src/com/itmill/toolkit/terminal/web/AjaxPaintTarget.java [deleted file]
src/com/itmill/toolkit/terminal/web/AjaxXmlPaintTarget.java [new file with mode: 0644]
src/com/itmill/toolkit/terminal/web/ApplicationServlet.java

index 298b95d2ca0b544530113a9d5aafb160336c6033..11b2ea7c16367515bb63c2021a8b7134502744d1 100644 (file)
@@ -54,6 +54,7 @@ import com.itmill.toolkit.Application;
 import com.itmill.toolkit.Application.WindowAttachEvent;
 import com.itmill.toolkit.Application.WindowDetachEvent;
 import com.itmill.toolkit.terminal.DownloadStream;
+import com.itmill.toolkit.terminal.PaintTarget;
 import com.itmill.toolkit.terminal.Paintable;
 import com.itmill.toolkit.terminal.URIHandler;
 import com.itmill.toolkit.terminal.Paintable.RepaintRequestEvent;
@@ -92,7 +93,7 @@ public class AjaxApplicationManager implements
 
        private Set removedWindows = new HashSet();
 
-       private AjaxPaintTarget paintTarget;
+       private PaintTarget paintTarget;
 
        public AjaxApplicationManager(Application application) {
                this.application = application;
@@ -131,6 +132,15 @@ public class AjaxApplicationManager implements
                application.removeListener((Application.WindowDetachListener) this);
        }
 
+       
+       public void handleUidlRequest(HttpServletRequest request,
+                       HttpServletResponse response, ThemeSource themeSource) throws IOException {
+               handleUidlRequest(request,
+                               response, themeSource, false); 
+               
+       }
+
+       
        /**
         * 
         * @param request
@@ -141,8 +151,8 @@ public class AjaxApplicationManager implements
         *             if the writing failed due to input/output error.
         */
        public void handleUidlRequest(HttpServletRequest request,
-                       HttpServletResponse response, ThemeSource themeSource)
-                       throws IOException {
+                       HttpServletResponse response, ThemeSource themeSource, boolean isJson) 
+               throws IOException {
 
                // repaint requested or sesssion has timed out and new one is created
                boolean repaintAll = (request.getParameter(GET_PARAM_REPAINT_ALL) != null)
@@ -191,11 +201,16 @@ public class AjaxApplicationManager implements
                                        if (window == null)
                                                return;
 
-                                       // Sets the response type
-                                       response.setContentType("application/xml; charset=UTF-8");
-
-                                       paintTarget = new AjaxPaintTarget(getVariableMap(), this,
-                                                       out);
+                                       if(isJson) {
+                                               // Sets the response type
+                                               response.setContentType("application/json; charset=UTF-8");
+                                               paintTarget = new AjaxJsonPaintTarget(getVariableMap(), 
+                                                               this, out);
+                                       } else {
+                                               response.setContentType("application/xml; charset=UTF-8");
+                                               paintTarget = new AjaxXmlPaintTarget(getVariableMap(), 
+                                                               this, out);
+                                       }
 
                                        // Render the removed windows
                                        Set removed = new HashSet(getRemovedWindows());
@@ -294,11 +309,11 @@ public class AjaxApplicationManager implements
                                                        paintTarget.addAttribute("pid", pid);
 
                                                        // Track paints to identify empty paints
-                                                       paintTarget.setTrackPaints(true);
+                                                       ((AjaxPaintTarget) paintTarget).setTrackPaints(true);
                                                        p.paint(paintTarget);
 
                                                        // If no paints add attribute empty
-                                                       if (paintTarget.getNumberOfPaints() <= 0) {
+                                                       if (((AjaxPaintTarget) paintTarget).getNumberOfPaints() <= 0) {
                                                                paintTarget.addAttribute("visible", false);
                                                        }
                                                        paintTarget.endTag("change");
@@ -306,64 +321,56 @@ public class AjaxApplicationManager implements
                                                }
                                        }
 
-                                       // add meta instruction for client to set focus if it is set
-                                       Paintable f = (Paintable) application.consumeFocus();
-                                       // .. or initializion (first uidl-request)
-                                       boolean init = application.ajaxInit();
-                                       if (init || f != null) {
-                                               paintTarget.startTag("meta");
-                                               if (init)
-                                                       paintTarget.addAttribute("appInit", true);
-                                               if (f != null) {
-                                                       paintTarget.startTag("focus");
-                                                       paintTarget.addAttribute("pid", getPaintableId(f));
-                                                       paintTarget.endTag("focus");
-                                               }
-                                               paintTarget.endTag("meta");
-                                       }
-
-                                       // Precache custom layouts
-                                       // TODO Does not support theme-get param or different themes
-                                       // in different windows -> Allways preload layouts with the
-                                       // theme specified by the applications
-                                       String themeName = application.getTheme() != null ? application
-                                                       .getTheme()
-                                                       : ApplicationServlet.DEFAULT_THEME;
-                                       // TODO We should only precache the layouts that are not
-                                       // cached already
-                                       for (Iterator i = paintTarget.preCachedResources.iterator(); i
-                                                       .hasNext();) {
-                                               String resource = (String) i.next();
-                                               InputStream is = null;
-                                               try {
-                                                       is = themeSource.getResource(themeName + "/"
-                                                                       + resource);
-                                               } catch (ThemeSource.ThemeException e) {
-                                                       Log.info(e.getMessage());
-                                               }
-                                               if (is != null) {
-                                                       paintTarget.startTag("precache");
-                                                       paintTarget.addAttribute("resource", resource);
-                                                       StringBuffer layout = new StringBuffer();
-
-                                                       try {
-                                                               InputStreamReader r = new InputStreamReader(is);
-                                                               char[] buffer = new char[20000];
-                                                               int charsRead = 0;
-                                                               while ((charsRead = r.read(buffer)) > 0)
-                                                                       layout.append(buffer, 0, charsRead);
-                                                               r.close();
-                                                       } catch (java.io.IOException e) {
-                                                               Log.info("Resource transfer failed:  "
-                                                                               + request.getRequestURI() + ". ("
-                                                                               + e.getMessage() + ")");
-                                                       }
-                                                       paintTarget.addCharacterData(layout.toString());
-                                                       paintTarget.endTag("precache");
-                                               }
-                                       }
-
-                                       paintTarget.close();
+                    // add meta instruction for client to set focus if it is set
+                    Paintable f = (Paintable) application.consumeFocus();
+                    // .. or initializion (first uidl-request)
+                    boolean init = application.ajaxInit();
+                    if(init || f != null) {
+                        paintTarget.startTag("meta");
+                        if(init)
+                               paintTarget.addAttribute("appInit", true);
+                        if(f != null) {
+                               paintTarget.startTag("focus");
+                               paintTarget.addAttribute("pid", getPaintableId(f));
+                               paintTarget.endTag("focus");
+                        }
+                        paintTarget.endTag("meta");
+                    }
+
+                    // Precache custom layouts
+                    // TODO Does not support theme-get param or different themes in different windows -> Allways preload layouts with the theme specified by the applications
+                    String themeName = application.getTheme() != null ? application.getTheme() : ApplicationServlet.DEFAULT_THEME;
+                    // TODO We should only precache the layouts that are not cached already
+                    for (Iterator i=((AjaxPaintTarget) paintTarget).getPreCachedResources().iterator(); i.hasNext();) {
+                       String resource = (String) i.next();
+                       InputStream is = null;
+                       try {
+                                       is = themeSource.getResource(themeName + "/" +  resource);
+                               } catch (ThemeSource.ThemeException e) {
+                                       Log.info(e.getMessage());
+                               }
+                       if (is != null) {
+                               paintTarget.startTag("precache");
+                               paintTarget.addAttribute("resource", resource);
+                               StringBuffer layout = new StringBuffer();
+
+                               try {
+                                       InputStreamReader r = new InputStreamReader(is);
+                                               char[] buffer = new char[20000];
+                                               int charsRead = 0;
+                                               while ((charsRead = r.read(buffer)) > 0)
+                                                       layout.append(buffer, 0, charsRead);
+                                               r.close();
+                               } catch (java.io.IOException e) {
+                                       Log.info("Resource transfer failed:  " + request.getRequestURI()
+                                                       + ". (" + e.getMessage() + ")");
+                               }
+                               paintTarget.addCharacterData(layout.toString());
+                               paintTarget.endTag("precache");
+                       }
+                    }
+                    
+                                       ((AjaxPaintTarget) paintTarget).close();
                                        out.flush();
                                } else {
 
@@ -591,10 +598,10 @@ public class AjaxApplicationManager implements
        public synchronized String getPaintableId(Paintable paintable) {
 
                String id = (String) paintableIdMap.get(paintable);
-               if (id == null)
-                       // get PID using growing sequence number
+               if (id == null) {
                        id = "PID" + Integer.toString(idSequence++);
-               paintableIdMap.put(paintable, id);
+                       paintableIdMap.put(paintable, id);
+               }
 
                return id;
        }
diff --git a/src/com/itmill/toolkit/terminal/web/AjaxJsonPaintTarget.java b/src/com/itmill/toolkit/terminal/web/AjaxJsonPaintTarget.java
new file mode 100644 (file)
index 0000000..fb0a45f
--- /dev/null
@@ -0,0 +1,993 @@
+/* *************************************************************************
+ IT Mill Toolkit 
+
+ Development of Browser User Interfaces Made Easy
+
+ Copyright (C) 2000-2006 IT Mill Ltd
+ *************************************************************************
+
+ This product is distributed under commercial license that can be found
+ from the product package on license.pdf. Use of this product might 
+ require purchasing a commercial license from IT Mill Ltd. For guidelines 
+ on usage, see licensing-guidelines.html
+
+ *************************************************************************
+ For more information, contact:
+ IT Mill Ltd                           phone: +358 2 4802 7180
+ Ruukinkatu 2-4                        fax:   +358 2 4802 7181
+ 20540, Turku                          email:  info@itmill.com
+ Finland                               company www: www.itmill.com
+ Primary source for information and releases: www.itmill.com
+
+ ********************************************************************** */
+
+package com.itmill.toolkit.terminal.web;
+
+import com.itmill.toolkit.Application;
+import com.itmill.toolkit.terminal.ApplicationResource;
+import com.itmill.toolkit.terminal.ExternalResource;
+import com.itmill.toolkit.terminal.PaintException;
+import com.itmill.toolkit.terminal.PaintTarget;
+import com.itmill.toolkit.terminal.Paintable;
+import com.itmill.toolkit.terminal.Resource;
+import com.itmill.toolkit.terminal.ThemeResource;
+import com.itmill.toolkit.terminal.UploadStream;
+import com.itmill.toolkit.terminal.VariableOwner;
+
+import java.io.BufferedWriter;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Stack;
+import java.util.Vector;
+
+/**
+ * User Interface Description Language Target.
+ * 
+ * @author IT Mill Ltd.
+ * @version
+ * @VERSION@
+ * @since 3.1
+ */
+public class AjaxJsonPaintTarget implements PaintTarget, AjaxPaintTarget {
+
+       /* Document type declarations */
+
+       private final static String UIDL_ARG_NAME = "name";
+
+       private final static String UIDL_ARG_VALUE = "value";
+
+       private final static String UIDL_ARG_ID = "id";
+
+       private Stack mOpenTags;
+       
+       private Stack openJsonTags;
+
+       private boolean mTagArgumentListOpen;
+
+       private PrintWriter uidlBuffer;
+
+       private AjaxVariableMap variableMap;
+
+       private boolean closed = false;
+
+       private AjaxApplicationManager manager;
+
+       private boolean trackPaints = false;
+
+       private int numberOfPaints = 0;
+       
+       private int changes = 0;
+       
+       Set preCachedResources = new HashSet();
+       private boolean customLayoutArgumentsOpen = false;
+
+       private JsonTag tag;
+
+       /**
+        * Creates a new XMLPrintWriter, without automatic line flushing.
+        * 
+        * @param variableMap
+        * @param manager
+        * @param output
+        *            A character-output stream.
+        * @throws PaintException
+        *             if the paint operation failed.
+        */
+       public AjaxJsonPaintTarget(AjaxVariableMap variableMap,
+                       AjaxApplicationManager manager, OutputStream output)
+                       throws PaintException {
+
+               this.manager = manager;
+               // Sets the variable map
+               this.variableMap = variableMap;
+
+
+               // Sets the target for UIDL writing
+               try {
+                       this.uidlBuffer = new PrintWriter(new BufferedWriter(
+                                       new OutputStreamWriter(output, "UTF-8")));
+               } catch (UnsupportedEncodingException e) {
+                       throw new RuntimeException("Internal error");
+               }
+
+               // Initialize tag-writing
+               mOpenTags = new Stack();
+               openJsonTags = new Stack();
+               mTagArgumentListOpen = false;
+
+               // Adds document declaration
+
+               // Adds UIDL start tag and its attributes
+               tag = new JsonTag();
+               openJsonTags.push(tag);
+               append("{");
+
+       }
+
+       /**
+        * Method append.This method is thread safe.
+        * 
+        * @param string
+        *            the text to insert.
+        */
+       private void append(String string) {
+               uidlBuffer.print(string);
+       }
+
+       
+       public void startTag(String tagName) throws PaintException {
+               startTag(tagName, false);
+       }
+
+       /**
+        * Prints the element start tag.
+        * 
+        * <pre>
+        * Todo:
+        *  Checking of input values
+        *  
+        * </pre>
+        * 
+        * @param tagName
+        *            the name of the start tag.
+        * @throws PaintException
+        *             if the paint operation failed.
+        * 
+        */
+       public void startTag(String tagName, boolean isChildNode) throws PaintException {
+               // In case of null data output nothing:
+               if (tagName == null)
+                       throw new NullPointerException();
+
+               // Increments paint tracker
+               if (this.isTrackPaints()) {
+                       this.numberOfPaints++;
+               }
+
+               // Ensures that the target is open
+               if (this.closed)
+                       throw new PaintException(
+                                       "Attempted to write to a closed PaintTarget.");
+
+               tagName = tag.postfixChildtag(tagName, true);
+               
+               // Checks tagName and attributes here
+               mOpenTags.push(tagName);
+               openJsonTags.push(tag);
+               
+               
+               if(isChildNode && !tag.childrenArrayOpen) {
+                       append(tag.startField());
+                       tag.openChildrenArray();
+               }
+               if(!isChildNode && tag.childrenArrayOpen)
+                       tag.closeChildrenArray();
+
+               append(tag.startField());
+               tag = new JsonTag();
+               if(isChildNode) {
+                       append("{");
+                       tag.setChildNode(true);
+               } else {
+                       // Prints the tag with attributes
+                       append("" + tagName +": {");
+               }
+
+               mTagArgumentListOpen = true;
+               
+               if ("customlayout".equals(tagName))
+                       customLayoutArgumentsOpen = true;
+       }
+
+       /**
+        * Prints the element end tag.
+        * 
+        * If the parent tag is closed before every child tag is closed an
+        * PaintException is raised.
+        * 
+        * @param tag
+        *            the name of the end tag.
+        * @throws Paintexception
+        *             if the paint operation failed.
+        */
+       public void endTag(String tagName) throws PaintException {
+               // In case of null data output nothing:
+               if (tagName == null)
+                       throw new NullPointerException();
+
+               // Ensure that the target is open
+               if (this.closed)
+                       throw new PaintException(
+                                       "Attempted to write to a closed PaintTarget.");
+               
+               JsonTag parent = (JsonTag) openJsonTags.pop();
+               if(parent != null)
+                       tagName = parent.postfixChildtag(tagName, false);
+
+               String lastTag = "";
+
+               lastTag = (String) mOpenTags.pop();
+               if (!tagName.equalsIgnoreCase(lastTag))
+                       throw new PaintException("Invalid UIDL: wrong ending tag: '"
+                                       + tagName + "' expected: '" + lastTag + "'.");
+
+               if(tag.childrenArrayOpen)
+                       tag.closeChildrenArray();
+               append(tag.getData());
+               append(tag.attributesAsJsonObject());
+               append(tag.variablesAsJsonObject());
+               // Writes the end (closing) tag
+               append("}");
+               tag = parent;
+               flush();
+       }
+
+       /**
+        * Substitutes the XML sensitive characters with predefined XML entities.
+        * 
+        * @param xml
+        *            the String to be substituted.
+        * @return A new string instance where all occurrences of XML sensitive
+        *         characters are substituted with entities.
+        */
+       static public String escapeXML(String xml) {
+               if (xml == null || xml.length() <= 0)
+                       return "";
+               return escapeXML(new StringBuffer(xml)).toString();
+       }
+
+       /**
+        * Substitutes the XML sensitive characters with predefined XML entities.
+        * 
+        * @param xml
+        *            the String to be substituted.
+        * @return A new StringBuffer instance where all occurrences of XML
+        *         sensitive characters are substituted with entities.
+        * 
+        */
+       static public StringBuffer escapeXML(StringBuffer xml) {
+               if (xml == null || xml.length() <= 0)
+                       return new StringBuffer("");
+
+               StringBuffer result = new StringBuffer(xml.length() * 2);
+
+               for (int i = 0; i < xml.length(); i++) {
+                       char c = xml.charAt(i);
+                       String s = toXmlChar(c);
+                       if (s != null) {
+                               result.append(s);
+                       } else {
+                               result.append(c);
+                       }
+               }
+               return result;
+       }
+       
+       static public String escapeJSON(String s) {
+               if(s==null)
+                       return "";
+               StringBuffer sb=new StringBuffer();
+               for(int i=0;i<s.length();i++){
+                       char ch=s.charAt(i);
+                       switch(ch){
+                       case '"':
+                               sb.append("\\\"");
+                               break;
+                       case '\\':
+                               sb.append("\\\\");
+                               break;
+                       case '\b':
+                               sb.append("\\b");
+                               break;
+                       case '\f':
+                               sb.append("\\f");
+                               break;
+                       case '\n':
+                               sb.append("\\n");
+                               break;
+                       case '\r':
+                               sb.append("\\r");
+                               break;
+                       case '\t':
+                               sb.append("\\t");
+                               break;
+                       case '/':
+                               sb.append("\\/");
+                               break;
+                       default:
+                               if(ch>='\u0000' && ch<='\u001F'){
+                                       String ss=Integer.toHexString(ch);
+                                       sb.append("\\u");
+                                       for(int k=0;k<4-ss.length();k++){
+                                               sb.append('0');
+                                       }
+                                       sb.append(ss.toUpperCase());
+                               }
+                               else{
+                                       sb.append(ch);
+                               }
+                       }
+               }
+               return sb.toString();
+       }
+
+       /**
+        * Substitutes a XML sensitive character with predefined XML entity.
+        * 
+        * @param c
+        *            the Character to be replaced with an entity.
+        * @return String of the entity or null if character is not to be replaced
+        *         with an entity.
+        */
+       private static String toXmlChar(char c) {
+               switch (c) {
+               case '&':
+                       return "&amp;"; // & => &amp;
+               case '>':
+                       return "&gt;"; // > => &gt;
+               case '<':
+                       return "&lt;"; // < => &lt;
+               case '"':
+                       return "&quot;"; // " => &quot;
+               case '\'':
+                       return "&apos;"; // ' => &apos;
+               default:
+                       return null;
+               }
+       }
+
+       /**
+        * Prints XML-escaped text.
+        * 
+        * @param str
+        * @throws PaintException
+        *             if the paint operation failed.
+        * 
+        */
+       public void addText(String str) throws PaintException {
+               tag.addData(escapeJSON(str));
+       }
+
+       /**
+        * Adds a boolean attribute to component. Atributes must be added before any
+        * content is written.
+        * 
+        * @param name
+        *            the Attribute name.
+        * @param value
+        *            the Attribute value.
+        * @throws PaintException
+        *             if the paint operation failed.
+        */
+       public void addAttribute(String name, boolean value) throws PaintException {
+               tag.addAttribute( name + ":" + (value ? "true" : "false"));
+       }
+
+       /**
+        * Adds a resource attribute to component. Atributes must be added before
+        * any content is written.
+        * 
+        * @param name
+        *            the Attribute name.
+        * @param value
+        *            the Attribute value.
+        * 
+        * @throws PaintException
+        *             if the paint operation failed.
+        */
+       public void addAttribute(String name, Resource value) throws PaintException {
+
+               if (value instanceof ExternalResource) {
+                       addAttribute(name, ((ExternalResource) value).getURL());
+
+               } else if (value instanceof ApplicationResource) {
+                       ApplicationResource r = (ApplicationResource) value;
+                       Application a = r.getApplication();
+                       if (a == null)
+                               throw new PaintException(
+                                               "Application not specified for resorce "
+                                                               + value.getClass().getName());
+                       String uri = a.getURL().getPath();
+                       if (uri.charAt(uri.length() - 1) != '/')
+                               uri += "/";
+                       uri += a.getRelativeLocation(r);
+                       addAttribute(name, uri);
+
+               } else if (value instanceof ThemeResource) {
+                       String uri = "theme://" + ((ThemeResource) value).getResourceId();
+                       addAttribute(name, uri);
+               } else
+                       throw new PaintException("Ajax adapter does not "
+                                       + "support resources of type: "
+                                       + value.getClass().getName());
+
+       }
+
+       /**
+        * Adds a integer attribute to component. Atributes must be added before any
+        * content is written.
+        * 
+        * @param name
+        *            the Attribute name.
+        * @param value
+        *            the Attribute value.
+        * 
+        * @throws PaintException
+        *             if the paint operation failed.
+        */
+       public void addAttribute(String name, int value) throws PaintException {
+               tag.addAttribute(name + ":" + String.valueOf(value));
+       }
+
+       /**
+        * Adds a long attribute to component. Atributes must be added before any
+        * content is written.
+        * 
+        * @param name
+        *            the Attribute name.
+        * @param value
+        *            the Attribute value.
+        * 
+        * @throws PaintException
+        *             if the paint operation failed.
+        */
+       public void addAttribute(String name, long value) throws PaintException {
+               tag.addAttribute(name + ":" + String.valueOf(value));
+       }
+
+       /**
+        * Adds a string attribute to component. Atributes must be added before any
+        * content is written.
+        * 
+        * @param name
+        *            the Boolean attribute name.
+        * @param value
+        *            the Boolean attribute value.
+        * 
+        * @throws PaintException
+        *             if the paint operation failed.
+        */
+       public void addAttribute(String name, String value) throws PaintException {
+               // In case of null data output nothing:
+               if ((value == null) || (name == null))
+                       throw new NullPointerException(
+                                       "Parameters must be non-null strings");
+
+
+               tag.addAttribute( name + ": \"" + escapeJSON(value) + "\"");
+               
+       }
+
+       /**
+        * Adds a string type variable.
+        * 
+        * @param owner
+        *            the Listener for variable changes.
+        * @param name
+        *            the Variable name.
+        * @param value
+        *            the Variable initial value.
+        * 
+        * @throws PaintException
+        *             if the paint operation failed.
+        */
+       public void addVariable(VariableOwner owner, String name, String value)
+                       throws PaintException {
+               tag.addVariable(new StringVariable(owner,name,value));
+       }
+
+       /**
+        * Adds a int type variable.
+        * 
+        * @param owner
+        *            the Listener for variable changes.
+        * @param name
+        *            the Variable name.
+        * @param value
+        *            the Variable initial value.
+        * 
+        * @throws PaintException
+        *             if the paint operation failed.
+        */
+       public void addVariable(VariableOwner owner, String name, int value)
+                       throws PaintException {
+               tag.addVariable(new IntVariable(owner,name,value));
+       }
+
+       /**
+        * Adds a boolean type variable.
+        * 
+        * @param owner
+        *            the Listener for variable changes.
+        * @param name
+        *            the Variable name.
+        * @param value
+        *            the Variable initial value.
+        * 
+        * @throws PaintException
+        *             if the paint operation failed.
+        */
+       public void addVariable(VariableOwner owner, String name, boolean value)
+                       throws PaintException {
+               tag.addVariable(new BooleanVariable(owner,name,value));
+       }
+
+       /**
+        * Adds a string array type variable.
+        * 
+        * @param owner
+        *            the Listener for variable changes.
+        * @param name
+        *            the Variable name.
+        * @param value
+        *            the Variable initial value.
+        * 
+        * @throws PaintException
+        *             if the paint operation failed.
+        */
+       public void addVariable(VariableOwner owner, String name, String[] value)
+                       throws PaintException {
+               tag.addVariable(new ArrayVariable(owner,name,value));
+       }
+
+       /**
+        * Adds a upload stream type variable.
+        * 
+        * TODO not converted for JSON
+        * 
+        * @param owner
+        *            the Listener for variable changes.
+        * @param name
+        *            the Variable name.
+        * 
+        * @throws PaintException
+        *             if the paint operation failed.
+        */
+       public void addUploadStreamVariable(VariableOwner owner, String name)
+                       throws PaintException {
+               String code = variableMap.registerVariable(name, UploadStream.class,
+                               null, owner);
+               startTag("uploadstream");
+               addAttribute(UIDL_ARG_ID, code);
+               addAttribute(UIDL_ARG_NAME, name);
+               endTag("uploadstream");
+       }
+
+       /**
+        * Prints the single text section.
+        * 
+        * Prints full text section. The section data is escaped from XML tags and
+        * surrounded by XML start and end-tags.
+        * 
+        * @param sectionTagName
+        *            the name of the tag.
+        * @param sectionData
+        *            the section data to be printed.
+        * @throws PaintException
+        *             if the paint operation failed.
+        */
+       public void addSection(String sectionTagName, String sectionData)
+                       throws PaintException {
+               startTag(sectionTagName);
+               addText(sectionData);
+               endTag(sectionTagName);
+       }
+
+       /**
+        * Adds XML directly to UIDL.
+        * 
+        * @param xml
+        *            the Xml to be added.
+        * @throws PaintException
+        *             if the paint operation failed.
+        */
+       public void addUIDL(String xml) throws PaintException {
+
+               // Ensure that the target is open
+               if (this.closed)
+                       throw new PaintException(
+                                       "Attempted to write to a closed PaintTarget.");
+
+               // Make sure that the open start tag is closed before
+               // anything is written.
+
+               // Escape and write what was given
+               if (xml != null)
+                       tag.addData(xml);
+
+       }
+
+       /**
+        * Adds XML section with namespace.
+        * 
+        * @param sectionTagName
+        *            the name of the tag.
+        * @param sectionData
+        *            the section data.
+        * @param namespace
+        *            the namespace to be added.
+        * @throws PaintException
+        *             if the paint operation failed.
+        * 
+        * @see com.itmill.toolkit.terminal.PaintTarget#addXMLSection(String,
+        *      String, String)
+        */
+       public void addXMLSection(String sectionTagName, String sectionData,
+                       String namespace) throws PaintException {
+
+               // Ensure that the target is open
+               if (this.closed)
+                       throw new PaintException(
+                                       "Attempted to write to a closed PaintTarget.");
+
+               startTag(sectionTagName);
+               if (namespace != null)
+                       addAttribute("xmlns", namespace);
+               mTagArgumentListOpen = false;
+
+               if (sectionData != null)
+                       tag.addData(sectionData);
+               endTag(sectionTagName);
+       }
+
+       /**
+        * Gets the UIDL already printed to stream. Paint target must be closed
+        * before the <code>getUIDL</code> can be called.
+        * 
+        * @return the UIDL.
+        */
+       public String getUIDL() {
+               if (this.closed) {
+                       return uidlBuffer.toString();
+               }
+               throw new IllegalStateException(
+                               "Tried to read UIDL from open PaintTarget");
+       }
+
+       /**
+        * Closes the paint target. Paint target must be closed before the
+        * <code>getUIDL</code> can be called. Subsequent attempts to write to
+        * paint target. If the target was already closed, call to this function is
+        * ignored. will generate an exception.
+        * 
+        * @throws PaintException
+        *             if the paint operation failed.
+        */
+       public void close() throws PaintException {
+               append("}");
+               if (!this.closed) {
+                       flush();
+
+                       // Close all
+                       this.uidlBuffer.close();
+                       this.closed = true;
+               }
+       }
+
+       /**
+        * Method flush.
+        */
+       private void flush() {
+               this.uidlBuffer.flush();
+       }
+
+       /**
+        * @see com.itmill.toolkit.terminal.PaintTarget#startTag(com.itmill.toolkit.terminal.Paintable,
+        *      java.lang.String)
+        */
+       public boolean startTag(Paintable paintable, String tagName)
+                       throws PaintException {
+               startTag(tagName, true);
+               String id = manager.getPaintableId(paintable);
+               paintable.addListener(manager);
+               addAttribute("id", id);
+               addAttribute("type", tagName);
+               return false;
+       }
+
+       /**
+        * @see com.itmill.toolkit.terminal.PaintTarget#addCharacterData(java.lang.String)
+        */
+       public void addCharacterData(String text) throws PaintException {
+               if (text != null)
+                       tag.addData(text);
+       }
+
+       /**
+        * 
+        * @return
+        */
+       public boolean isTrackPaints() {
+               return trackPaints;
+       }
+
+       /**
+        * Gets the number of paints.
+        * 
+        * @return the number of paints.
+        */
+       public int getNumberOfPaints() {
+               return numberOfPaints;
+       }
+
+       /**
+        * Sets the tracking to true or false.
+        * 
+        * This also resets the number of paints.
+        * 
+        * @param enabled
+        *            is the tracking is enabled or not.
+        * @see #getNumberOfPaints()
+        */
+       public void setTrackPaints(boolean enabled) {
+               this.trackPaints = enabled;
+               this.numberOfPaints = 0;
+       }
+       
+       /**
+        * This is basically a container for UI components variables, that will be 
+        * added at the end of JSON object.
+        * @author mattitahvonen
+        *
+        */
+       class JsonTag {
+               boolean firstField = true;
+               
+               Vector variables = new Vector();
+
+               Vector attr = new Vector();
+               
+               private HashMap childTagCounters = new HashMap();
+
+               StringBuffer data = new StringBuffer();
+               
+               public boolean childrenArrayOpen = false;
+
+               private boolean childNode = false;
+               
+               public JsonTag() {
+                       
+               }
+               
+               public void openChildrenArray() {
+                       if(!childrenArrayOpen) {
+                               append("children : [");
+                               childrenArrayOpen = true;
+                               firstField = true;
+                       }
+               }
+               
+               /**
+                * This is used to prevent possible collapses on tag names
+                * @param tagName
+                * @param start
+                * @return
+                */
+               public String postfixChildtag(String tagName, boolean start) {
+                       TagCounter i = (TagCounter) childTagCounters.get(tagName);
+                       if(i == null) {
+                               i = new TagCounter();
+                               childTagCounters.put(tagName, i);
+                       }
+                       tagName = i.postfix(tagName);
+                       if(!start)
+                               i.increment();
+                       return tagName;
+               }
+
+               public void closeChildrenArray() {
+                       append("]");
+                       firstField = false;
+               }
+
+               public void setChildNode(boolean b) {
+                       this.childNode = b;
+               }
+               
+               public boolean isChildNode(){
+                       return childNode;
+               }
+
+               public String startField() {
+                       if(firstField) {
+                               firstField = false;
+                               return "";
+                       } else {
+                               return ",";
+                       }
+               }
+               
+               public void addData(String s) {
+                       data.append(s);
+               }
+               
+               public String getData() {
+                       if(data.length() == 0)
+                               return "";
+                       return startField() + "data:\"" + escapeJSON(data.toString()) +"\"";
+               }
+               
+               public void addAttribute(String jsonNode) {
+                       attr.add(jsonNode);
+               }
+               
+               public String attributesAsJsonObject() {
+                       if(attr.size() == 0)
+                               return "";
+                       StringBuffer buf = new StringBuffer();
+                       buf.append(startField());
+                       buf.append("attr:{");
+                       for (Iterator iter = attr.iterator(); iter.hasNext();) {
+                               String element = (String) iter.next();
+                               buf.append(element);
+                               if(iter.hasNext())
+                                       buf.append(",");
+                       }
+                       buf.append("}");
+                       return buf.toString();
+               }
+               
+               public void addVariable(Variable v) {
+                       variables.add(v);
+               }
+               
+               public String variablesAsJsonObject() {
+                       if(variables.size() == 0)
+                               return "";
+                       StringBuffer buf = new StringBuffer();
+                       buf.append(startField());
+                       buf.append("variables:{");
+                       for (Iterator iter = variables.iterator(); iter.hasNext();) {
+                               Variable element = (Variable) iter.next();
+                               buf.append(element.getJsonPresentation());
+                               if(iter.hasNext())
+                                       buf.append(",");
+                       }
+                       buf.append("}");
+                       return buf.toString();
+               }
+               
+               class TagCounter {
+                       int count;
+                       public TagCounter() {
+                               count = 0;
+                       }
+                       public void increment() {
+                               count++;
+                       }
+                       public String postfix(String s) {
+                               if(count > 0) {
+                                       return s + count;
+                               }
+                               return s;
+                       }
+               }
+       }
+
+       abstract class Variable {
+               String code;
+               String name;
+               public abstract String getJsonPresentation();
+       }
+       
+       class BooleanVariable extends Variable {
+               boolean value;
+
+               public BooleanVariable(VariableOwner owner, String name, boolean v) {
+                       value = v;
+                       this.name = name;
+                       code = variableMap.registerVariable(name, Boolean.class,
+                                       new Boolean(value), owner);
+               }
+
+               public String getJsonPresentation() {
+                       return name +":{name:\""+name+"\",id:\"" +
+                                       code+"\",type:\"boolean\", value : " 
+                       + (value == true ? "true}" : "false}");
+               }
+               
+       }
+       
+       class StringVariable extends Variable {
+               String value;
+
+               public StringVariable(VariableOwner owner, String name, String v) {
+                       value = v;
+                       this.name = name;
+                       code = variableMap.registerVariable(name, String.class,
+                                       value, owner);
+               }
+
+               public String getJsonPresentation() {
+                       return name +":{name:\""+name+"\",id:\"" +
+                                       code+"\",type:\"string\", value : \"" 
+                                       + value + "\"}";
+               }
+               
+       }
+
+       class IntVariable extends Variable {
+               int value;
+
+               public IntVariable(VariableOwner owner, String name, int v) {
+                       value = v;
+                       this.name = name;
+                       code = variableMap.registerVariable(name, Boolean.class,
+                                       new Integer(value), owner);
+               }
+
+               public String getJsonPresentation() {
+                       return name +":{name:\""+name+"\",id:\"" +
+                                       code+"\",type:\"int\", value : " 
+                       + value + "}";
+               }
+       }
+
+       class ArrayVariable extends Variable {
+               String[] value;
+
+               public ArrayVariable(VariableOwner owner, String name, String[] v) {
+                       value = v;
+                       this.name = name;
+                       code = variableMap.registerVariable(name, String[].class,
+                                       value, owner);
+               }
+
+               public String getJsonPresentation() {
+                       String pres =  name +":{name:\""+name+"\",id:\"" +
+                                       code+"\",type:\"array\", value : [";
+                       for (int i = 0; i < value.length;) {
+                               pres += value[i];
+                               i++;
+                               if(i < value.length)
+                                       pres += ",";
+                       }
+                       pres += "]}";
+                       
+                       return pres;
+               }
+       }
+
+       public Set getPreCachedResources() {
+               return new HashSet();
+       }
+
+       public void setPreCachedResources(Set preCachedResources) {
+               // TODO Auto-generated method stub
+               
+       }
+
+       
+}
diff --git a/src/com/itmill/toolkit/terminal/web/AjaxPaintTarget.java b/src/com/itmill/toolkit/terminal/web/AjaxPaintTarget.java
deleted file mode 100644 (file)
index 70ece88..0000000
+++ /dev/null
@@ -1,753 +0,0 @@
-/* *************************************************************************
- IT Mill Toolkit 
-
- Development of Browser User Interfaces Made Easy
-
- Copyright (C) 2000-2006 IT Mill Ltd
- *************************************************************************
-
- This product is distributed under commercial license that can be found
- from the product package on license.pdf. Use of this product might 
- require purchasing a commercial license from IT Mill Ltd. For guidelines 
- on usage, see licensing-guidelines.html
-
- *************************************************************************
- For more information, contact:
- IT Mill Ltd                           phone: +358 2 4802 7180
- Ruukinkatu 2-4                        fax:   +358 2 4802 7181
- 20540, Turku                          email:  info@itmill.com
- Finland                               company www: www.itmill.com
- Primary source for information and releases: www.itmill.com
-
- ********************************************************************** */
-
-package com.itmill.toolkit.terminal.web;
-
-import com.itmill.toolkit.Application;
-import com.itmill.toolkit.terminal.ApplicationResource;
-import com.itmill.toolkit.terminal.ExternalResource;
-import com.itmill.toolkit.terminal.PaintException;
-import com.itmill.toolkit.terminal.PaintTarget;
-import com.itmill.toolkit.terminal.Paintable;
-import com.itmill.toolkit.terminal.Resource;
-import com.itmill.toolkit.terminal.ThemeResource;
-import com.itmill.toolkit.terminal.UploadStream;
-import com.itmill.toolkit.terminal.VariableOwner;
-
-import java.io.BufferedWriter;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.Stack;
-
-/**
- * User Interface Description Language Target.
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.1
- */
-public class AjaxPaintTarget implements PaintTarget {
-
-       /* Document type declarations */
-       private final static String UIDL_XML_DECL = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
-
-       private final static String UIDL_ARG_NAME = "name";
-
-       private final static String UIDL_ARG_VALUE = "value";
-
-       private final static String UIDL_ARG_ID = "id";
-
-       private Stack mOpenTags;
-
-       private boolean mTagArgumentListOpen;
-
-       private PrintWriter uidlBuffer;
-
-       private AjaxVariableMap variableMap;
-
-       private boolean closed = false;
-
-       private AjaxApplicationManager manager;
-
-       private boolean trackPaints = false;
-
-       private int numberOfPaints = 0;
-       
-       Set preCachedResources = new HashSet();
-       private boolean customLayoutArgumentsOpen = false;
-
-       /**
-        * Creates a new XMLPrintWriter, without automatic line flushing.
-        * 
-        * @param variableMap
-        * @param manager
-        * @param output
-        *            A character-output stream.
-        * @throws PaintException
-        *             if the paint operation failed.
-        */
-       public AjaxPaintTarget(AjaxVariableMap variableMap,
-                       AjaxApplicationManager manager, OutputStream output)
-                       throws PaintException {
-
-               // Sets the cache
-               this.manager = manager;
-
-               // Sets the variable map
-               this.variableMap = variableMap;
-
-               // Sets the target for UIDL writing
-               try {
-                       this.uidlBuffer = new PrintWriter(new BufferedWriter(
-                                       new OutputStreamWriter(output, "UTF-8")));
-               } catch (UnsupportedEncodingException e) {
-                       throw new RuntimeException("Internal error");
-               }
-
-               // Initialize tag-writing
-               mOpenTags = new Stack();
-               mTagArgumentListOpen = false;
-
-               // Adds document declaration
-               this.print(UIDL_XML_DECL + "\n\n");
-
-               // Adds UIDL start tag and its attributes
-               this.startTag("changes");
-
-       }
-
-       /**
-        * Ensures that the currently open element tag is closed.
-        */
-       private void ensureClosedTag() {
-               if (mTagArgumentListOpen) {
-                       append(">");
-                       mTagArgumentListOpen = false;
-                       customLayoutArgumentsOpen = false;
-               }
-       }
-
-       /**
-        * Method append.This method is thread safe.
-        * 
-        * @param string
-        *            the text to insert.
-        */
-       private void append(String string) {
-               uidlBuffer.print(string);
-       }
-
-       /**
-        * Prints the element start tag.
-        * 
-        * <pre>
-        * Todo:
-        *  Checking of input values
-        *  
-        * </pre>
-        * 
-        * @param tagName
-        *            the name of the start tag.
-        * @throws PaintException
-        *             if the paint operation failed.
-        * 
-        */
-       public void startTag(String tagName) throws PaintException {
-               // In case of null data output nothing:
-               if (tagName == null)
-                       throw new NullPointerException();
-
-               // Increments paint tracker
-               if (this.isTrackPaints()) {
-                       this.numberOfPaints++;
-               }
-
-               // Ensures that the target is open
-               if (this.closed)
-                       throw new PaintException(
-                                       "Attempted to write to a closed PaintTarget.");
-
-               // Makes sure that the open start tag is closed before
-               // anything is written.
-               ensureClosedTag();
-
-               // Checks tagName and attributes here
-               mOpenTags.push(tagName);
-
-               // Prints the tag with attributes
-               append("<" + tagName);
-
-               mTagArgumentListOpen = true;
-               
-               if ("customlayout".equals(tagName))
-                       customLayoutArgumentsOpen = true;
-       }
-
-       /**
-        * Prints the element end tag.
-        * 
-        * If the parent tag is closed before every child tag is closed an
-        * PaintException is raised.
-        * 
-        * @param tag
-        *            the name of the end tag.
-        * @throws Paintexception
-        *             if the paint operation failed.
-        */
-       public void endTag(String tagName) throws PaintException {
-               // In case of null data output nothing:
-               if (tagName == null)
-                       throw new NullPointerException();
-
-               // Ensure that the target is open
-               if (this.closed)
-                       throw new PaintException(
-                                       "Attempted to write to a closed PaintTarget.");
-
-               String lastTag = "";
-
-               lastTag = (String) mOpenTags.pop();
-               if (!tagName.equalsIgnoreCase(lastTag))
-                       throw new PaintException("Invalid UIDL: wrong ending tag: '"
-                                       + tagName + "' expected: '" + lastTag + "'.");
-
-               // Make sure that the open start tag is closed before
-               // anything is written.
-               if (mTagArgumentListOpen) {
-                       append(">");
-                       mTagArgumentListOpen = false;
-                       customLayoutArgumentsOpen = false;
-               }
-
-               // Writes the end (closing) tag
-               append("</" + lastTag + ">");
-               flush();
-       }
-
-       /**
-        * Substitutes the XML sensitive characters with predefined XML entities.
-        * 
-        * @param xml
-        *            the String to be substituted.
-        * @return A new string instance where all occurrences of XML sensitive
-        *         characters are substituted with entities.
-        */
-       static public String escapeXML(String xml) {
-               if (xml == null || xml.length() <= 0)
-                       return "";
-               return escapeXML(new StringBuffer(xml)).toString();
-       }
-
-       /**
-        * Substitutes the XML sensitive characters with predefined XML entities.
-        * 
-        * @param xml
-        *            the String to be substituted.
-        * @return A new StringBuffer instance where all occurrences of XML
-        *         sensitive characters are substituted with entities.
-        * 
-        */
-       static public StringBuffer escapeXML(StringBuffer xml) {
-               if (xml == null || xml.length() <= 0)
-                       return new StringBuffer("");
-
-               StringBuffer result = new StringBuffer(xml.length() * 2);
-
-               for (int i = 0; i < xml.length(); i++) {
-                       char c = xml.charAt(i);
-                       String s = toXmlChar(c);
-                       if (s != null) {
-                               result.append(s);
-                       } else {
-                               result.append(c);
-                       }
-               }
-               return result;
-       }
-
-       /**
-        * Substitutes a XML sensitive character with predefined XML entity.
-        * 
-        * @param c
-        *            the Character to be replaced with an entity.
-        * @return String of the entity or null if character is not to be replaced
-        *         with an entity.
-        */
-       private static String toXmlChar(char c) {
-               switch (c) {
-               case '&':
-                       return "&amp;"; // & => &amp;
-               case '>':
-                       return "&gt;"; // > => &gt;
-               case '<':
-                       return "&lt;"; // < => &lt;
-               case '"':
-                       return "&quot;"; // " => &quot;
-               case '\'':
-                       return "&apos;"; // ' => &apos;
-               default:
-                       return null;
-               }
-       }
-
-       /**
-        * Prints XML.
-        * 
-        * Writes pre-formatted XML to stream. Well-formness of XML is checked.
-        * 
-        * <pre>
-        * 
-        *  TODO: XML checking should be made
-        *  
-        * </pre>
-        * 
-        * @param str
-        *            the string to print.
-        */
-       private void print(String str) {
-               // In case of null data output nothing:
-               if (str == null)
-                       return;
-
-               // Make sure that the open start tag is closed before
-               // anything is written.
-               ensureClosedTag();
-
-               // Write what was given
-               append(str);
-       }
-
-       /**
-        * Prints XML-escaped text.
-        * 
-        * @param str
-        * @throws PaintException
-        *             if the paint operation failed.
-        * 
-        */
-       public void addText(String str) throws PaintException {
-               addUIDL(escapeXML(str));
-       }
-
-       /**
-        * Adds a boolean attribute to component. Atributes must be added before any
-        * content is written.
-        * 
-        * @param name
-        *            the Attribute name.
-        * @param value
-        *            the Attribute value.
-        * @throws PaintException
-        *             if the paint operation failed.
-        */
-       public void addAttribute(String name, boolean value) throws PaintException {
-               addAttribute(name, String.valueOf(value));
-       }
-
-       /**
-        * Adds a resource attribute to component. Atributes must be added before
-        * any content is written.
-        * 
-        * @param name
-        *            the Attribute name.
-        * @param value
-        *            the Attribute value.
-        * 
-        * @throws PaintException
-        *             if the paint operation failed.
-        */
-       public void addAttribute(String name, Resource value) throws PaintException {
-
-               if (value instanceof ExternalResource) {
-                       addAttribute(name, ((ExternalResource) value).getURL());
-
-               } else if (value instanceof ApplicationResource) {
-                       ApplicationResource r = (ApplicationResource) value;
-                       Application a = r.getApplication();
-                       if (a == null)
-                               throw new PaintException(
-                                               "Application not specified for resorce "
-                                                               + value.getClass().getName());
-                       String uri = a.getURL().getPath();
-                       if (uri.charAt(uri.length() - 1) != '/')
-                               uri += "/";
-                       uri += a.getRelativeLocation(r);
-                       addAttribute(name, uri);
-
-               } else if (value instanceof ThemeResource) {
-                       String uri = "theme://" + ((ThemeResource) value).getResourceId();
-                       addAttribute(name, uri);
-               } else
-                       throw new PaintException("Ajax adapter does not "
-                                       + "support resources of type: "
-                                       + value.getClass().getName());
-
-       }
-
-       /**
-        * Adds a integer attribute to component. Atributes must be added before any
-        * content is written.
-        * 
-        * @param name
-        *            the Attribute name.
-        * @param value
-        *            the Attribute value.
-        * 
-        * @throws PaintException
-        *             if the paint operation failed.
-        */
-       public void addAttribute(String name, int value) throws PaintException {
-               addAttribute(name, String.valueOf(value));
-       }
-
-       /**
-        * Adds a long attribute to component. Atributes must be added before any
-        * content is written.
-        * 
-        * @param name
-        *            the Attribute name.
-        * @param value
-        *            the Attribute value.
-        * 
-        * @throws PaintException
-        *             if the paint operation failed.
-        */
-       public void addAttribute(String name, long value) throws PaintException {
-               addAttribute(name, String.valueOf(value));
-       }
-
-       /**
-        * Adds a string attribute to component. Atributes must be added before any
-        * content is written.
-        * 
-        * @param name
-        *            the Boolean attribute name.
-        * @param value
-        *            the Boolean attribute value.
-        * 
-        * @throws PaintException
-        *             if the paint operation failed.
-        */
-       public void addAttribute(String name, String value) throws PaintException {
-               // In case of null data output nothing:
-               if ((value == null) || (name == null))
-                       throw new NullPointerException(
-                                       "Parameters must be non-null strings");
-
-               // Ensure that the target is open
-               if (this.closed)
-                       throw new PaintException(
-                                       "Attempted to write to a closed PaintTarget.");
-
-               // Check that argument list is writable.
-               if (!mTagArgumentListOpen)
-                       throw new PaintException("XML argument list not open.");
-
-               append(" " + name + "=\"" + escapeXML(value) + "\"");
-               
-               if (customLayoutArgumentsOpen && "style".equals(name))
-                       preCachedResources.add("layout/" + value + ".html");
-       }
-
-       /**
-        * Adds a string type variable.
-        * 
-        * @param owner
-        *            the Listener for variable changes.
-        * @param name
-        *            the Variable name.
-        * @param value
-        *            the Variable initial value.
-        * 
-        * @throws PaintException
-        *             if the paint operation failed.
-        */
-       public void addVariable(VariableOwner owner, String name, String value)
-                       throws PaintException {
-               String code = variableMap.registerVariable(name, String.class, value,
-                               owner);
-               startTag("string");
-               addAttribute(UIDL_ARG_ID, code);
-               addAttribute(UIDL_ARG_NAME, name);
-               addText(value);
-               endTag("string");
-       }
-
-       /**
-        * Adds a int type variable.
-        * 
-        * @param owner
-        *            the Listener for variable changes.
-        * @param name
-        *            the Variable name.
-        * @param value
-        *            the Variable initial value.
-        * 
-        * @throws PaintException
-        *             if the paint operation failed.
-        */
-       public void addVariable(VariableOwner owner, String name, int value)
-                       throws PaintException {
-               String code = variableMap.registerVariable(name, Integer.class,
-                               new Integer(value), owner);
-               startTag("integer");
-               addAttribute(UIDL_ARG_ID, code);
-               addAttribute(UIDL_ARG_NAME, name);
-               addAttribute(UIDL_ARG_VALUE, String.valueOf(value));
-               endTag("integer");
-       }
-
-       /**
-        * Adds a boolean type variable.
-        * 
-        * @param owner
-        *            the Listener for variable changes.
-        * @param name
-        *            the Variable name.
-        * @param value
-        *            the Variable initial value.
-        * 
-        * @throws PaintException
-        *             if the paint operation failed.
-        */
-       public void addVariable(VariableOwner owner, String name, boolean value)
-                       throws PaintException {
-               String code = variableMap.registerVariable(name, Boolean.class,
-                               new Boolean(value), owner);
-               startTag("boolean");
-               addAttribute(UIDL_ARG_ID, code);
-               addAttribute(UIDL_ARG_NAME, name);
-               addAttribute(UIDL_ARG_VALUE, String.valueOf(value));
-               endTag("boolean");
-       }
-
-       /**
-        * Adds a string array type variable.
-        * 
-        * @param owner
-        *            the Listener for variable changes.
-        * @param name
-        *            the Variable name.
-        * @param value
-        *            the Variable initial value.
-        * 
-        * @throws PaintException
-        *             if the paint operation failed.
-        */
-       public void addVariable(VariableOwner owner, String name, String[] value)
-                       throws PaintException {
-               String code = variableMap.registerVariable(name, String[].class, value,
-                               owner);
-               startTag("array");
-               addAttribute(UIDL_ARG_ID, code);
-               addAttribute(UIDL_ARG_NAME, name);
-               for (int i = 0; i < value.length; i++)
-                       addSection("ai", value[i]);
-               endTag("array");
-       }
-
-       /**
-        * Adds a upload stream type variable.
-        * 
-        * @param owner
-        *            the Listener for variable changes.
-        * @param name
-        *            the Variable name.
-        * 
-        * @throws PaintException
-        *             if the paint operation failed.
-        */
-       public void addUploadStreamVariable(VariableOwner owner, String name)
-                       throws PaintException {
-               String code = variableMap.registerVariable(name, UploadStream.class,
-                               null, owner);
-               startTag("uploadstream");
-               addAttribute(UIDL_ARG_ID, code);
-               addAttribute(UIDL_ARG_NAME, name);
-               endTag("uploadstream");
-       }
-
-       /**
-        * Prints the single text section.
-        * 
-        * Prints full text section. The section data is escaped from XML tags and
-        * surrounded by XML start and end-tags.
-        * 
-        * @param sectionTagName
-        *            the name of the tag.
-        * @param sectionData
-        *            the section data to be printed.
-        * @throws PaintException
-        *             if the paint operation failed.
-        */
-       public void addSection(String sectionTagName, String sectionData)
-                       throws PaintException {
-               startTag(sectionTagName);
-               addText(sectionData);
-               endTag(sectionTagName);
-       }
-
-       /**
-        * Adds XML directly to UIDL.
-        * 
-        * @param xml
-        *            the Xml to be added.
-        * @throws PaintException
-        *             if the paint operation failed.
-        */
-       public void addUIDL(String xml) throws PaintException {
-
-               // Ensure that the target is open
-               if (this.closed)
-                       throw new PaintException(
-                                       "Attempted to write to a closed PaintTarget.");
-
-               // Make sure that the open start tag is closed before
-               // anything is written.
-               ensureClosedTag();
-
-               // Escape and write what was given
-               if (xml != null)
-                       append(xml);
-
-       }
-
-       /**
-        * Adds XML section with namespace.
-        * 
-        * @param sectionTagName
-        *            the name of the tag.
-        * @param sectionData
-        *            the section data.
-        * @param namespace
-        *            the namespace to be added.
-        * @throws PaintException
-        *             if the paint operation failed.
-        * 
-        * @see com.itmill.toolkit.terminal.PaintTarget#addXMLSection(String,
-        *      String, String)
-        */
-       public void addXMLSection(String sectionTagName, String sectionData,
-                       String namespace) throws PaintException {
-
-               // Ensure that the target is open
-               if (this.closed)
-                       throw new PaintException(
-                                       "Attempted to write to a closed PaintTarget.");
-
-               startTag(sectionTagName);
-               if (namespace != null)
-                       addAttribute("xmlns", namespace);
-               append(">");
-               mTagArgumentListOpen = false;
-
-               if (sectionData != null)
-                       append(sectionData);
-               endTag(sectionTagName);
-       }
-
-       /**
-        * Gets the UIDL already printed to stream. Paint target must be closed
-        * before the <code>getUIDL</code> can be called.
-        * 
-        * @return the UIDL.
-        */
-       public String getUIDL() {
-               if (this.closed) {
-                       return uidlBuffer.toString();
-               }
-               throw new IllegalStateException(
-                               "Tried to read UIDL from open PaintTarget");
-       }
-
-       /**
-        * Closes the paint target. Paint target must be closed before the
-        * <code>getUIDL</code> can be called. Subsequent attempts to write to
-        * paint target. If the target was already closed, call to this function is
-        * ignored. will generate an exception.
-        * 
-        * @throws PaintException
-        *             if the paint operation failed.
-        */
-       public void close() throws PaintException {
-               if (!this.closed) {
-                       this.endTag("changes");
-                       flush();
-
-                       // Close all
-                       this.uidlBuffer.close();
-                       this.closed = true;
-               }
-       }
-
-       /**
-        * Method flush.
-        */
-       private void flush() {
-               this.uidlBuffer.flush();
-       }
-
-       /**
-        * @see com.itmill.toolkit.terminal.PaintTarget#startTag(com.itmill.toolkit.terminal.Paintable,
-        *      java.lang.String)
-        */
-       public boolean startTag(Paintable paintable, String tag)
-                       throws PaintException {
-               startTag(tag);
-               String id = manager.getPaintableId(paintable);
-               paintable.addListener(manager);
-               addAttribute("id", id);
-               return false;
-       }
-
-       /**
-        * @see com.itmill.toolkit.terminal.PaintTarget#addCharacterData(java.lang.String)
-        */
-       public void addCharacterData(String text) throws PaintException {
-               ensureClosedTag();
-               if (text != null)
-                       append("<![CDATA[" + text + "]]>");
-       }
-
-       /**
-        * 
-        * @return
-        */
-       public boolean isTrackPaints() {
-               return trackPaints;
-       }
-
-       /**
-        * Gets the number of paints.
-        * 
-        * @return the number of paints.
-        */
-       public int getNumberOfPaints() {
-               return numberOfPaints;
-       }
-
-       /**
-        * Sets the tracking to true or false.
-        * 
-        * This also resets the number of paints.
-        * 
-        * @param enabled
-        *            is the tracking is enabled or not.
-        * @see #getNumberOfPaints()
-        */
-       public void setTrackPaints(boolean enabled) {
-               this.trackPaints = enabled;
-               this.numberOfPaints = 0;
-       }
-
-}
diff --git a/src/com/itmill/toolkit/terminal/web/AjaxXmlPaintTarget.java b/src/com/itmill/toolkit/terminal/web/AjaxXmlPaintTarget.java
new file mode 100644 (file)
index 0000000..26dd13d
--- /dev/null
@@ -0,0 +1,598 @@
+/* *************************************************************************
+ IT Mill Toolkit 
+
+ Development of Browser User Interfaces Made Easy
+
+ Copyright (C) 2000-2006 IT Mill Ltd
+ *************************************************************************
+
+ This product is distributed under commercial license that can be found
+ from the product package on license.pdf. Use of this product might 
+ require purchasing a commercial license from IT Mill Ltd. For guidelines 
+ on usage, see licensing-guidelines.html
+
+ *************************************************************************
+ For more information, contact:
+ IT Mill Ltd                           phone: +358 2 4802 7180
+ Ruukinkatu 2-4                        fax:   +358 2 4802 7181
+ 20540, Turku                          email:  info@itmill.com
+ Finland                               company www: www.itmill.com
+ Primary source for information and releases: www.itmill.com
+
+ ********************************************************************** */
+
+package com.itmill.toolkit.terminal.web;
+
+import com.itmill.toolkit.Application;
+import com.itmill.toolkit.terminal.ApplicationResource;
+import com.itmill.toolkit.terminal.ExternalResource;
+import com.itmill.toolkit.terminal.PaintException;
+import com.itmill.toolkit.terminal.PaintTarget;
+import com.itmill.toolkit.terminal.Paintable;
+import com.itmill.toolkit.terminal.Resource;
+import com.itmill.toolkit.terminal.ThemeResource;
+import com.itmill.toolkit.terminal.UploadStream;
+import com.itmill.toolkit.terminal.VariableOwner;
+
+import java.io.BufferedWriter;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Stack;
+
+/**
+ * User Interface Description Language Target.
+ * 
+ * @author IT Mill Ltd.
+ * @version
+ * @VERSION@
+ * @since 3.1
+ */
+public class AjaxXmlPaintTarget implements PaintTarget, AjaxPaintTarget {
+
+       /* Document type declarations */
+       private final static String UIDL_XML_DECL = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
+
+       private final static String UIDL_ARG_NAME = "name";
+
+       private final static String UIDL_ARG_VALUE = "value";
+
+       private final static String UIDL_ARG_ID = "id";
+
+       private Stack mOpenTags;
+
+       private boolean mTagArgumentListOpen;
+
+       private PrintWriter uidlBuffer;
+
+       private AjaxVariableMap variableMap;
+
+       private boolean closed = false;
+
+       private AjaxApplicationManager manager;
+
+       private boolean trackPaints = false;
+
+       private int numberOfPaints = 0;
+       
+       private Set preCachedResources = new HashSet();
+       private boolean customLayoutArgumentsOpen = false;
+
+       /**
+        * Creates a new XMLPrintWriter, without automatic line flushing.
+        * 
+        * @param variableMap
+        * @param manager
+        * @param output
+        *            A character-output stream.
+        * @throws PaintException
+        *             if the paint operation failed.
+        */
+       public AjaxXmlPaintTarget(AjaxVariableMap variableMap,
+                       AjaxApplicationManager manager, OutputStream output)
+                       throws PaintException {
+
+               // Sets the cache
+               this.manager = manager;
+
+               // Sets the variable map
+               this.variableMap = variableMap;
+
+               // Sets the target for UIDL writing
+               try {
+                       this.uidlBuffer = new PrintWriter(new BufferedWriter(
+                                       new OutputStreamWriter(output, "UTF-8")));
+               } catch (UnsupportedEncodingException e) {
+                       throw new RuntimeException("Internal error");
+               }
+
+               // Initialize tag-writing
+               mOpenTags = new Stack();
+               mTagArgumentListOpen = false;
+
+               // Adds document declaration
+               this.print(UIDL_XML_DECL + "\n\n");
+
+               // Adds UIDL start tag and its attributes
+               this.startTag("changes");
+
+       }
+
+       /**
+        * Ensures that the currently open element tag is closed.
+        */
+       private void ensureClosedTag() {
+               if (mTagArgumentListOpen) {
+                       append(">");
+                       mTagArgumentListOpen = false;
+                       customLayoutArgumentsOpen = false;
+               }
+       }
+
+       /**
+        * Method append.This method is thread safe.
+        * 
+        * @param string
+        *            the text to insert.
+        */
+       private void append(String string) {
+               uidlBuffer.print(string);
+       }
+
+       /* (non-Javadoc)
+        * @see com.itmill.toolkit.terminal.web.AjaxPaintTarget#startTag(java.lang.String)
+        */
+       public void startTag(String tagName) throws PaintException {
+               // In case of null data output nothing:
+               if (tagName == null)
+                       throw new NullPointerException();
+
+               // Increments paint tracker
+               if (this.isTrackPaints()) {
+                       this.numberOfPaints++;
+               }
+
+               // Ensures that the target is open
+               if (this.closed)
+                       throw new PaintException(
+                                       "Attempted to write to a closed PaintTarget.");
+
+               // Makes sure that the open start tag is closed before
+               // anything is written.
+               ensureClosedTag();
+
+               // Checks tagName and attributes here
+               mOpenTags.push(tagName);
+
+               // Prints the tag with attributes
+               append("<" + tagName);
+
+               mTagArgumentListOpen = true;
+               
+               if ("customlayout".equals(tagName))
+                       customLayoutArgumentsOpen = true;
+       }
+
+       /* (non-Javadoc)
+        * @see com.itmill.toolkit.terminal.web.AjaxPaintTarget#endTag(java.lang.String)
+        */
+       public void endTag(String tagName) throws PaintException {
+               // In case of null data output nothing:
+               if (tagName == null)
+                       throw new NullPointerException();
+
+               // Ensure that the target is open
+               if (this.closed)
+                       throw new PaintException(
+                                       "Attempted to write to a closed PaintTarget.");
+
+               String lastTag = "";
+
+               lastTag = (String) mOpenTags.pop();
+               if (!tagName.equalsIgnoreCase(lastTag))
+                       throw new PaintException("Invalid UIDL: wrong ending tag: '"
+                                       + tagName + "' expected: '" + lastTag + "'.");
+
+               // Make sure that the open start tag is closed before
+               // anything is written.
+               if (mTagArgumentListOpen) {
+                       append(">");
+                       mTagArgumentListOpen = false;
+                       customLayoutArgumentsOpen = false;
+               }
+
+               // Writes the end (closing) tag
+               append("</" + lastTag + ">");
+               flush();
+       }
+
+       /**
+        * Substitutes the XML sensitive characters with predefined XML entities.
+        * 
+        * @param xml
+        *            the String to be substituted.
+        * @return A new string instance where all occurrences of XML sensitive
+        *         characters are substituted with entities.
+        */
+       static public String escapeXML(String xml) {
+               if (xml == null || xml.length() <= 0)
+                       return "";
+               return escapeXML(new StringBuffer(xml)).toString();
+       }
+
+       /**
+        * Substitutes the XML sensitive characters with predefined XML entities.
+        * 
+        * @param xml
+        *            the String to be substituted.
+        * @return A new StringBuffer instance where all occurrences of XML
+        *         sensitive characters are substituted with entities.
+        * 
+        */
+       static public StringBuffer escapeXML(StringBuffer xml) {
+               if (xml == null || xml.length() <= 0)
+                       return new StringBuffer("");
+
+               StringBuffer result = new StringBuffer(xml.length() * 2);
+
+               for (int i = 0; i < xml.length(); i++) {
+                       char c = xml.charAt(i);
+                       String s = toXmlChar(c);
+                       if (s != null) {
+                               result.append(s);
+                       } else {
+                               result.append(c);
+                       }
+               }
+               return result;
+       }
+
+       /**
+        * Substitutes a XML sensitive character with predefined XML entity.
+        * 
+        * @param c
+        *            the Character to be replaced with an entity.
+        * @return String of the entity or null if character is not to be replaced
+        *         with an entity.
+        */
+       private static String toXmlChar(char c) {
+               switch (c) {
+               case '&':
+                       return "&amp;"; // & => &amp;
+               case '>':
+                       return "&gt;"; // > => &gt;
+               case '<':
+                       return "&lt;"; // < => &lt;
+               case '"':
+                       return "&quot;"; // " => &quot;
+               case '\'':
+                       return "&apos;"; // ' => &apos;
+               default:
+                       return null;
+               }
+       }
+
+       /**
+        * Prints XML.
+        * 
+        * Writes pre-formatted XML to stream. Well-formness of XML is checked.
+        * 
+        * <pre>
+        * 
+        *  TODO: XML checking should be made
+        *  
+        * </pre>
+        * 
+        * @param str
+        *            the string to print.
+        */
+       private void print(String str) {
+               // In case of null data output nothing:
+               if (str == null)
+                       return;
+
+               // Make sure that the open start tag is closed before
+               // anything is written.
+               ensureClosedTag();
+
+               // Write what was given
+               append(str);
+       }
+
+       /* (non-Javadoc)
+        * @see com.itmill.toolkit.terminal.web.AjaxPaintTarget#addText(java.lang.String)
+        */
+       public void addText(String str) throws PaintException {
+               addUIDL(escapeXML(str));
+       }
+
+       /* (non-Javadoc)
+        * @see com.itmill.toolkit.terminal.web.AjaxPaintTarget#addAttribute(java.lang.String, boolean)
+        */
+       public void addAttribute(String name, boolean value) throws PaintException {
+               addAttribute(name, String.valueOf(value));
+       }
+
+       /* (non-Javadoc)
+        * @see com.itmill.toolkit.terminal.web.AjaxPaintTarget#addAttribute(java.lang.String, com.itmill.toolkit.terminal.Resource)
+        */
+       public void addAttribute(String name, Resource value) throws PaintException {
+
+               if (value instanceof ExternalResource) {
+                       addAttribute(name, ((ExternalResource) value).getURL());
+
+               } else if (value instanceof ApplicationResource) {
+                       ApplicationResource r = (ApplicationResource) value;
+                       Application a = r.getApplication();
+                       if (a == null)
+                               throw new PaintException(
+                                               "Application not specified for resorce "
+                                                               + value.getClass().getName());
+                       String uri = a.getURL().getPath();
+                       if (uri.charAt(uri.length() - 1) != '/')
+                               uri += "/";
+                       uri += a.getRelativeLocation(r);
+                       addAttribute(name, uri);
+
+               } else if (value instanceof ThemeResource) {
+                       String uri = "theme://" + ((ThemeResource) value).getResourceId();
+                       addAttribute(name, uri);
+               } else
+                       throw new PaintException("Ajax adapter does not "
+                                       + "support resources of type: "
+                                       + value.getClass().getName());
+
+       }
+
+       /* (non-Javadoc)
+        * @see com.itmill.toolkit.terminal.web.AjaxPaintTarget#addAttribute(java.lang.String, int)
+        */
+       public void addAttribute(String name, int value) throws PaintException {
+               addAttribute(name, String.valueOf(value));
+       }
+
+       /* (non-Javadoc)
+        * @see com.itmill.toolkit.terminal.web.AjaxPaintTarget#addAttribute(java.lang.String, long)
+        */
+       public void addAttribute(String name, long value) throws PaintException {
+               addAttribute(name, String.valueOf(value));
+       }
+
+       /* (non-Javadoc)
+        * @see com.itmill.toolkit.terminal.web.AjaxPaintTarget#addAttribute(java.lang.String, java.lang.String)
+        */
+       public void addAttribute(String name, String value) throws PaintException {
+               // In case of null data output nothing:
+               if ((value == null) || (name == null))
+                       throw new NullPointerException(
+                                       "Parameters must be non-null strings");
+
+               // Ensure that the target is open
+               if (this.closed)
+                       throw new PaintException(
+                                       "Attempted to write to a closed PaintTarget.");
+
+               // Check that argument list is writable.
+               if (!mTagArgumentListOpen)
+                       throw new PaintException("XML argument list not open.");
+
+               append(" " + name + "=\"" + escapeXML(value) + "\"");
+               
+               if (customLayoutArgumentsOpen && "style".equals(name))
+                       getPreCachedResources().add("layout/" + value + ".html");
+       }
+
+       /* (non-Javadoc)
+        * @see com.itmill.toolkit.terminal.web.AjaxPaintTarget#addVariable(com.itmill.toolkit.terminal.VariableOwner, java.lang.String, java.lang.String)
+        */
+       public void addVariable(VariableOwner owner, String name, String value)
+                       throws PaintException {
+               String code = variableMap.registerVariable(name, String.class, value,
+                               owner);
+               startTag("string");
+               addAttribute(UIDL_ARG_ID, code);
+               addAttribute(UIDL_ARG_NAME, name);
+               addText(value);
+               endTag("string");
+       }
+
+       /* (non-Javadoc)
+        * @see com.itmill.toolkit.terminal.web.AjaxPaintTarget#addVariable(com.itmill.toolkit.terminal.VariableOwner, java.lang.String, int)
+        */
+       public void addVariable(VariableOwner owner, String name, int value)
+                       throws PaintException {
+               String code = variableMap.registerVariable(name, Integer.class,
+                               new Integer(value), owner);
+               startTag("integer");
+               addAttribute(UIDL_ARG_ID, code);
+               addAttribute(UIDL_ARG_NAME, name);
+               addAttribute(UIDL_ARG_VALUE, String.valueOf(value));
+               endTag("integer");
+       }
+
+       /* (non-Javadoc)
+        * @see com.itmill.toolkit.terminal.web.AjaxPaintTarget#addVariable(com.itmill.toolkit.terminal.VariableOwner, java.lang.String, boolean)
+        */
+       public void addVariable(VariableOwner owner, String name, boolean value)
+                       throws PaintException {
+               String code = variableMap.registerVariable(name, Boolean.class,
+                               new Boolean(value), owner);
+               startTag("boolean");
+               addAttribute(UIDL_ARG_ID, code);
+               addAttribute(UIDL_ARG_NAME, name);
+               addAttribute(UIDL_ARG_VALUE, String.valueOf(value));
+               endTag("boolean");
+       }
+
+       /* (non-Javadoc)
+        * @see com.itmill.toolkit.terminal.web.AjaxPaintTarget#addVariable(com.itmill.toolkit.terminal.VariableOwner, java.lang.String, java.lang.String[])
+        */
+       public void addVariable(VariableOwner owner, String name, String[] value)
+                       throws PaintException {
+               String code = variableMap.registerVariable(name, String[].class, value,
+                               owner);
+               startTag("array");
+               addAttribute(UIDL_ARG_ID, code);
+               addAttribute(UIDL_ARG_NAME, name);
+               for (int i = 0; i < value.length; i++)
+                       addSection("ai", value[i]);
+               endTag("array");
+       }
+
+       /* (non-Javadoc)
+        * @see com.itmill.toolkit.terminal.web.AjaxPaintTarget#addUploadStreamVariable(com.itmill.toolkit.terminal.VariableOwner, java.lang.String)
+        */
+       public void addUploadStreamVariable(VariableOwner owner, String name)
+                       throws PaintException {
+               String code = variableMap.registerVariable(name, UploadStream.class,
+                               null, owner);
+               startTag("uploadstream");
+               addAttribute(UIDL_ARG_ID, code);
+               addAttribute(UIDL_ARG_NAME, name);
+               endTag("uploadstream");
+       }
+
+       /* (non-Javadoc)
+        * @see com.itmill.toolkit.terminal.web.AjaxPaintTarget#addSection(java.lang.String, java.lang.String)
+        */
+       public void addSection(String sectionTagName, String sectionData)
+                       throws PaintException {
+               startTag(sectionTagName);
+               addText(sectionData);
+               endTag(sectionTagName);
+       }
+
+       /* (non-Javadoc)
+        * @see com.itmill.toolkit.terminal.web.AjaxPaintTarget#addUIDL(java.lang.String)
+        */
+       public void addUIDL(String xml) throws PaintException {
+
+               // Ensure that the target is open
+               if (this.closed)
+                       throw new PaintException(
+                                       "Attempted to write to a closed PaintTarget.");
+
+               // Make sure that the open start tag is closed before
+               // anything is written.
+               ensureClosedTag();
+
+               // Escape and write what was given
+               if (xml != null)
+                       append(xml);
+
+       }
+
+       /* (non-Javadoc)
+        * @see com.itmill.toolkit.terminal.web.AjaxPaintTarget#addXMLSection(java.lang.String, java.lang.String, java.lang.String)
+        */
+       public void addXMLSection(String sectionTagName, String sectionData,
+                       String namespace) throws PaintException {
+
+               // Ensure that the target is open
+               if (this.closed)
+                       throw new PaintException(
+                                       "Attempted to write to a closed PaintTarget.");
+
+               startTag(sectionTagName);
+               if (namespace != null)
+                       addAttribute("xmlns", namespace);
+               append(">");
+               mTagArgumentListOpen = false;
+
+               if (sectionData != null)
+                       append(sectionData);
+               endTag(sectionTagName);
+       }
+
+       /* (non-Javadoc)
+        * @see com.itmill.toolkit.terminal.web.AjaxPaintTarget#getUIDL()
+        */
+       public String getUIDL() {
+               if (this.closed) {
+                       return uidlBuffer.toString();
+               }
+               throw new IllegalStateException(
+                               "Tried to read UIDL from open PaintTarget");
+       }
+
+       /* (non-Javadoc)
+        * @see com.itmill.toolkit.terminal.web.AjaxPaintTarget#close()
+        */
+       public void close() throws PaintException {
+               if (!this.closed) {
+                       this.endTag("changes");
+                       flush();
+
+                       // Close all
+                       this.uidlBuffer.close();
+                       this.closed = true;
+               }
+       }
+
+       /**
+        * Method flush.
+        */
+       private void flush() {
+               this.uidlBuffer.flush();
+       }
+
+       /* (non-Javadoc)
+        * @see com.itmill.toolkit.terminal.web.AjaxPaintTarget#startTag(com.itmill.toolkit.terminal.Paintable, java.lang.String)
+        */
+       public boolean startTag(Paintable paintable, String tag)
+                       throws PaintException {
+               startTag(tag);
+               String id = manager.getPaintableId(paintable);
+               paintable.addListener(manager);
+               addAttribute("id", id);
+               return false;
+       }
+
+       /* (non-Javadoc)
+        * @see com.itmill.toolkit.terminal.web.AjaxPaintTarget#addCharacterData(java.lang.String)
+        */
+       public void addCharacterData(String text) throws PaintException {
+               ensureClosedTag();
+               if (text != null)
+                       append("<![CDATA[" + text + "]]>");
+       }
+
+       /* (non-Javadoc)
+        * @see com.itmill.toolkit.terminal.web.AjaxPaintTarget#isTrackPaints()
+        */
+       public boolean isTrackPaints() {
+               return trackPaints;
+       }
+
+       /* (non-Javadoc)
+        * @see com.itmill.toolkit.terminal.web.AjaxPaintTarget#getNumberOfPaints()
+        */
+       public int getNumberOfPaints() {
+               return numberOfPaints;
+       }
+
+       /* (non-Javadoc)
+        * @see com.itmill.toolkit.terminal.web.AjaxPaintTarget#setTrackPaints(boolean)
+        */
+       public void setTrackPaints(boolean enabled) {
+               this.trackPaints = enabled;
+               this.numberOfPaints = 0;
+       }
+
+       public void setPreCachedResources(Set preCachedResources) {
+               this.preCachedResources = preCachedResources;
+       }
+
+       public Set getPreCachedResources() {
+               return preCachedResources;
+       }
+
+}
index 625684244ebac33600b1673184dc45692ef01871..fb7d7399b36cf3b1b3a67b1a1f4aad5650538c9a 100644 (file)
@@ -566,7 +566,7 @@ public class ApplicationServlet extends HttpServlet implements
                                String resourceId = request.getPathInfo();
                                if (resourceId != null && resourceId.startsWith(AJAX_UIDL_URI)) {
                                        getApplicationManager(application).handleUidlRequest(
-                                                       request, response, themeSource);
+                                                       request, response, themeSource, true);
                                        return;
                                }