]> source.dussan.org Git - vaadin-framework.git/commitdiff
Started a major refactoring: removed terminal.web, added terminal.gwt.server. Refacto...
authorJoonas Lehtinen <joonas.lehtinen@itmill.com>
Tue, 17 Jul 2007 08:28:41 +0000 (08:28 +0000)
committerJoonas Lehtinen <joonas.lehtinen@itmill.com>
Tue, 17 Jul 2007 08:28:41 +0000 (08:28 +0000)
svn changeset:1864/svn branch:trunk

47 files changed:
WebContent/WEB-INF/web.xml
src/com/itmill/toolkit/demo/features/IntroWelcome.java
src/com/itmill/toolkit/terminal/gwt/server/AjaxHttpUploadStream.java [new file with mode: 0644]
src/com/itmill/toolkit/terminal/gwt/server/AjaxVariableMap.java [new file with mode: 0644]
src/com/itmill/toolkit/terminal/gwt/server/ApplicationManager.java [new file with mode: 0644]
src/com/itmill/toolkit/terminal/gwt/server/ApplicationServlet.java [new file with mode: 0644]
src/com/itmill/toolkit/terminal/gwt/server/HttpUploadStream.java [new file with mode: 0644]
src/com/itmill/toolkit/terminal/gwt/server/HttpVariableMap.java [new file with mode: 0644]
src/com/itmill/toolkit/terminal/gwt/server/JSONPaintTarget.java [deleted file]
src/com/itmill/toolkit/terminal/gwt/server/JsonPaintTarget.java [new file with mode: 0644]
src/com/itmill/toolkit/terminal/gwt/server/Log.java [new file with mode: 0644]
src/com/itmill/toolkit/terminal/gwt/server/MultipartRequest.java [new file with mode: 0644]
src/com/itmill/toolkit/terminal/gwt/server/ServletMultipartRequest.java [new file with mode: 0644]
src/com/itmill/toolkit/terminal/gwt/server/WebApplicationContext.java [new file with mode: 0644]
src/com/itmill/toolkit/terminal/gwt/server/WebBrowser.java [new file with mode: 0644]
src/com/itmill/toolkit/terminal/gwt/server/WebBrowserProbe.java [new file with mode: 0644]
src/com/itmill/toolkit/terminal/web/AjaxApplicationManager.java [deleted file]
src/com/itmill/toolkit/terminal/web/AjaxHttpUploadStream.java [deleted file]
src/com/itmill/toolkit/terminal/web/AjaxJsonPaintTarget.java [deleted file]
src/com/itmill/toolkit/terminal/web/AjaxPaintTarget.java [deleted file]
src/com/itmill/toolkit/terminal/web/AjaxVariableMap.java [deleted file]
src/com/itmill/toolkit/terminal/web/AjaxXmlPaintTarget.java [deleted file]
src/com/itmill/toolkit/terminal/web/ApplicationServlet.java [deleted file]
src/com/itmill/toolkit/terminal/web/CollectionThemeSource.java [deleted file]
src/com/itmill/toolkit/terminal/web/DebugWindow.java [deleted file]
src/com/itmill/toolkit/terminal/web/DirectoryThemeSource.java [deleted file]
src/com/itmill/toolkit/terminal/web/HttpUploadStream.java [deleted file]
src/com/itmill/toolkit/terminal/web/HttpVariableMap.java [deleted file]
src/com/itmill/toolkit/terminal/web/JarThemeSource.java [deleted file]
src/com/itmill/toolkit/terminal/web/Log.java [deleted file]
src/com/itmill/toolkit/terminal/web/MultipartRequest.java [deleted file]
src/com/itmill/toolkit/terminal/web/ServletMultipartRequest.java [deleted file]
src/com/itmill/toolkit/terminal/web/ServletThemeSource.java [deleted file]
src/com/itmill/toolkit/terminal/web/TO BE DEPRECATED FROM 5.0 [deleted file]
src/com/itmill/toolkit/terminal/web/Theme.java [deleted file]
src/com/itmill/toolkit/terminal/web/ThemeFunctionLibrary.java [deleted file]
src/com/itmill/toolkit/terminal/web/ThemeSource.java [deleted file]
src/com/itmill/toolkit/terminal/web/UIDLTransformer.java [deleted file]
src/com/itmill/toolkit/terminal/web/UIDLTransformerException.java [deleted file]
src/com/itmill/toolkit/terminal/web/UIDLTransformerFactory.java [deleted file]
src/com/itmill/toolkit/terminal/web/UIDLTransformerType.java [deleted file]
src/com/itmill/toolkit/terminal/web/WebApplicationContext.java [deleted file]
src/com/itmill/toolkit/terminal/web/WebBrowser.java [deleted file]
src/com/itmill/toolkit/terminal/web/WebBrowserProbe.java [deleted file]
src/com/itmill/toolkit/terminal/web/WebPaintTarget.java [deleted file]
src/com/itmill/toolkit/terminal/web/XSLReader.java [deleted file]
src/com/itmill/toolkit/terminal/web/package.html [deleted file]

index adad2341584d29a42fb5b63db4b63c92f99dd56f..21961382a706f3639d5a6b19ff32b65a88281268 100644 (file)
@@ -13,7 +13,7 @@
 \r
   <servlet>\r
     <servlet-name>SelectDemo</servlet-name>\r
-    <servlet-class>com.itmill.toolkit.terminal.web.ApplicationServlet</servlet-class>\r
+    <servlet-class>com.itmill.toolkit.terminal.gwt.server.ApplicationServlet</servlet-class>\r
     <init-param>\r
       <param-name>application</param-name>\r
       <param-value>com.itmill.toolkit.demo.SelectDemo</param-value>\r
@@ -22,7 +22,7 @@
 \r
   <servlet>\r
     <servlet-name>BufferedComponents</servlet-name>\r
-    <servlet-class>com.itmill.toolkit.terminal.web.ApplicationServlet</servlet-class>\r
+    <servlet-class>com.itmill.toolkit.terminal.gwt.server.ApplicationServlet</servlet-class>\r
     <init-param>\r
       <param-name>application</param-name>\r
       <param-value>com.itmill.toolkit.demo.BufferedComponents</param-value>\r
@@ -31,7 +31,7 @@
 \r
   <servlet>\r
     <servlet-name>TableDemo</servlet-name>\r
-    <servlet-class>com.itmill.toolkit.terminal.web.ApplicationServlet</servlet-class>\r
+    <servlet-class>com.itmill.toolkit.terminal.gwt.server.ApplicationServlet</servlet-class>\r
     <init-param>\r
       <param-name>application</param-name>\r
       <param-value>com.itmill.toolkit.demo.TableDemo</param-value>\r
@@ -40,7 +40,7 @@
 \r
   <servlet>\r
     <servlet-name>CustomLayoutDemo</servlet-name>\r
-    <servlet-class>com.itmill.toolkit.terminal.web.ApplicationServlet</servlet-class>\r
+    <servlet-class>com.itmill.toolkit.terminal.gwt.server.ApplicationServlet</servlet-class>\r
     <init-param>\r
       <param-name>application</param-name>\r
       <param-value>com.itmill.toolkit.demo.CustomLayoutDemo</param-value>\r
@@ -49,7 +49,7 @@
 \r
   <servlet>\r
     <servlet-name>LayoutDemo</servlet-name>\r
-    <servlet-class>com.itmill.toolkit.terminal.web.ApplicationServlet</servlet-class>\r
+    <servlet-class>com.itmill.toolkit.terminal.gwt.server.ApplicationServlet</servlet-class>\r
     <init-param>\r
       <param-name>application</param-name>\r
       <param-value>com.itmill.toolkit.demo.LayoutDemo</param-value>\r
@@ -58,7 +58,7 @@
 \r
   <servlet>\r
     <servlet-name>FilterSelect</servlet-name>\r
-    <servlet-class>com.itmill.toolkit.terminal.web.ApplicationServlet</servlet-class>\r
+    <servlet-class>com.itmill.toolkit.terminal.gwt.server.ApplicationServlet</servlet-class>\r
     <init-param>\r
       <param-name>application</param-name>\r
       <param-value>com.itmill.toolkit.demo.FilterSelect</param-value>\r
@@ -67,7 +67,7 @@
 \r
   <servlet>\r
     <servlet-name>FeaturesApplication</servlet-name>\r
-    <servlet-class>com.itmill.toolkit.terminal.web.ApplicationServlet</servlet-class>\r
+    <servlet-class>com.itmill.toolkit.terminal.gwt.server.ApplicationServlet</servlet-class>\r
     <init-param>\r
       <param-name>application</param-name>\r
       <param-value>com.itmill.toolkit.demo.features.FeaturesApplication</param-value>\r
@@ -76,7 +76,7 @@
 \r
   <servlet>\r
     <servlet-name>Parameters</servlet-name>\r
-    <servlet-class>com.itmill.toolkit.terminal.web.ApplicationServlet</servlet-class>\r
+    <servlet-class>com.itmill.toolkit.terminal.gwt.server.ApplicationServlet</servlet-class>\r
     <init-param>\r
       <param-name>application</param-name>\r
       <param-value>com.itmill.toolkit.demo.Parameters</param-value>\r
@@ -85,7 +85,7 @@
 \r
   <servlet>\r
     <servlet-name>UpgradingSample</servlet-name>\r
-    <servlet-class>com.itmill.toolkit.terminal.web.ApplicationServlet</servlet-class>\r
+    <servlet-class>com.itmill.toolkit.terminal.gwt.server.ApplicationServlet</servlet-class>\r
     <init-param>\r
       <param-name>application</param-name>\r
       <param-value>com.itmill.toolkit.demo.UpgradingSample</param-value>\r
@@ -94,7 +94,7 @@
 \r
   <servlet>\r
     <servlet-name>QueryContainerDemo</servlet-name>\r
-    <servlet-class>com.itmill.toolkit.terminal.web.ApplicationServlet</servlet-class>\r
+    <servlet-class>com.itmill.toolkit.terminal.gwt.server.ApplicationServlet</servlet-class>\r
     <init-param>\r
       <param-name>application</param-name>\r
       <param-value>com.itmill.toolkit.demo.QueryContainerDemo</param-value>\r
 \r
   <servlet>\r
     <servlet-name>TreeFilesystemContainer</servlet-name>\r
-    <servlet-class>com.itmill.toolkit.terminal.web.ApplicationServlet</servlet-class>\r
+    <servlet-class>com.itmill.toolkit.terminal.gwt.server.ApplicationServlet</servlet-class>\r
     <init-param>\r
       <param-name>application</param-name>\r
       <param-value>com.itmill.toolkit.demo.TreeFilesystemContainer</param-value>\r
 \r
   <servlet>\r
     <servlet-name>TreeFilesystem</servlet-name>\r
-    <servlet-class>com.itmill.toolkit.terminal.web.ApplicationServlet</servlet-class>\r
+    <servlet-class>com.itmill.toolkit.terminal.gwt.server.ApplicationServlet</servlet-class>\r
     <init-param>\r
       <param-name>application</param-name>\r
       <param-value>com.itmill.toolkit.demo.TreeFilesystem</param-value>\r
 \r
   <servlet>\r
     <servlet-name>ModalWindow</servlet-name>\r
-    <servlet-class>com.itmill.toolkit.terminal.web.ApplicationServlet</servlet-class>\r
+    <servlet-class>com.itmill.toolkit.terminal.gwt.server.ApplicationServlet</servlet-class>\r
     <init-param>\r
       <param-name>application</param-name>\r
       <param-value>com.itmill.toolkit.demo.ModalWindow</param-value>\r
 \r
   <servlet>\r
     <servlet-name>HelloWorld</servlet-name>\r
-    <servlet-class>com.itmill.toolkit.terminal.web.ApplicationServlet</servlet-class>\r
+    <servlet-class>com.itmill.toolkit.terminal.gwt.server.ApplicationServlet</servlet-class>\r
     <init-param>\r
       <param-name>application</param-name>\r
       <param-value>com.itmill.toolkit.demo.HelloWorld</param-value>\r
 \r
   <servlet>\r
     <servlet-name>Calc</servlet-name>\r
-    <servlet-class>com.itmill.toolkit.terminal.web.ApplicationServlet</servlet-class>\r
+    <servlet-class>com.itmill.toolkit.terminal.gwt.server.ApplicationServlet</servlet-class>\r
     <init-param>\r
       <param-name>application</param-name>\r
       <param-value>com.itmill.toolkit.demo.Calc</param-value>\r
 \r
   <servlet>\r
     <servlet-name>KeyboardShortcut</servlet-name>\r
-    <servlet-class>com.itmill.toolkit.terminal.web.ApplicationServlet</servlet-class>\r
+    <servlet-class>com.itmill.toolkit.terminal.gwt.server.ApplicationServlet</servlet-class>\r
     <init-param>\r
       <param-name>application</param-name>\r
       <param-value>com.itmill.toolkit.demo.KeyboardShortcut</param-value>\r
index 75a643e1c4f99e05eb0988f83f72ac8685b44f91..89c0efb0cd689412894617ab383eece4d6f772c4 100644 (file)
@@ -38,8 +38,8 @@ import com.itmill.toolkit.terminal.PaintException;
 import com.itmill.toolkit.terminal.PaintTarget;
 import com.itmill.toolkit.terminal.ParameterHandler;
 import com.itmill.toolkit.terminal.URIHandler;
-import com.itmill.toolkit.terminal.web.ApplicationServlet;
-import com.itmill.toolkit.terminal.web.WebBrowser;
+import com.itmill.toolkit.terminal.gwt.server.ApplicationServlet;
+import com.itmill.toolkit.terminal.gwt.server.WebBrowser;
 import com.itmill.toolkit.ui.Component;
 import com.itmill.toolkit.ui.Form;
 import com.itmill.toolkit.ui.Label;
diff --git a/src/com/itmill/toolkit/terminal/gwt/server/AjaxHttpUploadStream.java b/src/com/itmill/toolkit/terminal/gwt/server/AjaxHttpUploadStream.java
new file mode 100644 (file)
index 0000000..e431d51
--- /dev/null
@@ -0,0 +1,114 @@
+/* *************************************************************************
+ 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.gwt.server;
+
+import java.io.InputStream;
+
+/**
+ * AjaxAdapter implementation of the UploadStream interface.
+ * 
+ * @author IT Mill Ltd.
+ * @version
+ * @VERSION@
+ * @since 5.0
+ */
+public class AjaxHttpUploadStream implements
+               com.itmill.toolkit.terminal.UploadStream {
+
+       /**
+        * Holds value of property variableName.
+        */
+       private String streamName;
+
+       private String contentName;
+
+       private String contentType;
+
+       /**
+        * Holds value of property variableValue.
+        */
+       private InputStream stream;
+
+       /**
+        * Creates a new instance of UploadStreamImpl.
+        * 
+        * @param name
+        *            the name of the stream.
+        * @param stream
+        *            the input stream.
+        * @param contentName
+        *            the name of the content.
+        * @param contentType
+        *            the type of the content.
+        */
+       public AjaxHttpUploadStream(String name, InputStream stream,
+                       String contentName, String contentType) {
+               this.streamName = name;
+               this.stream = stream;
+               this.contentName = contentName;
+               this.contentType = contentType;
+       }
+
+       /**
+        * Gets the name of the stream.
+        * 
+        * @return the name of the stream.
+        */
+       public String getStreamName() {
+               return this.streamName;
+       }
+
+       /**
+        * Gets the input stream.
+        * 
+        * @return the Input stream.
+        */
+       public InputStream getStream() {
+               return this.stream;
+       }
+
+       /**
+        * Gets the input stream content type.
+        * 
+        * @return the content type of the input stream.
+        */
+       public String getContentType() {
+               return this.contentType;
+       }
+
+       /**
+        * Gets the stream content name. Stream content name usually differs from
+        * the actual stream name. It is used to identify the content of the stream.
+        * 
+        * @return the Name of the stream content.
+        */
+       public String getContentName() {
+               return this.contentName;
+       }
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/server/AjaxVariableMap.java b/src/com/itmill/toolkit/terminal/gwt/server/AjaxVariableMap.java
new file mode 100644 (file)
index 0000000..54c0013
--- /dev/null
@@ -0,0 +1,803 @@
+/* *************************************************************************
+ 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.gwt.server;
+
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.WeakHashMap;
+
+import javax.servlet.http.HttpServletRequest;
+
+import com.itmill.toolkit.terminal.SystemError;
+import com.itmill.toolkit.terminal.Terminal;
+import com.itmill.toolkit.terminal.UploadStream;
+import com.itmill.toolkit.terminal.VariableOwner;
+
+/**
+ * Variable map for ajax applications.
+ * 
+ * @author IT Mill Ltd.
+ * @version
+ * @VERSION@
+ * @since 5.0
+ */
+public class AjaxVariableMap {
+
+       // Id <-> (Owner,Name) mapping
+       private Map idToNameMap = new HashMap();
+
+       private Map idToTypeMap = new HashMap();
+
+       private Map idToOwnerMap = new HashMap();
+
+       private Map idToValueMap = new HashMap();
+
+       private Map ownerToNameToIdMap = new WeakHashMap();
+
+       private Object mapLock = new Object();
+
+       // Id generator
+       private long lastId = 0;
+
+       /**
+        * Converts the string to a supported class.
+        * 
+        * @param type
+        * @param value
+        * @return
+        * @throws java.lang.ClassCastException
+        *             if the code has attempted to cast an object to a subclass of
+        *             which it is not an instance
+        */
+       private static Object convert(Class type, String value)
+                       throws java.lang.ClassCastException {
+               try {
+
+                       // Boolean typed variables
+                       if (type.equals(Boolean.class))
+                               return new Boolean(!(value.equals("") || value.equals("false")));
+
+                       // Integer typed variables
+                       if (type.equals(Integer.class))
+                               return new Integer(value.trim());
+
+                       // String typed variables
+                       if (type.equals(String.class))
+                               return value;
+
+                       throw new ClassCastException("Unsupported type: " + type.getName());
+               } catch (NumberFormatException e) {
+                       return null;
+               }
+       }
+
+       /**
+        * Registers a new variable.
+        * 
+        * @param name
+        *            the Variable name.
+        * @param type
+        * @param value
+        * @param owner
+        *            the Listener for variable changes.
+        * @return id to assigned for this variable.
+        */
+       public String registerVariable(String name, Class type, Object value,
+                       VariableOwner owner) {
+
+               // Checks that the type of the class is supported
+               if (!(type.equals(Boolean.class) || type.equals(Integer.class)
+                               || type.equals(String.class) || type.equals(String[].class) || type
+                               .equals(UploadStream.class)))
+                       throw new SystemError("Unsupported variable type: "
+                                       + type.getClass());
+
+               synchronized (mapLock) {
+
+                       // Checks if the variable is already mapped
+                       HashMap nameToIdMap = (HashMap) ownerToNameToIdMap.get(owner);
+                       if (nameToIdMap == null) {
+                               nameToIdMap = new HashMap();
+                               ownerToNameToIdMap.put(owner, nameToIdMap);
+                       }
+                       String id = (String) nameToIdMap.get(name);
+
+                       if (id == null) {
+                               // Generates new id and register it
+
+// ----------
+// TODO This HACK is only included for testing GWT integration                         
+//Original                             id = "v" + String.valueOf(++lastId);
+                               Object pid = ApplicationManager.paintableIdMap.get(owner);
+                               id = pid + "_"+name;
+// ----------
+                               
+                               
+                               nameToIdMap.put(name, id);
+                               idToOwnerMap.put(id, new WeakReference(owner));
+                               idToNameMap.put(id, name);
+                               idToTypeMap.put(id, type);
+                       }
+
+                       idToValueMap.put(id, value);
+
+                       return id;
+               }
+       }
+
+       /**
+        * Unregisters the variable.
+        * 
+        * @param name
+        *            the Variable name.
+        * @param owner
+        *            the Listener for variable changes.
+        */
+       public void unregisterVariable(String name, VariableOwner owner) {
+
+               synchronized (mapLock) {
+
+                       // Get the id
+                       HashMap nameToIdMap = (HashMap) ownerToNameToIdMap.get(owner);
+                       if (nameToIdMap == null)
+                               return;
+                       String id = (String) nameToIdMap.get(name);
+                       if (id != null)
+                               return;
+
+                       // Remove all the mappings
+                       nameToIdMap.remove(name);
+                       if (nameToIdMap.isEmpty())
+                               ownerToNameToIdMap.remove(owner);
+                       idToNameMap.remove(id);
+                       idToTypeMap.remove(id);
+                       idToValueMap.remove(id);
+                       idToOwnerMap.remove(id);
+
+               }
+       }
+
+       /**
+        * @author IT Mill Ltd.
+        * @version
+        * @VERSION@
+        * @since 3.0
+        */
+       private class ParameterContainer {
+
+               /**
+                * Constructs the mapping: listener to set of listened parameter names.
+                */
+               private HashMap parameters = new HashMap();
+
+               /**
+                * Parameter values.
+                */
+               private HashMap values = new HashMap();
+
+               /**
+                * Multipart parser used for parsing the request.
+                */
+               private ServletMultipartRequest parser = null;
+
+               /**
+                * Name - Value mapping of parameters that are not variables.
+                */
+               private HashMap nonVariables = new HashMap();
+
+               /**
+                * Creates a new parameter container and parse the parameters from the
+                * request using GET, POST and POST/MULTIPART parsing
+                * 
+                * @param req
+                *            the Http request to handle.
+                * @throws IOException
+                *             if the writing failed due to input/output error.
+                */
+               public ParameterContainer(HttpServletRequest req) throws IOException {
+                       // Parse GET / POST parameters
+                       for (Enumeration e = req.getParameterNames(); e.hasMoreElements();) {
+                               String paramName = (String) e.nextElement();
+                               String[] paramValues = req.getParameterValues(paramName);
+                               addParam(paramName, paramValues);
+                       }
+
+                       // Parse multipart variables
+                       try {
+                               parser = new ServletMultipartRequest(req,
+                                               MultipartRequest.MAX_READ_BYTES);
+                       } catch (IllegalArgumentException ignored) {
+                               parser = null;
+                       }
+
+                       if (parser != null) {
+                               for (Enumeration e = parser.getFileParameterNames(); e
+                                               .hasMoreElements();) {
+                                       String paramName = (String) e.nextElement();
+                                       addParam(paramName, null);
+                               }
+                               for (Enumeration e = parser.getParameterNames(); e
+                                               .hasMoreElements();) {
+                                       String paramName = (String) e.nextElement();
+                                       Enumeration val = parser.getURLParameters(paramName);
+
+                                       // Create a linked list from enumeration to calculate
+                                       // elements
+                                       LinkedList l = new LinkedList();
+                                       while (val.hasMoreElements())
+                                               l.addLast(val.nextElement());
+
+                                       // String array event constructor
+                                       String[] s = new String[l.size()];
+                                       Iterator i = l.iterator();
+                                       for (int j = 0; j < s.length; j++)
+                                               s[j] = (String) i.next();
+
+                                       addParam(paramName, s);
+                               }
+                       }
+
+               }
+
+               /**
+                * Adds the parameter to container.
+                * 
+                * @param name
+                *            the Parameter name.
+                * @param value
+                *            the Parameter value.
+                */
+               private void addParam(String name, String[] value) {
+
+                       // Support name="set:name=value" value="ignored" notation
+                       if (name.startsWith("set:")) {
+                               int equalsIndex = name.indexOf('=');
+                               value[0] = name.substring(equalsIndex + 1, name.length());
+                               name = name.substring(4, equalsIndex);
+                               String[] curVal = (String[]) values.get(name);
+                               if (curVal != null) {
+                                       String[] newVal = new String[1 + curVal.length];
+                                       newVal[curVal.length] = value[0];
+                                       for (int i = 0; i < curVal.length; i++)
+                                               newVal[i] = curVal[i];
+                                       value = newVal;
+
+                                       // Special case - if the set:-method is used for
+                                       // declaring array of length 2, where either of the
+                                       // following conditions are true:
+                                       // - the both items are the same
+                                       // - the both items have the same length and
+                                       // - the items only differ on last character
+                                       // - second last character is '.'
+                                       // - last char of one string is 'x' and other is 'y'
+                                       // Browser is unporposely modifying the name.
+                                       if (value.length == 2
+                                                       && value[0].length() == value[1].length()) {
+                                               boolean same = true;
+                                               for (int i = 0; i < value[0].length() - 1 && same; i++)
+                                                       if (value[0].charAt(i) != value[1].charAt(i))
+                                                               same = false;
+                                               if (same
+                                                               && ((value[0].charAt(value[0].length() - 1) == 'x' && value[1]
+                                                                               .charAt(value[1].length() - 1) == 'y') || (value[0]
+                                                                               .charAt(value[0].length() - 1) == 'y' && value[1]
+                                                                               .charAt(value[1].length() - 1) == 'x'))) {
+                                                       value = new String[] { value[0].substring(0,
+                                                                       value[1].length() - 2) };
+                                               } else if (same && value[0].equals(value[1]))
+                                                       value = new String[] { value[0] };
+                                       }
+
+                                       // Special case - if the set:-method is used for
+                                       // declaring array of length 3, where all of the
+                                       // following conditions are true:
+                                       // - two last items have the same length
+                                       // - the first item is 2 chars shorter
+                                       // - the longer items only differ on last character
+                                       // - the shortest item is a prefix of the longer ones
+                                       // - second last character of longer ones is '.'
+                                       // - last char of one long string is 'x' and other is 'y'
+                                       // Browser is unporposely modifying the name. (Mozilla,
+                                       // Firefox, ..)
+                                       if (value.length == 3
+                                                       && value[1].length() == value[2].length()
+                                                       && value[0].length() + 2 == value[1].length()) {
+                                               boolean same = true;
+                                               for (int i = 0; i < value[1].length() - 1 && same; i++)
+                                                       if (value[2].charAt(i) != value[1].charAt(i))
+                                                               same = false;
+                                               for (int i = 0; i < value[0].length() && same; i++)
+                                                       if (value[0].charAt(i) != value[1].charAt(i))
+                                                               same = false;
+                                               if (same
+                                                               && (value[2].charAt(value[2].length() - 1) == 'x' && value[1]
+                                                                               .charAt(value[1].length() - 1) == 'y')
+                                                               || (value[2].charAt(value[2].length() - 1) == 'y' && value[1]
+                                                                               .charAt(value[1].length() - 1) == 'x')) {
+                                                       value = new String[] { value[0] };
+                                               }
+                                       }
+
+                               }
+                       }
+
+                       // Support for setting arrays in format
+                       // set-array:name=value1,value2,value3,...
+                       else if (name.startsWith("set-array:")) {
+                               int equalsIndex = name.indexOf('=');
+                               if (equalsIndex < 0)
+                                       return;
+
+                               StringTokenizer commalist = new StringTokenizer(name
+                                               .substring(equalsIndex + 1), ",");
+                               name = name.substring(10, equalsIndex);
+                               String[] curVal = (String[]) values.get(name);
+                               ArrayList elems = new ArrayList();
+
+                               // Add old values if present.
+                               if (curVal != null) {
+                                       for (int i = 0; i < curVal.length; i++)
+                                               elems.add(curVal[i]);
+                               }
+                               while (commalist.hasMoreTokens()) {
+                                       String token = commalist.nextToken();
+                                       if (token != null && token.length() > 0)
+                                               elems.add(token);
+                               }
+                               value = new String[elems.size()];
+                               for (int i = 0; i < value.length; i++)
+                                       value[i] = (String) elems.get(i);
+
+                       }
+
+                       // Support name="array:name" value="val1,val2,val3" notation
+                       // All the empty elements are ignored
+                       else if (name.startsWith("array:")) {
+
+                               name = name.substring(6);
+                               StringTokenizer commalist = new StringTokenizer(value[0], ",");
+                               String[] curVal = (String[]) values.get(name);
+                               ArrayList elems = new ArrayList();
+
+                               // Add old values if present.
+                               if (curVal != null) {
+                                       for (int i = 0; i < curVal.length; i++)
+                                               elems.add(curVal[i]);
+                               }
+                               while (commalist.hasMoreTokens()) {
+                                       String token = commalist.nextToken();
+                                       if (token != null && token.length() > 0)
+                                               elems.add(token);
+                               }
+                               value = new String[elems.size()];
+                               for (int i = 0; i < value.length; i++)
+                                       value[i] = (String) elems.get(i);
+                       }
+
+                       // Support declaring variables with name="declare:name"
+                       else if (name.startsWith("declare:")) {
+                               name = name.substring(8);
+                               value = (String[]) values.get(name);
+                               if (value == null)
+                                       value = new String[0];
+                       }
+
+                       // Gets the owner
+                       WeakReference ref = (WeakReference) idToOwnerMap.get(name);
+                       VariableOwner owner = null;
+                       if (ref != null)
+                               owner = (VariableOwner) ref.get();
+
+                       // Adds the parameter to mapping only if they have owners
+                       if (owner != null) {
+                               Set p = (Set) parameters.get(owner);
+                               if (p == null)
+                                       parameters.put(owner, p = new HashSet());
+                               p.add(name);
+                               if (value != null)
+                                       values.put(name, value);
+                       }
+
+                       // If the owner can not be found
+                       else {
+
+                               // If parameter has been mapped before, remove the old owner
+                               // mapping
+                               if (ref != null) {
+
+                                       // The owner has been destroyed, so we remove the mappings
+                                       idToNameMap.remove(name);
+                                       idToOwnerMap.remove(name);
+                                       idToTypeMap.remove(name);
+                                       idToValueMap.remove(name);
+                               }
+
+                               // Adds the parameter to set of non-variables
+                               nonVariables.put(name, value);
+                       }
+
+               }
+
+               /**
+                * Gets the set of all parameters connected to given variable owner.
+                * 
+                * @param owner
+                *            the Listener for variable changes.
+                * @return the set of all the parameters.
+                */
+               public Set getParameters(VariableOwner owner) {
+                       if (owner == null)
+                               return null;
+                       return (Set) parameters.get(owner);
+               }
+
+               /**
+                * Gets the set of all variable owners owning parameters in this
+                * request.
+                * 
+                * @return the set of all varaible owners.
+                */
+               public Set getOwners() {
+                       return parameters.keySet();
+               }
+
+               /**
+                * Gets the value of a parameter.
+                * 
+                * @param parameterName
+                *            the name of the parameter.
+                * @return the value of the parameter.
+                */
+               public String[] getValue(String parameterName) {
+                       return (String[]) values.get(parameterName);
+               }
+
+               /**
+                * Gets the servlet multipart parser.
+                * 
+                * @return the parser.
+                */
+               public ServletMultipartRequest getParser() {
+                       return parser;
+               }
+
+               /**
+                * Gets the name - value[] mapping of non variable parameters.
+                * 
+                * @return the mapping of non variable parameters.
+                */
+               public Map getNonVariables() {
+                       return nonVariables;
+               }
+       }
+
+       /**
+        * Handles all variable changes in this request.
+        * 
+        * @param req
+        *            the Http request to handle.
+        * @param errorListener
+        *            the listeners If the list is non null, only the listed
+        *            listeners are served. Otherwise all the listeners are served.
+        * @return Name to Value[] mapping of unhandled variables.
+        * @throws IOException
+        *             if the writing failed due to input/output error.
+        */
+       public Map handleVariables(HttpServletRequest req,
+                       Terminal.ErrorListener errorListener) throws IOException {
+
+               // Gets the parameters
+               ParameterContainer parcon = new ParameterContainer(req);
+
+               // Sorts listeners to dependency order
+               List listeners = getDependencySortedListenerList(parcon.getOwners());
+
+               // Handles all parameters for all listeners
+               while (!listeners.isEmpty()) {
+                       VariableOwner listener = (VariableOwner) listeners.remove(0);
+                       boolean changed = false; // Has any of this owners variabes
+                                                                               // changed
+                       // Handles all parameters for listener
+                       Set params = parcon.getParameters(listener);
+                       if (params != null) { // Name value mapping
+                               Map variables = new HashMap();
+                               for (Iterator pi = params.iterator(); pi.hasNext();) {
+                                       // Gets the name of the parameter
+                                       String param = (String) pi.next();
+                                       // Extracts more information about the parameter
+                                       String varName = (String) idToNameMap.get(param);
+                                       Class varType = (Class) idToTypeMap.get(param);
+                                       Object varOldValue = idToValueMap.get(param);
+                                       if (varName == null || varType == null)
+                                               // TODO Remove this?
+                                               System.err
+                                                               .println("VariableMap: No variable found for parameter "
+                                                                               + param
+                                                                               + " ("
+                                                                               + varName
+                                                                               + ","
+                                                                               + listener + ")");
+                                       else {
+
+                                               ServletMultipartRequest parser = parcon.getParser();
+
+                                               // Uploads events
+                                               if (varType.equals(UploadStream.class)) {
+                                                       if (parser != null
+                                                                       && parser.getFileParameter(param,
+                                                                                       MultipartRequest.FILENAME) != null) {
+                                                               String filename = (String) parser
+                                                                               .getFileParameter(param,
+                                                                                               MultipartRequest.FILENAME);
+                                                               String contentType = (String) parser
+                                                                               .getFileParameter(param,
+                                                                                               MultipartRequest.CONTENT_TYPE);
+                                                               UploadStream upload = new AjaxHttpUploadStream(
+                                                                               varName, parser.getFileContents(param),
+                                                                               filename, contentType);
+                                                               variables.put(varName, upload);
+                                                               changed = true;
+                                                       }
+                                               }
+
+                                               // Normal variable change events
+                                               else {
+                                                       // First try to parse the event without multipart
+                                                       String[] values = parcon.getValue(param);
+                                                       if (values != null) {
+
+                                                               if (varType.equals(String[].class)) {
+                                                                       variables.put(varName, values);
+                                                                       changed |= (!Arrays.equals(values,
+                                                                                       (String[]) varOldValue));
+                                                               } else {
+                                                                       try {
+                                                                               if (values.length == 1) {
+                                                                                       Object val = convert(varType,
+                                                                                                       values[0]);
+                                                                                       variables.put(varName, val);
+                                                                                       changed |= ((val == null && varOldValue != null) || (val != null && !val
+                                                                                                       .equals(varOldValue)));
+                                                                               } else if (values.length == 0
+                                                                                               && varType
+                                                                                                               .equals(Boolean.class)) {
+                                                                                       Object val = new Boolean(false);
+                                                                                       variables.put(varName, val);
+                                                                                       changed |= (!val
+                                                                                                       .equals(varOldValue));
+                                                                               } else {
+                                                                                       // TODO Remove this?
+                                                                                       System.err
+                                                                                                       .println("Empty variable '"
+                                                                                                                       + varName
+                                                                                                                       + "' of type "
+                                                                                                                       + varType
+                                                                                                                                       .toString());
+                                                                               }
+
+                                                                       } catch (java.lang.ClassCastException e) {
+                                                                               // TODO Remove this?
+                                                                               System.err
+                                                                                               .println("WebVariableMap conversion exception");
+                                                                               e.printStackTrace(System.err);
+                                                                               errorListener
+                                                                                               .terminalError(new TerminalErrorImpl(
+                                                                                                               e));
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               // Do the valuechange if the listener is enabled
+                               if (listener.isEnabled() && changed) {
+                                       try {
+                                               listener.changeVariables(req, variables);
+                                       } catch (Throwable t) {
+                                               // Notify the error listener
+                                               errorListener.terminalError(new VariableOwnerErrorImpl(
+                                                               listener, t));
+                                       }
+                               }
+                       }
+               }
+
+               return parcon.getNonVariables();
+       }
+
+       /**
+        * Implementation of VariableOwner.Error interface.
+        */
+       public class TerminalErrorImpl implements Terminal.ErrorEvent {
+               private Throwable throwable;
+
+               /**
+                * 
+                * @param throwable
+                */
+               private TerminalErrorImpl(Throwable throwable) {
+                       this.throwable = throwable;
+               }
+
+               /**
+                * @see com.itmill.toolkit.terminal.Terminal.ErrorEvent#getThrowable()
+                */
+               public Throwable getThrowable() {
+                       return this.throwable;
+               }
+
+       }
+
+       /**
+        * Implementation of VariableOwner.Error interface.
+        */
+       public class VariableOwnerErrorImpl extends TerminalErrorImpl implements
+                       VariableOwner.ErrorEvent {
+
+               private VariableOwner owner;
+
+               /**
+                * 
+                * @param owner
+                *            the Listener for variable changes.
+                * @param throwable
+                */
+               private VariableOwnerErrorImpl(VariableOwner owner, Throwable throwable) {
+                       super(throwable);
+                       this.owner = owner;
+               }
+
+               /**
+                * @see com.itmill.toolkit.terminal.VariableOwner.ErrorEvent#getVariableOwner()
+                */
+               public VariableOwner getVariableOwner() {
+                       return this.owner;
+               }
+
+       }
+
+       /**
+        * Resolves the VariableOwners needed from the request and sort them to
+        * assure that the dependencies are met (as well as possible).
+        * 
+        * @param listeners
+        * @return List of variable list changers, that are needed for handling all
+        *         the variables in the request
+        */
+       private List getDependencySortedListenerList(Set listeners) {
+
+               LinkedList resultNormal = new LinkedList();
+               LinkedList resultImmediate = new LinkedList();
+
+               // Go trough the listeners and either add them to result or resolve
+               // their dependencies
+               HashMap deepdeps = new HashMap();
+               LinkedList unresolved = new LinkedList();
+               for (Iterator li = listeners.iterator(); li.hasNext();) {
+
+                       VariableOwner listener = (VariableOwner) li.next();
+                       if (listener != null) {
+                               Set dependencies = listener.getDirectDependencies();
+
+                               // The listeners with no dependencies are added to the front of
+                               // the
+                               // list directly
+                               if (dependencies == null || dependencies.isEmpty()) {
+                                       if (listener.isImmediate())
+                                               resultImmediate.addFirst(listener);
+                                       else
+                                               resultNormal.addFirst(listener);
+                               }
+
+                               // Resolve deep dependencies for the listeners with dependencies
+                               // (the listeners will be added to the end of results in correct
+                               // dependency order later). Also the dependencies of all the
+                               // depended listeners are resolved.
+                               else if (deepdeps.get(listener) == null) {
+
+                                       // Set the fifo for unresolved parents to contain only the
+                                       // listener to be resolved
+                                       unresolved.clear();
+                                       unresolved.add(listener);
+
+                                       // Resolve dependencies
+                                       HashSet tmpdeepdeps = new HashSet();
+                                       while (!unresolved.isEmpty()) {
+
+                                               VariableOwner l = (VariableOwner) unresolved
+                                                               .removeFirst();
+                                               if (!tmpdeepdeps.contains(l)) {
+                                                       tmpdeepdeps.add(l);
+                                                       if (deepdeps.containsKey(l)) {
+                                                               tmpdeepdeps.addAll((Set) deepdeps.get(l));
+                                                       } else {
+                                                               Set deps = l.getDirectDependencies();
+                                                               if (deps != null && !deps.isEmpty())
+                                                                       for (Iterator di = deps.iterator(); di
+                                                                                       .hasNext();) {
+                                                                               Object d = di.next();
+                                                                               if (d != null
+                                                                                               && !tmpdeepdeps.contains(d))
+                                                                                       unresolved.addLast(d);
+                                                                       }
+                                                       }
+                                               }
+                                       }
+
+                                       tmpdeepdeps.remove(listener);
+                                       deepdeps.put(listener, tmpdeepdeps);
+                               }
+                       }
+               }
+
+               // Adds the listeners with dependencies in sane order to the result
+               for (Iterator li = deepdeps.keySet().iterator(); li.hasNext();) {
+                       VariableOwner l = (VariableOwner) li.next();
+                       boolean immediate = l.isImmediate();
+
+                       // Adds each listener after the last depended listener already in
+                       // the list
+                       int index = -1;
+                       for (Iterator di = ((Set) deepdeps.get(l)).iterator(); di.hasNext();) {
+                               int k;
+                               Object depended = di.next();
+                               if (immediate) {
+                                       k = resultImmediate.lastIndexOf(depended);
+                               } else {
+                                       k = resultNormal.lastIndexOf(depended);
+                               }
+                               if (k > index)
+                                       index = k;
+                       }
+                       if (immediate) {
+                               resultImmediate.add(index + 1, l);
+                       } else {
+                               resultNormal.add(index + 1, l);
+                       }
+               }
+
+               // Appends immediate listeners to normal listeners
+               // This way the normal handlers are always called before
+               // immediate ones
+               resultNormal.addAll(resultImmediate);
+               return resultNormal;
+       }
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/server/ApplicationManager.java b/src/com/itmill/toolkit/terminal/gwt/server/ApplicationManager.java
new file mode 100644 (file)
index 0000000..3a3c27a
--- /dev/null
@@ -0,0 +1,929 @@
+/* *************************************************************************
+ 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.gwt.server;
+
+import java.io.BufferedWriter;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.text.DateFormatSymbols;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.GregorianCalendar;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+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;
+import com.itmill.toolkit.ui.Component;
+import com.itmill.toolkit.ui.FrameWindow;
+import com.itmill.toolkit.ui.Window;
+
+/**
+ * Application manager processes changes and paints for single application
+ * instance.
+ * 
+ * @author IT Mill Ltd.
+ * @version
+ * @VERSION@
+ * @since 5.0
+ */
+public class ApplicationManager implements
+               Paintable.RepaintRequestListener, Application.WindowAttachListener,
+               Application.WindowDetachListener {
+
+       private static String GET_PARAM_REPAINT_ALL = "repaintAll";
+
+       private static int DEFAULT_BUFFER_SIZE = 32 * 1024;
+
+       private static int MAX_BUFFER_SIZE = 64 * 1024;
+
+       private WeakHashMap applicationToVariableMapMap = new WeakHashMap();
+
+       private HashSet dirtyPaintabletSet = new HashSet();
+
+
+       // TODO THIS TEMPORARY HACK IS ONLY HERE TO MAKE GWT DEVEL EASIER
+    static WeakHashMap paintableIdMap = new WeakHashMap();
+
+       private int idSequence = 0;
+
+       private Application application;
+
+       private Set removedWindows = new HashSet();
+
+       private JsonPaintTarget paintTarget;
+       
+       private List locales;
+       
+       private int pendingLocalesIndex;
+       
+       private ApplicationServlet applicationServlet;
+
+       public ApplicationManager(Application application, ApplicationServlet applicationServlet) {
+               this.application = application;
+               this.applicationServlet = applicationServlet;
+               requireLocale(application.getLocale().toString());
+       }
+
+       /**
+        * 
+        * @return
+        */
+       private AjaxVariableMap getVariableMap() {
+               AjaxVariableMap vm = (AjaxVariableMap) applicationToVariableMapMap
+                               .get(application);
+               if (vm == null) {
+                       vm = new AjaxVariableMap();
+                       applicationToVariableMapMap.put(application, vm);
+               }
+               return vm;
+       }
+
+       /**
+        * 
+        * 
+        */
+       public void takeControl() {
+               application.addListener((Application.WindowAttachListener) this);
+               application.addListener((Application.WindowDetachListener) this);
+
+       }
+
+       /**
+        * 
+        * 
+        */
+       public void releaseControl() {
+               application.removeListener((Application.WindowAttachListener) this);
+               application.removeListener((Application.WindowDetachListener) this);
+       }
+
+       
+       public void handleUidlRequest(HttpServletRequest request,
+                       HttpServletResponse response) throws IOException {
+
+               // repaint requested or sesssion has timed out and new one is created
+               boolean repaintAll = (request.getParameter(GET_PARAM_REPAINT_ALL) != null)
+                               || request.getSession().isNew();
+
+               OutputStream out = response.getOutputStream();
+               PrintWriter outWriter = new PrintWriter(new BufferedWriter(
+                               new OutputStreamWriter(out, "UTF-8")));
+               
+               outWriter.print(")/*{"); // some dirt to prevent cross site scripting vulnerabilities
+
+               try {
+
+                       // Is this a download request from application
+                       DownloadStream download = null;
+
+                       // The rest of the process is synchronized with the application
+                       // in order to guarantee that no parallel variable handling is
+                       // made
+                       synchronized (application) {
+
+                               // Change all variables based on request parameters
+                               Map unhandledParameters = getVariableMap().handleVariables(
+                                               request, application);
+
+                               // Handles the URI if the application is still running
+                               if (application.isRunning())
+                                       download = handleURI(application, request, response);
+
+                               // If this is not a download request
+                               if (download == null) {
+
+                                       // Finds the window within the application
+                                       Window window = null;
+                                       if (application.isRunning())
+                                               window = getApplicationWindow(request, application);
+
+                                       // Handles the unhandled parameters if the application is
+                                       // still running
+                                       if (window != null && unhandledParameters != null
+                                                       && !unhandledParameters.isEmpty())
+                                               window.handleParameters(unhandledParameters);
+
+                                       // Removes application if it has stopped
+                                       if (!application.isRunning()) {
+                                               endApplication(request, response, application);
+                                               return;
+                                       }
+
+                                       // Returns if no window found
+                                       if (window == null)
+                                               return;
+
+                                       // Sets the response type
+                                       response.setContentType("application/json; charset=UTF-8");
+                                       outWriter.print("\"changes\":[");
+                                       
+                                       paintTarget = new JsonPaintTarget(getVariableMap(), 
+                                                       this, outWriter);
+
+                                       // Paints components
+                                       Set paintables;
+                                       if (repaintAll) {
+                                               paintables = new LinkedHashSet();
+                                               paintables.add(window);
+                                               
+                                               // Reset sent locales
+                                               locales = null;
+                                               requireLocale(application.getLocale().toString());
+
+                                               // Adds all non-native windows
+                                               for (Iterator i = window.getApplication().getWindows()
+                                                               .iterator(); i.hasNext();) {
+                                                       Window w = (Window) i.next();
+                                                       if (!"native".equals(w.getStyle()) && w != window)
+                                                               paintables.add(w);
+                                               }
+                                       } else
+                                               paintables = getDirtyComponents();
+                                       if (paintables != null) {
+
+                                               // Creates "working copy" of the current state.
+                                               List currentPaintables = new ArrayList(paintables);
+
+                                               // Sorts the paintable so that parent windows
+                                               // are always painted before child windows
+                                               Collections.sort(currentPaintables, new Comparator() {
+
+                                                       public int compare(Object o1, Object o2) {
+
+                                                               // If first argumement is now window
+                                                               // the second is "smaller" if it is.
+                                                               if (!(o1 instanceof Window)) {
+                                                                       return (o2 instanceof Window) ? 1 : 0;
+                                                               }
+
+                                                               // Now, if second is not window the
+                                                               // first is smaller.
+                                                               if (!(o2 instanceof Window)) {
+                                                                       return -1;
+                                                               }
+
+                                                               // Both are windows.
+                                                               String n1 = ((Window) o1).getName();
+                                                               String n2 = ((Window) o2).getName();
+                                                               if (o1 instanceof FrameWindow) {
+                                                                       if (((FrameWindow) o1).getFrameset()
+                                                                                       .getFrame(n2) != null) {
+                                                                               return -1;
+                                                                       } else if (!(o2 instanceof FrameWindow)) {
+                                                                               return -1;
+                                                                       }
+                                                               }
+                                                               if (o2 instanceof FrameWindow) {
+                                                                       if (((FrameWindow) o2).getFrameset()
+                                                                                       .getFrame(n1) != null) {
+                                                                               return 1;
+                                                                       } else if (!(o1 instanceof FrameWindow)) {
+                                                                               return 1;
+                                                                       }
+                                                               }
+
+                                                               return 0;
+                                                       }
+                                               });
+
+                                               for (Iterator i = currentPaintables.iterator(); i
+                                                               .hasNext();) {
+                                                       Paintable p = (Paintable) i.next();
+
+                                                       // TODO CLEAN
+                                                       if (p instanceof Window) {
+                                                               Window w = (Window) p;
+                                                               if (w.getTerminal() == null)
+                                                                       w.setTerminal(application.getMainWindow()
+                                                                                       .getTerminal());
+                                                       }
+
+                                                       paintTarget.startTag("change");
+                                                       paintTarget.addAttribute("format", "uidl");
+                                                       String pid = getPaintableId(p);
+                                                       paintTarget.addAttribute("pid", pid);
+
+                                                       // Track paints to identify empty paints
+                                                       paintTarget.setTrackPaints(true);
+                                                       p.paint(paintTarget);
+
+                                                       // If no paints add attribute empty
+                                                       if (paintTarget.getNumberOfPaints() <= 0) {
+                                                               paintTarget.addAttribute("visible", false);
+                                                       }
+                                                       paintTarget.endTag("change");
+                                                       paintablePainted(p);
+                                               }
+                                       }
+
+                                       
+                                                       paintTarget.close();
+                                       outWriter.print("]"); // close changes
+
+
+                                       // Render the removed windows
+                                       // TODO refactor commented area to send some meta instructions to close window
+//                                     Set removed = new HashSet(getRemovedWindows());
+//                                     if (removed.size() > 0) {
+//                                             for (Iterator i = removed.iterator(); i.hasNext();) {
+//                                                     Window w = (Window) i.next();
+//                                                     paintTarget.startTag("change");
+//                                                     paintTarget.addAttribute("format", "uidl");
+//                                                     String pid = getPaintableId(w);
+//                                                     paintTarget.addAttribute("pid", pid);
+//                                                     paintTarget.addAttribute("windowname", w.getName());
+//                                                     paintTarget.addAttribute("visible", false);
+//                                                     paintTarget.endTag("change");
+//                                                     removedWindowNotified(w);
+//
+//                                             }
+//                                     }
+
+
+                                       
+                       outWriter.print(", \"meta\" : {");
+                       boolean metaOpen = false;
+
+                                       
+                    // .. or initializion (first uidl-request)
+                    if(application.ajaxInit()) {
+                       outWriter.print("\"appInit\":true");
+                    }
+                    // add meta instruction for client to set focus if it is set
+                    Paintable f = (Paintable) application.consumeFocus();
+                    if(f != null) {
+                       if(metaOpen)
+                               outWriter.append(",");
+                       outWriter.write("\"focus\":\""+ getPaintableId(f) +"\"");
+                    }
+
+                       outWriter.print("}, \"resources\" : {");
+
+                    // 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
+                       int resourceIndex = 0;
+                    for (Iterator i=paintTarget.getPreCachedResources().iterator(); i.hasNext();) {
+                       String resource = (String) i.next();
+                       InputStream is = null;
+                       try {
+                               is = applicationServlet.getServletContext().getResourceAsStream(ApplicationServlet.THEME_DIRECTORY_PATH + themeName + "/" +  resource);
+                               } catch (Exception e) {
+                                       Log.info(e.getMessage());
+                               }
+                       if (is != null) {
+                               
+                               outWriter.print((resourceIndex++ > 0 ? ", " : "") + "\""+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() + ")");
+                               }
+                               outWriter.print("\"" + JsonPaintTarget.escapeJSON(layout.toString()) + "\"");
+                       }
+                    }
+                       outWriter.print("}");
+                       
+                       
+                       /* -----------------------------
+                        * Sending Locale sensitive date
+                        * -----------------------------
+                        */
+                       
+                       // Store JVM default locale for later restoration
+                       // (we'll have to change the default locale for a while)
+                       Locale jvmDefault = Locale.getDefault();
+                       
+                    // Send locale informations to client
+                       outWriter.print(", \"locales\":[");
+                       for(;pendingLocalesIndex < locales.size(); pendingLocalesIndex++) {
+                               
+                               Locale l = generateLocale((String) locales.get(pendingLocalesIndex));
+                               // Locale name
+                               outWriter.print("{\"name\":\"" + l.toString() + "\",");
+                               
+                               /*
+                                * Month names (both short and full)
+                                */
+                               DateFormatSymbols dfs = new DateFormatSymbols(l);
+                               String[] short_months = dfs.getShortMonths();
+                               String[] months = dfs.getMonths();
+                               outWriter.print("\"smn\":[\"" + // ShortMonthNames
+                                               short_months[0] + "\",\"" +
+                                               short_months[1] + "\",\"" +
+                                               short_months[2] + "\",\"" +
+                                               short_months[3] + "\",\"" +
+                                               short_months[4] + "\",\"" +
+                                               short_months[5] + "\",\"" +
+                                               short_months[6] + "\",\"" +
+                                               short_months[7] + "\",\"" +
+                                               short_months[8] + "\",\"" +
+                                               short_months[9] + "\",\"" +
+                                               short_months[10] + "\",\"" +
+                                               short_months[11] + "\"" +
+                                               "],");
+                               outWriter.print("\"mn\":[\"" + // MonthNames
+                                               months[0] + "\",\"" +
+                                               months[1] + "\",\"" +
+                                               months[2] + "\",\"" +
+                                               months[3] + "\",\"" +
+                                               months[4] + "\",\"" +
+                                               months[5] + "\",\"" +
+                                               months[6] + "\",\"" +
+                                               months[7] + "\",\"" +
+                                               months[8] + "\",\"" +
+                                               months[9] + "\",\"" +
+                                               months[10] + "\",\"" +
+                                               months[11] + "\"" +
+                                               "],");
+       
+                           /*
+                            * Weekday names (both short and full)
+                            */
+                               String[] short_days = dfs.getShortWeekdays();
+                               String[] days = dfs.getWeekdays();
+                           outWriter.print("\"sdn\":[\"" + // ShortDayNames
+                                               short_days[1] + "\",\"" +
+                                               short_days[2] + "\",\"" +
+                                               short_days[3] + "\",\"" +
+                                               short_days[4] + "\",\"" +
+                                               short_days[5] + "\",\"" +
+                                               short_days[6] + "\",\"" +
+                                               short_days[7] + "\"" +
+                                               "],");
+                               outWriter.print("\"dn\":[\"" + // DayNames
+                                               days[1] + "\",\"" +
+                                               days[2] + "\",\"" +
+                                               days[3] + "\",\"" +
+                                               days[4] + "\",\"" +
+                                               days[5] + "\",\"" +
+                                               days[6] + "\",\"" +
+                                               days[7] + "\"" +
+                                               "],");
+                               
+                               /*
+                                * First day of week (0 = sunday, 1 = monday)
+                                */
+                               Calendar cal = new GregorianCalendar(l);
+                               outWriter.print("\"fdow\":" + (cal.getFirstDayOfWeek() - 1) + ",");
+                               
+                               /*
+                                * Date formatting (MM/DD/YYYY etc.)
+                                */
+                               // Force our locale as JVM default for a while (SimpleDateFormat uses JVM default)
+                               Locale.setDefault(l);
+                               String df = new SimpleDateFormat().toPattern();
+                               int timeStart = df.indexOf("H");
+                               if(timeStart < 0)
+                                       timeStart = df.indexOf("h");
+                               int ampm_first = df.indexOf("a");
+                               // E.g. in Korean locale AM/PM is before h:mm
+                               // TODO should take that into consideration on client-side as well, now always h:mm a
+                               if(ampm_first > 0 && ampm_first < timeStart)
+                                       timeStart = ampm_first;
+                               String dateformat = df.substring(0, timeStart-1);
+                               
+                               outWriter.print("\"df\":\"" + dateformat.trim() + "\",");
+                               
+                               /*
+                                * Time formatting (24 or 12 hour clock and AM/PM suffixes)
+                                */
+                               String timeformat = df.substring(timeStart, df.length()); // Doesn't return second or milliseconds
+                               // We use timeformat to determine 12/24-hour clock
+                               boolean twelve_hour_clock = timeformat.contains("a");
+                               // TODO there are other possibilities as well, like 'h' in french (ignore them, too complicated)
+                               String hour_min_delimiter = timeformat.contains(".")? "." : ":";
+                               //outWriter.print("\"tf\":\"" + timeformat + "\",");
+                               outWriter.print("\"thc\":" + twelve_hour_clock + ",");
+                               outWriter.print("\"hmd\":\"" + hour_min_delimiter + "\"");
+                               if(twelve_hour_clock) {
+                                       String[] ampm = dfs.getAmPmStrings();
+                                       outWriter.print(",\"ampm\":[\""+ampm[0]+"\",\""+ampm[1]+"\"]");
+                               }
+                               outWriter.print("}");
+                               if(pendingLocalesIndex < locales.size()-1)
+                                       outWriter.print(",");
+                       }
+                       outWriter.print("]"); // Close locales
+                       
+                       // Restore JVM default locale
+                       Locale.setDefault(jvmDefault);
+                
+                       outWriter.flush();
+                    outWriter.close();
+                                       out.flush();
+                               } else {
+
+                                       // For download request, transfer the downloaded data
+                                       handleDownload(download, request, response);
+                               }
+                       }
+
+                       out.flush();
+                       out.close();
+
+               } catch (Throwable e) {
+                       // Writes the error report to client
+                       OutputStreamWriter w = new OutputStreamWriter(out);
+                       PrintWriter err = new PrintWriter(w);
+                       err
+                                       .write("<html><head><title>Application Internal Error</title></head><body>");
+                       err.write("<h1>" + e.toString() + "</h1><pre>\n");
+                       e.printStackTrace(new PrintWriter(err));
+                       err.write("\n</pre></body></html>");
+                       err.close();
+               } finally {
+
+               }
+
+       }
+
+       /**
+        * Gets the existing application or create a new one. Get a window within an
+        * application based on the requested URI.
+        * 
+        * @param request
+        *            the HTTP Request.
+        * @param application
+        *            the Application to query for window.
+        * @return Window mathing the given URI or null if not found.
+        * @throws ServletException
+        *             if an exception has occurred that interferes with the
+        *             servlet's normal operation.
+        */
+       private Window getApplicationWindow(HttpServletRequest request,
+                       Application application) throws ServletException {
+
+               Window window = null;
+
+               // Find the window where the request is handled
+               String path = request.getPathInfo();
+
+               // Main window as the URI is empty
+               if (path == null || path.length() == 0 || path.equals("/"))
+                       window = application.getMainWindow();
+
+               // Try to search by window name
+               else {
+                       String windowName = null;
+                       if (path.charAt(0) == '/')
+                               path = path.substring(1);
+                       int index = path.indexOf('/');
+                       if (index < 0) {
+                               windowName = path;
+                               path = "";
+                       } else {
+                               windowName = path.substring(0, index);
+                               path = path.substring(index + 1);
+                       }
+                       window = application.getWindow(windowName);
+
+                       // By default, we use main window
+                       if (window == null)
+                               window = application.getMainWindow();
+               }
+
+               return window;
+       }
+
+       /**
+        * Handles the requested URI. An application can add handlers to do special
+        * processing, when a certain URI is requested. The handlers are invoked
+        * before any windows URIs are processed and if a DownloadStream is returned
+        * it is sent to the client.
+        * 
+        * @param application
+        *            the Application owning the URI.
+        * @param request
+        *            the HTTP request instance.
+        * @param response
+        *            the HTTP response to write to.
+        * @return boolean <code>true</code> if the request was handled and
+        *         further processing should be suppressed, otherwise
+        *         <code>false</code>.
+        * @see com.itmill.toolkit.terminal.URIHandler
+        */
+       private DownloadStream handleURI(Application application,
+                       HttpServletRequest request, HttpServletResponse response) {
+
+               String uri = request.getPathInfo();
+
+               // If no URI is available
+               if (uri == null || uri.length() == 0 || uri.equals("/"))
+                       return null;
+
+               // Remove the leading /
+               while (uri.startsWith("/") && uri.length() > 0)
+                       uri = uri.substring(1);
+
+               // Handle the uri
+               DownloadStream stream = null;
+               try {
+                       stream = application.handleURI(application.getURL(), uri);
+               } catch (Throwable t) {
+                       application.terminalError(new URIHandlerErrorImpl(application, t));
+               }
+
+               return stream;
+       }
+
+       /**
+        * Handles the requested URI. An application can add handlers to do special
+        * processing, when a certain URI is requested. The handlers are invoked
+        * before any windows URIs are processed and if a DownloadStream is returned
+        * it is sent to the client.
+        * 
+        * @param stream
+        *            the downloadable stream.
+        * 
+        * @param request
+        *            the HTTP request instance.
+        * @param response
+        *            the HTTP response to write to.
+        * 
+        * @see com.itmill.toolkit.terminal.URIHandler
+        */
+       private void handleDownload(DownloadStream stream,
+                       HttpServletRequest request, HttpServletResponse response) {
+
+               // Download from given stream
+               InputStream data = stream.getStream();
+               if (data != null) {
+
+                       // Sets content type
+                       response.setContentType(stream.getContentType());
+
+                       // Sets cache headers
+                       long cacheTime = stream.getCacheTime();
+                       if (cacheTime <= 0) {
+                               response.setHeader("Cache-Control", "no-cache");
+                               response.setHeader("Pragma", "no-cache");
+                               response.setDateHeader("Expires", 0);
+                       } else {
+                               response.setHeader("Cache-Control", "max-age=" + cacheTime
+                                               / 1000);
+                               response.setDateHeader("Expires", System.currentTimeMillis()
+                                               + cacheTime);
+                               response.setHeader("Pragma", "cache"); // Required to apply
+                               // caching in some
+                               // Tomcats
+                       }
+
+                       // Copy download stream parameters directly
+                       // to HTTP headers.
+                       Iterator i = stream.getParameterNames();
+                       if (i != null) {
+                               while (i.hasNext()) {
+                                       String param = (String) i.next();
+                                       response.setHeader((String) param, stream
+                                                       .getParameter(param));
+                               }
+                       }
+
+                       int bufferSize = stream.getBufferSize();
+                       if (bufferSize <= 0 || bufferSize > MAX_BUFFER_SIZE)
+                               bufferSize = DEFAULT_BUFFER_SIZE;
+                       byte[] buffer = new byte[bufferSize];
+                       int bytesRead = 0;
+
+                       try {
+                               OutputStream out = response.getOutputStream();
+
+                               while ((bytesRead = data.read(buffer)) > 0) {
+                                       out.write(buffer, 0, bytesRead);
+                                       out.flush();
+                               }
+                               out.close();
+                       } catch (IOException ignored) {
+                       }
+
+               }
+
+       }
+
+       /**
+        * Ends the Application.
+        * 
+        * @param request
+        *            the HTTP request instance.
+        * @param response
+        *            the HTTP response to write to.
+        * @param application
+        *            the Application to end.
+        * @throws IOException
+        *             if the writing failed due to input/output error.
+        */
+       private void endApplication(HttpServletRequest request,
+                       HttpServletResponse response, Application application)
+                       throws IOException {
+
+               String logoutUrl = application.getLogoutURL();
+               if (logoutUrl == null)
+                       logoutUrl = application.getURL().toString();
+               // clients JS app is still running, send a special xml file to
+               // tell client that application is quit and where to point browser now
+               // Set the response type
+               response.setContentType("application/xml; charset=UTF-8");
+               ServletOutputStream out = response.getOutputStream();
+               out.println("<redirect url=\"" + logoutUrl + "\">");
+               out.println("</redirect>");
+       }
+
+       /**
+        * Gets the Paintable Id.
+        * 
+        * @param paintable
+        * @return the paintable Id.
+        */
+       public synchronized String getPaintableId(Paintable paintable) {
+
+               String id = (String) paintableIdMap.get(paintable);
+               if (id == null) {
+                       id = "PID" + Integer.toString(idSequence++);
+                       paintableIdMap.put(paintable, id);
+               }
+
+               return id;
+       }
+
+       /**
+        * 
+        * @return
+        */
+       public synchronized Set getDirtyComponents() {
+
+               // Remove unnecessary repaints from the list
+               Object[] paintables = dirtyPaintabletSet.toArray();
+               for (int i = 0; i < paintables.length; i++) {
+                       if (paintables[i] instanceof Component) {
+                               Component c = (Component) paintables[i];
+
+                               // Check if any of the parents of c already exist in the list
+                               Component p = c.getParent();
+                               while (p != null) {
+                                       if (dirtyPaintabletSet.contains(p)) {
+
+                                               // Remove component c from the dirty paintables as its
+                                               // parent is also dirty
+                                               dirtyPaintabletSet.remove(c);
+                                               p = null;
+                                       } else
+                                               p = p.getParent();
+                               }
+                       }
+               }
+
+               return Collections.unmodifiableSet(dirtyPaintabletSet);
+       }
+
+       /**
+        * Clears the Dirty Components.
+        * 
+        */
+       public synchronized void clearDirtyComponents() {
+               dirtyPaintabletSet.clear();
+       }
+
+       /**
+        * @see com.itmill.toolkit.terminal.Paintable.RepaintRequestListener#repaintRequested(com.itmill.toolkit.terminal.Paintable.RepaintRequestEvent)
+        */
+       public void repaintRequested(RepaintRequestEvent event) {
+               Paintable p = event.getPaintable();
+               dirtyPaintabletSet.add(p);
+
+               // For FrameWindows we mark all frames (windows) dirty
+               if (p instanceof FrameWindow) {
+                       FrameWindow fw = (FrameWindow) p;
+                       repaintFrameset(fw.getFrameset());
+               }
+       }
+
+       /**
+        * Recursively request repaint for all frames in frameset.
+        * 
+        * @param fs
+        *            the Framewindow.Frameset.
+        */
+       private void repaintFrameset(FrameWindow.Frameset fs) {
+               List frames = fs.getFrames();
+               for (Iterator i = frames.iterator(); i.hasNext();) {
+                       FrameWindow.Frame f = (FrameWindow.Frame) i.next();
+                       if (f instanceof FrameWindow.Frameset) {
+                               repaintFrameset((FrameWindow.Frameset) f);
+                       } else {
+                               Window w = f.getWindow();
+                               if (w != null) {
+                                       w.requestRepaint();
+                               }
+                       }
+               }
+       }
+
+       /**
+        * 
+        * @param p
+        */
+       public void paintablePainted(Paintable p) {
+               dirtyPaintabletSet.remove(p);
+               p.requestRepaintRequests();
+       }
+
+       /**
+        * 
+        * @param paintable
+        * @return
+        */
+       public boolean isDirty(Paintable paintable) {
+               return (dirtyPaintabletSet.contains(paintable));
+       }
+
+       /**
+        * @see com.itmill.toolkit.Application.WindowAttachListener#windowAttached(com.itmill.toolkit.Application.WindowAttachEvent)
+        */
+       public void windowAttached(WindowAttachEvent event) {
+               event.getWindow().addListener(this);
+               dirtyPaintabletSet.add(event.getWindow());
+       }
+
+       /**
+        * @see com.itmill.toolkit.Application.WindowDetachListener#windowDetached(com.itmill.toolkit.Application.WindowDetachEvent)
+        */
+       public void windowDetached(WindowDetachEvent event) {
+               event.getWindow().removeListener(this);
+               // Notify client of the close operation
+               removedWindows.add(event.getWindow());
+       }
+
+       /**
+        * 
+        * @return
+        */
+       public synchronized Set getRemovedWindows() {
+               return Collections.unmodifiableSet(removedWindows);
+
+       }
+
+       /**
+        * 
+        * @param w
+        */
+       private void removedWindowNotified(Window w) {
+               this.removedWindows.remove(w);
+       }
+
+       /**
+        * Implementation of URIHandler.ErrorEvent interface.
+        */
+       public class URIHandlerErrorImpl implements URIHandler.ErrorEvent {
+
+               private URIHandler owner;
+
+               private Throwable throwable;
+
+               /**
+                * 
+                * @param owner
+                * @param throwable
+                */
+               private URIHandlerErrorImpl(URIHandler owner, Throwable throwable) {
+                       this.owner = owner;
+                       this.throwable = throwable;
+               }
+
+               /**
+                * @see com.itmill.toolkit.terminal.Terminal.ErrorEvent#getThrowable()
+                */
+               public Throwable getThrowable() {
+                       return this.throwable;
+               }
+
+               /**
+                * @see com.itmill.toolkit.terminal.URIHandler.ErrorEvent#getURIHandler()
+                */
+               public URIHandler getURIHandler() {
+                       return this.owner;
+               }
+       }
+
+       public void requireLocale(String value) {
+               if(locales == null) {
+                       locales = new ArrayList();
+                       locales.add(application.getLocale().toString());
+                       pendingLocalesIndex = 0;
+               }
+               if(!locales.contains(value))
+                               locales.add(value);
+       }
+       
+       private Locale generateLocale(String value) {
+               String[] temp = value.split("_");
+               if(temp.length == 1)
+                       return new Locale(temp[0]);
+               else if(temp.length == 2)
+                       return new Locale(temp[0], temp[1]);
+               else
+                       return new Locale(temp[0], temp[1], temp[2]);
+       }
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/server/ApplicationServlet.java b/src/com/itmill/toolkit/terminal/gwt/server/ApplicationServlet.java
new file mode 100644 (file)
index 0000000..62c561b
--- /dev/null
@@ -0,0 +1,1423 @@
+/* *************************************************************************
+ 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.gwt.server;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionBindingListener;
+
+import org.xml.sax.SAXException;
+
+import com.itmill.toolkit.Application;
+import com.itmill.toolkit.service.FileTypeResolver;
+import com.itmill.toolkit.service.License;
+import com.itmill.toolkit.service.License.InvalidLicenseFile;
+import com.itmill.toolkit.service.License.LicenseFileHasNotBeenRead;
+import com.itmill.toolkit.service.License.LicenseSignatureIsInvalid;
+import com.itmill.toolkit.service.License.LicenseViolation;
+import com.itmill.toolkit.terminal.DownloadStream;
+import com.itmill.toolkit.terminal.Paintable;
+import com.itmill.toolkit.terminal.ParameterHandler;
+import com.itmill.toolkit.terminal.ThemeResource;
+import com.itmill.toolkit.terminal.URIHandler;
+import com.itmill.toolkit.ui.Window;
+
+/**
+ * This servlet connects IT Mill Toolkit Application to Web. This servlet
+ * replaces both WebAdapterServlet and AjaxAdapterServlet.
+ * 
+ * @author IT Mill Ltd.
+ * @version
+ * @VERSION@
+ * @since 4.0
+ */
+
+public class ApplicationServlet extends HttpServlet {
+
+       private static final long serialVersionUID = -4937882979845826574L;
+
+       /**
+        * Version number of this release. For example "4.0.0".
+        */
+       public static final String VERSION;
+
+       /**
+        * Major version number. For example 4 in 4.1.0.
+        */
+       public static final int VERSION_MAJOR;
+
+       /**
+        * Minor version number. For example 1 in 4.1.0.
+        */
+       public static final int VERSION_MINOR;
+
+       /**
+        * Builds number. For example 0-beta1 in 4.0.0-beta1.
+        */
+       public static final String VERSION_BUILD;
+
+       /* Initialize version numbers from string replaced by build-script. */
+       static {
+               if ("@VERSION@".equals("@" + "VERSION" + "@"))
+                       VERSION = "4.9.9-INTERNAL-NONVERSIONED-DEBUG-BUILD";
+               else
+                       VERSION = "@VERSION@";
+               String[] digits = VERSION.split("\\.");
+               VERSION_MAJOR = Integer.parseInt(digits[0]);
+               VERSION_MINOR = Integer.parseInt(digits[1]);
+               VERSION_BUILD = digits[2];
+       }
+
+       // Configurable parameter names
+       private static final String PARAMETER_DEBUG = "Debug";
+
+       private static final int DEFAULT_BUFFER_SIZE = 32 * 1024;
+
+       private static final int MAX_BUFFER_SIZE = 64 * 1024;
+
+       // TODO: these should be moved to session object and stored directly into
+       // session
+       private static final String SESSION_ATTR_VARMAP = "itmill-toolkit-varmap";
+
+       private static final String SESSION_ATTR_CONTEXT = "itmill-toolkit-context";
+
+       protected static final String SESSION_ATTR_APPS = "itmill-toolkit-apps";
+
+       private static final String SESSION_BINDING_LISTENER = "itmill-toolkit-bindinglistener";
+
+       private static HashMap applicationToLastRequestDate = new HashMap();
+
+       private static HashMap applicationToAjaxAppMgrMap = new HashMap();
+
+       // License for ApplicationServlets
+       private static HashMap licenseForApplicationClass = new HashMap();
+
+       private static HashMap licensePrintedForApplicationClass = new HashMap();
+
+       // TODO Should default or base theme be the default?
+       protected static final String DEFAULT_THEME = "base";
+
+       private static final String RESOURCE_URI = "/RES/";
+
+       private static final String AJAX_UIDL_URI = "/UIDL/";
+
+       static final String THEME_DIRECTORY_PATH = "/theme/";
+
+       // Maximum delay between request for an user to be considered active (in ms)
+       private static final long ACTIVE_USER_REQUEST_INTERVAL = 1000 * 45;
+       
+       private static final int DEFAULT_THEME_CACHETIME = 1000 * 60 * 60 * 24;
+       // Private fields
+       private Class applicationClass;
+
+       private Properties applicationProperties;
+
+       private String resourcePath = null;
+
+       private String debugMode = "";
+
+       /**
+        * Called by the servlet container to indicate to a servlet that the servlet
+        * is being placed into service.
+        * 
+        * @param servletConfig
+        *            the object containing the servlet's configuration and
+        *            initialization parameters
+        * @throws javax.servlet.ServletException
+        *             if an exception has occurred that interferes with the
+        *             servlet's normal operation.
+        */
+       public void init(javax.servlet.ServletConfig servletConfig)
+                       throws javax.servlet.ServletException {
+               super.init(servletConfig);
+
+               // Gets the application class name
+               String applicationClassName = servletConfig
+                               .getInitParameter("application");
+               if (applicationClassName == null) {
+                       Log.error("Application not specified in servlet parameters");
+               }
+
+               // Stores the application parameters into Properties object
+               this.applicationProperties = new Properties();
+               for (Enumeration e = servletConfig.getInitParameterNames(); e
+                               .hasMoreElements();) {
+                       String name = (String) e.nextElement();
+                       this.applicationProperties.setProperty(name, servletConfig
+                                       .getInitParameter(name));
+               }
+
+               // Overrides with server.xml parameters
+               ServletContext context = servletConfig.getServletContext();
+               for (Enumeration e = context.getInitParameterNames(); e
+                               .hasMoreElements();) {
+                       String name = (String) e.nextElement();
+                       this.applicationProperties.setProperty(name, context
+                                       .getInitParameter(name));
+               }
+
+               // Gets the debug window parameter
+               String debug = getApplicationOrSystemProperty(PARAMETER_DEBUG, "")
+                               .toLowerCase();
+
+               // Enables application specific debug
+               if (!"".equals(debug) && !"true".equals(debug)
+                               && !"false".equals(debug))
+                       throw new ServletException(
+                                       "If debug parameter is given for an application, it must be 'true' or 'false'");
+               this.debugMode = debug;
+
+               // Loads the application class using the same class loader
+               // as the servlet itself
+               ClassLoader loader = this.getClass().getClassLoader();
+               try {
+                       this.applicationClass = loader.loadClass(applicationClassName);
+               } catch (ClassNotFoundException e) {
+                       throw new ServletException("Failed to load application class: "
+                                       + applicationClassName);
+               }
+       }
+
+       /**
+        * Gets an application or system property value.
+        * 
+        * @param parameterName
+        *            the Name or the parameter.
+        * @param defaultValue
+        *            the Default to be used.
+        * @return String value or default if not found
+        */
+       private String getApplicationOrSystemProperty(String parameterName,
+                       String defaultValue) {
+
+               // Try application properties
+               String val = this.applicationProperties.getProperty(parameterName);
+               if (val != null) {
+                       return val;
+               }
+
+               // Try lowercased application properties for backward compability with
+               // 3.0.2 and earlier
+               val = this.applicationProperties.getProperty(parameterName
+                               .toLowerCase());
+               if (val != null) {
+                       return val;
+               }
+
+               // Try system properties
+               String pkgName;
+               Package pkg = this.getClass().getPackage();
+               if (pkg != null) {
+                       pkgName = pkg.getName();
+               } else {
+                       String className = this.getClass().getName();
+                       pkgName = new String(className.toCharArray(), 0, className
+                                       .lastIndexOf('.'));
+               }
+               val = System.getProperty(pkgName + "." + parameterName);
+               if (val != null) {
+                       return val;
+               }
+
+               // Try lowercased system properties
+               val = System.getProperty(pkgName + "." + parameterName.toLowerCase());
+               if (val != null) {
+                       return val;
+               }
+
+               return defaultValue;
+       }
+
+       /**
+        * Receives standard HTTP requests from the public service method and
+        * dispatches them.
+        * 
+        * @param request
+        *            the object that contains the request the client made of the
+        *            servlet.
+        * @param response
+        *            the object that contains the response the servlet returns to
+        *            the client.
+        * @throws ServletException
+        *             if an input or output error occurs while the servlet is
+        *             handling the TRACE request.
+        * @throws IOException
+        *             if the request for the TRACE cannot be handled.
+        */
+       protected void service(HttpServletRequest request,
+                       HttpServletResponse response) throws ServletException, IOException {
+
+               // Transformer and output stream for the result
+               HttpVariableMap variableMap = null;
+               OutputStream out = response.getOutputStream();
+               Application application = null;
+               try {
+
+                       // Gets the application
+                       application = getApplication(request);
+
+                       // Creates application if it doesn't exist
+                       if (application == null)
+                               application = createApplication(request);
+
+                       // Sets the last application request date
+                       synchronized (applicationToLastRequestDate) {
+                               applicationToLastRequestDate.put(application, new Date());
+                       }
+
+                       // Invokes context transaction listeners
+                       ((WebApplicationContext) application.getContext())
+                                       .startTransaction(application, request);
+
+                       // Is this a download request from application
+                       DownloadStream download = null;
+
+                       // The rest of the process is synchronized with the application
+                       // in order to guarantee that no parallel variable handling is
+                       // made
+                       synchronized (application) {
+
+                               // Handles AJAX UIDL requests
+                               String resourceId = request.getPathInfo();
+                               if (resourceId != null && resourceId.startsWith(AJAX_UIDL_URI)) {
+                                       getApplicationManager(application).handleUidlRequest(
+                                                       request, response);
+                                       return;
+                               }
+
+                               // Gets the variable map
+                               variableMap = getVariableMap(application, request);
+                               if (variableMap == null)
+                                       return;
+
+                               // Change all variables based on request parameters
+                               Map unhandledParameters = variableMap.handleVariables(request,
+                                               application);
+
+                               // Check/handle client side feature checks
+                               WebBrowserProbe
+                                               .handleProbeRequest(request, unhandledParameters);
+
+                               // If rendering mode is not defined or detecting requested
+                               // try to detect it
+                               WebBrowser wb = WebBrowserProbe.getTerminalType(request
+                                               .getSession());
+
+                               boolean detect = false;
+                               if (unhandledParameters.get("renderingMode") != null) {
+                                       detect = ((String) ((Object[]) unhandledParameters
+                                                       .get("renderingMode"))[0]).equals("detect");
+                               }
+                               if (detect) {
+                                       String themeName = application.getTheme();
+                                       if (themeName == null)
+                                               themeName = DEFAULT_THEME;
+                                       if (unhandledParameters.get("theme") != null) {
+                                               themeName = (String) ((Object[]) unhandledParameters
+                                                               .get("theme"))[0];
+                                       }
+                               }
+                       
+                               // Handles the URI if the application is still running
+                               if (application.isRunning())
+                                       download = handleURI(application, request, response);
+
+                               // If this is not a download request
+                               if (download == null) {
+
+                                       // Window renders are not cacheable
+                                       response.setHeader("Cache-Control", "no-cache");
+                                       response.setHeader("Pragma", "no-cache");
+                                       response.setDateHeader("Expires", 0);
+
+                                       // Finds the window within the application
+                                       Window window = null;
+                                       if (application.isRunning())
+                                               window = getApplicationWindow(request, application,
+                                                               unhandledParameters);
+
+                                       // Handles the unhandled parameters if the application is
+                                       // still running
+                                       if (window != null && unhandledParameters != null
+                                                       && !unhandledParameters.isEmpty()) {
+                                               try {
+                                                       window.handleParameters(unhandledParameters);
+                                               } catch (Throwable t) {
+                                                       application
+                                                                       .terminalError(new ParameterHandlerErrorImpl(
+                                                                                       window, t));
+                                               }
+                                       }
+
+                                       // Removes application if it has stopped
+                                       if (!application.isRunning()) {
+                                               endApplication(request, response, application);
+                                               return;
+                                       }
+
+                                       // Returns blank page, if no window found
+                                       if (window == null) {
+                                               response.setContentType("text/html");
+                                               BufferedWriter page = new BufferedWriter(
+                                                               new OutputStreamWriter(out));
+                                               page.write("<html><head><script>");
+                                               // WAS GENERATE WINDOW SCRIPT
+                                               page.write("</script></head><body>");
+                                               page
+                                                               .write("The requested window has been removed from application.");
+                                               page.write("</body></html>");
+                                               page.close();
+
+                                               return;
+                                       }
+
+                                       // Sets terminal type for the window, if not already set
+                                       if (window.getTerminal() == null) {
+                                               window.setTerminal(wb);
+                                       }
+
+                                       // Finds theme
+                                       String themeName = window.getTheme() != null ? window
+                                                       .getTheme() : DEFAULT_THEME;
+                                       if (unhandledParameters.get("theme") != null) {
+                                               themeName = (String) ((Object[]) unhandledParameters
+                                                               .get("theme"))[0];
+                                       }
+                                       
+                                                                               // Handles resource requests
+                                       if (handleResourceRequest(request, response, themeName))
+                                               return;
+
+                                       
+                                               writeAjaxPage(request, response, out,
+                                                               unhandledParameters, window, wb, themeName);
+                               }
+                       }
+
+                       // For normal requests, transform the window
+                       if (download != null) 
+
+                               handleDownload(download, request, response);
+               
+
+
+               } catch (Throwable e) {
+                       // Print stacktrace
+                       e.printStackTrace();
+                       // Re-throw other exceptions
+                       throw new ServletException(e);
+               } finally {
+
+                       // Notifies transaction end
+                       if (application != null)
+                               ((WebApplicationContext) application.getContext())
+                                               .endTransaction(application, request);
+               }
+       }
+
+       /**
+        * 
+        * @param request
+        *            the HTTP request.
+        * @param response
+        *            the HTTP response to write to.
+        * @param out
+        * @param unhandledParameters
+        * @param window
+        * @param terminalType
+        * @param theme
+        * @throws IOException
+        *             if the writing failed due to input/output error.
+        * @throws MalformedURLException
+        *             if the application is denied access the persistent data store
+        *             represented by the given URL.
+        */
+       private void writeAjaxPage(HttpServletRequest request,
+                       HttpServletResponse response, OutputStream out,
+                       Map unhandledParameters, Window window, WebBrowser terminalType, String themeName) throws IOException, MalformedURLException {
+               response.setContentType("text/html");
+               BufferedWriter page = new BufferedWriter(new OutputStreamWriter(out));
+
+               page
+                               .write("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" "
+                                               + "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n");
+
+               
+               
+               page.write("<html>\n<head>\n<title>IT Mill Toolkit 5</title>\n" +
+                               "<meta name='gwt:module' content='../com.itmill.toolkit.terminal.gwt.Client=com.itmill.toolkit.terminal.gwt.Client'>\n" +
+                               "<script type=\"text/javascript\">\n" +
+                               "       var itmtk = {\n" +
+                               "               appUri:'");
+               
+               String[] urlParts = getApplicationUrl(request).toString().split("\\/");
+               String appUrl = "";
+               // don't use server and port in uri. It may cause problems with some
+               // virtual server configurations which lose the server name
+               for (int i = 3; i < urlParts.length; i++)
+                       appUrl += "/" + urlParts[i];
+               if (appUrl.endsWith("/"))
+                       appUrl = appUrl.substring(0, appUrl.length() - 1);
+               
+               page.write(appUrl);
+               
+               page.write("'\n};\n" +
+                               "</script>\n" +
+                               "<link REL=\"stylesheet\" TYPE=\"text/css\" HREF=\""+request.getContextPath() + THEME_DIRECTORY_PATH+themeName+"/style.css\">" + 
+                               "</head>\n<body>\n<script language=\"javascript\" src=\"/tk/com.itmill.toolkit.terminal.gwt.Client/gwt.js\"></script>\n" +
+                               "       <iframe id=\"__gwt_historyFrame\" style=\"width:0;height:0;border:0\"></iframe>\n" +
+                               "       <div id=\"itmtk-ajax-window\"></div>" +
+                               "       <div id=\"itmtk-loki\" style=\"width: 100%; position: absolute; left: 0px; bottom: 0; height: 0px; border-top: 1px solid gray; background-color: #f6f6f6; overflow: scroll; font-size: x-small;color:red !important;\"" +
+                               "></div>\n" +
+                               "<div id='itm-loki-exp' style='right: 0; bottom: 0px; position: absolute; padding-left: 5px; padding-right: 5px; border-left: 1px solid gray; border-top: 1px solid gray; background-color: #f6f6f6;' onclick='itm_loki_exp()'>console</div><script language='JavaScript'>itm_loki_exp = function() {var l=document.getElementById('itmtk-loki'); var e=document.getElementById('itm-loki-exp'); if (e.style.bottom=='400px') {e.style.bottom='0px'; l.style.height='0px'; e.innerHTML='console';} else {e.style.bottom='400px'; l.style.height='400px'; e.innerHTML='-';}}</script>"+
+                               "       <div style=\"position: absolute; right: 5px; top: 5px; color: gray;\"><strong>IT Mill Toolkit 5 Prototype</strong></div>\n" + 
+                               "       </body>\n" + 
+                               "</html>\n");
+               
+               
+               
+//             Theme t = theme;
+//             Vector themes = new Vector();
+//             themes.add(t);
+//             while (t.getParent() != null) {
+//                     String parentName = t.getParent();
+//                     t = themeSource.getThemeByName(parentName);
+//                     themes.add(t);
+//             }
+//             for (int k = themes.size() - 1; k >= 0; k--) {
+//                     t = (Theme) themes.get(k);
+//                     Collection files = t.getFileNames(terminalType, Theme.MODE_AJAX);
+//                     for (Iterator i = files.iterator(); i.hasNext();) {
+//                             String file = (String) i.next();
+//                             if (file.endsWith(".css"))
+//                                     page.write("<link rel=\"stylesheet\" href=\""
+//                                                     + getResourceLocation(t.getName(),
+//                                                                     new ThemeResource(file))
+//                                                     + "\" type=\"text/css\" />\n");
+//                             else if (file.endsWith(".js")) {
+//                                     page.write("<script src=\"");
+//
+//                                     // TODO remove this and implement behaviour in themes
+//                                     // description.xml files
+//                                     if (file.endsWith("firebug.js")
+//                                                     && !isDebugMode(unhandledParameters)) {
+//                                             file = file.replaceFirst("bug.js", "bugx.js");
+//                                     }
+//                                     page.write(getResourceLocation(t.getName(),
+//                                                     new ThemeResource(file)));
+//                                     page.write("\" type=\"text/javascript\"></script>\n");
+//                             }
+//                     }
+//
+//             }
+
+
+//             page.write("itmill.tmp = new itmill.Client("
+//                             + "document.getElementById('ajax-window')," + "\"" + appUrl
+//                             + "/UIDL/" + "\",\"" + resourcePath
+//                             + ((Theme) themes.get(themes.size() - 1)).getName() + "/"
+//
+//                             + "client/\",document.getElementById('ajax-wait'));\n");
+
+               // TODO Only current theme is registered to the client
+               // for (int k = themes.size() - 1; k >= 0; k--) {
+               // t = (Theme) themes.get(k);
+//             t = theme;
+//             String themeObjName = "itmill.themes."
+//                             + t.getName().substring(0, 1).toUpperCase()
+//                             + t.getName().substring(1);
+//             page.write(" (new " + themeObjName + "(\"" + resourcePath + t.getName()
+//                             + "/\")).registerTo(itmill.tmp);\n");
+               // }
+
+               page.close();
+       }
+
+       /**
+        * Handles the requested URI. An application can add handlers to do special
+        * processing, when a certain URI is requested. The handlers are invoked
+        * before any windows URIs are processed and if a DownloadStream is returned
+        * it is sent to the client.
+        * 
+        * @param application
+        *            the Application owning the URI.
+        * @param request
+        *            the HTTP request instance.
+        * @param response
+        *            the HTTP response to write to.
+        * @return boolean <code>true</code> if the request was handled and
+        *         further processing should be suppressed, <code>false</code>
+        *         otherwise.
+        * @see com.itmill.toolkit.terminal.URIHandler
+        */
+       private DownloadStream handleURI(Application application,
+                       HttpServletRequest request, HttpServletResponse response) {
+
+               String uri = request.getPathInfo();
+
+               // If no URI is available
+               if (uri == null || uri.length() == 0 || uri.equals("/"))
+                       return null;
+
+               // Removes the leading /
+               while (uri.startsWith("/") && uri.length() > 0)
+                       uri = uri.substring(1);
+
+               // Handles the uri
+               DownloadStream stream = null;
+               try {
+                       stream = application.handleURI(application.getURL(), uri);
+               } catch (Throwable t) {
+                       application.terminalError(new URIHandlerErrorImpl(application, t));
+               }
+
+               return stream;
+       }
+
+       /**
+        * Handles the requested URI. An application can add handlers to do special
+        * processing, when a certain URI is requested. The handlers are invoked
+        * before any windows URIs are processed and if a DownloadStream is returned
+        * it is sent to the client.
+        * 
+        * @param stream
+        *            the download stream.
+        * 
+        * @param request
+        *            the HTTP request instance.
+        * @param response
+        *            the HTTP response to write to.
+        * 
+        * @see com.itmill.toolkit.terminal.URIHandler
+        */
+       private void handleDownload(DownloadStream stream,
+                       HttpServletRequest request, HttpServletResponse response) {
+
+               // Download from given stream
+               InputStream data = stream.getStream();
+               if (data != null) {
+
+                       // Sets content type
+                       response.setContentType(stream.getContentType());
+
+                       // Sets cache headers
+                       long cacheTime = stream.getCacheTime();
+                       if (cacheTime <= 0) {
+                               response.setHeader("Cache-Control", "no-cache");
+                               response.setHeader("Pragma", "no-cache");
+                               response.setDateHeader("Expires", 0);
+                       } else {
+                               response.setHeader("Cache-Control", "max-age=" + cacheTime
+                                               / 1000);
+                               response.setDateHeader("Expires", System.currentTimeMillis()
+                                               + cacheTime);
+                               response.setHeader("Pragma", "cache"); // Required to apply
+                               // caching in some
+                               // Tomcats
+                       }
+
+                       // Copy download stream parameters directly
+                       // to HTTP headers.
+                       Iterator i = stream.getParameterNames();
+                       if (i != null) {
+                               while (i.hasNext()) {
+                                       String param = (String) i.next();
+                                       response.setHeader((String) param, stream
+                                                       .getParameter(param));
+                               }
+                       }
+
+                       int bufferSize = stream.getBufferSize();
+                       if (bufferSize <= 0 || bufferSize > MAX_BUFFER_SIZE)
+                               bufferSize = DEFAULT_BUFFER_SIZE;
+                       byte[] buffer = new byte[bufferSize];
+                       int bytesRead = 0;
+
+                       try {
+                               OutputStream out = response.getOutputStream();
+
+                               while ((bytesRead = data.read(buffer)) > 0) {
+                                       out.write(buffer, 0, bytesRead);
+                                       out.flush();
+                               }
+                               out.close();
+                       } catch (IOException ignored) {
+                       }
+
+               }
+
+       }
+       
+       /**
+        * Handles theme resource file requests. Resources supplied with the themes
+        * are provided by the WebAdapterServlet.
+        * 
+        * @param request
+        *            the HTTP request.
+        * @param response
+        *            the HTTP response.
+        * @return boolean <code>true</code> if the request was handled and
+        *         further processing should be suppressed, <code>false</code>
+        *         otherwise.
+        * @throws ServletException
+        *             if an exception has occurred that interferes with the
+        *             servlet's normal operation.
+        */
+       private boolean handleResourceRequest(HttpServletRequest request,
+                       HttpServletResponse response, String themeName) throws ServletException {
+
+               // If the resource path is unassigned, initialize it
+               if (resourcePath == null) {
+                       resourcePath = request.getContextPath() + request.getServletPath()
+                                       + RESOURCE_URI;
+                       // WebSphere Application Server related fix
+                       resourcePath = resourcePath.replaceAll("//", "/");
+               }
+
+               String resourceId = request.getPathInfo();
+
+               // Checks if this really is a resource request
+               if (resourceId == null || !resourceId.startsWith(RESOURCE_URI))
+                       return false;
+
+               // Checks the resource type
+               resourceId = resourceId.substring(RESOURCE_URI.length());
+               InputStream data = null;
+               
+               // Gets theme resources
+               try {
+                       data = getServletContext().getResourceAsStream(THEME_DIRECTORY_PATH + themeName + "/" + resourceId);
+               } catch (Exception e) {
+                       Log.info(e.getMessage());
+                       data = null;
+               }
+
+               // Writes the response
+               try {
+                       if (data != null) {
+                               response.setContentType(FileTypeResolver
+                                               .getMIMEType(resourceId));
+
+                               // Use default cache time for theme resources
+                                       response.setHeader("Cache-Control", "max-age="
+                                                       + DEFAULT_THEME_CACHETIME / 1000);
+                                       response.setDateHeader("Expires", System
+                                                       .currentTimeMillis()
+                                                       + DEFAULT_THEME_CACHETIME);
+                                       response.setHeader("Pragma", "cache"); // Required to apply
+                                       // caching in some
+                                       // Tomcats
+               
+                               // Writes the data to client
+                               byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
+                               int bytesRead = 0;
+                               OutputStream out = response.getOutputStream();
+                               while ((bytesRead = data.read(buffer)) > 0) {
+                                       out.write(buffer, 0, bytesRead);
+                               }
+                               out.close();
+                               data.close();
+                       } else {
+                               response.sendError(HttpServletResponse.SC_NOT_FOUND);
+                       }
+
+               } catch (java.io.IOException e) {
+                       Log.info("Resource transfer failed:  " + request.getRequestURI()
+                                       + ". (" + e.getMessage() + ")");
+               }
+
+               return true;
+       }
+
+       /**
+        * Gets the variable map for the session.
+        * 
+        * @param application
+        * @param request
+        *            the HTTP request.
+        * @return the variable map.
+        * 
+        */
+       private static synchronized HttpVariableMap getVariableMap(
+                       Application application, HttpServletRequest request) {
+
+               HttpSession session = request.getSession();
+
+               // Gets the application to variablemap map
+               Map varMapMap = (Map) session.getAttribute(SESSION_ATTR_VARMAP);
+               if (varMapMap == null) {
+                       varMapMap = new WeakHashMap();
+                       session.setAttribute(SESSION_ATTR_VARMAP, varMapMap);
+               }
+
+               // Creates a variable map, if it does not exists.
+               HttpVariableMap variableMap = (HttpVariableMap) varMapMap
+                               .get(application);
+               if (variableMap == null) {
+                       variableMap = new HttpVariableMap();
+                       varMapMap.put(application, variableMap);
+               }
+
+               return variableMap;
+       }
+
+       /**
+        * Gets the current application URL from request.
+        * 
+        * @param request
+        *            the HTTP request.
+        * @throws MalformedURLException
+        *             if the application is denied access to the persistent data
+        *             store represented by the given URL.
+        */
+       private URL getApplicationUrl(HttpServletRequest request)
+                       throws MalformedURLException {
+
+               URL applicationUrl;
+               try {
+                       URL reqURL = new URL(
+                                       (request.isSecure() ? "https://" : "http://")
+                                                       + request.getServerName()
+                                                       + ((request.isSecure() && request.getServerPort() == 443)
+                                                                       || (!request.isSecure() && request
+                                                                                       .getServerPort() == 80) ? "" : ":"
+                                                                       + request.getServerPort())
+                                                       + request.getRequestURI());
+                       String servletPath = request.getContextPath()
+                                       + request.getServletPath();
+                       if (servletPath.length() == 0
+                                       || servletPath.charAt(servletPath.length() - 1) != '/')
+                               servletPath = servletPath + "/";
+                       applicationUrl = new URL(reqURL, servletPath);
+               } catch (MalformedURLException e) {
+                       Log.error("Error constructing application url "
+                                       + request.getRequestURI() + " (" + e + ")");
+                       throw e;
+               }
+
+               return applicationUrl;
+       }
+
+       /**
+        * Gets the existing application for given request. Looks for application
+        * instance for given request based on the requested URL.
+        * 
+        * @param request
+        *            the HTTP request.
+        * @return Application instance, or null if the URL does not map to valid
+        *         application.
+        * @throws MalformedURLException
+        *             if the application is denied access to the persistent data
+        *             store represented by the given URL.
+        */
+       private Application getApplication(HttpServletRequest request)
+                       throws MalformedURLException {
+
+               // Ensures that the session is still valid
+               HttpSession session = request.getSession(false);
+               if (session == null)
+                       return null;
+
+               // Gets application list for the session.
+               LinkedList applications = (LinkedList) session
+                               .getAttribute(SESSION_ATTR_APPS);
+               if (applications == null)
+                       return null;
+
+               // Search for the application (using the application URI) from the list
+               Application application = null;
+               for (Iterator i = applications.iterator(); i.hasNext()
+                               && application == null;) {
+                       Application a = (Application) i.next();
+                       String aPath = a.getURL().getPath();
+                       String servletPath = request.getContextPath()
+                                       + request.getServletPath();
+                       if (servletPath.length() < aPath.length())
+                               servletPath += "/";
+                       if (servletPath.equals(aPath))
+                               application = a;
+               }
+
+               // Removes stopped applications from the list
+               if (application != null && !application.isRunning()) {
+                       applications.remove(application);
+                       application = null;
+               }
+
+               return application;
+       }
+
+       /**
+        * Creates a new application.
+        * 
+        * @param request
+        *            the HTTP request.
+        * @return the New application instance.
+        * @throws MalformedURLException
+        *             if the application is denied access to the persistent data
+        *             store represented by the given URL.
+        * @throws InstantiationException
+        *             if a new instance of the class cannot be instantiated.
+        * @throws IllegalAccessException
+        *             if it does not have access to the property accessor method.
+        * @throws LicenseFileHasNotBeenRead
+        *             if the license file has not been read.
+        * @throws LicenseSignatureIsInvalid
+        *             if the license file has been changed or signature is
+        *             otherwise invalid.
+        * @throws InvalidLicenseFile
+        *             if the license file is not of correct XML format.
+        * @throws LicenseViolation
+        * 
+        * @throws SAXException
+        *             the Error parsing the license file.
+        */
+       private Application createApplication(HttpServletRequest request)
+                       throws MalformedURLException, InstantiationException,
+                       IllegalAccessException, LicenseFileHasNotBeenRead,
+                       LicenseSignatureIsInvalid, InvalidLicenseFile, LicenseViolation,
+                       SAXException {
+
+               Application application = null;
+
+               // Gets the application url
+               URL applicationUrl = getApplicationUrl(request);
+
+               // Gets application list.
+               HttpSession session = request.getSession();
+               if (session == null)
+                       return null;
+               LinkedList applications = (LinkedList) session
+                               .getAttribute(SESSION_ATTR_APPS);
+               if (applications == null) {
+                       applications = new LinkedList();
+                       session.setAttribute(SESSION_ATTR_APPS, applications);
+                       HttpSessionBindingListener sessionBindingListener = new SessionBindingListener(
+                                       applications);
+                       session.setAttribute(SESSION_BINDING_LISTENER,
+                                       sessionBindingListener);
+               }
+
+               // Creates new application and start it
+               try {
+                       application = (Application) this.applicationClass.newInstance();
+                       applications.add(application);
+
+                       // Sets locale
+                       application.setLocale(request.getLocale());
+
+                       // Gets application context for this session
+                       WebApplicationContext context = (WebApplicationContext) session
+                                       .getAttribute(SESSION_ATTR_CONTEXT);
+                       if (context == null) {
+                               context = new WebApplicationContext(session);
+                               session.setAttribute(SESSION_ATTR_CONTEXT, context);
+                       }
+
+                       // Starts application and check license
+                       initializeLicense(application);
+                       application.start(applicationUrl, this.applicationProperties,
+                                       context);
+                       checkLicense(application);
+
+               } catch (IllegalAccessException e) {
+                       Log.error("Illegal access to application class "
+                                       + this.applicationClass.getName());
+                       throw e;
+               } catch (InstantiationException e) {
+                       Log.error("Failed to instantiate application class: "
+                                       + this.applicationClass.getName());
+                       throw e;
+               }
+
+               return application;
+       }
+
+       /**
+        * 
+        * @param application
+        */
+       private void initializeLicense(Application application) {
+               License license;
+               synchronized (licenseForApplicationClass) {
+                       license = (License) licenseForApplicationClass.get(application
+                                       .getClass());
+                       if (license == null) {
+                               license = new License();
+                               licenseForApplicationClass.put(application.getClass(), license);
+                       }
+               }
+               application.setToolkitLicense(license);
+       }
+
+       /**
+        * 
+        * @param application
+        * @throws LicenseFileHasNotBeenRead
+        *             if the license file has not been read.
+        * @throws LicenseSignatureIsInvalid
+        *             if the license file has been changed or signature is
+        *             otherwise invalid.
+        * @throws InvalidLicenseFile
+        *             if the license file is not of correct XML format.
+        * @throws LicenseViolation
+        * 
+        * @throws SAXException
+        *             the Error parsing the license file.
+        */
+       private void checkLicense(Application application)
+                       throws LicenseFileHasNotBeenRead, LicenseSignatureIsInvalid,
+                       InvalidLicenseFile, LicenseViolation, SAXException {
+               License license = application.getToolkitLicense();
+
+               if (!license.hasBeenRead())
+                       // Lock threads that have not yet read license
+                       synchronized (license) {
+                               if (!license.hasBeenRead()) {
+                                       InputStream lis;
+                                       try {
+                                               URL url = getServletContext().getResource(
+                                                               "/WEB-INF/itmill-toolkit-license.xml");
+                                               if (url == null) {
+                                                       throw new RuntimeException(
+                                                                       "License file could not be read. "
+                                                                                       + "You can install it to "
+                                                                                       + "WEB-INF/itmill-toolkit-license.xml.");
+                                               }
+                                               lis = url.openStream();
+                                               license.readLicenseFile(lis);
+                                       } catch (MalformedURLException e) {
+                                               // This should not happen
+                                               throw new RuntimeException(e);
+                                       } catch (IOException e) {
+                                               // This should not happen
+                                               throw new RuntimeException(e);
+                                       }
+
+                                       // For each application class, print license description -
+                                       // once
+                                       if (!licensePrintedForApplicationClass
+                                                       .containsKey(applicationClass)) {
+                                               licensePrintedForApplicationClass.put(applicationClass,
+                                                               Boolean.TRUE);
+                                               if (license.shouldLimitsBePrintedOnInit()) {
+                                                       System.out.println(license
+                                                                       .getDescription(application.getClass()
+                                                                                       .toString()));
+                                               }
+                                       }
+
+                                       // Checks license validity
+                                       try {
+                                               license.check(applicationClass, VERSION_MAJOR,
+                                                               VERSION_MINOR, "IT Mill Toolkit", null);
+                                       } catch (LicenseFileHasNotBeenRead e) {
+                                               application.close();
+                                               throw e;
+                                       } catch (LicenseSignatureIsInvalid e) {
+                                               application.close();
+                                               throw e;
+                                       } catch (InvalidLicenseFile e) {
+                                               application.close();
+                                               throw e;
+                                       } catch (LicenseViolation e) {
+                                               application.close();
+                                               throw e;
+                                       }
+                               }
+                       }
+
+               // Checks concurrent user limit
+               try {
+                       license.checkConcurrentUsers(getNumberOfActiveUsers() + 1);
+               } catch (LicenseViolation e) {
+                       application.close();
+                       throw e;
+               }
+       }
+
+       /**
+        * Gets the number of active application-user pairs.
+        * 
+        * This returns total number of all applications in the server that are
+        * considered to be active. For an application to be active, it must have
+        * been accessed less than ACTIVE_USER_REQUEST_INTERVAL ms.
+        * 
+        * @return the Number of active application instances in the server.
+        */
+       private int getNumberOfActiveUsers() {
+               int active = 0;
+
+               synchronized (applicationToLastRequestDate) {
+                       Set apps = applicationToLastRequestDate.keySet();
+                       long now = System.currentTimeMillis();
+                       for (Iterator i = apps.iterator(); i.hasNext();) {
+                               Date lastReq = (Date) applicationToLastRequestDate
+                                               .get(i.next());
+                               if (now - lastReq.getTime() < ACTIVE_USER_REQUEST_INTERVAL)
+                                       active++;
+                       }
+               }
+
+               return active;
+       }
+
+       /**
+        * Ends the application.
+        * 
+        * @param request
+        *            the HTTP request.
+        * @param response
+        *            the HTTP response to write to.
+        * @param application
+        *            the application to end.
+        * @throws IOException
+        *             if the writing failed due to input/output error.
+        */
+       private void endApplication(HttpServletRequest request,
+                       HttpServletResponse response, Application application)
+                       throws IOException {
+
+               String logoutUrl = application.getLogoutURL();
+               if (logoutUrl == null)
+                       logoutUrl = application.getURL().toString();
+
+               HttpSession session = request.getSession();
+               if (session != null) {
+                       LinkedList applications = (LinkedList) session
+                                       .getAttribute(SESSION_ATTR_APPS);
+                       if (applications != null)
+                               applications.remove(application);
+               }
+
+               response.sendRedirect(response.encodeRedirectURL(logoutUrl));
+       }
+
+       /**
+        * Gets the existing application or create a new one. Get a window within an
+        * application based on the requested URI.
+        * 
+        * @param request
+        *            the HTTP Request.
+        * @param application
+        *            the Application to query for window.
+        * @return Window mathing the given URI or null if not found.
+        * @throws ServletException
+        *             if an exception has occurred that interferes with the
+        *             servlet's normal operation.
+        */
+       private Window getApplicationWindow(HttpServletRequest request,
+                       Application application, Map params) throws ServletException {
+
+               Window window = null;
+
+               // Finds the window where the request is handled
+               String path = request.getPathInfo();
+
+               // Main window as the URI is empty
+               if (path == null || path.length() == 0 || path.equals("/"))
+                       window = application.getMainWindow();
+
+               // Try to search by window name
+               else {
+                       String windowName = null;
+                       if (path.charAt(0) == '/')
+                               path = path.substring(1);
+                       int index = path.indexOf('/');
+                       if (index < 0) {
+                               windowName = path;
+                               path = "";
+                       } else {
+                               windowName = path.substring(0, index);
+                               path = path.substring(index + 1);
+                       }
+                       window = application.getWindow(windowName);
+
+                       if (window == null) {
+                               // By default, we use main window
+                               window = application.getMainWindow();
+                       } else if (!window.isVisible()) {
+                               // Implicitly painting without actually invoking paint()
+                               window.requestRepaintRequests();
+
+                               // If the window is invisible send a blank page
+                               return null;
+                       }
+               }
+
+               return window;
+       }
+
+       /**
+        * Gets relative location of a theme resource.
+        * 
+        * @param theme
+        *            the Theme name.
+        * @param resource
+        *            the Theme resource.
+        * @return External URI specifying the resource
+        */
+       public String getResourceLocation(String theme, ThemeResource resource) {
+
+               if (resourcePath == null)
+                       return resource.getResourceId();
+               return resourcePath + theme + "/" + resource.getResourceId();
+       }
+
+       /**
+        * Checks if web adapter is in debug mode. Extra output is generated to log
+        * when debug mode is enabled.
+        * 
+        * @param parameters
+        * @return <code>true</code> if the web adapter is in debug mode.
+        *         otherwise <code>false</code>.
+        */
+       public boolean isDebugMode(Map parameters) {
+               if (parameters != null) {
+                       Object[] debug = (Object[]) parameters.get("debug");
+                       if (debug != null && !"false".equals(debug[0].toString())
+                                       && !"false".equals(debugMode))
+                               return true;
+               }
+               return "true".equals(debugMode);
+       }
+
+       /**
+        * 
+        * SessionBindingListener performs Application cleanups after sessions are
+        * expired. For each session exists one SessionBindingListener. It contains
+        * references to all applications related to single session.
+        * 
+        * @author IT Mill Ltd.
+        * @version
+        * @VERSION@
+        * @since 4.0
+        */
+
+       private class SessionBindingListener implements HttpSessionBindingListener {
+               private LinkedList applications;
+
+               /**
+                * 
+                * @param applications
+                */
+               protected SessionBindingListener(LinkedList applications) {
+                       this.applications = applications;
+               }
+
+               /**
+                * @see javax.servlet.http.HttpSessionBindingListener#valueBound(HttpSessionBindingEvent)
+                */
+               public void valueBound(HttpSessionBindingEvent arg0) {
+                       // We are not interested in bindings
+               }
+
+               /**
+                * @see javax.servlet.http.HttpSessionBindingListener#valueUnbound(HttpSessionBindingEvent)
+                */
+               public void valueUnbound(HttpSessionBindingEvent event) {
+                       // If the binding listener is unbound from the session, the
+                       // session must be closing
+                       if (event.getName().equals(SESSION_BINDING_LISTENER)) {
+                               // Close all applications related to given session
+                               Object[] apps = applications.toArray();
+                               for (int i = 0; i < apps.length; i++) {
+                                       if (apps[i] != null) {
+                                               // Close application
+                                               ((Application) apps[i]).close();
+
+                                               synchronized (applicationToLastRequestDate) {
+                                                       applicationToLastRequestDate.remove(apps[i]);
+                                               }
+                                               synchronized (applicationToAjaxAppMgrMap) {
+                                                       applicationToAjaxAppMgrMap.remove(apps[i]);
+                                               }
+                                               // Remove application from applications list
+                                               applications.remove(apps[i]);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Implementation of ParameterHandler.ErrorEvent interface.
+        */
+       public class ParameterHandlerErrorImpl implements
+                       ParameterHandler.ErrorEvent {
+
+               private ParameterHandler owner;
+
+               private Throwable throwable;
+
+               /**
+                * 
+                * @param owner
+                * @param throwable
+                */
+               private ParameterHandlerErrorImpl(ParameterHandler owner,
+                               Throwable throwable) {
+                       this.owner = owner;
+                       this.throwable = throwable;
+               }
+
+               /**
+                * Gets the contained throwable.
+                * 
+                * @see com.itmill.toolkit.terminal.Terminal.ErrorEvent#getThrowable()
+                */
+               public Throwable getThrowable() {
+                       return this.throwable;
+               }
+
+               /**
+                * Gets the source ParameterHandler.
+                * 
+                * @see com.itmill.toolkit.terminal.ParameterHandler.ErrorEvent#getParameterHandler()
+                */
+               public ParameterHandler getParameterHandler() {
+                       return this.owner;
+               }
+
+       }
+
+       /**
+        * Implementation of URIHandler.ErrorEvent interface.
+        */
+       public class URIHandlerErrorImpl implements URIHandler.ErrorEvent {
+
+               private URIHandler owner;
+
+               private Throwable throwable;
+
+               /**
+                * 
+                * @param owner
+                * @param throwable
+                */
+               private URIHandlerErrorImpl(URIHandler owner, Throwable throwable) {
+                       this.owner = owner;
+                       this.throwable = throwable;
+               }
+
+               /**
+                * Gets the contained throwable.
+                * 
+                * @see com.itmill.toolkit.terminal.Terminal.ErrorEvent#getThrowable()
+                */
+               public Throwable getThrowable() {
+                       return this.throwable;
+               }
+
+               /**
+                * Gets the source URIHandler.
+                * 
+                * @see com.itmill.toolkit.terminal.URIHandler.ErrorEvent#getURIHandler()
+                */
+               public URIHandler getURIHandler() {
+                       return this.owner;
+               }
+       }
+
+       /**
+        * Gets AJAX application manager for an application.
+        * 
+        * If this application has not been running in ajax mode before, new manager
+        * is created and web adapter stops listening to changes.
+        * 
+        * @param application
+        * @return AJAX Application Manager
+        */
+       private ApplicationManager getApplicationManager(Application application) {
+               ApplicationManager mgr = (ApplicationManager) applicationToAjaxAppMgrMap
+                               .get(application);
+
+               // This application is going from Web to AJAX mode, create new manager
+               if (mgr == null) {
+                       // Creates new manager
+                       mgr = new ApplicationManager(application, this);
+                       applicationToAjaxAppMgrMap.put(application, mgr);
+
+                       // Manager takes control over the application
+                       mgr.takeControl();
+               }
+
+               return mgr;
+       }
+
+       /**
+        * Gets resource path using different implementations. Required fo
+        * supporting different servlet container implementations (application
+        * servers).
+        * 
+        * @param servletContext
+        * @param path
+        *            the resource path.
+        * @return the resource path.
+        */
+       protected static String getResourcePath(ServletContext servletContext,
+                       String path) {
+               String resultPath = null;
+               resultPath = servletContext.getRealPath(path);
+               if (resultPath != null) {
+                       return resultPath;
+               } else {
+                       try {
+                               URL url = servletContext.getResource(path);
+                               resultPath = url.getFile();
+                       } catch (Exception e) {
+                               // ignored
+                       }
+               }
+               return resultPath;
+       }
+
+}
\ No newline at end of file
diff --git a/src/com/itmill/toolkit/terminal/gwt/server/HttpUploadStream.java b/src/com/itmill/toolkit/terminal/gwt/server/HttpUploadStream.java
new file mode 100644 (file)
index 0000000..b92fb9d
--- /dev/null
@@ -0,0 +1,114 @@
+/* *************************************************************************
+ 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.gwt.server;
+
+import java.io.InputStream;
+
+/**
+ * WebAdapter implementation of the UploadStream interface.
+ * 
+ * @author IT Mill Ltd.
+ * @version
+ * @VERSION@
+ * @since 3.0
+ */
+public class HttpUploadStream implements
+               com.itmill.toolkit.terminal.UploadStream {
+
+       /**
+        * Holds value of property variableName.
+        */
+       private String streamName;
+
+       private String contentName;
+
+       private String contentType;
+
+       /**
+        * Holds value of property variableValue.
+        */
+       private InputStream stream;
+
+       /**
+        * Creates a new instance of UploadStreamImpl
+        * 
+        * @param name
+        *            the name of the stream.
+        * @param stream
+        *            the input stream.
+        * @param contentName
+        *            the name of the content.
+        * @param contentType
+        *            the type of the content.
+        */
+       public HttpUploadStream(String name, InputStream stream,
+                       String contentName, String contentType) {
+               this.streamName = name;
+               this.stream = stream;
+               this.contentName = contentName;
+               this.contentType = contentType;
+       }
+
+       /**
+        * Gets the name of the stream.
+        * 
+        * @return the name of the stream.
+        */
+       public String getStreamName() {
+               return this.streamName;
+       }
+
+       /**
+        * Gets the input stream.
+        * 
+        * @return the Input stream.
+        */
+       public InputStream getStream() {
+               return this.stream;
+       }
+
+       /**
+        * Gets the input stream content type.
+        * 
+        * @return the content type of the input stream.
+        */
+       public String getContentType() {
+               return this.contentType;
+       }
+
+       /**
+        * Gets the stream content name. Stream content name usually differs from
+        * the actual stream name. It is used to identify the content of the stream.
+        * 
+        * @return the Name of the stream content.
+        */
+       public String getContentName() {
+               return this.contentName;
+       }
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/server/HttpVariableMap.java b/src/com/itmill/toolkit/terminal/gwt/server/HttpVariableMap.java
new file mode 100644 (file)
index 0000000..5fd4407
--- /dev/null
@@ -0,0 +1,791 @@
+/* *************************************************************************
+ 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.gwt.server;
+
+import com.itmill.toolkit.terminal.SystemError;
+import com.itmill.toolkit.terminal.Terminal;
+import com.itmill.toolkit.terminal.UploadStream;
+import com.itmill.toolkit.terminal.VariableOwner;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.Enumeration;
+import java.util.WeakHashMap;
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.LinkedList;
+import java.util.Iterator;
+
+/**
+ * Class implementing the variable mappings.
+ * 
+ * @author IT Mill Ltd.
+ * @version
+ * @VERSION@
+ * @since 3.0
+ */
+public class HttpVariableMap {
+
+       // Id <-> (Owner,Name) mapping
+       private Map idToNameMap = new HashMap();
+
+       private Map idToTypeMap = new HashMap();
+
+       private Map idToOwnerMap = new HashMap();
+
+       private Map idToValueMap = new HashMap();
+
+       private Map ownerToNameToIdMap = new WeakHashMap();
+
+       private Object mapLock = new Object();
+
+       // Id generator
+       private long lastId = 0;
+
+       /**
+        * Converts the string to a supported class.
+        * 
+        * @param type
+        * @param value
+        * @throws java.lang.ClassCastException
+        */
+       private static Object convert(Class type, String value)
+                       throws java.lang.ClassCastException {
+               try {
+
+                       // Boolean typed variables
+                       if (type.equals(Boolean.class))
+                               return new Boolean(!(value.equals("") || value.equals("false")));
+
+                       // Integer typed variables
+                       if (type.equals(Integer.class))
+                               return new Integer(value.trim());
+
+                       // String typed variables
+                       if (type.equals(String.class))
+                               return value;
+
+                       throw new ClassCastException("Unsupported type: " + type.getName());
+               } catch (NumberFormatException e) {
+                       return null;
+               }
+       }
+
+       /**
+        * Registers a new variable.
+        * 
+        * @param name
+        *            the name of the variable.
+        * @param type
+        * @param value
+        * @param owner
+        *            the Listener for variable changes.
+        * 
+        * @return id to assigned for this variable.
+        */
+       public String registerVariable(String name, Class type, Object value,
+                       VariableOwner owner) {
+
+               // Checks that the type of the class is supported
+               if (!(type.equals(Boolean.class) || type.equals(Integer.class)
+                               || type.equals(String.class) || type.equals(String[].class) || type
+                               .equals(UploadStream.class)))
+                       throw new SystemError("Unsupported variable type: "
+                                       + type.getClass());
+
+               synchronized (mapLock) {
+
+                       // Checks if the variable is already mapped
+                       HashMap nameToIdMap = (HashMap) ownerToNameToIdMap.get(owner);
+                       if (nameToIdMap == null) {
+                               nameToIdMap = new HashMap();
+                               ownerToNameToIdMap.put(owner, nameToIdMap);
+                       }
+                       String id = (String) nameToIdMap.get(name);
+
+                       if (id == null) {
+                               // Generates new id and register it
+                               id = "v" + String.valueOf(++lastId);
+                               nameToIdMap.put(name, id);
+                               idToOwnerMap.put(id, new WeakReference(owner));
+                               idToNameMap.put(id, name);
+                               idToTypeMap.put(id, type);
+                       }
+
+                       idToValueMap.put(id, value);
+
+                       return id;
+               }
+       }
+
+       /**
+        * Unregisters the variable.
+        * 
+        * @param name
+        *            the name of the variable.
+        * @param owner
+        *            the Listener for variable changes.
+        */
+       public void unregisterVariable(String name, VariableOwner owner) {
+
+               synchronized (mapLock) {
+
+                       // Gets the id
+                       HashMap nameToIdMap = (HashMap) ownerToNameToIdMap.get(owner);
+                       if (nameToIdMap == null)
+                               return;
+                       String id = (String) nameToIdMap.get(name);
+                       if (id != null)
+                               return;
+
+                       // Removes all the mappings
+                       nameToIdMap.remove(name);
+                       if (nameToIdMap.isEmpty())
+                               ownerToNameToIdMap.remove(owner);
+                       idToNameMap.remove(id);
+                       idToTypeMap.remove(id);
+                       idToValueMap.remove(id);
+                       idToOwnerMap.remove(id);
+
+               }
+       }
+
+       /**
+        * @author IT Mill Ltd.
+        * @version
+        * @VERSION@
+        * @since 3.0
+        */
+       private class ParameterContainer {
+
+               /**
+                * Constructs the mapping: listener to set of listened parameter names.
+                */
+               private HashMap parameters = new HashMap();
+
+               /**
+                * Parameter values.
+                */
+               private HashMap values = new HashMap();
+
+               /**
+                * Multipart parser used for parsing the request.
+                */
+               private ServletMultipartRequest parser = null;
+
+               /**
+                * Name - Value mapping of parameters that are not variables.
+                */
+               private HashMap nonVariables = new HashMap();
+
+               /**
+                * Creates a new parameter container and parse the parameters from the
+                * request using GET, POST and POST/MULTIPART parsing.
+                * 
+                * @param req
+                *            the HTTP request.
+                * @throws IOException
+                *             if the writing failed due to input/output error.
+                */
+               public ParameterContainer(HttpServletRequest req) throws IOException {
+                       // Parse GET / POST parameters
+                       for (Enumeration e = req.getParameterNames(); e.hasMoreElements();) {
+                               String paramName = (String) e.nextElement();
+                               String[] paramValues = req.getParameterValues(paramName);
+                               addParam(paramName, paramValues);
+                       }
+
+                       // Parse multipart variables
+                       try {
+                               parser = new ServletMultipartRequest(req,
+                                               MultipartRequest.MAX_READ_BYTES);
+                       } catch (IllegalArgumentException ignored) {
+                               parser = null;
+                       }
+
+                       if (parser != null) {
+                               for (Enumeration e = parser.getFileParameterNames(); e
+                                               .hasMoreElements();) {
+                                       String paramName = (String) e.nextElement();
+                                       addParam(paramName, null);
+                               }
+                               for (Enumeration e = parser.getParameterNames(); e
+                                               .hasMoreElements();) {
+                                       String paramName = (String) e.nextElement();
+                                       Enumeration val = parser.getURLParameters(paramName);
+
+                                       // Create a linked list from enumeration to calculate
+                                       // elements
+                                       LinkedList l = new LinkedList();
+                                       while (val.hasMoreElements())
+                                               l.addLast(val.nextElement());
+
+                                       // String array event constructor
+                                       String[] s = new String[l.size()];
+                                       Iterator i = l.iterator();
+                                       for (int j = 0; j < s.length; j++)
+                                               s[j] = (String) i.next();
+
+                                       addParam(paramName, s);
+                               }
+                       }
+
+               }
+
+               /**
+                * Adds the parameter to container.
+                * 
+                * @param name
+                *            the name of the parameter.
+                * @param value
+                */
+               private void addParam(String name, String[] value) {
+
+                       // Support name="set:name=value" value="ignored" notation
+                       if (name.startsWith("set:")) {
+                               int equalsIndex = name.indexOf('=');
+                               value[0] = name.substring(equalsIndex + 1, name.length());
+                               name = name.substring(4, equalsIndex);
+                               String[] curVal = (String[]) values.get(name);
+                               if (curVal != null) {
+                                       String[] newVal = new String[1 + curVal.length];
+                                       newVal[curVal.length] = value[0];
+                                       for (int i = 0; i < curVal.length; i++)
+                                               newVal[i] = curVal[i];
+                                       value = newVal;
+
+                                       // Special case - if the set:-method is used for
+                                       // declaring array of length 2, where either of the
+                                       // following conditions are true:
+                                       // - the both items are the same
+                                       // - the both items have the same length and
+                                       // - the items only differ on last character
+                                       // - second last character is '.'
+                                       // - last char of one string is 'x' and other is 'y'
+                                       // Browser is unporposely modifying the name.
+                                       if (value.length == 2
+                                                       && value[0].length() == value[1].length()) {
+                                               boolean same = true;
+                                               for (int i = 0; i < value[0].length() - 1 && same; i++)
+                                                       if (value[0].charAt(i) != value[1].charAt(i))
+                                                               same = false;
+                                               if (same
+                                                               && ((value[0].charAt(value[0].length() - 1) == 'x' && value[1]
+                                                                               .charAt(value[1].length() - 1) == 'y') || (value[0]
+                                                                               .charAt(value[0].length() - 1) == 'y' && value[1]
+                                                                               .charAt(value[1].length() - 1) == 'x'))) {
+                                                       value = new String[] { value[0].substring(0,
+                                                                       value[1].length() - 2) };
+                                               } else if (same && value[0].equals(value[1]))
+                                                       value = new String[] { value[0] };
+                                       }
+
+                                       // Special case - if the set:-method is used for
+                                       // declaring array of length 3, where all of the
+                                       // following conditions are true:
+                                       // - two last items have the same length
+                                       // - the first item is 2 chars shorter
+                                       // - the longer items only differ on last character
+                                       // - the shortest item is a prefix of the longer ones
+                                       // - second last character of longer ones is '.'
+                                       // - last char of one long string is 'x' and other is 'y'
+                                       // Browser is unporposely modifying the name. (Mozilla,
+                                       // Firefox, ..)
+                                       if (value.length == 3
+                                                       && value[1].length() == value[2].length()
+                                                       && value[0].length() + 2 == value[1].length()) {
+                                               boolean same = true;
+                                               for (int i = 0; i < value[1].length() - 1 && same; i++)
+                                                       if (value[2].charAt(i) != value[1].charAt(i))
+                                                               same = false;
+                                               for (int i = 0; i < value[0].length() && same; i++)
+                                                       if (value[0].charAt(i) != value[1].charAt(i))
+                                                               same = false;
+                                               if (same
+                                                               && (value[2].charAt(value[2].length() - 1) == 'x' && value[1]
+                                                                               .charAt(value[1].length() - 1) == 'y')
+                                                               || (value[2].charAt(value[2].length() - 1) == 'y' && value[1]
+                                                                               .charAt(value[1].length() - 1) == 'x')) {
+                                                       value = new String[] { value[0] };
+                                               }
+                                       }
+
+                               }
+                       }
+
+                       // Support for setting arrays in format
+                       // set-array:name=value1,value2,value3,...
+                       else if (name.startsWith("set-array:")) {
+                               int equalsIndex = name.indexOf('=');
+                               if (equalsIndex < 0)
+                                       return;
+
+                               StringTokenizer commalist = new StringTokenizer(name
+                                               .substring(equalsIndex + 1), ",");
+                               name = name.substring(10, equalsIndex);
+                               String[] curVal = (String[]) values.get(name);
+                               ArrayList elems = new ArrayList();
+
+                               // Adds old values if present.
+                               if (curVal != null) {
+                                       for (int i = 0; i < curVal.length; i++)
+                                               elems.add(curVal[i]);
+                               }
+                               while (commalist.hasMoreTokens()) {
+                                       String token = commalist.nextToken();
+                                       if (token != null && token.length() > 0)
+                                               elems.add(token);
+                               }
+                               value = new String[elems.size()];
+                               for (int i = 0; i < value.length; i++)
+                                       value[i] = (String) elems.get(i);
+
+                       }
+
+                       // Support name="array:name" value="val1,val2,val3" notation
+                       // All the empty elements are ignored
+                       else if (name.startsWith("array:")) {
+
+                               name = name.substring(6);
+                               StringTokenizer commalist = new StringTokenizer(value[0], ",");
+                               String[] curVal = (String[]) values.get(name);
+                               ArrayList elems = new ArrayList();
+
+                               // Adds old values if present.
+                               if (curVal != null) {
+                                       for (int i = 0; i < curVal.length; i++)
+                                               elems.add(curVal[i]);
+                               }
+                               while (commalist.hasMoreTokens()) {
+                                       String token = commalist.nextToken();
+                                       if (token != null && token.length() > 0)
+                                               elems.add(token);
+                               }
+                               value = new String[elems.size()];
+                               for (int i = 0; i < value.length; i++)
+                                       value[i] = (String) elems.get(i);
+                       }
+
+                       // Support declaring variables with name="declare:name"
+                       else if (name.startsWith("declare:")) {
+                               name = name.substring(8);
+                               value = (String[]) values.get(name);
+                               if (value == null)
+                                       value = new String[0];
+                       }
+
+                       // Gets the owner
+                       WeakReference ref = (WeakReference) idToOwnerMap.get(name);
+                       VariableOwner owner = null;
+                       if (ref != null)
+                               owner = (VariableOwner) ref.get();
+
+                       // Adds the parameter to mapping only if they have owners
+                       if (owner != null) {
+                               Set p = (Set) parameters.get(owner);
+                               if (p == null)
+                                       parameters.put(owner, p = new HashSet());
+                               p.add(name);
+                               if (value != null)
+                                       values.put(name, value);
+                       }
+
+                       // If the owner can not be found
+                       else {
+
+                               // If parameter has been mapped before, remove the old owner
+                               // mapping
+                               if (ref != null) {
+
+                                       // The owner has been destroyed, so we remove the mappings
+                                       idToNameMap.remove(name);
+                                       idToOwnerMap.remove(name);
+                                       idToTypeMap.remove(name);
+                                       idToValueMap.remove(name);
+                               }
+
+                               // Adds the parameter to set of non-variables
+                               nonVariables.put(name, value);
+                       }
+
+               }
+
+               /**
+                * Gets the set of all parameters connected to given variable owner.
+                * 
+                * @param owner
+                *            the Listener for variable changes.
+                * @return the set of all parameters connected to variable owner.
+                */
+               public Set getParameters(VariableOwner owner) {
+                       if (owner == null)
+                               return null;
+                       return (Set) parameters.get(owner);
+               }
+
+               /**
+                * Gets the set of all variable owners owning parameters in this
+                * request.
+                * 
+                * @return
+                */
+               public Set getOwners() {
+                       return parameters.keySet();
+               }
+
+               /**
+                * Gets the value of a parameter.
+                * 
+                * @param parameterName
+                *            the name of the parameter.
+                * @return the value of the parameter.
+                */
+               public String[] getValue(String parameterName) {
+                       return (String[]) values.get(parameterName);
+               }
+
+               /**
+                * Gets the servlet multipart parser.
+                * 
+                * @return the parser.
+                */
+               public ServletMultipartRequest getParser() {
+                       return parser;
+               }
+
+               /**
+                * Gets the name - value[] mapping of non variable paramteres.
+                * 
+                * @return
+                */
+               public Map getNonVariables() {
+                       return nonVariables;
+               }
+       }
+
+       /**
+        * Handles all variable changes in this request.
+        * 
+        * @param req
+        *            the Http request to handle.
+        * @param errorListener
+        *            If the list is non null, only the listed listeners are served.
+        *            Otherwise all the listeners are served.
+        * @return Name to Value[] mapping of unhandled variables.
+        * @throws IOException
+        *             if the writing failed due to input/output error.
+        */
+       public Map handleVariables(HttpServletRequest req,
+                       Terminal.ErrorListener errorListener) throws IOException {
+
+               // Gets the parameters
+               ParameterContainer parcon = new ParameterContainer(req);
+
+               // Sorts listeners to dependency order
+               List listeners = getDependencySortedListenerList(parcon.getOwners());
+
+               // Handles all parameters for all listeners
+               while (!listeners.isEmpty()) {
+                       VariableOwner listener = (VariableOwner) listeners.remove(0);
+                       boolean changed = false; // Has any of this owners variabes
+                                                                               // changed
+                       // Handle all parameters for listener
+                       Set params = parcon.getParameters(listener);
+                       if (params != null) { // Name value mapping
+                               Map variables = new HashMap();
+                               for (Iterator pi = params.iterator(); pi.hasNext();) {
+                                       // Gets the name of the parameter
+                                       String param = (String) pi.next();
+                                       // Extracts more information about the parameter
+                                       String varName = (String) idToNameMap.get(param);
+                                       Class varType = (Class) idToTypeMap.get(param);
+                                       Object varOldValue = idToValueMap.get(param);
+                                       if (varName == null || varType == null)
+                                               Log
+                                                               .warn("VariableMap: No variable found for parameter "
+                                                                               + param
+                                                                               + " ("
+                                                                               + varName
+                                                                               + ","
+                                                                               + listener + ")");
+                                       else {
+
+                                               ServletMultipartRequest parser = parcon.getParser();
+
+                                               // Upload events
+                                               if (varType.equals(UploadStream.class)) {
+                                                       if (parser != null
+                                                                       && parser.getFileParameter(param,
+                                                                                       MultipartRequest.FILENAME) != null) {
+                                                               String filename = (String) parser
+                                                                               .getFileParameter(param,
+                                                                                               MultipartRequest.FILENAME);
+                                                               String contentType = (String) parser
+                                                                               .getFileParameter(param,
+                                                                                               MultipartRequest.CONTENT_TYPE);
+                                                               UploadStream upload = new HttpUploadStream(
+                                                                               varName, parser.getFileContents(param),
+                                                                               filename, contentType);
+                                                               variables.put(varName, upload);
+                                                               changed = true;
+                                                       }
+                                               }
+
+                                               // Normal variable change events
+                                               else {
+                                                       // First try to parse the event without multipart
+                                                       String[] values = parcon.getValue(param);
+                                                       if (values != null) {
+
+                                                               if (varType.equals(String[].class)) {
+                                                                       variables.put(varName, values);
+                                                                       changed |= (!Arrays.equals(values,
+                                                                                       (String[]) varOldValue));
+                                                               } else {
+                                                                       try {
+                                                                               if (values.length == 1) {
+                                                                                       Object val = convert(varType,
+                                                                                                       values[0]);
+                                                                                       variables.put(varName, val);
+                                                                                       changed |= ((val == null && varOldValue != null) || (val != null && !val
+                                                                                                       .equals(varOldValue)));
+                                                                               } else if (values.length == 0
+                                                                                               && varType
+                                                                                                               .equals(Boolean.class)) {
+                                                                                       Object val = new Boolean(false);
+                                                                                       variables.put(varName, val);
+                                                                                       changed |= (!val
+                                                                                                       .equals(varOldValue));
+                                                                               } else {
+                                                                                       Log.warn("Empty variable '"
+                                                                                                       + varName + "' of type "
+                                                                                                       + varType.toString());
+                                                                               }
+
+                                                                       } catch (java.lang.ClassCastException e) {
+                                                                               Log
+                                                                                               .except(
+                                                                                                               "WebVariableMap conversion exception",
+                                                                                                               e);
+                                                                               errorListener
+                                                                                               .terminalError(new TerminalErrorImpl(
+                                                                                                               e));
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               // Do the valuechange if the listener is enabled
+                               if (listener.isEnabled() && changed) {
+                                       try {
+                                               listener.changeVariables(req, variables);
+                                       } catch (Throwable t) {
+                                               // Notify the error listener
+                                               errorListener.terminalError(new VariableOwnerErrorImpl(
+                                                               listener, t));
+                                       }
+                               }
+                       }
+               }
+
+               return parcon.getNonVariables();
+       }
+
+       /**
+        * Implementation of VariableOwner.Error interface.
+        */
+       public class TerminalErrorImpl implements Terminal.ErrorEvent {
+               private Throwable throwable;
+
+               /**
+                * 
+                * @param throwable
+                */
+               private TerminalErrorImpl(Throwable throwable) {
+                       this.throwable = throwable;
+               }
+
+               /**
+                * Gets the contained throwable.
+                * 
+                * @see com.itmill.toolkit.terminal.Terminal.ErrorEvent#getThrowable()
+                */
+               public Throwable getThrowable() {
+                       return this.throwable;
+               }
+
+       }
+
+       /**
+        * Implementation of VariableOwner.Error interface.
+        */
+       public class VariableOwnerErrorImpl extends TerminalErrorImpl implements
+                       VariableOwner.ErrorEvent {
+
+               private VariableOwner owner;
+
+               /**
+                * 
+                * @param owner
+                *            the Listener for variable changes.
+                * @param throwable
+                */
+               private VariableOwnerErrorImpl(VariableOwner owner, Throwable throwable) {
+                       super(throwable);
+                       this.owner = owner;
+               }
+
+               /**
+                * Gets the source VariableOwner.
+                * 
+                * @see com.itmill.toolkit.terminal.VariableOwner.ErrorEvent#getVariableOwner()
+                */
+               public VariableOwner getVariableOwner() {
+                       return this.owner;
+               }
+
+       }
+
+       /**
+        * Resolves the VariableOwners needed from the request and sort them to
+        * assure that the dependencies are met (as well as possible).
+        * 
+        * @param listeners
+        * @return List of variable list changers, that are needed for handling all
+        *         the variables in the request
+        */
+       private List getDependencySortedListenerList(Set listeners) {
+
+               LinkedList resultNormal = new LinkedList();
+               LinkedList resultImmediate = new LinkedList();
+
+               // Go trough the listeners and either add them to result or resolve
+               // their dependencies
+               HashMap deepdeps = new HashMap();
+               LinkedList unresolved = new LinkedList();
+               for (Iterator li = listeners.iterator(); li.hasNext();) {
+
+                       VariableOwner listener = (VariableOwner) li.next();
+                       if (listener != null) {
+                               Set dependencies = listener.getDirectDependencies();
+
+                               // The listeners with no dependencies are added to the front of
+                               // the
+                               // list directly
+                               if (dependencies == null || dependencies.isEmpty()) {
+                                       if (listener.isImmediate())
+                                               resultImmediate.addFirst(listener);
+                                       else
+                                               resultNormal.addFirst(listener);
+                               }
+
+                               // Resolve deep dependencies for the listeners with dependencies
+                               // (the listeners will be added to the end of results in correct
+                               // dependency order later). Also the dependencies of all the
+                               // depended listeners are resolved.
+                               else if (deepdeps.get(listener) == null) {
+
+                                       // Set the fifo for unresolved parents to contain only the
+                                       // listener to be resolved
+                                       unresolved.clear();
+                                       unresolved.add(listener);
+
+                                       // Resolve dependencies
+                                       HashSet tmpdeepdeps = new HashSet();
+                                       while (!unresolved.isEmpty()) {
+
+                                               VariableOwner l = (VariableOwner) unresolved
+                                                               .removeFirst();
+                                               if (!tmpdeepdeps.contains(l)) {
+                                                       tmpdeepdeps.add(l);
+                                                       if (deepdeps.containsKey(l)) {
+                                                               tmpdeepdeps.addAll((Set) deepdeps.get(l));
+                                                       } else {
+                                                               Set deps = l.getDirectDependencies();
+                                                               if (deps != null && !deps.isEmpty())
+                                                                       for (Iterator di = deps.iterator(); di
+                                                                                       .hasNext();) {
+                                                                               Object d = di.next();
+                                                                               if (d != null
+                                                                                               && !tmpdeepdeps.contains(d))
+                                                                                       unresolved.addLast(d);
+                                                                       }
+                                                       }
+                                               }
+                                       }
+
+                                       tmpdeepdeps.remove(listener);
+                                       deepdeps.put(listener, tmpdeepdeps);
+                               }
+                       }
+               }
+
+               // Adds the listeners with dependencies in sane order to the result
+               for (Iterator li = deepdeps.keySet().iterator(); li.hasNext();) {
+                       VariableOwner l = (VariableOwner) li.next();
+                       boolean immediate = l.isImmediate();
+
+                       // Adds each listener after the last depended listener already in
+                       // the list
+                       int index = -1;
+                       for (Iterator di = ((Set) deepdeps.get(l)).iterator(); di.hasNext();) {
+                               int k;
+                               Object depended = di.next();
+                               if (immediate) {
+                                       k = resultImmediate.lastIndexOf(depended);
+                               } else {
+                                       k = resultNormal.lastIndexOf(depended);
+                               }
+                               if (k > index)
+                                       index = k;
+                       }
+                       if (immediate) {
+                               resultImmediate.add(index + 1, l);
+                       } else {
+                               resultNormal.add(index + 1, l);
+                       }
+               }
+
+               // Appends immediate listeners to normal listeners
+               // This way the normal handlers are always called before
+               // immediate ones
+               resultNormal.addAll(resultImmediate);
+               return resultNormal;
+       }
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/server/JSONPaintTarget.java b/src/com/itmill/toolkit/terminal/gwt/server/JSONPaintTarget.java
deleted file mode 100644 (file)
index a1a6291..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-package com.itmill.toolkit.terminal.gwt.server;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Stack;
-
-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.VariableOwner;
-
-public class JSONPaintTarget implements PaintTarget {
-
-       Stack tags = new Stack();
-       Tag tag = null;
-
-       public void addAttribute(String name, boolean value) throws PaintException {
-               tag.attrs.put(name, new Boolean(value));
-       }
-
-       public void addAttribute(String name, int value) throws PaintException {
-               tag.attrs.put(name, new Integer(value));
-       }
-
-       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());
-       }
-
-       public void addAttribute(String name, long value) throws PaintException {
-               tag.attrs.put(name, new Long(value));
-       }
-
-       public void addAttribute(String name, String value) throws PaintException {
-               tag.attrs.put(name, value);
-       }
-
-       public void addCharacterData(String text) throws PaintException {
-               if (tag.data != null || tag.xml != null || tag.children.size() > 0)
-                       throw new IllegalStateException("Character data can not be combined with XML or child-nodes");
-               tag.data = text;
-       }
-
-       public void addSection(String sectionTagName, String sectionData)
-                       throws PaintException {
-               Tag t = new Tag(sectionTagName);
-               t.data = sectionData;
-               if (tag.data != null || tag.xml != null)
-                       throw new IllegalStateException("Children can not be combined with XML or chardata");
-               tag.children.add(t);
-       }
-
-       public void addText(String text) throws PaintException {
-               if (tag.data != null || tag.xml != null || tag.children.size() > 0)
-                       throw new IllegalStateException("Text-data can not be combined with XML or child-nodes");
-               tag.data = text;
-       }
-
-       public void addUIDL(String uidl) throws PaintException {
-               if (tag.data != null || tag.xml != null || tag.children.size() > 0)
-                       throw new IllegalStateException("XML can not be combined with text or child-nodes");
-               tag.xml = uidl;
-       }
-
-       public void addUploadStreamVariable(VariableOwner owner, String name)
-                       throws PaintException {
-               // TODO Auto-generated method stub
-
-       }
-
-       public void addVariable(VariableOwner owner, String name, String value)
-                       throws PaintException {
-               // TODO Auto-generated method stub
-
-       }
-
-       public void addVariable(VariableOwner owner, String name, int value)
-                       throws PaintException {
-               // TODO Auto-generated method stub
-
-       }
-
-       public void addVariable(VariableOwner owner, String name, boolean value)
-                       throws PaintException {
-               // TODO Auto-generated method stub
-
-       }
-
-       public void addVariable(VariableOwner owner, String name, String[] value)
-                       throws PaintException {
-               // TODO Auto-generated method stub
-
-       }
-
-       public void addXMLSection(String sectionTagName, String sectionData,
-                       String namespace) throws PaintException {
-               // TODO Auto-generated method stub
-
-       }
-
-       public void endTag(String tagName) throws PaintException {
-               
-       }
-
-       public boolean startTag(Paintable paintable, String tag)
-                       throws PaintException {
-               // TODO Auto-generated method stub
-               return false;
-       }
-
-       public void startTag(String tagName) throws PaintException {
-               // TODO Auto-generated method stub
-
-       }
-
-       private class Tag {
-               HashMap attrs = new HashMap();
-
-               ArrayList children = new ArrayList();
-
-               ArrayList vars = new ArrayList();
-
-               String xml = null;
-               
-               String data = null;
-               
-               String tag;
-               
-               Tag(String tag) {
-                       this.tag = tag;
-               }
-       }
-
-       public void addAttribute(String string, Object[] keys) {
-               // TODO Auto-generated method stub
-               
-       }
-
-}
diff --git a/src/com/itmill/toolkit/terminal/gwt/server/JsonPaintTarget.java b/src/com/itmill/toolkit/terminal/gwt/server/JsonPaintTarget.java
new file mode 100644 (file)
index 0000000..6e4662e
--- /dev/null
@@ -0,0 +1,980 @@
+/* *************************************************************************
+ 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.gwt.server;
+
+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 5.0
+ */
+public class JsonPaintTarget implements PaintTarget {
+
+       /* 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 ApplicationManager 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 outWriter
+        *            A character-output stream.
+        * @throws PaintException
+        *             if the paint operation failed.
+        */
+       public JsonPaintTarget(AjaxVariableMap variableMap,
+                       ApplicationManager manager, PrintWriter outWriter)
+                       throws PaintException {
+
+               this.manager = manager;
+               // Sets the variable map
+               this.variableMap = variableMap;
+
+               // Sets the target for UIDL writing
+               this.uidlBuffer = outWriter;
+
+               // Initialize tag-writing
+               mOpenTags = new Stack();
+               openJsonTags = new Stack();
+               mTagArgumentListOpen = false;
+
+               // Adds document declaration
+
+               // Adds UIDL start tag and its attributes
+       }
+
+       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.");
+
+               if (tag != null) {
+                       openJsonTags.push(tag);
+               }
+               // Checks tagName and attributes here
+               mOpenTags.push(tagName);
+
+               tag = new JsonTag(tagName);
+
+               mTagArgumentListOpen = true;
+
+               customLayoutArgumentsOpen = "customlayout".equals(tagName);
+       }
+
+       /**
+        * 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.");
+
+               if (openJsonTags.size() > 0) {
+                       JsonTag parent = (JsonTag) openJsonTags.pop();
+
+                       String lastTag = "";
+
+                       lastTag = (String) mOpenTags.pop();
+                       if (!tagName.equalsIgnoreCase(lastTag))
+                               throw new PaintException("Invalid UIDL: wrong ending tag: '"
+                                               + tagName + "' expected: '" + lastTag + "'.");
+
+                       parent.addData(tag.getJSON());
+
+                       tag = parent;
+               } else {
+                       changes++;
+                       this.uidlBuffer.print(((changes > 1) ? "," : "") + tag.getJSON());
+                       tag = null;
+               }
+       }
+
+       /**
+        * 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 String attribute name.
+        * @param value
+        *            the String 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) + "\"");
+
+               if (customLayoutArgumentsOpen && "style".equals(name))
+                       getPreCachedResources().add("layout/" + value + ".html");
+               
+               if(name.equals("locale"))
+                       manager.requireLocale(value);
+
+       }
+
+       public void addAttribute(String name, Object[] values) {
+               // In case of null data output nothing:
+               if ((values == null) || (name == null))
+                       throw new NullPointerException(
+                                       "Parameters must be non-null strings");
+               StringBuffer buf = new StringBuffer();
+               buf.append("\"" + name + "\":[");
+               for (int i = 0; i < values.length; i++) {
+                       if (i > 0)
+                               buf.append(",");
+                       buf.append("\"");
+                       buf.append(escapeJSON(values[i].toString()));
+                       buf.append("\"");
+               }
+               buf.append("]");
+               tag.addAttribute(buf.toString());
+       }
+
+       /**
+        * 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
+        * 
+        * @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 {
+               tag.addData("{\"" + sectionTagName + "\":\"" + escapeJSON(sectionData)
+                               + "\"}");
+       }
+
+       /**
+        * 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("\"" + escapeJSON(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;
+               customLayoutArgumentsOpen = false;
+
+               if (sectionData != null)
+                       tag.addData("\"" + escapeJSON(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 (tag != null)
+                       uidlBuffer.append(tag.getJSON());
+               flush();
+               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);
+               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 = false;
+
+               Vector variables = new Vector();
+
+               Vector children = new Vector();
+
+               Vector attr = new Vector();
+
+               private HashMap childTagCounters = new HashMap();
+
+               StringBuffer data = new StringBuffer();
+
+               public boolean childrenArrayOpen = false;
+
+               private boolean childNode = false;
+
+               private boolean tagClosed = false;
+
+               public JsonTag(String tagName) {
+                       data.append("[\"" + tagName + "\"");
+               }
+
+               private void closeTag() {
+                       if (!tagClosed) {
+                               data.append(attributesAsJsonObject());
+                               data.append(getData());
+                               // Writes the end (closing) tag
+                               data.append("]");
+                               this.tagClosed = true;
+                       }
+               }
+
+               public String getJSON() {
+                       if (!tagClosed) {
+                               this.closeTag();
+                       }
+                       return data.toString();
+               }
+
+               public void openChildrenArray() {
+                       if (!childrenArrayOpen) {
+                               // append("c : [");
+                               childrenArrayOpen = true;
+                               // firstField = true;
+                       }
+               }
+
+               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 ",";
+                       }
+               }
+
+               /**
+                * 
+                * @param s
+                *            json string, object or array
+                */
+               public void addData(String s) {
+                       children.add(s);
+               }
+
+               public String getData() {
+                       StringBuffer buf = new StringBuffer();
+                       Iterator it = children.iterator();
+                       while (it.hasNext()) {
+                               buf.append(startField());
+                               buf.append(it.next());
+                       }
+                       return buf.toString();
+               }
+
+               public void addAttribute(String jsonNode) {
+                       attr.add(jsonNode);
+               }
+
+               private String attributesAsJsonObject() {
+                       StringBuffer buf = new StringBuffer();
+                       buf.append(startField());
+                       buf.append("{");
+                       for (Iterator iter = attr.iterator(); iter.hasNext();) {
+                               String element = (String) iter.next();
+                               buf.append(element);
+                               if (iter.hasNext())
+                                       buf.append(",");
+                       }
+                       buf.append(tag.variablesAsJsonObject());
+                       buf.append("}");
+                       return buf.toString();
+               }
+
+               public void addVariable(Variable v) {
+                       variables.add(v);
+               }
+
+               private String variablesAsJsonObject() {
+                       if (variables.size() == 0)
+                               return "";
+                       StringBuffer buf = new StringBuffer();
+                       buf.append(startField());
+                       buf.append("\"v\":{");
+                       Iterator iter = variables.iterator();
+                       while (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 + "\":" + (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 + "\":\"" + value + "\"";
+               }
+
+       }
+
+       class IntVariable extends Variable {
+               int value;
+
+               public IntVariable(VariableOwner owner, String name, int v) {
+                       value = v;
+                       this.name = name;
+                       code = variableMap.registerVariable(name, Integer.class,
+                                       new Integer(value), owner);
+               }
+
+               public String getJsonPresentation() {
+                       return "\"" + name + "\":" + 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 + "\":[";
+                       for (int i = 0; i < value.length;) {
+                               pres += "\"" + value[i] + "\"";
+                               i++;
+                               if (i < value.length)
+                                       pres += ",";
+                       }
+                       pres += "]";
+                       return pres;
+               }
+       }
+
+       public Set getPreCachedResources() {
+               return preCachedResources;
+       }
+
+       public void setPreCachedResources(Set preCachedResources) {
+               // TODO Auto-generated method stub
+
+       }
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/server/Log.java b/src/com/itmill/toolkit/terminal/gwt/server/Log.java
new file mode 100644 (file)
index 0000000..7a84341
--- /dev/null
@@ -0,0 +1,133 @@
+/* *************************************************************************
+ 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.gwt.server;
+
+/**
+ * <p>
+ * Class providing centralized logging services. The logger defines five message
+ * types, and provides methods to create messages of those types. These types
+ * are:
+ * </p>
+ * 
+ * <ul>
+ * <li> <code>info</code> - Useful information generated during normal
+ * operation of the application.
+ * <li> <code>warning</code> - An error situation has occurred, but the
+ * operation was able to finish succesfully.
+ * <li> <code>error</code> - An error situation which prevented the operation
+ * from finishing succesfully.
+ * <li> <code>debug</code> - Internal information from the application meant
+ * for developers.
+ * <li> <code>exception</code> - A Java exception reported using the logger.
+ * Includes the exception stack trace and a possible free-form message.
+ * </ul>
+ * 
+ * <p>
+ * Currently the class offers logging only to the standard output.
+ * </p>
+ * 
+ * @author IT Mill Ltd.
+ * @version
+ * @VERSION@
+ * @since 3.0
+ */
+public class Log {
+
+       private static boolean useStdOut = true;
+
+       private static String LOG_MSG_INFO = "[INFO]";
+
+       private static String LOG_MSG_ERROR = "[ERROR]";
+
+       private static String LOG_MSG_WARN = "[WARNING]";
+
+       private static String LOG_MSG_DEBUG = "[DEBUG]";
+
+       private static String LOG_MSG_EXCEPT = "[EXCEPTION]";
+
+       /**
+        * Logs the <code>warning</code> message.
+        * 
+        * @param message
+        *            the Message String to be logged.
+        */
+       protected static synchronized void warn(java.lang.String message) {
+               if (Log.useStdOut)
+                       System.out.println(LOG_MSG_WARN + " " + message);
+       }
+
+       /**
+        * Logs the <code>debug</code> message.
+        * 
+        * @param message
+        *            the Message String to be logged.
+        */
+       protected static synchronized void debug(java.lang.String message) {
+               if (Log.useStdOut)
+                       System.out.println(LOG_MSG_DEBUG + " " + message);
+       }
+
+       /**
+        * Logs an <code>info</code> message.
+        * 
+        * @param message
+        *            the Message String to be logged.
+        */
+       protected static synchronized void info(java.lang.String message) {
+               if (Log.useStdOut)
+                       System.out.println(LOG_MSG_INFO + " " + message);
+       }
+
+       /**
+        * Logs the Java exception and an accompanying error message.
+        * 
+        * @param message
+        *            the Message String to be logged.
+        * @param e
+        *            the Exception to be logged.
+        */
+       protected static synchronized void except(java.lang.String message,
+                       Exception e) {
+               if (Log.useStdOut) {
+                       System.out.println(LOG_MSG_EXCEPT + " " + message);
+                       e.printStackTrace();
+               }
+       }
+
+       /**
+        * Logs the <code>error</code> message.
+        * 
+        * @param message
+        *            the Message String to be logged.
+        */
+       protected static synchronized void error(java.lang.String message) {
+               if (Log.useStdOut)
+                       System.out.println(LOG_MSG_ERROR + " " + message);
+       }
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/server/MultipartRequest.java b/src/com/itmill/toolkit/terminal/gwt/server/MultipartRequest.java
new file mode 100644 (file)
index 0000000..ae22f5b
--- /dev/null
@@ -0,0 +1,1332 @@
+/* *************************************************************************
+ 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.gwt.server;
+
+import java.util.Hashtable;
+import java.io.BufferedOutputStream;
+import java.io.BufferedInputStream;
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.FileOutputStream;
+import java.io.UnsupportedEncodingException;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+import java.io.File;
+
+/**
+ * A Multipart form data parser. Parses an input stream and writes out any files
+ * found, making available a hashtable of other url parameters. As of version
+ * 1.17 the files can be saved to memory, and optionally written to a database,
+ * etc.
+ * 
+ * <BR>
+ * <BR>
+ * Copyright (C)2001 Jason Pell. <BR>
+ * 
+ * <PRE>
+ * 
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2.1 of the License, or (at your option)
+ * any later version. <BR>
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details. <BR>
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA <BR>
+ * Email: jasonpell@hotmail.com Url: http://www.geocities.com/jasonpell
+ * 
+ * </PRE>
+ * 
+ * @author Jason Pell
+ * 
+ * @version 1.18 Fixed some serious bugs. A new method readAndWrite(InputStream
+ *          in, OutputStream out) which now does the generic processing in
+ *          common for readAndWriteFile and readFile. The differences are that
+ *          now the two extra bytes at the end of a file upload are processed
+ *          once, instead of after each line. Also if an empty file is
+ *          encountered, an outputstream is opened, but then deleted if no data
+ *          written to it. The <code>getCharArray</code> method has been
+ *          removed. Replaced by the new String(bytes, encoding) method using a
+ *          specific encoding (Defaults to ISO-8859-1) to ensure that extended
+ *          characters are supported. All strings are processed using this
+ *          encoding. The addition of static methods setEncoding(String) and
+ *          <code>getEncoding</code> method to allow the use of
+ *          <code>MultipartRequest</code> with a specific encoding type. All
+ *          instances of MultipartRequest will utilise the static charEncoding
+ *          variable value, that the <code>setEncoding</code> method can be
+ *          used to set. Started to introduce support for multiple file uploads
+ *          with the same form field name, but not completed for v1.18.
+ *          26/06/2001
+ * 
+ * @version 1.17 A few _very_ minor fixes. Plus a cool new feature added. The
+ *          ability to save files into memory. <b>Thanks to Mark Latham for the
+ *          idea and some of the code.</b> 11/04/2001
+ * @version 1.16 Added support for multiple parameter values. Also fixed
+ *          getCharArray(...) method to support parameters with non-english
+ *          ascii values (ascii above 127). Thanks to Stefan Schmidt & Michael
+ *          Elvers for this. (No fix yet for reported problems with Tomcat 3.2
+ *          or a single extra byte appended to uploads of certain files). By
+ *          1.17 hopefully will have a resolution for the second problem.
+ *          14/03/2001
+ * @version 1.15 A new parameter added, intMaxReadBytes, to allow arbitrary
+ *          length files. Released under the LGPL (Lesser General Public
+ *          License). 03/02/2001
+ * @version 1.14 Fix for IE problem with filename being empty. This is because
+ *          IE includes a default Content-Type even when no file is uploaded.
+ *          16/02/2001
+ * @version 1.13 If an upload directory is not specified, then all file contents
+ *          are sent into oblivion, but the rest of the parsing works as normal.
+ * @version 1.12 Fix, was allowing zero length files. Will not even create the
+ *          output file until there is something to write. getFile(String) now
+ *          returns null, if a zero length file was specified. 06/11/2000
+ * @version 1.11 Fix, in case Content-type is not specified.
+ * @version 1.1 Removed dependence on Servlets. Now passes in a generic
+ *          InputStream instead. "Borrowed" readLine from Tomcat 3.1
+ *          ServletInputStream class, so we can remove some of the dependencies
+ *          on ServletInputStream. Fixed bug where a empty INPUT TYPE="FILE"
+ *          value, would cause an exception.
+ * @version 1.0 Initial Release.
+ */
+
+public class MultipartRequest {
+       /**
+        * Defines Character Encoding method here.
+        */
+       private String charEncoding = "UTF-8";
+
+       // If not null, send debugging out here.
+       private PrintWriter debug = null;
+
+       private Hashtable htParameters = null;
+
+       private Hashtable htFiles = null;
+
+       private String strBoundary = null;
+
+       // If this Directory spec remains null, writing of files will be disabled...
+       private File fileOutPutDirectory = null;
+
+       private boolean loadIntoMemory = false;
+
+       private long intContentLength = -1;
+
+       private long intTotalRead = -1;
+
+       /**
+        * Prevent a denial of service by defining this, will never read more data.
+        * If Content-Length is specified to be more than this, will throw an
+        * exception.
+        * 
+        * This limits the maximum number of bytes to the value of an int, which is
+        * 2 Gigabytes.
+        */
+       public static final int MAX_READ_BYTES = Integer.MAX_VALUE;
+
+       /**
+        * Defines the number of bytes to read per readLine call. 128K
+        */
+       public static final int READ_LINE_BLOCK = 1024 * 128;
+
+       /**
+        * Store a read from the input stream here. Global so we do not keep
+        * creating new arrays each read.
+        */
+       private byte[] blockOfBytes = null;
+
+       /**
+        * Type constant for File FILENAME.
+        */
+       public static final int FILENAME = 0;
+
+       /**
+        * Type constant for the File CONTENT_TYPE.
+        */
+       public static final int CONTENT_TYPE = 1;
+
+       /**
+        * Type constant for the File SIZE.
+        */
+       public static final int SIZE = 2;
+
+       /**
+        * Type constant for the File CONTENTS.
+        * 
+        * <b>Note: </b>Only used for file upload to memory.
+        */
+       public static final int CONTENTS = 3;
+
+       /**
+        * This method should be called on the <code>MultipartRequest</code>
+        * itself, not on any instances of <code>MultipartRequest</code>, because
+        * this sets up the encoding for all instances of multipartrequest. You can
+        * set the encoding to null, in which case the default encoding will be
+        * applied. The default encoding if this method is not called has been set
+        * to ISO-8859-1, which seems to offer the best hope of support for
+        * international characters, such as german "Umlaut" characters.
+        * 
+        * <p>
+        * <b>Warning:</b> In multithreaded environments it is the responsibility
+        * of the implementer to make sure that this method is not called while
+        * another instance is being constructed. When an instance of
+        * MultipartRequest is constructed, it parses the input data, and uses the
+        * result of <code>getEncoding</code> method to convert between bytes and
+        * strings. If <code>setEncoding</code> method is called by another
+        * thread, while the private <code>parse</code> method is executing, the
+        * method will utilise this new encoding, which may cause serious problems.
+        * </p>
+        */
+       public void setEncoding(String enc) throws UnsupportedEncodingException {
+               if (enc == null || enc.trim() == "")
+                       charEncoding = System.getProperty("file.encoding");
+               else {
+                       // This will test the encoding for validity.
+                       new String(new byte[] { '\n' }, enc);
+
+                       charEncoding = enc;
+               }
+       }
+
+       /**
+        * Gets the current encoding method.
+        * 
+        * @return the encoding method.
+        */
+       public String getEncoding() {
+               return charEncoding;
+       }
+
+       /**
+        * Constructor.
+        * 
+        * @param strContentTypeText
+        *            the &quot;Content-Type&quot; HTTP header value.
+        * @param intContentLength
+        *            the &quot;Content-Length&quot; HTTP header value.
+        * @param in
+        *            the InputStream to read and parse.
+        * @param strSaveDirectory
+        *            the temporary directory to save the file from where they can
+        *            then be moved to wherever by the calling process. <b>If you
+        *            specify <u>null</u> for this parameter, then any files
+        *            uploaded will be silently ignored.</b>
+        * 
+        * @exception IllegalArgumentException
+        *                If the strContentTypeText does not contain a Content-Type
+        *                of "multipart/form-data" or the boundary is not found.
+        * @exception IOException
+        *                If the intContentLength is higher than MAX_READ_BYTES or
+        *                strSaveDirectory is invalid or cannot be written to.
+        * 
+        * @see #MAX_READ_BYTES
+        */
+       public MultipartRequest(String strContentTypeText, int intContentLength,
+                       InputStream in, String strSaveDirectory)
+                       throws IllegalArgumentException, IOException {
+               this(null, strContentTypeText, intContentLength, in, strSaveDirectory,
+                               MAX_READ_BYTES);
+       }
+
+       /**
+        * Constructor.
+        * 
+        * @param strContentTypeText
+        *            the &quot;Content-Type&quot; HTTP header value.
+        * @param intContentLength
+        *            the &quot;Content-Length&quot; HTTP header value.
+        * @param in
+        *            the InputStream to read and parse.
+        * @param strSaveDirectory
+        *            the temporary directory to save the file from where they can
+        *            then be moved to wherever by the calling process. <b>If you
+        *            specify <u>null</u> for this parameter, then any files
+        *            uploaded will be silently ignored.</B>
+        * @param intMaxReadBytes
+        *            Overrides the MAX_BYTES_READ value, to allow arbitrarily long
+        *            files.
+        * 
+        * @exception IllegalArgumentException
+        *                If the strContentTypeText does not contain a Content-Type
+        *                of "multipart/form-data" or the boundary is not found.
+        * @exception IOException
+        *                If the intContentLength is higher than MAX_READ_BYTES or
+        *                strSaveDirectory is invalid or cannot be written to.
+        * 
+        * @see #MAX_READ_BYTES
+        */
+       public MultipartRequest(String strContentTypeText, int intContentLength,
+                       InputStream in, String strSaveDirectory, int intMaxReadBytes)
+                       throws IllegalArgumentException, IOException {
+               this(null, strContentTypeText, intContentLength, in, strSaveDirectory,
+                               intMaxReadBytes);
+       }
+
+       /**
+        * Constructor.
+        * 
+        * @param debug
+        *            A PrintWriter that can be used for debugging.
+        * @param strContentTypeText
+        *            the &quot;Content-Type&quot; HTTP header value.
+        * @param intContentLength
+        *            the &quot;Content-Length&quot; HTTP header value.
+        * @param in
+        *            the InputStream to read and parse.
+        * @param strSaveDirectory
+        *            the temporary directory to save the file from where they can
+        *            then be moved to wherever by the calling process. <b>If you
+        *            specify <u>null</u> for this parameter, then any files
+        *            uploaded will be silently ignored.</B>
+        * 
+        * @exception IllegalArgumentException
+        *                If the strContentTypeText does not contain a Content-Type
+        *                of "multipart/form-data" or the boundary is not found.
+        * @exception IOException
+        *                If the intContentLength is higher than MAX_READ_BYTES or
+        *                strSaveDirectory is invalid or cannot be written to.
+        * 
+        * @see #MAX_READ_BYTES
+        * @deprecated Replaced by MultipartRequest(PrintWriter, String, int,
+        *             InputStream, int) You can specify
+        *             MultipartRequest.MAX_READ_BYTES for the intMaxReadBytes
+        *             parameter
+        */
+       public MultipartRequest(PrintWriter debug, String strContentTypeText,
+                       int intContentLength, InputStream in, String strSaveDirectory)
+                       throws IllegalArgumentException, IOException {
+               this(debug, strContentTypeText, intContentLength, in, strSaveDirectory,
+                               MAX_READ_BYTES);
+
+       }
+
+       /**
+        * Constructor - load into memory constructor
+        * 
+        * @param debug
+        *            A PrintWriter that can be used for debugging.
+        * @param strContentTypeText
+        *            the &quot;Content-Type&quot; HTTP header value.
+        * @param intContentLength
+        *            the &quot;Content-Length&quot; HTTP header value.
+        * @param in
+        *            the InputStream to read and parse.
+        * @param intMaxReadBytes
+        *            Overrides the MAX_BYTES_READ value, to allow arbitrarily long
+        *            files.
+        * 
+        * @exception IllegalArgumentException
+        *                If the strContentTypeText does not contain a Content-Type
+        *                of "multipart/form-data" or the boundary is not found.
+        * @exception IOException
+        *                If the intContentLength is higher than MAX_READ_BYTES or
+        *                strSaveDirectory is invalid or cannot be written to.
+        * 
+        * @see #MAX_READ_BYTES
+        */
+       public MultipartRequest(PrintWriter debug, String strContentTypeText,
+                       int intContentLength, InputStream in, int intMaxReadBytes)
+                       throws IllegalArgumentException, IOException {
+               this.loadIntoMemory = true;
+
+               // Now initialise the object, which will actually call the parse method
+               // to parse multipart stream.
+               init(debug, strContentTypeText, intContentLength, in, intMaxReadBytes);
+       }
+
+       /**
+        * Constructor.
+        * 
+        * @param debug
+        *            A PrintWriter that can be used for debugging.
+        * @param strContentTypeText
+        *            the &quot;Content-Type&quot; HTTP header value.
+        * @param intContentLength
+        *            the &quot;Content-Length&quot; HTTP header value.
+        * @param in
+        *            the InputStream to read and parse.
+        * @param strSaveDirectory
+        *            the temporary directory to save the file from where they can
+        *            then be moved to wherever by the calling process. <b>If you
+        *            specify <u>null</u> for this parameter, then any files
+        *            uploaded will be silently ignored.</B>
+        * @param intMaxReadBytes
+        *            Overrides the MAX_BYTES_READ value, to allow arbitrarily long
+        *            files.
+        * 
+        * @exception IllegalArgumentException
+        *                If the strContentTypeText does not contain a Content-Type
+        *                of "multipart/form-data" or the boundary is not found.
+        * @exception IOException
+        *                If the intContentLength is higher than MAX_READ_BYTES or
+        *                strSaveDirectory is invalid or cannot be written to.
+        * 
+        * @see #MAX_READ_BYTES
+        */
+       public MultipartRequest(PrintWriter debug, String strContentTypeText,
+                       int intContentLength, InputStream in, String strSaveDirectory,
+                       int intMaxReadBytes) throws IllegalArgumentException, IOException {
+               // IF strSaveDirectory == NULL, then we should ignore any files
+               // uploaded.
+               if (strSaveDirectory != null) {
+                       fileOutPutDirectory = new File(strSaveDirectory);
+                       if (!fileOutPutDirectory.exists())
+                               throw new IOException("Directory [" + strSaveDirectory
+                                               + "] is invalid.");
+                       else if (!fileOutPutDirectory.canWrite())
+                               throw new IOException("Directory [" + strSaveDirectory
+                                               + "] is readonly.");
+               }
+
+               // Now initialise the object, which will actually call the parse method
+               // to parse multipart stream.
+               init(debug, strContentTypeText, intContentLength, in, intMaxReadBytes);
+       }
+
+       /**
+        * Initialise the parser.
+        * 
+        * @param debug
+        *            A PrintWriter that can be used for debugging.
+        * @param strContentTypeText
+        *            the &quot;Content-Type&quot; HTTP header value.
+        * @param intContentLength
+        *            the &quot;Content-Length&quot; HTTP header value.
+        * @param in
+        *            the InputStream to read and parse.
+        * @param strSaveDirectory
+        *            the temporary directory to save the file from where they can
+        *            then be moved to wherever by the calling process. <b>If you
+        *            specify <u>null</u> for this parameter, then any files
+        *            uploaded will be silently ignored.</B>
+        * @param intMaxReadBytes
+        *            Overrides the MAX_BYTES_READ value, to allow arbitrarily long
+        *            files.
+        * 
+        * @exception IllegalArgumentException
+        *                If the strContentTypeText does not contain a Content-Type
+        *                of "multipart/form-data" or the boundary is not found.
+        * @exception IOException
+        *                If the intContentLength is higher than MAX_READ_BYTES or
+        *                strSaveDirectory is invalid or cannot be written to.
+        * 
+        * @see #MAX_READ_BYTES
+        */
+       private void init(PrintWriter debug, String strContentTypeText,
+                       int intContentLength, InputStream in, int intMaxReadBytes)
+                       throws IllegalArgumentException, IOException {
+               // saves reference to debug stream for later.
+               this.debug = debug;
+
+               if (strContentTypeText != null
+                               && strContentTypeText.startsWith("multipart/form-data")
+                               && strContentTypeText.indexOf("boundary=") != -1)
+                       strBoundary = strContentTypeText.substring(
+                                       strContentTypeText.indexOf("boundary=")
+                                                       + "boundary=".length()).trim();
+               else {
+                       // <mtl,jpell>
+                       debug("ContentType = " + strContentTypeText);
+                       throw new IllegalArgumentException("Invalid Content Type.");
+               }
+
+               this.intContentLength = intContentLength;
+               // FIX: 115
+               if (intContentLength > intMaxReadBytes)
+                       throw new IOException("Content Length Error (" + intContentLength
+                                       + " > " + intMaxReadBytes + ")");
+
+               // Instantiate the hashtable...
+               htParameters = new Hashtable();
+               htFiles = new Hashtable();
+               blockOfBytes = new byte[READ_LINE_BLOCK];
+
+               // Now parse the data.
+               parse(new BufferedInputStream(in));
+
+               // No need for this once parse is complete.
+               this.blockOfBytes = null;
+               this.debug = null;
+               this.strBoundary = null;
+       }
+
+       /**
+        * Gets the value of the strName URLParameter. If more than one value for a
+        * particular Parameter, will return the first. If an error occurs will
+        * return null.
+        * 
+        * @param strName
+        *            the form field name, used to upload the file. This identifies
+        *            the formfield location in the storage facility.
+        * @return the value of the URL Parameter.
+        */
+       public String getURLParameter(String strName) {
+               Object value = htParameters.get(strName);
+               if (value instanceof Vector)
+                       return (String) ((Vector) value).firstElement();
+               else
+                       return (String) htParameters.get(strName);
+       }
+
+       /**
+        * Gets an enumeration of all values for the strName parameter. Even if a
+        * single value for, will always return an enumeration, although it may
+        * actually be empty if no value was encountered for strName or it is an
+        * invalid parameter name.
+        * 
+        * @param strName
+        *            the form field name, used to upload the file. This identifies
+        *            the formfield location in the storage facility.
+        * @return the enumeration of all values.
+        */
+       public Enumeration getURLParameters(String strName) {
+               Object value = htParameters.get(strName);
+               if (value instanceof Vector)
+                       return ((Vector) value).elements();
+               else {
+                       Vector vector = new Vector();
+                       if (value != null)
+                               vector.addElement(value);
+                       return vector.elements();
+               }
+       }
+
+       /**
+        * Gets the enumeration of all URL Parameters for the current HTTP Request.
+        * 
+        * @return the enumeration of URl Parameters.
+        */
+       public Enumeration getParameterNames() {
+               return htParameters.keys();
+       }
+
+       /**
+        * Gets the enumeration of all INPUT TYPE=FILE parameter NAMES as
+        * encountered during the upload.
+        * 
+        * @return
+        */
+       public Enumeration getFileParameterNames() {
+               return htFiles.keys();
+       }
+
+       /**
+        * Returns the Content-Type of a file.
+        * 
+        * @see #getFileParameter(java.lang.String, int)
+        */
+       public String getContentType(String strName) {
+               // Can cast null, it will be ignored.
+               return (String) getFileParameter(strName, CONTENT_TYPE);
+       }
+
+       /**
+        * If files were uploaded into memory, this method will retrieve the
+        * contents of the file as a InputStream.
+        * 
+        * @param strName
+        *            the form field name, used to upload the file. This identifies
+        *            the formfield location in the storage facility.
+        * @return the contents of the file as a InputStream, or null if not file
+        *         uploaded, or file uploaded to file system directory.
+        * @see #getFileParameter(java.lang.String, int)
+        */
+       public InputStream getFileContents(String strName) {
+               Object obj = getFileParameter(strName, CONTENTS);
+               if (obj != null)
+                       return new ByteArrayInputStream((byte[]) obj);
+               else
+                       return null;
+       }
+
+       /**
+        * Returns a File reference to the uploaded file. This reference is to the
+        * files uploaded location, and allows you to read/move/delete the file.
+        * This method is only of use, if files were uploaded to the file system.
+        * Will return null if uploaded to memory, in which case you should use
+        * getFileContents(strName) instead.
+        * 
+        * @param strName
+        *            the form field name, used to upload the file. This identifies
+        *            the formfield location in the storage facility.
+        * @return a null file reference if a call to getFileSize(strName) returns
+        *         zero or files were uploaded to memory.
+        * @see #getFileSize(java.lang.String)
+        * @see #getFileContents(java.lang.String)
+        * @see #getFileSystemName(java.lang.String)
+        */
+       public File getFile(String strName) {
+               String filename = getFileSystemName(strName);
+               // Fix: If fileOutPutDirectory is null, then we are ignoring any file
+               // contents, so we must return null.
+               if (filename != null && getFileSize(strName) > 0
+                               && fileOutPutDirectory != null)
+                       return new File(fileOutPutDirectory, filename);
+               else
+                       return null;
+       }
+
+       /**
+        * Gets the file system basename of an uploaded file.
+        * 
+        * @param strName
+        *            the form field name, used to upload the file. This identifies
+        *            the formfield location in the storage facility.
+        * @return null if strName not found.
+        * 
+        * @see #getFileParameter(java.lang.String, int)
+        */
+       public String getFileSystemName(String strName) {
+               // Can cast null, it will be ignored.
+               return (String) getFileParameter(strName, FILENAME);
+       }
+
+       /**
+        * Returns the File Size of a uploaded file.
+        * 
+        * @param strName
+        *            the form field name, used to upload the file. This identifies
+        *            the formfield location in the storage facility.
+        * @return -1 if file size not defined.
+        * 
+        * @see #getFileParameter(java.lang.String, int)
+        */
+       public long getFileSize(String strName) {
+               Object obj = getFileParameter(strName, SIZE);
+               if (obj != null)
+                       return ((Long) obj).longValue();
+               else
+                       return (long) -1;
+       }
+
+       /**
+        * Access an attribute of a file upload parameter record.
+        * <p>
+        * The getFileSystemName(String strName),getFileSize(String
+        * strName),getContentType(String strName), getContents(String strName)
+        * methods all use this method passing in a different type argument.
+        * </p>
+        * 
+        * <p>
+        * <b>Note: </b>This class has been changed to provide for future
+        * functionality where you will be able to access all files uploaded, even
+        * if they are uploaded using the same form field name. At this point
+        * however, only the first file uploaded via a form field name is
+        * accessible.
+        * </p>
+        * 
+        * @param strName
+        *            the form field name, used to upload the file. This identifies
+        *            the formfield location in the storage facility.
+        * 
+        * @param type
+        *            What attribute you want from the File Parameter. The following
+        *            types are supported: MultipartRequest.FILENAME,
+        *            MultipartRequest.CONTENT_TYPE, MultipartRequest.SIZE,
+        *            MultipartRequest.CONTENTS
+        * 
+        * @see #getContentType(java.lang.String)
+        * @see #getFileSize(java.lang.String)
+        * @see #getFileContents(java.lang.String)
+        * @see #getFileSystemName(java.lang.String)
+        */
+       public Object getFileParameter(String strName, int type) {
+               Object[] objArray = null;
+               Object value = htFiles.get(strName);
+               if (value instanceof Vector)
+                       objArray = (Object[]) ((Vector) value).firstElement();
+               else
+                       objArray = (Object[]) htFiles.get(strName);
+
+               // Now ensure valid value.
+               if (objArray != null && type >= FILENAME && type <= CONTENTS)
+                       return objArray[type];
+               else
+                       return null;
+       }
+
+       /**
+        * This is the main parse method.
+        * 
+        * @param in
+        *            the InputStream to read and parse.
+        * @throws IOException
+        *             If the intContentLength is higher than MAX_READ_BYTES or
+        *             strSaveDirectory is invalid or cannot be written to.
+        */
+       private void parse(InputStream in) throws IOException {
+               String strContentType = null;
+               String strName = null;
+               String strFilename = null;
+               String strLine = null;
+               int read = -1;
+
+               // First run through, check that the first line is a boundary, otherwise
+               // throw a exception as format incorrect.
+               read = readLine(in, blockOfBytes);
+               strLine = read > 0 ? new String(blockOfBytes, 0, read, charEncoding)
+                               : null;
+
+               // Must be boundary at top of loop, otherwise we have finished.
+               if (strLine == null || strLine.indexOf(this.strBoundary) == -1)
+                       // Just exit. Exception would be overkill
+                       return;
+               // throw new IOException("Invalid Form Data, no boundary encountered.");
+
+               // At the top of loop, we assume that the Content-Disposition line is
+               // next, otherwise we are at the end.
+               while (true) {
+                       // Get Content-Disposition line.
+                       read = readLine(in, blockOfBytes);
+                       if (read <= 0)
+                               break; // Nothing to do.
+                       else {
+                               strLine = new String(blockOfBytes, 0, read, charEncoding);
+
+                               // Mac IE4 adds extra line after last boundary - 1.21
+                               if (strLine == null || strLine.length() == 0
+                                               || strLine.trim().length() == 0)
+                                       break;
+
+                               strName = trimQuotes(getValue("name", strLine));
+                               // If this is not null, it indicates that we are processing a
+                               // filename.
+                               strFilename = trimQuotes(getValue("filename", strLine));
+                               // Now if not null, strip it of any directory information.
+
+                               if (strFilename != null) {
+                                       // Fix: did not check whether filename was empty string
+                                       // indicating FILE contents were not passed.
+                                       if (strFilename.length() > 0) {
+                                               // Need to get the content type.
+                                               read = readLine(in, blockOfBytes);
+                                               strLine = read > 0 ? new String(blockOfBytes, 0, read,
+                                                               charEncoding) : null;
+
+                                               strContentType = "application/octet-stream";
+                                               // Fix 1.11: If not null AND strLine.length() is long
+                                               // enough.
+                                               if (strLine != null
+                                                               && strLine.length() > "Content-Type: ".length())
+                                                       strContentType = strLine.substring("Content-Type: "
+                                                                       .length());// Changed 1.13
+                                       } else {
+                                               // FIX 1.14: IE problem with empty filename.
+                                               read = readLine(in, blockOfBytes);
+                                               strLine = read > 0 ? new String(blockOfBytes, 0, read,
+                                                               charEncoding) : null;
+
+                                               if (strLine != null
+                                                               && strLine.startsWith("Content-Type:"))
+                                                       readLine(in, blockOfBytes);
+                                       }
+                               }
+
+                               // Ignore next line, as it should be blank.
+                               readLine(in, blockOfBytes);
+
+                               // No filename specified at all.
+                               if (strFilename == null) {
+                                       String param = readParameter(in);
+                                       addParameter(strName, param);
+                               } else {
+                                       if (strFilename.length() > 0) {
+                                               long filesize = -1;
+                                               // Will remain null for read onto file system uploads.
+                                               byte[] contentsOfFile = null;
+
+                                               // Get the BASENAME version of strFilename.
+                                               strFilename = getBasename(strFilename);
+
+                                               // Are we loading files into memory instead of the
+                                               // filesystem?
+                                               if (loadIntoMemory) {
+                                                       contentsOfFile = readFile(in);
+                                                       if (contentsOfFile != null)
+                                                               filesize = contentsOfFile.length;
+                                               } else
+                                                       // Read the file onto file system.
+                                                       filesize = readAndWriteFile(in, strFilename);
+
+                                               // Fix 1.18 for multiple FILE parameter values.
+                                               if (filesize > 0)
+                                                       addFileParameter(strName, new Object[] {
+                                                                       strFilename, strContentType,
+                                                                       new Long(filesize), contentsOfFile });
+                                               else
+                                                       // Zero length file.
+                                                       addFileParameter(strName, new Object[] {
+                                                                       strFilename, null, new Long(0), null });
+                                       } else // Fix: FILE INPUT TYPE, but no file passed as
+                                                       // input...
+                                       {
+                                               addFileParameter(strName, new Object[] { null, null,
+                                                               null, null });
+                                               readLine(in, blockOfBytes);
+                                       }
+                               }
+                       }
+               }// while
+       }
+
+       /**
+        * So we can put the logic for supporting multiple parameters with the same
+        * form field name in the one location.
+        * 
+        * @param strName
+        *            the form field name, used to upload the file. This identifies
+        *            the formfield location in the storage facility.
+        * @param value
+        *            the form field value.
+        */
+       private void addParameter(String strName, String value) {
+               // Fix NPE in case of null name
+               if (strName == null)
+                       return;
+
+               // Fix 1.16: for multiple parameter values.
+               Object objParms = htParameters.get(strName);
+
+               // Adds an new entry to the param vector.
+               if (objParms instanceof Vector)
+                       ((Vector) objParms).addElement(value);
+               else if (objParms instanceof String)// There is only one entry, so we
+                                                                                       // create a vector!
+               {
+                       Vector vecParms = new Vector();
+                       vecParms.addElement(objParms);
+                       vecParms.addElement(value);
+
+                       htParameters.put(strName, vecParms);
+               } else
+                       // first entry for strName.
+                       htParameters.put(strName, value);
+       }
+
+       /**
+        * So we can put the logic for supporting multiple files with the same form
+        * field name in the one location.
+        * 
+        * Assumes that this method will never be called with a null fileObj or
+        * strFilename.
+        * 
+        * @param strName
+        *            the form field name, used to upload the file. This identifies
+        *            the formfield location in the storage facility.
+        * @param fileObj
+        */
+       private void addFileParameter(String strName, Object[] fileObj) {
+               Object objParms = htFiles.get(strName);
+
+               // Add an new entry to the param vector.
+               if (objParms instanceof Vector)
+                       ((Vector) objParms).addElement(fileObj);
+               else if (objParms instanceof Object[])// There is only one entry, so
+                                                                                               // we create a vector!
+               {
+                       Vector vecParms = new Vector();
+                       vecParms.addElement(objParms);
+                       vecParms.addElement(fileObj);
+
+                       htFiles.put(strName, vecParms);
+               } else
+                       // first entry for strName.
+                       htFiles.put(strName, fileObj);
+       }
+
+       /**
+        * Reads the parameters, assume already passed Content-Disposition and blank
+        * line.
+        * 
+        * @param in
+        *            the InputStream to read and parse.
+        * @return the value read in.
+        * @throws IOException
+        *             if an error occurs writing the file.
+        */
+       private String readParameter(InputStream in) throws IOException {
+               StringBuffer buf = new StringBuffer();
+               int read = -1;
+
+               String line = null;
+               while (true) {
+                       read = readLine(in, blockOfBytes);
+                       if (read < 0)
+                               throw new IOException("Stream ended prematurely.");
+
+                       // Change v1.18: Only instantiate string once for performance
+                       // reasons.
+                       line = new String(blockOfBytes, 0, read, charEncoding);
+                       if (read < blockOfBytes.length
+                                       && line.indexOf(this.strBoundary) != -1)
+                               break; // Boundary found, we need to finish up.
+                       else
+                               buf.append(line);
+               }
+
+               if (buf.length() > 0)
+                       buf.setLength(getLengthMinusEnding(buf));
+               return buf.toString();
+       }
+
+       /**
+        * Read from in, write to out, minus last two line ending bytes.
+        * 
+        * @param in
+        *            the InputStream to read and parse.
+        * @param out
+        *            the OutputStream.
+        * @throws IOException
+        *             if an error occurs writing the file.
+        */
+       private long readAndWrite(InputStream in, OutputStream out)
+                       throws IOException {
+               long fileSize = 0;
+               int read = -1;
+
+               // This variable will be assigned the bytes actually read.
+               byte[] secondLineOfBytes = new byte[blockOfBytes.length];
+               // So we do not have to keep creating the second array.
+               int sizeOfSecondArray = 0;
+
+               while (true) {
+                       read = readLine(in, blockOfBytes);
+                       if (read < 0)
+                               throw new IOException("Stream ended prematurely.");
+
+                       // Found boundary.
+                       if (read < blockOfBytes.length
+                                       && new String(blockOfBytes, 0, read, charEncoding)
+                                                       .indexOf(this.strBoundary) != -1) {
+                               // Writes the line, minus any line ending bytes.
+                               // The secondLineOfBytes will NEVER BE NON-NULL if out==null, so
+                               // there is no need to included this in the test
+                               if (sizeOfSecondArray != 0) {
+                                       // Only used once, so declare here.
+                                       int actualLength = getLengthMinusEnding(secondLineOfBytes,
+                                                       sizeOfSecondArray);
+                                       if (actualLength > 0 && out != null) {
+                                               out.write(secondLineOfBytes, 0, actualLength);
+                                               // Updates the file size.
+                                               fileSize += actualLength;
+                                       }
+                               }
+                               break;
+                       } else {
+                               // Writes the out previous line.
+                               // The sizeOfSecondArray will NEVER BE ZERO if out==null, so
+                               // there is no need to included this in the test
+                               if (sizeOfSecondArray != 0) {
+                                       out.write(secondLineOfBytes, 0, sizeOfSecondArray);
+                                       // Updates the file size.
+                                       fileSize += sizeOfSecondArray;
+                               }
+
+                               // out will always be null, so there is no need to reset
+                               // sizeOfSecondArray to zero each time.
+                               if (out != null) {
+                                       // Copy the read bytes into the array.
+                                       System.arraycopy(blockOfBytes, 0, secondLineOfBytes, 0,
+                                                       read);
+                                       // That is how many bytes to read from the secondLineOfBytes
+                                       sizeOfSecondArray = read;
+                               }
+                       }
+               }
+
+               // Returns the number of bytes written to outstream.
+               return fileSize;
+       }
+
+       /**
+        * Reads a Multipart section that is a file type. Assumes that the
+        * Content-Disposition/Content-Type and blank line have already been
+        * processed. So we read until we hit a boundary, then close file and
+        * return.
+        * 
+        * @param in
+        *            the InputStream to read and parse.
+        * @param strFilename
+        *            the FileSystemName of the file.
+        * @return the number of bytes read.
+        * @throws IOException
+        *             if an error occurs writing the file.
+        */
+       private long readAndWriteFile(InputStream in, String strFilename)
+                       throws IOException {
+               // Stores a reference to this, as we may need to delete it later.
+               File outFile = new File(fileOutPutDirectory, strFilename);
+
+               BufferedOutputStream out = null;
+               // Do not bother opening a OutputStream, if we cannot even write the
+               // file.
+               if (fileOutPutDirectory != null)
+                       out = new BufferedOutputStream(new FileOutputStream(outFile));
+
+               long count = readAndWrite(in, out);
+               // Count would NOT be larger than zero if out was null.
+               if (count > 0) {
+                       out.flush();
+                       out.close();
+               } else {
+                       out.close();
+                       // Deletes the file as empty. We should be able to delete it, if we
+                       // can open it!
+                       outFile.delete();
+               }
+               return count;
+       }
+
+       /**
+        * If the fileOutPutDirectory wasn't specified, just read the file to
+        * memory.
+        * 
+        * @param in
+        *            the InputStream to read and parse.
+        * @return contents of file, from which you can garner the size as well.
+        * @throws IOException
+        *             if the writing failed due to input/output error.
+        */
+       private byte[] readFile(InputStream in) throws IOException {
+               // In this case, we do not need to worry about a outputdirectory.
+               ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+               long count = readAndWrite(in, out);
+               // Count would NOT be larger than zero if out was null.
+               if (count > 0) {
+                       // Return contents of file to parse method for inclusion in htFiles
+                       // object.
+                       return out.toByteArray();
+               } else
+                       return null;
+       }
+
+       /**
+        * Gets the length of the line minus line ending.
+        * 
+        * @param byteLine
+        * @param endOfArray
+        *            This is because in many cases the byteLine will have garbage
+        *            data at the end, so we act as though the actual end of the
+        *            array is this parameter. If you want to process the complete
+        *            byteLine, specify byteLine.length as the endOfArray parameter.
+        * @return the length.
+        */
+       private static final int getLengthMinusEnding(byte byteLine[],
+                       int endOfArray) {
+               if (byteLine == null)
+                       return 0;
+
+               if (endOfArray >= 2 && byteLine[endOfArray - 2] == '\r'
+                               && byteLine[endOfArray - 1] == '\n')
+                       return endOfArray - 2;
+               else if (endOfArray >= 1 && byteLine[endOfArray - 1] == '\n'
+                               || byteLine[endOfArray - 1] == '\r')
+                       return endOfArray - 1;
+               else
+                       return endOfArray;
+       }
+
+       /**
+        * 
+        * @param buf
+        * @return
+        */
+       private static final int getLengthMinusEnding(StringBuffer buf) {
+               if (buf.length() >= 2 && buf.charAt(buf.length() - 2) == '\r'
+                               && buf.charAt(buf.length() - 1) == '\n')
+                       return buf.length() - 2;
+               else if (buf.length() >= 1 && buf.charAt(buf.length() - 1) == '\n'
+                               || buf.charAt(buf.length() - 1) == '\r')
+                       return buf.length() - 1;
+               else
+                       return buf.length();
+       }
+
+       /**
+        * Reads at most READ_BLOCK blocks of data, or a single line whichever is
+        * smaller. Returns -1, if nothing to read, or we have reached the specified
+        * content-length.
+        * 
+        * Assumes that bytToBeRead.length indicates the block size to read.
+        * 
+        * @param in
+        *            the InputStream to read and parse.
+        * @param bytesToBeRead
+        *            the bytes to be read.
+        * @return -1 if stream has ended, before a newline encountered (should
+        *         never happen) OR we have read past the Content-Length specified.
+        *         (Should also not happen). Otherwise return the number of
+        *         characters read. You can test whether the number returned is less
+        *         than bytesToBeRead.length, which indicates that we have read the
+        *         last line of a file or parameter or a border line, or some other
+        *         formatting stuff.
+        * @throws IOException
+        *             if the writing failed due to input/output error.
+        */
+       private int readLine(InputStream in, byte[] bytesToBeRead)
+                       throws IOException {
+               // Ensure that there is still stuff to read...
+               if (intTotalRead >= intContentLength)
+                       return -1;
+
+               // Get the length of what we are wanting to read.
+               int length = bytesToBeRead.length;
+
+               // End of content, but some servers (apparently) may not realise this
+               // and end the InputStream, so
+               // we cover ourselves this way.
+               if (length > (intContentLength - intTotalRead))
+                       length = (int) (intContentLength - intTotalRead); // So we only
+                                                                                                                               // read the data
+                                                                                                                               // that is left.
+
+               int result = readLine(in, bytesToBeRead, 0, length);
+               // Only if we get actually read something, otherwise something weird has
+               // happened, such as the end of stream.
+               if (result > 0)
+                       intTotalRead += result;
+
+               return result;
+       }
+
+       /**
+        * This needs to support the possibility of a / or a \ separator.
+        * 
+        * @param strFilename
+        *            the FileSystemName of the file.
+        * @return the strFilename after removing all characters before the last
+        *         occurence of / or \.
+        */
+       private static final String getBasename(String strFilename) {
+               if (strFilename == null)
+                       return strFilename;
+
+               int intIndex = strFilename.lastIndexOf("/");
+               if (intIndex == -1 || strFilename.lastIndexOf("\\") > intIndex)
+                       intIndex = strFilename.lastIndexOf("\\");
+
+               if (intIndex != -1)
+                       return strFilename.substring(intIndex + 1);
+               else
+                       return strFilename;
+       }
+
+       /**
+        * Trims any quotes from the start and end of a string.
+        * 
+        * @param strItem
+        * @return the trimmed string.
+        */
+       private static final String trimQuotes(String strItem) {
+               // Saves having to go any further....
+               if (strItem == null || strItem.indexOf("\"") == -1)
+                       return strItem;
+
+               // Gets the rid of any whitespace..
+               strItem = strItem.trim();
+
+               if (strItem.charAt(0) == '\"')
+                       strItem = strItem.substring(1);
+
+               if (strItem.charAt(strItem.length() - 1) == '\"')
+                       strItem = strItem.substring(0, strItem.length() - 1);
+
+               return strItem;
+       }
+
+       /**
+        * Format of string name=value; name=value; If not found, will return null.
+        * 
+        * @param strName
+        *            the form field name, used to upload the file. This identifies
+        *            the formfield location in the storage facility.
+        * @param strToDecode
+        * 
+        */
+       private static final String getValue(String strName, String strToDecode) {
+               strName = strName + "=";
+
+               int startIndexOf = 0;
+               while (startIndexOf < strToDecode.length()) {
+                       int indexOf = strToDecode.indexOf(strName, startIndexOf);
+                       // Ensure either first name, or a space or ; precedes it.
+                       if (indexOf != -1) {
+                               if (indexOf == 0
+                                               || Character.isWhitespace(strToDecode
+                                                               .charAt(indexOf - 1))
+                                               || strToDecode.charAt(indexOf - 1) == ';') {
+                                       int endIndexOf = strToDecode.indexOf(";", indexOf
+                                                       + strName.length());
+                                       if (endIndexOf == -1) // May return an empty string...
+                                               return strToDecode
+                                                               .substring(indexOf + strName.length());
+                                       else
+                                               return strToDecode.substring(
+                                                               indexOf + strName.length(), endIndexOf);
+                               } else
+                                       startIndexOf = indexOf + strName.length();
+                       } else
+                               return null;
+               }
+               return null;
+       }
+
+       /**
+        * <I>Tomcat's ServletInputStream.readLine(byte[],int,int) Slightly Modified
+        * to utilise in.read()</I> <BR>
+        * Reads the input stream, one line at a time. Starting at an offset, reads
+        * bytes into an array, until it reads a certain number of bytes or reaches
+        * a newline character, which it reads into the array as well.
+        * 
+        * <p>
+        * This method <u><b>does not</b></u> returns -1 if it reaches the end of
+        * the input stream before reading the maximum number of bytes, it returns
+        * -1, if no bytes read.
+        * 
+        * @param in
+        *            the InputStream to read and parse.
+        * @param b
+        *            an array of bytes into which data is read.
+        * 
+        * @param off
+        *            an integer specifying the character at which this method
+        *            begins reading.
+        * 
+        * @param len
+        *            an integer specifying the maximum number of bytes to read.
+        * 
+        * @return an integer specifying the actual number of bytes read, or -1 if
+        *         the end of the stream is reached.
+        * 
+        * @throws IOException
+        *             if an input or output exception has occurred
+        * 
+        * 
+        * Note: We have a problem with Tomcat reporting an erroneous number of
+        * bytes, so we need to check this. This is the method where we get an
+        * infinite loop, but only with binary files.
+        */
+       private int readLine(InputStream in, byte[] b, int off, int len)
+                       throws IOException {
+               if (len <= 0)
+                       return 0;
+
+               int count = 0, c;
+
+               while ((c = in.read()) != -1) {
+                       b[off++] = (byte) c;
+                       count++;
+                       if (c == '\n' || count == len)
+                               break;
+               }
+
+               return count > 0 ? count : -1;
+       }
+
+       /**
+        * Prints the given debugging message.
+        * 
+        * @param x
+        *            the message to print.
+        */
+       protected void debug(String x) {
+               if (debug != null) {
+                       debug.println(x);
+                       debug.flush();
+               }
+       }
+
+       /**
+        * Gets the Html Table.For debugging.
+        */
+       public String getHtmlTable() {
+               StringBuffer sbReturn = new StringBuffer();
+
+               sbReturn.append("<h2>Parameters</h2>");
+               sbReturn
+                               .append("\n<table border=3><tr><td><b>Name</b></td><td><b>Value</b></td></tr>");
+               for (Enumeration e = getParameterNames(); e.hasMoreElements();) {
+                       String strName = (String) e.nextElement();
+                       sbReturn.append("\n<tr>" + "<td>" + strName + "</td>");
+
+                       sbReturn.append("<td><table border=1><tr>");
+                       for (Enumeration f = getURLParameters(strName); f.hasMoreElements();) {
+                               String value = (String) f.nextElement();
+                               sbReturn.append("<td>" + value + "</td>");
+                       }
+                       sbReturn.append("</tr></table></td></tr>");
+               }
+               sbReturn.append("</table>");
+
+               sbReturn.append("<h2>File Parameters</h2>");
+
+               sbReturn
+                               .append("\n<table border=2><tr><td><b>Name</b></td><td><b>Filename</b></td><td><b>Path</b></td><td><b>Content Type</b></td><td><b>Size</b></td></tr>");
+               for (Enumeration e = getFileParameterNames(); e.hasMoreElements();) {
+                       String strName = (String) e.nextElement();
+
+                       sbReturn
+                                       .append("\n<tr>"
+                                                       + "<td>"
+                                                       + strName
+                                                       + "</td>"
+                                                       + "<td>"
+                                                       + (getFileSystemName(strName) != null ? getFileSystemName(strName)
+                                                                       : "") + "</td>");
+
+                       if (loadIntoMemory)
+                               sbReturn.append("<td>"
+                                               + (getFileSize(strName) > 0 ? "<i>in memory</i>" : "")
+                                               + "</td>");
+                       else
+                               sbReturn.append("<td>"
+                                               + (getFile(strName) != null ? getFile(strName)
+                                                               .getAbsolutePath() : "") + "</td>");
+
+                       sbReturn
+                                       .append("<td>"
+                                                       + (getContentType(strName) != null ? getContentType(strName)
+                                                                       : "")
+                                                       + "</td>"
+                                                       + "<td>"
+                                                       + (getFileSize(strName) != -1 ? getFileSize(strName)
+                                                                       + ""
+                                                                       : "") + "</td>" + "</tr>");
+               }
+               sbReturn.append("</table>");
+
+               return sbReturn.toString();
+       }
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/server/ServletMultipartRequest.java b/src/com/itmill/toolkit/terminal/gwt/server/ServletMultipartRequest.java
new file mode 100644 (file)
index 0000000..a0352e5
--- /dev/null
@@ -0,0 +1,139 @@
+/* *************************************************************************
+ 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.gwt.server;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * This class wraps the MultipartRequest class by Jason Pell for the Servlet
+ * environment.
+ * 
+ * @author IT Mill Ltd
+ * @version
+ * @VERSION@
+ * @since 3.0
+ */
+public class ServletMultipartRequest extends MultipartRequest {
+       /**
+        * Constructor wrapper, unwraps the InputStream, content type and content
+        * length from the servlet request object.
+        * 
+        * @param request
+        *            the HttpServletRequest will be used to initialise the
+        *            MultipartRequest super class.
+        * @param strSaveDirectory
+        *            the temporary directory to save the file from where they can
+        *            then be moved to wherever by the calling process. <b>If you
+        *            specify <u>null</u> for this parameter, then any files
+        *            uploaded will be silently ignored.</B>
+        * 
+        * @throws IllegalArgumentException
+        *             If the request.getContentType() does not contain a
+        *             Content-Type of "multipart/form-data" or the boundary is not
+        *             found.
+        * @throws IOException
+        *             If the request.getContentLength() is higher than
+        *             MAX_READ_BYTES or strSaveDirectory is invalid or cannot be
+        *             written to.
+        * 
+        * @see MultipartRequest#MAX_READ_BYTES
+        */
+       public ServletMultipartRequest(HttpServletRequest request,
+                       String strSaveDirectory) throws IllegalArgumentException,
+                       IOException {
+               super(null, request.getContentType(), request.getContentLength(),
+                               request.getInputStream(), strSaveDirectory,
+                               MultipartRequest.MAX_READ_BYTES);
+       }
+
+       /**
+        * Constructor wrapper, unwraps the InputStream, content type and content
+        * lenght from the servlet request object. Also allow to explicitly set the
+        * max permissable length of the request.
+        * 
+        * @param request
+        *            the HttpServletRequest will be used to initialise the
+        *            MultipartRequest super class.
+        * @param strSaveDirectory
+        *            the temporary directory to save the file from where they can
+        *            then be moved to wherever by the calling process. <b>If you
+        *            specify <u>null</u> for this parameter, then any files
+        *            uploaded will be silently ignored.</B>
+        * @param intMaxReadBytes
+        *            Overrides the MAX_BYTES_READ value, to allow arbitrarily long
+        *            files.
+        * 
+        * @throws IllegalArgumentException
+        *             If the request.getContentType() does not contain a
+        *             Content-Type of "multipart/form-data" or the boundary is not
+        *             found.
+        * @throws IOException
+        *             If the request.getContentLength() is higher than
+        *             MAX_READ_BYTES or strSaveDirectory is invalid or cannot be
+        *             written to.
+        * 
+        * @see MultipartRequest#MAX_READ_BYTES
+        */
+       public ServletMultipartRequest(HttpServletRequest request,
+                       String strSaveDirectory, int intMaxReadBytes)
+                       throws IllegalArgumentException, IOException {
+               super(null, request.getContentType(), request.getContentLength(),
+                               request.getInputStream(), strSaveDirectory, intMaxReadBytes);
+       }
+
+       /**
+        * Constructor wrapper for loading the request into memory rather than
+        * temp-file.
+        * 
+        * @param request
+        *            the HttpServletRequest will be used to initialise the
+        *            MultipartRequest super class.
+        * @param intMaxReadBytes
+        *            Overrides the MAX_BYTES_READ value, to allow arbitrarily long
+        *            files.
+        * 
+        * @throws IllegalArgumentException
+        *             If the request.getContentType() does not contain a
+        *             Content-Type of "multipart/form-data" or the boundary is not
+        *             found.
+        * @throws IOException
+        *             If the request.getContentLength() is higher than
+        *             MAX_READ_BYTES or strSaveDirectory is invalid or cannot be
+        *             written to.
+        * 
+        * @see MultipartRequest#MAX_READ_BYTES
+        */
+       public ServletMultipartRequest(HttpServletRequest request,
+                       int intMaxReadBytes) throws IllegalArgumentException, IOException {
+               super(null, request.getContentType(), request.getContentLength(),
+                               request.getInputStream(), intMaxReadBytes);
+       }
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/server/WebApplicationContext.java b/src/com/itmill/toolkit/terminal/gwt/server/WebApplicationContext.java
new file mode 100644 (file)
index 0000000..0c53f87
--- /dev/null
@@ -0,0 +1,261 @@
+/* *************************************************************************
+ 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.gwt.server;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.WeakHashMap;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import com.itmill.toolkit.Application;
+import com.itmill.toolkit.service.ApplicationContext;
+import com.itmill.toolkit.ui.Window;
+
+/**
+ * Web application context for the IT Mill Toolkit applications.
+ * 
+ * @author IT Mill Ltd.
+ * @version
+ * @VERSION@
+ * @since 3.1
+ */
+public class WebApplicationContext implements ApplicationContext {
+
+       private List listeners;
+
+       private HttpSession session;
+
+       private WeakHashMap formActions = new WeakHashMap();
+
+       /**
+        * Creates a new Web Application Context.
+        * 
+        * @param session
+        *            the HTTP session.
+        */
+       WebApplicationContext(HttpSession session) {
+               this.session = session;
+       }
+
+       /**
+        * Gets the form action for given window.
+        * <p>
+        * By default, this action is "", which preserves the current url. Commonly
+        * this is wanted to be set to <code>application.getUrl.toString</code> or
+        * <code>window.getUrl.toString</code> in order to clean any local links
+        * or parameters set from the action.
+        * </p>
+        * 
+        * @param window
+        *            the Window for which the action is queried.
+        * @return the Action to be set into Form action attribute.
+        */
+       public String getWindowFormAction(Window window) {
+               String action = (String) formActions.get(window);
+               return action == null ? "" : action;
+       }
+
+       /**
+        * Sets the form action for given window.
+        * <p>
+        * By default, this action is "", which preserves the current url. Commonly
+        * this is wanted to be set to <code>application.getUrl.toString</code> or
+        * <code>window.getUrl.toString</code> in order to clean any local links
+        * or parameters set from the action.
+        * </p>
+        * 
+        * @param window
+        *            the Window for which the action is set.
+        * @param action
+        *            the New action for the window.
+        */
+       public void setWindowFormAction(Window window, String action) {
+               if (action == null || action == "")
+                       formActions.remove(window);
+               else
+                       formActions.put(window, action);
+       }
+
+       /**
+        * Gets the application context base directory.
+        * 
+        * @see com.itmill.toolkit.service.ApplicationContext#getBaseDirectory()
+        */
+       public File getBaseDirectory() {
+               String realPath = ApplicationServlet.getResourcePath(session
+                               .getServletContext(), "/");
+               if (realPath == null)
+                       return null;
+               return new File(realPath);
+       }
+
+       /**
+        * Gets the http-session application is running in.
+        * 
+        * @return HttpSession this application context resides in.
+        */
+       public HttpSession getHttpSession() {
+               return session;
+       }
+
+       /**
+        * Gets the applications in this context.
+        * 
+        * @see com.itmill.toolkit.service.ApplicationContext#getApplications()
+        */
+       public Collection getApplications() {
+               LinkedList applications = (LinkedList) session
+                               .getAttribute(ApplicationServlet.SESSION_ATTR_APPS);
+
+               return Collections
+                               .unmodifiableCollection(applications == null ? (new LinkedList())
+                                               : applications);
+       }
+
+       /**
+        * Gets the application context for HttpSession.
+        * 
+        * @param session
+        *            the HTTP session.
+        * @return the application context for HttpSession.
+        */
+       static public WebApplicationContext getApplicationContext(
+                       HttpSession session) {
+               return new WebApplicationContext(session);
+       }
+
+       /**
+        * Returns <code>true</code> if and only if the argument is not
+        * <code>null</code> and is a Boolean object that represents the same
+        * boolean value as this object.
+        * 
+        * @param obj
+        *            the object to compare with.
+        * @see java.lang.Object#equals(java.lang.Object)
+        */
+       public boolean equals(Object obj) {
+               return session.equals(obj);
+       }
+
+       /**
+        * Returns the hash code value .
+        * 
+        * @see java.lang.Object#hashCode()
+        */
+       public int hashCode() {
+               return session.hashCode();
+       }
+
+       /**
+        * Adds the transaction listener to this context.
+        * 
+        * @see com.itmill.toolkit.service.ApplicationContext#addTransactionListener(com.itmill.toolkit.service.ApplicationContext.TransactionListener)
+        */
+       public void addTransactionListener(TransactionListener listener) {
+               if (this.listeners == null)
+                       this.listeners = new LinkedList();
+               this.listeners.add(listener);
+       }
+
+       /**
+        * Removes the transaction listener from this context.
+        * 
+        * @see com.itmill.toolkit.service.ApplicationContext#removeTransactionListener(com.itmill.toolkit.service.ApplicationContext.TransactionListener)
+        */
+       public void removeTransactionListener(TransactionListener listener) {
+               if (this.listeners != null)
+                       this.listeners.remove(listener);
+
+       }
+
+       /**
+        * Notifies the transaction start.
+        * 
+        * @param application
+        * @param request
+        *            the HTTP request.
+        */
+       protected void startTransaction(Application application,
+                       HttpServletRequest request) {
+               if (this.listeners == null)
+                       return;
+               for (Iterator i = this.listeners.iterator(); i.hasNext();) {
+                       ((ApplicationContext.TransactionListener) i.next())
+                                       .transactionStart(application, request);
+               }
+       }
+
+       /**
+        * Notifies the transaction end.
+        * 
+        * @param application
+        * @param request
+        *            the HTTP request.
+        */
+       protected void endTransaction(Application application,
+                       HttpServletRequest request) {
+               if (this.listeners == null)
+                       return;
+
+               LinkedList exceptions = null;
+               for (Iterator i = this.listeners.iterator(); i.hasNext();)
+                       try {
+                               ((ApplicationContext.TransactionListener) i.next())
+                                               .transactionEnd(application, request);
+                       } catch (RuntimeException t) {
+                               if (exceptions == null)
+                                       exceptions = new LinkedList();
+                               exceptions.add(t);
+                       }
+
+               // If any runtime exceptions occurred, throw a combined exception
+               if (exceptions != null) {
+                       StringBuffer msg = new StringBuffer();
+                       for (Iterator i = listeners.iterator(); i.hasNext();) {
+                               RuntimeException e = (RuntimeException) i.next();
+                               if (msg.length() == 0)
+                                       msg.append("\n\n--------------------------\n\n");
+                               msg.append(e.getMessage() + "\n");
+                               StringWriter trace = new StringWriter();
+                               e.printStackTrace(new PrintWriter(trace, true));
+                               msg.append(trace.toString());
+                       }
+                       throw new RuntimeException(msg.toString());
+               }
+       }
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/server/WebBrowser.java b/src/com/itmill/toolkit/terminal/gwt/server/WebBrowser.java
new file mode 100644 (file)
index 0000000..f89db74
--- /dev/null
@@ -0,0 +1,703 @@
+/* *************************************************************************
+ 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.gwt.server;
+
+import com.itmill.toolkit.terminal.Terminal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Locale;
+
+/**
+ * Web browser terminal type.
+ * 
+ * This class implements web browser properties, which declare the features of
+ * the web browser.
+ * 
+ * @author IT Mill Ltd.
+ * @version
+ * @VERSION@
+ * @since 3.0
+ */
+public class WebBrowser implements Terminal {
+
+       private static WebBrowser DEFAULT = new WebBrowser();
+
+       /**
+        * Content type.
+        */
+       private String contentType = "text/html; charset=utf-8";
+
+       /**
+        * Holds the collection of accepted locales.
+        */
+       private Collection locales = new ArrayList();
+
+       /**
+        * Holds value of property browserApplication.
+        */
+       private String browserApplication = null;
+
+       /**
+        * Should the client side checkking be done.
+        */
+       private boolean performClientCheck = true;
+
+       /**
+        * Holds value for property isClientSideChecked.
+        */
+       private boolean clientSideChecked = false;
+
+       /**
+        * Holds value of property javaScriptVersion.
+        */
+       private JavaScriptVersion javaScriptVersion = JAVASCRIPT_UNCHECKED;
+
+       /**
+        * Holds value of property javaEnabled.
+        */
+       private boolean javaEnabled = false;
+
+       /**
+        * Holds value of property frameSupport.
+        */
+       private boolean frameSupport = false;
+
+       /**
+        * Holds value of property markup version.
+        */
+       private MarkupVersion markupVersion = MARKUP_HTML_3_2;
+
+       /**
+        * Pixel width of the terminal screen.
+        */
+       private int screenWidth = -1;
+
+       /**
+        * Pixel height of the terminal screen.
+        */
+       private int screenHeight = -1;
+
+       /**
+        * Constuctor with some autorecognition capabilities Retrieves all
+        * capability information reported in http request headers:
+        * <ul>
+        * <li>User web browser (User-Agent)</li>
+        * <li>Supported locale(s)</li>
+        * </ul>
+        */
+
+       /**
+        * Constructor WebBrowserType. Creates a default WebBrowserType instance.
+        */
+       public WebBrowser() {
+       }
+
+       /**
+        * Gets the name of the default theme.
+        * 
+        * @return the Name of the terminal window.
+        */
+       public String getDefaultTheme() {
+               return ApplicationServlet.DEFAULT_THEME;
+       }
+
+       /**
+        * Gets the name and version of the web browser application. This is the
+        * version string reported by the web-browser in http headers.
+        * 
+        * @return the Web browser application.
+        */
+       public String getBrowserApplication() {
+               return this.browserApplication;
+       }
+
+       /**
+        * Gets the version of the supported Java Script by the browser.
+        * 
+        * <code>Null</code> if the Java Script is not supported.
+        * 
+        * @return the Version of the supported Java Script.
+        */
+       public JavaScriptVersion getJavaScriptVersion() {
+               return this.javaScriptVersion;
+       }
+
+       /**
+        * Does the browser support frames ?
+        * 
+        * @return <code>true</code> if the browser supports frames, otherwise
+        *         <code>false</code>.
+        */
+       public boolean isFrameSupport() {
+               return this.frameSupport;
+       }
+
+       /**
+        * Sets the browser frame support.
+        * 
+        * @param frameSupport
+        *            True if the browser supports frames, False if not.
+        */
+       public void setFrameSupport(boolean frameSupport) {
+               this.frameSupport = frameSupport;
+       }
+
+       /**
+        * Gets the supported markup language.
+        * 
+        * @return the Supported markup language
+        */
+       public MarkupVersion getMarkupVersion() {
+               return this.markupVersion;
+       }
+
+       /**
+        * Gets the height of the terminal window in pixels.
+        * 
+        * @return the Height of the terminal window.
+        */
+       public int getScreenHeight() {
+               return this.screenHeight;
+       }
+
+       /**
+        * Gets the width of the terminal window in pixels.
+        * 
+        * @return the Width of the terminal window.
+        */
+       public int getScreenWidth() {
+               return this.screenWidth;
+       }
+
+       /**
+        * Gets the default locale requested by the browser.
+        * 
+        * @return the Default locale.
+        */
+       public Locale getDefaultLocale() {
+               if (this.locales.isEmpty())
+                       return null;
+               return (Locale) this.locales.iterator().next();
+       }
+
+       /**
+        * Hash code composed of the properties of the web browser type.
+        * 
+        * @see java.lang.Object#hashCode()
+        */
+       public int hashCode() {
+               return toString().hashCode();
+       }
+
+       /**
+        * Tests the equality of the properties for two web browser types.
+        * 
+        * @see java.lang.Object#equals(java.lang.Object)
+        */
+       public boolean equals(Object obj) {
+               if (obj != null && obj instanceof WebBrowser) {
+                       return toString().equals(obj.toString());
+               }
+               return false;
+       }
+
+       /**
+        * @see java.lang.Object#toString()
+        */
+       public String toString() {
+
+               String localeString = "[";
+               for (Iterator i = this.locales.iterator(); i.hasNext(); localeString += ",") {
+                       localeString += ((Locale) i.next()).toString();
+               }
+               localeString += "]";
+
+               // Returns catenation of the properties
+               return "Browser:" + this.browserApplication + ", " + "Locales:"
+                               + localeString + ", " + "Frames:" + this.frameSupport + ", "
+                               + "JavaScript:" + this.javaScriptVersion + ", " + "Java: "
+                               + this.javaEnabled + ", " + "Markup:" + this.markupVersion
+                               + ", " + "Height:" + this.screenHeight + ", " + "Width:"
+                               + this.screenWidth + ", ClientCheck:" + this.performClientCheck
+                               + ", ClientCheckDone:" + this.clientSideChecked;
+       }
+
+       /**
+        * Gets the preferred content type.
+        * 
+        * @return the content type.
+        */
+       public String getContentType() {
+               return contentType;
+       }
+
+       /**
+        * Checks if this type supports also given browser.
+        * 
+        * @param browser
+        *            the browser type.
+        * @return true if this type matches the given browser.
+        */
+       public boolean supports(String browser) {
+               return this.getBrowserApplication().indexOf(browser) >= 0;
+       }
+
+       /**
+        * Checks if this type supports given markup language version.
+        * 
+        * @param html
+        *            the markup language version.
+        * @return <code>true</ocde> if this type supports the given markup version,otherwise <code>false</code>.
+        */
+       public boolean supports(MarkupVersion html) {
+               return this.getMarkupVersion().supports(html);
+       }
+
+       /**
+        * Checks if this type supports given javascript version.
+        * 
+        * @param js
+        *            the javascript version to check for.
+        * @return true if this type supports the given javascript version.
+        */
+       public boolean supports(JavaScriptVersion js) {
+               return this.getJavaScriptVersion().supports(js);
+       }
+
+       /**
+        * Parses HTML version from string.
+        * 
+        * @param html
+        * @return HTMLVersion instance.
+        */
+       private MarkupVersion doParseHTMLVersion(String html) {
+               for (int i = 0; i < MARKUP_VERSIONS.length; i++) {
+                       if (MARKUP_VERSIONS[i].name.equals(html))
+                               return MARKUP_VERSIONS[i];
+               }
+               return MARKUP_UNKNOWN;
+       }
+
+       /**
+        * Parses JavaScript version from string.
+        * 
+        * @param js
+        *            the javascript version to check for.
+        * @return HTMLVersion instance.
+        */
+       private JavaScriptVersion doParseJavaScriptVersion(String js) {
+               for (int i = 0; i < JAVASCRIPT_VERSIONS.length; i++) {
+                       if (JAVASCRIPT_VERSIONS[i].name.toLowerCase().startsWith(
+                                       js.toLowerCase()))
+                               return JAVASCRIPT_VERSIONS[i];
+               }
+               return JAVASCRIPT_NONE;
+       }
+
+       /**
+        * Parses HTML version from string.
+        * 
+        * @param html
+        * @return the HTMLVersion instance.
+        */
+       public static MarkupVersion parseHTMLVersion(String html) {
+               return DEFAULT.doParseHTMLVersion(html);
+       }
+
+       /**
+        * Parse JavaScript version from string.
+        * 
+        * @param js
+        *            the javascript version to check for.
+        * @return the HTMLVersion instance.
+        */
+       public static JavaScriptVersion parseJavaScriptVersion(String js) {
+               return DEFAULT.doParseJavaScriptVersion(js);
+       }
+
+       /**
+        * Gets the client side cheked property. Certain terminal features can only
+        * be detected at client side. This property indicates if the client side
+        * detections have been performed for this type.
+        * 
+        * @return <code>true</code> if client has sent information about its
+        *         properties. Default is <code>false</code>.
+        */
+       public boolean isClientSideChecked() {
+               return this.clientSideChecked;
+       }
+
+       /**
+        * Sets the client side checked property. Certain terminal features can only
+        * be detected at client side. This property indicates if the client side
+        * detections have been performed for this type.
+        * 
+        * @param value
+        *            true if client has sent information about its properties,
+        *            false otherweise.
+        */
+       public void setClientSideChecked(boolean value) {
+               this.clientSideChecked = value;
+       }
+
+       /**
+        * Should the client features be checked using remote scripts. Should the
+        * client side terminal feature check be performed.
+        * 
+        * @return <code>true</code> if client side checking should be performed
+        *         for this terminal type. Default is <code>false</code>.
+        */
+       public boolean performClientCheck() {
+               return this.performClientCheck;
+       }
+
+       /**
+        * Should the client features be checked using remote scripts.
+        * 
+        * @param value
+        * @return <code>true</code> if client side checking should be performed
+        *         for this terminal type. Default <code>false</code>.
+        */
+       public void performClientCheck(boolean value) {
+               this.performClientCheck = value;
+       }
+
+       /**
+        * Checks if web browser supports Java.
+        * 
+        * @return <code>true<code> if the browser supports java otherwise <code>false</code>.
+        */
+       public boolean isJavaEnabled() {
+               return javaEnabled;
+       }
+
+       /**
+        * Returns the locales supported by the web browser.
+        * 
+        * @return the Collection.
+        */
+       public Collection getLocales() {
+               return locales;
+       }
+
+       /**
+        * Sets the browser application. This corresponds to User-Agent HTTP header.
+        * 
+        * @param browserApplication
+        *            the browserApplication to set.
+        */
+       public void setBrowserApplication(String browserApplication) {
+               this.browserApplication = browserApplication;
+       }
+
+       /**
+        * Sets the default content type. Default is <code>text/html</code>
+        * 
+        * @param contentType
+        *            the contentType to set.
+        */
+       public void setContentType(String contentType) {
+               this.contentType = contentType;
+       }
+
+       /**
+        * Sets the java enabled property.
+        * 
+        * @param javaEnabled
+        *            the javaEnabled to set.
+        */
+       public void setJavaEnabled(boolean javaEnabled) {
+               this.javaEnabled = javaEnabled;
+       }
+
+       /**
+        * Sets the JavaScript version.
+        * 
+        * @param javaScriptVersion
+        *            the JavaScript version to set.
+        */
+       public void setJavaScriptVersion(JavaScriptVersion javaScriptVersion) {
+               this.javaScriptVersion = javaScriptVersion;
+       }
+
+       /**
+        * Sets the markup language version.
+        * 
+        * @param markupVersion
+        *            the markup language version to set.
+        */
+       public void setMarkupVersion(MarkupVersion markupVersion) {
+               this.markupVersion = markupVersion;
+       }
+
+       /**
+        * Sets the screen height.
+        * 
+        * @param screenHeight
+        *            the screen height to set in pixels.
+        */
+       public void setScreenHeight(int screenHeight) {
+               this.screenHeight = screenHeight;
+       }
+
+       /**
+        * Sets the screen width.
+        * 
+        * @param screenWidth
+        *            the screenWidth to set in pixels.
+        */
+       public void setScreenWidth(int screenWidth) {
+               this.screenWidth = screenWidth;
+       }
+
+       /*
+        * Consts defining the supported markup language versions @author IT Mill
+        * Ltd.
+        * 
+        * @version @VERSION@
+        * @since 3.0
+        */
+       public class MarkupVersion {
+               private String name;
+
+               private int order;
+
+               /**
+                * Returns <code>true</code> if and only if the argument is not
+                * <code>null</code> and is a Boolean object that represents the same
+                * boolean value as this object.
+                * 
+                * @param obj
+                *            the object to compare with.
+                * @see java.lang.Object#equals(Object)
+                */
+               public boolean equals(Object obj) {
+                       if (obj != null && obj instanceof MarkupVersion)
+                               return name.equals(((MarkupVersion) obj).name);
+                       return false;
+               }
+
+               /**
+                * @see java.lang.Object#toString()
+                */
+               public String toString() {
+                       return name;
+               }
+
+               /**
+                * 
+                * @param name
+                * @param order
+                */
+               private MarkupVersion(String name, int order) {
+                       this.name = name;
+                       this.order = order;
+               }
+
+               /**
+                * Checks the compability with other HTML version.
+                * 
+                * @param other
+                *            the HTML version.
+                * @return <code>true</code> if this is compatible with the other,
+                *         otherwise <code>false</code>.
+                */
+               public boolean supports(MarkupVersion other) {
+                       return (this.order >= other.order);
+               }
+
+       }
+
+       public static final MarkupVersion MARKUP_UNKNOWN = DEFAULT.new MarkupVersion(
+                       "HTML unknown", 0);
+
+       public static final MarkupVersion MARKUP_HTML_2_0 = DEFAULT.new MarkupVersion(
+                       "HTML 2.0", 20);
+
+       public static final MarkupVersion MARKUP_HTML_3_2 = DEFAULT.new MarkupVersion(
+                       "HTML 3.2", 32);
+
+       public static final MarkupVersion MARKUP_HTML_4_0 = DEFAULT.new MarkupVersion(
+                       "HTML 4.0", 40);
+
+       public static final MarkupVersion MARKUP_XHTML_1_0 = DEFAULT.new MarkupVersion(
+                       "XHTML 1.0", 110);
+
+       public static final MarkupVersion MARKUP_XHTML_2_0 = DEFAULT.new MarkupVersion(
+                       "XHTML 2.0", 120);
+
+       public static final MarkupVersion MARKUP_WML_1_0 = DEFAULT.new MarkupVersion(
+                       "WML 1.0", 10);
+
+       public static final MarkupVersion MARKUP_WML_1_1 = DEFAULT.new MarkupVersion(
+                       "WML 1.1", 11);
+
+       public static final MarkupVersion MARKUP_WML_1_2 = DEFAULT.new MarkupVersion(
+                       "WML 1.2", 12);
+
+       public static final MarkupVersion[] MARKUP_VERSIONS = new MarkupVersion[] {
+                       MARKUP_UNKNOWN, MARKUP_HTML_2_0, MARKUP_HTML_3_2, MARKUP_HTML_4_0,
+                       MARKUP_XHTML_1_0, MARKUP_XHTML_2_0, MARKUP_WML_1_0, MARKUP_WML_1_1,
+                       MARKUP_WML_1_2 };
+
+       /*
+        * Consts defining the supported JavaScript versions @author IT Mill Ltd.
+        * 
+        * @version @VERSION@
+        * @since 3.0
+        */
+       public class JavaScriptVersion {
+               private String name;
+
+               private int order;
+
+               /**
+                * @see java.lang.Object#equals(Object)
+                */
+               public boolean equals(Object obj) {
+                       if (obj != null && obj instanceof JavaScriptVersion)
+                               return name.equals(((JavaScriptVersion) obj).name);
+                       return false;
+               }
+
+               /**
+                * @see java.lang.Object#toString()
+                */
+               public String toString() {
+                       return name;
+               }
+
+               /**
+                * 
+                * @param name
+                * @param order
+                */
+               private JavaScriptVersion(String name, int order) {
+                       this.name = name;
+                       this.order = order;
+               }
+
+               /**
+                * Checks the compability with other JavaScript version. Use this like:
+                * <code>boolean isEcma = someVersion.supports(ECMA_262);</code>
+                * 
+                * @param other
+                *            the java script version.
+                * @return <code>true</code> if this supports the other, otherwise
+                *         <code>false</code>.
+                */
+               public boolean supports(JavaScriptVersion other) {
+
+                       // ECMA-262 support compare
+                       if (other.equals(ECMA_262)) {
+
+                               // JScript over 5.0 support ECMA-262
+                               if (this.order >= 100) {
+                                       return (this.order >= JSCRIPT_5_0.order);
+                               } else {
+                                       return (this.order >= JAVASCRIPT_1_3.order);
+                               }
+                       }
+
+                       // JavaScript version compare
+                       else if (this.order < 100 && other.order < 100) {
+                               return (this.order >= other.order);
+                       }
+
+                       // JScript version compare
+                       else if (this.order >= 100 && other.order >= 100) {
+                               return (this.order >= other.order);
+                       }
+
+                       return false;
+
+               }
+
+       }
+
+       public static final JavaScriptVersion JAVASCRIPT_UNCHECKED = DEFAULT.new JavaScriptVersion(
+                       "JavaScript unchecked", -1);
+
+       public static final JavaScriptVersion JAVASCRIPT_NONE = DEFAULT.new JavaScriptVersion(
+                       "JavaScript none", -1);
+
+       public static final JavaScriptVersion JAVASCRIPT_1_0 = DEFAULT.new JavaScriptVersion(
+                       "JavaScript 1.0", 10);
+
+       public static final JavaScriptVersion JAVASCRIPT_1_1 = DEFAULT.new JavaScriptVersion(
+                       "JavaScript 1.1", 11);
+
+       public static final JavaScriptVersion JAVASCRIPT_1_2 = DEFAULT.new JavaScriptVersion(
+                       "JavaScript 1.2", 12);
+
+       public static final JavaScriptVersion JAVASCRIPT_1_3 = DEFAULT.new JavaScriptVersion(
+                       "JavaScript 1.3", 13);
+
+       public static final JavaScriptVersion JAVASCRIPT_1_4 = DEFAULT.new JavaScriptVersion(
+                       "JavaScript 1.4", 14);
+
+       public static final JavaScriptVersion JAVASCRIPT_1_5 = DEFAULT.new JavaScriptVersion(
+                       "JavaScript 1.5", 15);
+
+       public static final JavaScriptVersion JSCRIPT_1_0 = DEFAULT.new JavaScriptVersion(
+                       "JScript 1.0", 110);
+
+       public static final JavaScriptVersion JSCRIPT_3_0 = DEFAULT.new JavaScriptVersion(
+                       "JScript 3.0", 130);
+
+       public static final JavaScriptVersion JSCRIPT_4_0 = DEFAULT.new JavaScriptVersion(
+                       "JScript 4.0", 140);
+
+       public static final JavaScriptVersion JSCRIPT_5_0 = DEFAULT.new JavaScriptVersion(
+                       "JScript 5.0", 150);
+
+       public static final JavaScriptVersion JSCRIPT_5_1 = DEFAULT.new JavaScriptVersion(
+                       "JScript 5.1", 151);
+
+       public static final JavaScriptVersion JSCRIPT_5_5 = DEFAULT.new JavaScriptVersion(
+                       "JScript 5.5", 155);
+
+       public static final JavaScriptVersion JSCRIPT_5_6 = DEFAULT.new JavaScriptVersion(
+                       "JScript 5.6", 156);
+
+       public static final JavaScriptVersion JSCRIPT_5_7 = DEFAULT.new JavaScriptVersion(
+                       "JScript 5.7", 157);
+
+       public static final JavaScriptVersion ECMA_262 = DEFAULT.new JavaScriptVersion(
+                       "ECMA-262", 262);
+
+       public static final JavaScriptVersion[] JAVASCRIPT_VERSIONS = new JavaScriptVersion[] {
+                       JAVASCRIPT_UNCHECKED, JAVASCRIPT_NONE, JAVASCRIPT_1_0,
+                       JAVASCRIPT_1_1, JAVASCRIPT_1_2, JAVASCRIPT_1_3, JAVASCRIPT_1_4,
+                       JAVASCRIPT_1_5, JSCRIPT_1_0, JSCRIPT_3_0, JSCRIPT_4_0, JSCRIPT_5_0,
+                       JSCRIPT_5_1, JSCRIPT_5_5, JSCRIPT_5_6, JSCRIPT_5_7, ECMA_262 };
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/server/WebBrowserProbe.java b/src/com/itmill/toolkit/terminal/gwt/server/WebBrowserProbe.java
new file mode 100644 (file)
index 0000000..d6ca56c
--- /dev/null
@@ -0,0 +1,349 @@
+/* *************************************************************************
+ 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.gwt.server;
+
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+/**
+ * The <code>WebBrowserProbe</code> uses JavaScript to determine the
+ * capabilities of the client browser.
+ * 
+ * @author IT Mill Ltd.
+ * @version
+ * @VERSION@
+ * @since 3.0
+ */
+public class WebBrowserProbe {
+
+       private static final String WA_NOSCRIPT = "WA_NOSCRIPT";
+
+       private static final String CLIENT_TYPE = "wa_browser";
+
+       /**
+        * Returns the terminal type from the given session.
+        * 
+        * @param session
+        *            the HTTP session.
+        * @return WebBrowser instance for the given session.
+        */
+       public static WebBrowser getTerminalType(HttpSession session) {
+               if (session != null)
+                       return (WebBrowser) session.getAttribute(CLIENT_TYPE);
+               return null;
+       }
+
+       /**
+        * Sets the terminal type for the given session.
+        * 
+        * @param session
+        *            the HTTP session.
+        * @param terminal
+        *            the web browser.
+        * @return WebBrowser instance for the given session.
+        */
+       public static void setTerminalType(HttpSession session, WebBrowser terminal) {
+               if (session != null)
+                       session.setAttribute(CLIENT_TYPE, terminal);
+       }
+
+       /**
+        * Handles the client checking.
+        * 
+        * @param request
+        *            the HTTP request to process.
+        * @param parameters
+        *            the Parameters to be used as defaults.
+        * @return <code>true</code> if response should include a probe
+        *         script,otherwise <code>false</code>.
+        * @throws ServletException
+        *             if an exception has occurred that interferes with the
+        *             servlet's normal operation.
+        */
+       public static boolean handleProbeRequest(HttpServletRequest request,
+                       Map parameters) throws ServletException {
+
+               HttpSession s = request.getSession();
+               WebBrowser browser = getTerminalType(s);
+               if (browser != null) {
+
+                       // Check if no-script was requested
+                       if (parameters.containsKey(WA_NOSCRIPT)) {
+                               String val = ((String[]) parameters.get(WA_NOSCRIPT))[0];
+                               if (val != null && "1".equals(val)) {
+                                       browser.setJavaScriptVersion(WebBrowser.JAVASCRIPT_NONE);
+                                       browser.setClientSideChecked(true);
+                               } else {
+                                       // Recheck
+                                       browser.setClientSideChecked(false);
+                               }
+                       }
+
+                       // If client is alredy checked disable further checking
+                       if (browser.isClientSideChecked())
+                               return false;
+
+               }
+
+               // Creates new type based on client parameters
+               browser = probe(browser, request, parameters);
+               setTerminalType(s, browser);
+
+               // Sets client as checked if parameters were found
+               if (parameters.containsKey("wa_clientprobe")) {
+                       String val = ((String[]) parameters.get("wa_clientprobe"))[0];
+                       browser.setClientSideChecked(val != null && "1".equals(val));
+               }
+
+               // Include probe script if requested and not alredy probed
+               return browser.performClientCheck() && !browser.isClientSideChecked();
+
+       }
+
+       /**
+        * Determines versions based on user agent string.
+        * 
+        * @param agent
+        *            the HTTP User-Agent request header.
+        * @return new WebBrowser instance initialized based on agent features.
+        */
+       public static WebBrowser probe(String agent) {
+               WebBrowser res = new WebBrowser();
+               if (agent == null)
+                       return res;
+
+               // Set the agent string
+               res.setBrowserApplication(agent);
+
+               // Konqueror
+               if (agent.indexOf("Konqueror") >= 0) {
+                       res.setJavaScriptVersion(WebBrowser.JSCRIPT_5_6);
+                       res.setJavaEnabled(true);
+                       res.setFrameSupport(true);
+               }
+
+               // Opera
+               else if (agent.indexOf("Opera 3.") >= 0) {
+                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_1_3);
+                       res.setJavaEnabled(false);
+                       res.setFrameSupport(true);
+               } else if (agent.indexOf("Opera") >= 0) {
+                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_1_3);
+                       res.setJavaEnabled(true);
+                       res.setFrameSupport(true);
+                       res.setMarkupVersion(WebBrowser.MARKUP_HTML_4_0);
+                       if (agent.indexOf("Opera/9") >= 0)
+                               res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_1_5);
+               }
+
+               // OmniWeb
+               else if (agent.indexOf("OmniWeb") >= 0) {
+                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_1_3);
+                       res.setJavaEnabled(true);
+                       res.setFrameSupport(true);
+               }
+
+               // Mosaic
+               else if (agent.indexOf("Mosaic") >= 0) {
+                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_1_3);
+                       res.setJavaEnabled(true);
+                       res.setFrameSupport(true);
+                       res.setMarkupVersion(WebBrowser.MARKUP_HTML_2_0);
+               }
+
+               // Lynx
+               else if (agent.indexOf("Lynx") >= 0) {
+                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_NONE);
+                       res.setJavaEnabled(false);
+                       res.setFrameSupport(true);
+               }
+
+               // Microsoft Browsers
+               // See Microsoft documentation for details:
+               // http://msdn.microsoft.com/library/default.asp?url=/library/
+               // en-us/script56/html/js56jsoriversioninformation.asp
+               else if (agent.indexOf("MSIE 7.") >= 0) {
+                       res.setJavaScriptVersion(WebBrowser.JSCRIPT_5_7);
+                       res.setJavaEnabled(true);
+                       res.setFrameSupport(true);
+                       res.setMarkupVersion(WebBrowser.MARKUP_HTML_4_0);
+               } else if (agent.indexOf("MSIE 6.") >= 0) {
+                       res.setJavaScriptVersion(WebBrowser.JSCRIPT_5_6);
+                       res.setJavaEnabled(true);
+                       res.setFrameSupport(true);
+                       res.setMarkupVersion(WebBrowser.MARKUP_HTML_4_0);
+               } else if (agent.indexOf("MSIE 5.5") >= 0) {
+                       res.setJavaScriptVersion(WebBrowser.JSCRIPT_5_5);
+                       res.setJavaEnabled(true);
+                       res.setFrameSupport(true);
+                       res.setMarkupVersion(WebBrowser.MARKUP_HTML_4_0);
+               } else if (agent.indexOf("MSIE 5.") >= 0) {
+                       res.setJavaScriptVersion(WebBrowser.JSCRIPT_5_0);
+                       res.setJavaEnabled(true);
+                       res.setFrameSupport(true);
+                       res.setMarkupVersion(WebBrowser.MARKUP_HTML_4_0);
+               } else if (agent.indexOf("MSIE 4.") >= 0) {
+                       res.setJavaScriptVersion(WebBrowser.JSCRIPT_3_0);
+                       res.setJavaEnabled(true);
+                       res.setFrameSupport(true);
+                       res.setMarkupVersion(WebBrowser.MARKUP_HTML_4_0);
+               } else if (agent.indexOf("MSIE 3.") >= 0) {
+                       res.setJavaScriptVersion(WebBrowser.JSCRIPT_3_0);
+                       res.setJavaEnabled(true);
+                       res.setFrameSupport(true);
+               } else if (agent.indexOf("MSIE 2.") >= 0) {
+                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_NONE);
+                       res.setJavaEnabled(false);
+                       if (agent.indexOf("Mac") >= 0) {
+                               res.setFrameSupport(true);
+                       } else {
+                               res.setFrameSupport(false);
+                       }
+               }
+
+               // Netscape browsers
+               else if (agent.indexOf("Netscape6") >= 0) {
+                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_1_5);
+                       res.setJavaEnabled(true);
+                       res.setFrameSupport(true);
+                       res.setMarkupVersion(WebBrowser.MARKUP_HTML_4_0);
+               } else if ((agent.indexOf("Mozilla/4.06") >= 0)
+                               || (agent.indexOf("Mozilla/4.7") >= 0)) {
+                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_1_3);
+                       res.setJavaEnabled(true);
+                       res.setFrameSupport(true);
+                       res.setMarkupVersion(WebBrowser.MARKUP_HTML_4_0);
+               } else if (agent.indexOf("Mozilla/4.") >= 0) {
+                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_1_2);
+                       res.setJavaEnabled(true);
+                       res.setFrameSupport(true);
+               } else if (agent.indexOf("Mozilla/3.") >= 0) {
+                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_1_1);
+                       res.setJavaEnabled(true);
+                       res.setFrameSupport(true);
+               } else if (agent.indexOf("Mozilla/2.") >= 0) {
+                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_1_0);
+                       res.setJavaEnabled(true);
+                       res.setFrameSupport(true);
+               }
+
+               // Mozilla Open-Source Browsers
+               else if (agent.indexOf("Mozilla/5.") >= 0) {
+                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_1_5);
+                       res.setJavaEnabled(true);
+                       res.setFrameSupport(true);
+                       res.setMarkupVersion(WebBrowser.MARKUP_HTML_4_0);
+               }
+
+               // Unknown browser
+               else {
+                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_UNCHECKED);
+                       res.setJavaEnabled(false);
+                       res.setMarkupVersion(WebBrowser.MARKUP_UNKNOWN);
+                       res.setFrameSupport(false);
+               }
+
+               return res;
+       }
+
+       /**
+        * Creates new instance of WebBrowser by initializing the values based on
+        * user request.
+        * 
+        * @param browser
+        *            the browser to be updated. If null a new instance is created.
+        * @param request
+        *            the Request to be used as defaults.
+        * @param params
+        *            the Parameters to be used as defaults.
+        * @return new WebBrowser instance initialized based on request parameters.
+        */
+       public static WebBrowser probe(WebBrowser browser,
+                       HttpServletRequest request, Map params) {
+
+               // Initialize defaults based on client features
+               WebBrowser res = browser;
+               if (res == null) {
+                       res = probe(request.getHeader("User-Agent"));
+               }
+
+               // Client locales
+               Collection locales = res.getLocales();
+               locales.clear();
+               for (Enumeration e = request.getLocales(); e.hasMoreElements();) {
+                       locales.add(e.nextElement());
+               }
+
+               // Javascript version
+               if (params.containsKey("wa_jsversion")) {
+                       String val = ((String[]) params.get("wa_jsversion"))[0];
+                       if (val != null) {
+                               res
+                                               .setJavaScriptVersion(WebBrowser
+                                                               .parseJavaScriptVersion(val));
+                       }
+               }
+               // Java support
+               if (params.containsKey("wa_javaenabled")) {
+                       String val = ((String[]) params.get("wa_javaenabled"))[0];
+                       if (val != null) {
+                               res.setJavaEnabled(Boolean.valueOf(val).booleanValue());
+                       }
+               }
+               // Screen width
+               if (params.containsKey("wa_screenwidth")) {
+                       String val = ((String[]) params.get("wa_screenwidth"))[0];
+                       if (val != null) {
+                               try {
+                                       res.setScreenWidth(Integer.parseInt(val));
+                               } catch (NumberFormatException e) {
+                                       res.setScreenWidth(-1);
+                               }
+                       }
+               }
+               // Screen height
+               if (params.containsKey("wa_screenheight")) {
+                       String val = ((String[]) params.get("wa_screenheight"))[0];
+                       if (val != null) {
+                               try {
+                                       res.setScreenHeight(Integer.parseInt(val));
+                               } catch (NumberFormatException e) {
+                                       res.setScreenHeight(-1);
+                               }
+                       }
+               }
+
+               return res;
+       }
+}
\ No newline at end of file
diff --git a/src/com/itmill/toolkit/terminal/web/AjaxApplicationManager.java b/src/com/itmill/toolkit/terminal/web/AjaxApplicationManager.java
deleted file mode 100644 (file)
index 0b7d7f3..0000000
+++ /dev/null
@@ -1,940 +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 java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.text.DateFormatSymbols;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.GregorianCalendar;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.WeakHashMap;
-
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-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;
-import com.itmill.toolkit.ui.Component;
-import com.itmill.toolkit.ui.FrameWindow;
-import com.itmill.toolkit.ui.Window;
-
-/**
- * Application manager processes changes and paints for single application
- * instance.
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.1
- */
-public class AjaxApplicationManager implements
-               Paintable.RepaintRequestListener, Application.WindowAttachListener,
-               Application.WindowDetachListener {
-
-       private static String GET_PARAM_REPAINT_ALL = "repaintAll";
-
-       private static int DEFAULT_BUFFER_SIZE = 32 * 1024;
-
-       private static int MAX_BUFFER_SIZE = 64 * 1024;
-
-       private WeakHashMap applicationToVariableMapMap = new WeakHashMap();
-
-       private HashSet dirtyPaintabletSet = new HashSet();
-
-       // TODO THIS TEMPORARY HACK IS ONLY HERE TO MAKE GWT DEVEL EASIER
-    static WeakHashMap paintableIdMap = new WeakHashMap();
-
-       private int idSequence = 0;
-
-       private Application application;
-
-       private Set removedWindows = new HashSet();
-
-       private PaintTarget paintTarget;
-       
-       private List locales;
-       
-       private int pendingLocalesIndex;
-
-       public AjaxApplicationManager(Application application) {
-               this.application = application;
-               requireLocale(application.getLocale().toString());
-       }
-
-       /**
-        * 
-        * @return
-        */
-       private AjaxVariableMap getVariableMap() {
-               AjaxVariableMap vm = (AjaxVariableMap) applicationToVariableMapMap
-                               .get(application);
-               if (vm == null) {
-                       vm = new AjaxVariableMap();
-                       applicationToVariableMapMap.put(application, vm);
-               }
-               return vm;
-       }
-
-       /**
-        * 
-        * 
-        */
-       public void takeControl() {
-               application.addListener((Application.WindowAttachListener) this);
-               application.addListener((Application.WindowDetachListener) this);
-
-       }
-
-       /**
-        * 
-        * 
-        */
-       public void releaseControl() {
-               application.removeListener((Application.WindowAttachListener) this);
-               application.removeListener((Application.WindowDetachListener) this);
-       }
-
-       
-       public void handleUidlRequest(HttpServletRequest request,
-                       HttpServletResponse response, ThemeSource themeSource) throws IOException {
-               handleUidlRequest(request,
-                               response, themeSource, false); 
-               
-       }
-
-       
-       /**
-        * 
-        * @param request
-        *            the HTTP Request.
-        * @param response
-        *            the HTTP Response.
-        * @throws IOException
-        *             if the writing failed due to input/output error.
-        */
-       public void handleUidlRequest(HttpServletRequest request,
-                       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)
-                               || request.getSession().isNew();
-
-               OutputStream out = response.getOutputStream();
-               PrintWriter outWriter = new PrintWriter(new BufferedWriter(
-                               new OutputStreamWriter(out, "UTF-8")));
-               
-               outWriter.print(")/*{"); // some dirt to prevent cross site scripting vulnerabilities
-
-               try {
-
-                       // Is this a download request from application
-                       DownloadStream download = null;
-
-                       // The rest of the process is synchronized with the application
-                       // in order to guarantee that no parallel variable handling is
-                       // made
-                       synchronized (application) {
-
-                               // Change all variables based on request parameters
-                               Map unhandledParameters = getVariableMap().handleVariables(
-                                               request, application);
-
-                               // Handles the URI if the application is still running
-                               if (application.isRunning())
-                                       download = handleURI(application, request, response);
-
-                               // If this is not a download request
-                               if (download == null) {
-
-                                       // Finds the window within the application
-                                       Window window = null;
-                                       if (application.isRunning())
-                                               window = getApplicationWindow(request, application);
-
-                                       // Handles the unhandled parameters if the application is
-                                       // still running
-                                       if (window != null && unhandledParameters != null
-                                                       && !unhandledParameters.isEmpty())
-                                               window.handleParameters(unhandledParameters);
-
-                                       // Removes application if it has stopped
-                                       if (!application.isRunning()) {
-                                               endApplication(request, response, application);
-                                               return;
-                                       }
-
-                                       // Returns if no window found
-                                       if (window == null)
-                                               return;
-
-                                       // Sets the response type
-                                       response.setContentType("application/json; charset=UTF-8");
-                                       outWriter.print("\"changes\":[");
-                                       
-                                       paintTarget = new AjaxJsonPaintTarget(getVariableMap(), 
-                                                       this, outWriter);
-
-                                       // Paints components
-                                       Set paintables;
-                                       if (repaintAll) {
-                                               paintables = new LinkedHashSet();
-                                               paintables.add(window);
-                                               
-                                               // Reset sent locales
-                                               locales = null;
-                                               requireLocale(application.getLocale().toString());
-
-                                               // Adds all non-native windows
-                                               for (Iterator i = window.getApplication().getWindows()
-                                                               .iterator(); i.hasNext();) {
-                                                       Window w = (Window) i.next();
-                                                       if (!"native".equals(w.getStyle()) && w != window)
-                                                               paintables.add(w);
-                                               }
-                                       } else
-                                               paintables = getDirtyComponents();
-                                       if (paintables != null) {
-
-                                               // Creates "working copy" of the current state.
-                                               List currentPaintables = new ArrayList(paintables);
-
-                                               // Sorts the paintable so that parent windows
-                                               // are always painted before child windows
-                                               Collections.sort(currentPaintables, new Comparator() {
-
-                                                       public int compare(Object o1, Object o2) {
-
-                                                               // If first argumement is now window
-                                                               // the second is "smaller" if it is.
-                                                               if (!(o1 instanceof Window)) {
-                                                                       return (o2 instanceof Window) ? 1 : 0;
-                                                               }
-
-                                                               // Now, if second is not window the
-                                                               // first is smaller.
-                                                               if (!(o2 instanceof Window)) {
-                                                                       return -1;
-                                                               }
-
-                                                               // Both are windows.
-                                                               String n1 = ((Window) o1).getName();
-                                                               String n2 = ((Window) o2).getName();
-                                                               if (o1 instanceof FrameWindow) {
-                                                                       if (((FrameWindow) o1).getFrameset()
-                                                                                       .getFrame(n2) != null) {
-                                                                               return -1;
-                                                                       } else if (!(o2 instanceof FrameWindow)) {
-                                                                               return -1;
-                                                                       }
-                                                               }
-                                                               if (o2 instanceof FrameWindow) {
-                                                                       if (((FrameWindow) o2).getFrameset()
-                                                                                       .getFrame(n1) != null) {
-                                                                               return 1;
-                                                                       } else if (!(o1 instanceof FrameWindow)) {
-                                                                               return 1;
-                                                                       }
-                                                               }
-
-                                                               return 0;
-                                                       }
-                                               });
-
-                                               for (Iterator i = currentPaintables.iterator(); i
-                                                               .hasNext();) {
-                                                       Paintable p = (Paintable) i.next();
-
-                                                       // TODO CLEAN
-                                                       if (p instanceof Window) {
-                                                               Window w = (Window) p;
-                                                               if (w.getTerminal() == null)
-                                                                       w.setTerminal(application.getMainWindow()
-                                                                                       .getTerminal());
-                                                       }
-
-                                                       paintTarget.startTag("change");
-                                                       paintTarget.addAttribute("format", "uidl");
-                                                       String pid = getPaintableId(p);
-                                                       paintTarget.addAttribute("pid", pid);
-
-                                                       // Track paints to identify empty paints
-                                                       ((AjaxPaintTarget) paintTarget).setTrackPaints(true);
-                                                       p.paint(paintTarget);
-
-                                                       // If no paints add attribute empty
-                                                       if (((AjaxPaintTarget) paintTarget).getNumberOfPaints() <= 0) {
-                                                               paintTarget.addAttribute("visible", false);
-                                                       }
-                                                       paintTarget.endTag("change");
-                                                       paintablePainted(p);
-                                               }
-                                       }
-
-                                       ((AjaxPaintTarget) paintTarget).close();
-                                       outWriter.print("]"); // close changes
-
-
-                                       // Render the removed windows
-                                       // TODO refactor commented area to send some meta instructions to close window
-//                                     Set removed = new HashSet(getRemovedWindows());
-//                                     if (removed.size() > 0) {
-//                                             for (Iterator i = removed.iterator(); i.hasNext();) {
-//                                                     Window w = (Window) i.next();
-//                                                     paintTarget.startTag("change");
-//                                                     paintTarget.addAttribute("format", "uidl");
-//                                                     String pid = getPaintableId(w);
-//                                                     paintTarget.addAttribute("pid", pid);
-//                                                     paintTarget.addAttribute("windowname", w.getName());
-//                                                     paintTarget.addAttribute("visible", false);
-//                                                     paintTarget.endTag("change");
-//                                                     removedWindowNotified(w);
-//
-//                                             }
-//                                     }
-
-
-                                       
-                       outWriter.print(", \"meta\" : {");
-                       boolean metaOpen = false;
-
-                                       
-                    // .. or initializion (first uidl-request)
-                    if(application.ajaxInit()) {
-                       outWriter.print("\"appInit\":true");
-                    }
-                    // add meta instruction for client to set focus if it is set
-                    Paintable f = (Paintable) application.consumeFocus();
-                    if(f != null) {
-                       if(metaOpen)
-                               outWriter.append(",");
-                       outWriter.write("\"focus\":\""+ getPaintableId(f) +"\"");
-                    }
-
-                       outWriter.print("}, \"resources\" : {");
-
-                    // 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
-                       int resourceIndex = 0;
-                    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) {
-                               
-                               outWriter.print((resourceIndex++ > 0 ? ", " : "") + "\""+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() + ")");
-                               }
-                               outWriter.print("\"" + AjaxJsonPaintTarget.escapeJSON(layout.toString()) + "\"");
-                       }
-                    }
-                       outWriter.print("}");
-                       
-                       
-                       /* -----------------------------
-                        * Sending Locale sensitive date
-                        * -----------------------------
-                        */
-                       
-                       // Store JVM default locale for later restoration
-                       // (we'll have to change the default locale for a while)
-                       Locale jvmDefault = Locale.getDefault();
-                       
-                    // Send locale informations to client
-                       outWriter.print(", \"locales\":[");
-                       for(;pendingLocalesIndex < locales.size(); pendingLocalesIndex++) {
-                               
-                               Locale l = generateLocale((String) locales.get(pendingLocalesIndex));
-                               // Locale name
-                               outWriter.print("{\"name\":\"" + l.toString() + "\",");
-                               
-                               /*
-                                * Month names (both short and full)
-                                */
-                               DateFormatSymbols dfs = new DateFormatSymbols(l);
-                               String[] short_months = dfs.getShortMonths();
-                               String[] months = dfs.getMonths();
-                               outWriter.print("\"smn\":[\"" + // ShortMonthNames
-                                               short_months[0] + "\",\"" +
-                                               short_months[1] + "\",\"" +
-                                               short_months[2] + "\",\"" +
-                                               short_months[3] + "\",\"" +
-                                               short_months[4] + "\",\"" +
-                                               short_months[5] + "\",\"" +
-                                               short_months[6] + "\",\"" +
-                                               short_months[7] + "\",\"" +
-                                               short_months[8] + "\",\"" +
-                                               short_months[9] + "\",\"" +
-                                               short_months[10] + "\",\"" +
-                                               short_months[11] + "\"" +
-                                               "],");
-                               outWriter.print("\"mn\":[\"" + // MonthNames
-                                               months[0] + "\",\"" +
-                                               months[1] + "\",\"" +
-                                               months[2] + "\",\"" +
-                                               months[3] + "\",\"" +
-                                               months[4] + "\",\"" +
-                                               months[5] + "\",\"" +
-                                               months[6] + "\",\"" +
-                                               months[7] + "\",\"" +
-                                               months[8] + "\",\"" +
-                                               months[9] + "\",\"" +
-                                               months[10] + "\",\"" +
-                                               months[11] + "\"" +
-                                               "],");
-       
-                           /*
-                            * Weekday names (both short and full)
-                            */
-                               String[] short_days = dfs.getShortWeekdays();
-                               String[] days = dfs.getWeekdays();
-                           outWriter.print("\"sdn\":[\"" + // ShortDayNames
-                                               short_days[1] + "\",\"" +
-                                               short_days[2] + "\",\"" +
-                                               short_days[3] + "\",\"" +
-                                               short_days[4] + "\",\"" +
-                                               short_days[5] + "\",\"" +
-                                               short_days[6] + "\",\"" +
-                                               short_days[7] + "\"" +
-                                               "],");
-                               outWriter.print("\"dn\":[\"" + // DayNames
-                                               days[1] + "\",\"" +
-                                               days[2] + "\",\"" +
-                                               days[3] + "\",\"" +
-                                               days[4] + "\",\"" +
-                                               days[5] + "\",\"" +
-                                               days[6] + "\",\"" +
-                                               days[7] + "\"" +
-                                               "],");
-                               
-                               /*
-                                * First day of week (0 = sunday, 1 = monday)
-                                */
-                               Calendar cal = new GregorianCalendar(l);
-                               outWriter.print("\"fdow\":" + (cal.getFirstDayOfWeek() - 1) + ",");
-                               
-                               /*
-                                * Date formatting (MM/DD/YYYY etc.)
-                                */
-                               // Force our locale as JVM default for a while (SimpleDateFormat uses JVM default)
-                               Locale.setDefault(l);
-                               String df = new SimpleDateFormat().toPattern();
-                               int timeStart = df.indexOf("H");
-                               if(timeStart < 0)
-                                       timeStart = df.indexOf("h");
-                               int ampm_first = df.indexOf("a");
-                               // E.g. in Korean locale AM/PM is before h:mm
-                               // TODO should take that into consideration on client-side as well, now always h:mm a
-                               if(ampm_first > 0 && ampm_first < timeStart)
-                                       timeStart = ampm_first;
-                               String dateformat = df.substring(0, timeStart-1);
-                               
-                               outWriter.print("\"df\":\"" + dateformat.trim() + "\",");
-                               
-                               /*
-                                * Time formatting (24 or 12 hour clock and AM/PM suffixes)
-                                */
-                               String timeformat = df.substring(timeStart, df.length()); // Doesn't return second or milliseconds
-                               // We use timeformat to determine 12/24-hour clock
-                               boolean twelve_hour_clock = timeformat.contains("a");
-                               // TODO there are other possibilities as well, like 'h' in french (ignore them, too complicated)
-                               String hour_min_delimiter = timeformat.contains(".")? "." : ":";
-                               //outWriter.print("\"tf\":\"" + timeformat + "\",");
-                               outWriter.print("\"thc\":" + twelve_hour_clock + ",");
-                               outWriter.print("\"hmd\":\"" + hour_min_delimiter + "\"");
-                               if(twelve_hour_clock) {
-                                       String[] ampm = dfs.getAmPmStrings();
-                                       outWriter.print(",\"ampm\":[\""+ampm[0]+"\",\""+ampm[1]+"\"]");
-                               }
-                               outWriter.print("}");
-                               if(pendingLocalesIndex < locales.size()-1)
-                                       outWriter.print(",");
-                       }
-                       outWriter.print("]"); // Close locales
-                       
-                       // Restore JVM default locale
-                       Locale.setDefault(jvmDefault);
-                
-                       outWriter.flush();
-                    outWriter.close();
-                                       out.flush();
-                               } else {
-
-                                       // For download request, transfer the downloaded data
-                                       handleDownload(download, request, response);
-                               }
-                       }
-
-                       out.flush();
-                       out.close();
-
-               } catch (Throwable e) {
-                       // Writes the error report to client
-                       OutputStreamWriter w = new OutputStreamWriter(out);
-                       PrintWriter err = new PrintWriter(w);
-                       err
-                                       .write("<html><head><title>Application Internal Error</title></head><body>");
-                       err.write("<h1>" + e.toString() + "</h1><pre>\n");
-                       e.printStackTrace(new PrintWriter(err));
-                       err.write("\n</pre></body></html>");
-                       err.close();
-               } finally {
-
-               }
-
-       }
-
-       /**
-        * Gets the existing application or create a new one. Get a window within an
-        * application based on the requested URI.
-        * 
-        * @param request
-        *            the HTTP Request.
-        * @param application
-        *            the Application to query for window.
-        * @return Window mathing the given URI or null if not found.
-        * @throws ServletException
-        *             if an exception has occurred that interferes with the
-        *             servlet's normal operation.
-        */
-       private Window getApplicationWindow(HttpServletRequest request,
-                       Application application) throws ServletException {
-
-               Window window = null;
-
-               // Find the window where the request is handled
-               String path = request.getPathInfo();
-
-               // Main window as the URI is empty
-               if (path == null || path.length() == 0 || path.equals("/"))
-                       window = application.getMainWindow();
-
-               // Try to search by window name
-               else {
-                       String windowName = null;
-                       if (path.charAt(0) == '/')
-                               path = path.substring(1);
-                       int index = path.indexOf('/');
-                       if (index < 0) {
-                               windowName = path;
-                               path = "";
-                       } else {
-                               windowName = path.substring(0, index);
-                               path = path.substring(index + 1);
-                       }
-                       window = application.getWindow(windowName);
-
-                       // By default, we use main window
-                       if (window == null)
-                               window = application.getMainWindow();
-               }
-
-               return window;
-       }
-
-       /**
-        * Handles the requested URI. An application can add handlers to do special
-        * processing, when a certain URI is requested. The handlers are invoked
-        * before any windows URIs are processed and if a DownloadStream is returned
-        * it is sent to the client.
-        * 
-        * @param application
-        *            the Application owning the URI.
-        * @param request
-        *            the HTTP request instance.
-        * @param response
-        *            the HTTP response to write to.
-        * @return boolean <code>true</code> if the request was handled and
-        *         further processing should be suppressed, otherwise
-        *         <code>false</code>.
-        * @see com.itmill.toolkit.terminal.URIHandler
-        */
-       private DownloadStream handleURI(Application application,
-                       HttpServletRequest request, HttpServletResponse response) {
-
-               String uri = request.getPathInfo();
-
-               // If no URI is available
-               if (uri == null || uri.length() == 0 || uri.equals("/"))
-                       return null;
-
-               // Remove the leading /
-               while (uri.startsWith("/") && uri.length() > 0)
-                       uri = uri.substring(1);
-
-               // Handle the uri
-               DownloadStream stream = null;
-               try {
-                       stream = application.handleURI(application.getURL(), uri);
-               } catch (Throwable t) {
-                       application.terminalError(new URIHandlerErrorImpl(application, t));
-               }
-
-               return stream;
-       }
-
-       /**
-        * Handles the requested URI. An application can add handlers to do special
-        * processing, when a certain URI is requested. The handlers are invoked
-        * before any windows URIs are processed and if a DownloadStream is returned
-        * it is sent to the client.
-        * 
-        * @param stream
-        *            the downloadable stream.
-        * 
-        * @param request
-        *            the HTTP request instance.
-        * @param response
-        *            the HTTP response to write to.
-        * 
-        * @see com.itmill.toolkit.terminal.URIHandler
-        */
-       private void handleDownload(DownloadStream stream,
-                       HttpServletRequest request, HttpServletResponse response) {
-
-               // Download from given stream
-               InputStream data = stream.getStream();
-               if (data != null) {
-
-                       // Sets content type
-                       response.setContentType(stream.getContentType());
-
-                       // Sets cache headers
-                       long cacheTime = stream.getCacheTime();
-                       if (cacheTime <= 0) {
-                               response.setHeader("Cache-Control", "no-cache");
-                               response.setHeader("Pragma", "no-cache");
-                               response.setDateHeader("Expires", 0);
-                       } else {
-                               response.setHeader("Cache-Control", "max-age=" + cacheTime
-                                               / 1000);
-                               response.setDateHeader("Expires", System.currentTimeMillis()
-                                               + cacheTime);
-                               response.setHeader("Pragma", "cache"); // Required to apply
-                               // caching in some
-                               // Tomcats
-                       }
-
-                       // Copy download stream parameters directly
-                       // to HTTP headers.
-                       Iterator i = stream.getParameterNames();
-                       if (i != null) {
-                               while (i.hasNext()) {
-                                       String param = (String) i.next();
-                                       response.setHeader((String) param, stream
-                                                       .getParameter(param));
-                               }
-                       }
-
-                       int bufferSize = stream.getBufferSize();
-                       if (bufferSize <= 0 || bufferSize > MAX_BUFFER_SIZE)
-                               bufferSize = DEFAULT_BUFFER_SIZE;
-                       byte[] buffer = new byte[bufferSize];
-                       int bytesRead = 0;
-
-                       try {
-                               OutputStream out = response.getOutputStream();
-
-                               while ((bytesRead = data.read(buffer)) > 0) {
-                                       out.write(buffer, 0, bytesRead);
-                                       out.flush();
-                               }
-                               out.close();
-                       } catch (IOException ignored) {
-                       }
-
-               }
-
-       }
-
-       /**
-        * Ends the Application.
-        * 
-        * @param request
-        *            the HTTP request instance.
-        * @param response
-        *            the HTTP response to write to.
-        * @param application
-        *            the Application to end.
-        * @throws IOException
-        *             if the writing failed due to input/output error.
-        */
-       private void endApplication(HttpServletRequest request,
-                       HttpServletResponse response, Application application)
-                       throws IOException {
-
-               String logoutUrl = application.getLogoutURL();
-               if (logoutUrl == null)
-                       logoutUrl = application.getURL().toString();
-               // clients JS app is still running, send a special xml file to
-               // tell client that application is quit and where to point browser now
-               // Set the response type
-               response.setContentType("application/xml; charset=UTF-8");
-               ServletOutputStream out = response.getOutputStream();
-               out.println("<redirect url=\"" + logoutUrl + "\">");
-               out.println("</redirect>");
-       }
-
-       /**
-        * Gets the Paintable Id.
-        * 
-        * @param paintable
-        * @return the paintable Id.
-        */
-       public synchronized String getPaintableId(Paintable paintable) {
-
-               String id = (String) paintableIdMap.get(paintable);
-               if (id == null) {
-                       id = "PID" + Integer.toString(idSequence++);
-                       paintableIdMap.put(paintable, id);
-               }
-
-               return id;
-       }
-
-       /**
-        * 
-        * @return
-        */
-       public synchronized Set getDirtyComponents() {
-
-               // Remove unnecessary repaints from the list
-               Object[] paintables = dirtyPaintabletSet.toArray();
-               for (int i = 0; i < paintables.length; i++) {
-                       if (paintables[i] instanceof Component) {
-                               Component c = (Component) paintables[i];
-
-                               // Check if any of the parents of c already exist in the list
-                               Component p = c.getParent();
-                               while (p != null) {
-                                       if (dirtyPaintabletSet.contains(p)) {
-
-                                               // Remove component c from the dirty paintables as its
-                                               // parent is also dirty
-                                               dirtyPaintabletSet.remove(c);
-                                               p = null;
-                                       } else
-                                               p = p.getParent();
-                               }
-                       }
-               }
-
-               return Collections.unmodifiableSet(dirtyPaintabletSet);
-       }
-
-       /**
-        * Clears the Dirty Components.
-        * 
-        */
-       public synchronized void clearDirtyComponents() {
-               dirtyPaintabletSet.clear();
-       }
-
-       /**
-        * @see com.itmill.toolkit.terminal.Paintable.RepaintRequestListener#repaintRequested(com.itmill.toolkit.terminal.Paintable.RepaintRequestEvent)
-        */
-       public void repaintRequested(RepaintRequestEvent event) {
-               Paintable p = event.getPaintable();
-               dirtyPaintabletSet.add(p);
-
-               // For FrameWindows we mark all frames (windows) dirty
-               if (p instanceof FrameWindow) {
-                       FrameWindow fw = (FrameWindow) p;
-                       repaintFrameset(fw.getFrameset());
-               }
-       }
-
-       /**
-        * Recursively request repaint for all frames in frameset.
-        * 
-        * @param fs
-        *            the Framewindow.Frameset.
-        */
-       private void repaintFrameset(FrameWindow.Frameset fs) {
-               List frames = fs.getFrames();
-               for (Iterator i = frames.iterator(); i.hasNext();) {
-                       FrameWindow.Frame f = (FrameWindow.Frame) i.next();
-                       if (f instanceof FrameWindow.Frameset) {
-                               repaintFrameset((FrameWindow.Frameset) f);
-                       } else {
-                               Window w = f.getWindow();
-                               if (w != null) {
-                                       w.requestRepaint();
-                               }
-                       }
-               }
-       }
-
-       /**
-        * 
-        * @param p
-        */
-       public void paintablePainted(Paintable p) {
-               dirtyPaintabletSet.remove(p);
-               p.requestRepaintRequests();
-       }
-
-       /**
-        * 
-        * @param paintable
-        * @return
-        */
-       public boolean isDirty(Paintable paintable) {
-               return (dirtyPaintabletSet.contains(paintable));
-       }
-
-       /**
-        * @see com.itmill.toolkit.Application.WindowAttachListener#windowAttached(com.itmill.toolkit.Application.WindowAttachEvent)
-        */
-       public void windowAttached(WindowAttachEvent event) {
-               event.getWindow().addListener(this);
-               dirtyPaintabletSet.add(event.getWindow());
-       }
-
-       /**
-        * @see com.itmill.toolkit.Application.WindowDetachListener#windowDetached(com.itmill.toolkit.Application.WindowDetachEvent)
-        */
-       public void windowDetached(WindowDetachEvent event) {
-               event.getWindow().removeListener(this);
-               // Notify client of the close operation
-               removedWindows.add(event.getWindow());
-       }
-
-       /**
-        * 
-        * @return
-        */
-       public synchronized Set getRemovedWindows() {
-               return Collections.unmodifiableSet(removedWindows);
-
-       }
-
-       /**
-        * 
-        * @param w
-        */
-       private void removedWindowNotified(Window w) {
-               this.removedWindows.remove(w);
-       }
-
-       /**
-        * Implementation of URIHandler.ErrorEvent interface.
-        */
-       public class URIHandlerErrorImpl implements URIHandler.ErrorEvent {
-
-               private URIHandler owner;
-
-               private Throwable throwable;
-
-               /**
-                * 
-                * @param owner
-                * @param throwable
-                */
-               private URIHandlerErrorImpl(URIHandler owner, Throwable throwable) {
-                       this.owner = owner;
-                       this.throwable = throwable;
-               }
-
-               /**
-                * @see com.itmill.toolkit.terminal.Terminal.ErrorEvent#getThrowable()
-                */
-               public Throwable getThrowable() {
-                       return this.throwable;
-               }
-
-               /**
-                * @see com.itmill.toolkit.terminal.URIHandler.ErrorEvent#getURIHandler()
-                */
-               public URIHandler getURIHandler() {
-                       return this.owner;
-               }
-       }
-
-       public void requireLocale(String value) {
-               if(locales == null) {
-                       locales = new ArrayList();
-                       locales.add(application.getLocale().toString());
-                       pendingLocalesIndex = 0;
-               }
-               if(!locales.contains(value))
-                               locales.add(value);
-       }
-       
-       private Locale generateLocale(String value) {
-               String[] temp = value.split("_");
-               if(temp.length == 1)
-                       return new Locale(temp[0]);
-               else if(temp.length == 2)
-                       return new Locale(temp[0], temp[1]);
-               else
-                       return new Locale(temp[0], temp[1], temp[2]);
-       }
-}
diff --git a/src/com/itmill/toolkit/terminal/web/AjaxHttpUploadStream.java b/src/com/itmill/toolkit/terminal/web/AjaxHttpUploadStream.java
deleted file mode 100644 (file)
index d277bd1..0000000
+++ /dev/null
@@ -1,114 +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 java.io.InputStream;
-
-/**
- * AjaxAdapter implementation of the UploadStream interface.
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.1
- */
-public class AjaxHttpUploadStream implements
-               com.itmill.toolkit.terminal.UploadStream {
-
-       /**
-        * Holds value of property variableName.
-        */
-       private String streamName;
-
-       private String contentName;
-
-       private String contentType;
-
-       /**
-        * Holds value of property variableValue.
-        */
-       private InputStream stream;
-
-       /**
-        * Creates a new instance of UploadStreamImpl.
-        * 
-        * @param name
-        *            the name of the stream.
-        * @param stream
-        *            the input stream.
-        * @param contentName
-        *            the name of the content.
-        * @param contentType
-        *            the type of the content.
-        */
-       public AjaxHttpUploadStream(String name, InputStream stream,
-                       String contentName, String contentType) {
-               this.streamName = name;
-               this.stream = stream;
-               this.contentName = contentName;
-               this.contentType = contentType;
-       }
-
-       /**
-        * Gets the name of the stream.
-        * 
-        * @return the name of the stream.
-        */
-       public String getStreamName() {
-               return this.streamName;
-       }
-
-       /**
-        * Gets the input stream.
-        * 
-        * @return the Input stream.
-        */
-       public InputStream getStream() {
-               return this.stream;
-       }
-
-       /**
-        * Gets the input stream content type.
-        * 
-        * @return the content type of the input stream.
-        */
-       public String getContentType() {
-               return this.contentType;
-       }
-
-       /**
-        * Gets the stream content name. Stream content name usually differs from
-        * the actual stream name. It is used to identify the content of the stream.
-        * 
-        * @return the Name of the stream content.
-        */
-       public String getContentName() {
-               return this.contentName;
-       }
-}
diff --git a/src/com/itmill/toolkit/terminal/web/AjaxJsonPaintTarget.java b/src/com/itmill/toolkit/terminal/web/AjaxJsonPaintTarget.java
deleted file mode 100644 (file)
index 882dd8f..0000000
+++ /dev/null
@@ -1,980 +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.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 outWriter
-        *            A character-output stream.
-        * @throws PaintException
-        *             if the paint operation failed.
-        */
-       public AjaxJsonPaintTarget(AjaxVariableMap variableMap,
-                       AjaxApplicationManager manager, PrintWriter outWriter)
-                       throws PaintException {
-
-               this.manager = manager;
-               // Sets the variable map
-               this.variableMap = variableMap;
-
-               // Sets the target for UIDL writing
-               this.uidlBuffer = outWriter;
-
-               // Initialize tag-writing
-               mOpenTags = new Stack();
-               openJsonTags = new Stack();
-               mTagArgumentListOpen = false;
-
-               // Adds document declaration
-
-               // Adds UIDL start tag and its attributes
-       }
-
-       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.");
-
-               if (tag != null) {
-                       openJsonTags.push(tag);
-               }
-               // Checks tagName and attributes here
-               mOpenTags.push(tagName);
-
-               tag = new JsonTag(tagName);
-
-               mTagArgumentListOpen = true;
-
-               customLayoutArgumentsOpen = "customlayout".equals(tagName);
-       }
-
-       /**
-        * 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.");
-
-               if (openJsonTags.size() > 0) {
-                       JsonTag parent = (JsonTag) openJsonTags.pop();
-
-                       String lastTag = "";
-
-                       lastTag = (String) mOpenTags.pop();
-                       if (!tagName.equalsIgnoreCase(lastTag))
-                               throw new PaintException("Invalid UIDL: wrong ending tag: '"
-                                               + tagName + "' expected: '" + lastTag + "'.");
-
-                       parent.addData(tag.getJSON());
-
-                       tag = parent;
-               } else {
-                       changes++;
-                       this.uidlBuffer.print(((changes > 1) ? "," : "") + tag.getJSON());
-                       tag = null;
-               }
-       }
-
-       /**
-        * 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 String attribute name.
-        * @param value
-        *            the String 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) + "\"");
-
-               if (customLayoutArgumentsOpen && "style".equals(name))
-                       getPreCachedResources().add("layout/" + value + ".html");
-               
-               if(name.equals("locale"))
-                       manager.requireLocale(value);
-
-       }
-
-       public void addAttribute(String name, Object[] values) {
-               // In case of null data output nothing:
-               if ((values == null) || (name == null))
-                       throw new NullPointerException(
-                                       "Parameters must be non-null strings");
-               StringBuffer buf = new StringBuffer();
-               buf.append("\"" + name + "\":[");
-               for (int i = 0; i < values.length; i++) {
-                       if (i > 0)
-                               buf.append(",");
-                       buf.append("\"");
-                       buf.append(escapeJSON(values[i].toString()));
-                       buf.append("\"");
-               }
-               buf.append("]");
-               tag.addAttribute(buf.toString());
-       }
-
-       /**
-        * 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
-        * 
-        * @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 {
-               tag.addData("{\"" + sectionTagName + "\":\"" + escapeJSON(sectionData)
-                               + "\"}");
-       }
-
-       /**
-        * 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("\"" + escapeJSON(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;
-               customLayoutArgumentsOpen = false;
-
-               if (sectionData != null)
-                       tag.addData("\"" + escapeJSON(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 (tag != null)
-                       uidlBuffer.append(tag.getJSON());
-               flush();
-               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);
-               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 = false;
-
-               Vector variables = new Vector();
-
-               Vector children = new Vector();
-
-               Vector attr = new Vector();
-
-               private HashMap childTagCounters = new HashMap();
-
-               StringBuffer data = new StringBuffer();
-
-               public boolean childrenArrayOpen = false;
-
-               private boolean childNode = false;
-
-               private boolean tagClosed = false;
-
-               public JsonTag(String tagName) {
-                       data.append("[\"" + tagName + "\"");
-               }
-
-               private void closeTag() {
-                       if (!tagClosed) {
-                               data.append(attributesAsJsonObject());
-                               data.append(getData());
-                               // Writes the end (closing) tag
-                               data.append("]");
-                               this.tagClosed = true;
-                       }
-               }
-
-               public String getJSON() {
-                       if (!tagClosed) {
-                               this.closeTag();
-                       }
-                       return data.toString();
-               }
-
-               public void openChildrenArray() {
-                       if (!childrenArrayOpen) {
-                               // append("c : [");
-                               childrenArrayOpen = true;
-                               // firstField = true;
-                       }
-               }
-
-               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 ",";
-                       }
-               }
-
-               /**
-                * 
-                * @param s
-                *            json string, object or array
-                */
-               public void addData(String s) {
-                       children.add(s);
-               }
-
-               public String getData() {
-                       StringBuffer buf = new StringBuffer();
-                       Iterator it = children.iterator();
-                       while (it.hasNext()) {
-                               buf.append(startField());
-                               buf.append(it.next());
-                       }
-                       return buf.toString();
-               }
-
-               public void addAttribute(String jsonNode) {
-                       attr.add(jsonNode);
-               }
-
-               private String attributesAsJsonObject() {
-                       StringBuffer buf = new StringBuffer();
-                       buf.append(startField());
-                       buf.append("{");
-                       for (Iterator iter = attr.iterator(); iter.hasNext();) {
-                               String element = (String) iter.next();
-                               buf.append(element);
-                               if (iter.hasNext())
-                                       buf.append(",");
-                       }
-                       buf.append(tag.variablesAsJsonObject());
-                       buf.append("}");
-                       return buf.toString();
-               }
-
-               public void addVariable(Variable v) {
-                       variables.add(v);
-               }
-
-               private String variablesAsJsonObject() {
-                       if (variables.size() == 0)
-                               return "";
-                       StringBuffer buf = new StringBuffer();
-                       buf.append(startField());
-                       buf.append("\"v\":{");
-                       Iterator iter = variables.iterator();
-                       while (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 + "\":" + (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 + "\":\"" + value + "\"";
-               }
-
-       }
-
-       class IntVariable extends Variable {
-               int value;
-
-               public IntVariable(VariableOwner owner, String name, int v) {
-                       value = v;
-                       this.name = name;
-                       code = variableMap.registerVariable(name, Integer.class,
-                                       new Integer(value), owner);
-               }
-
-               public String getJsonPresentation() {
-                       return "\"" + name + "\":" + 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 + "\":[";
-                       for (int i = 0; i < value.length;) {
-                               pres += "\"" + value[i] + "\"";
-                               i++;
-                               if (i < value.length)
-                                       pres += ",";
-                       }
-                       pres += "]";
-                       return pres;
-               }
-       }
-
-       public Set getPreCachedResources() {
-               return preCachedResources;
-       }
-
-       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 8db97e7..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.itmill.toolkit.terminal.web;
-
-import java.util.Set;
-
-import com.itmill.toolkit.terminal.PaintException;
-import com.itmill.toolkit.terminal.Paintable;
-import com.itmill.toolkit.terminal.Resource;
-import com.itmill.toolkit.terminal.VariableOwner;
-
-public interface AjaxPaintTarget {
-
-       /**
-        * Gets the UIDL already printed to stream. Paint target must be closed
-        * before the <code>getUIDL</code> can be called.
-        * 
-        * @return the UIDL.
-        */
-       public abstract String getUIDL();
-
-       /**
-        * 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 abstract void close() throws PaintException;
-
-       /**
-        * 
-        * @return
-        */
-       public abstract boolean isTrackPaints();
-
-       /**
-        * Gets the number of paints.
-        * 
-        * @return the number of paints.
-        */
-       public abstract int getNumberOfPaints();
-
-       /**
-        * 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 abstract void setTrackPaints(boolean enabled);
-
-       public abstract void setPreCachedResources(Set preCachedResources);
-
-       public abstract Set getPreCachedResources() ;
-
-}
\ No newline at end of file
diff --git a/src/com/itmill/toolkit/terminal/web/AjaxVariableMap.java b/src/com/itmill/toolkit/terminal/web/AjaxVariableMap.java
deleted file mode 100644 (file)
index 80980d8..0000000
+++ /dev/null
@@ -1,803 +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 java.io.IOException;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.StringTokenizer;
-import java.util.WeakHashMap;
-
-import javax.servlet.http.HttpServletRequest;
-
-import com.itmill.toolkit.terminal.SystemError;
-import com.itmill.toolkit.terminal.Terminal;
-import com.itmill.toolkit.terminal.UploadStream;
-import com.itmill.toolkit.terminal.VariableOwner;
-
-/**
- * Variable map for ajax applications.
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.1
- */
-public class AjaxVariableMap {
-
-       // Id <-> (Owner,Name) mapping
-       private Map idToNameMap = new HashMap();
-
-       private Map idToTypeMap = new HashMap();
-
-       private Map idToOwnerMap = new HashMap();
-
-       private Map idToValueMap = new HashMap();
-
-       private Map ownerToNameToIdMap = new WeakHashMap();
-
-       private Object mapLock = new Object();
-
-       // Id generator
-       private long lastId = 0;
-
-       /**
-        * Converts the string to a supported class.
-        * 
-        * @param type
-        * @param value
-        * @return
-        * @throws java.lang.ClassCastException
-        *             if the code has attempted to cast an object to a subclass of
-        *             which it is not an instance
-        */
-       private static Object convert(Class type, String value)
-                       throws java.lang.ClassCastException {
-               try {
-
-                       // Boolean typed variables
-                       if (type.equals(Boolean.class))
-                               return new Boolean(!(value.equals("") || value.equals("false")));
-
-                       // Integer typed variables
-                       if (type.equals(Integer.class))
-                               return new Integer(value.trim());
-
-                       // String typed variables
-                       if (type.equals(String.class))
-                               return value;
-
-                       throw new ClassCastException("Unsupported type: " + type.getName());
-               } catch (NumberFormatException e) {
-                       return null;
-               }
-       }
-
-       /**
-        * Registers a new variable.
-        * 
-        * @param name
-        *            the Variable name.
-        * @param type
-        * @param value
-        * @param owner
-        *            the Listener for variable changes.
-        * @return id to assigned for this variable.
-        */
-       public String registerVariable(String name, Class type, Object value,
-                       VariableOwner owner) {
-
-               // Checks that the type of the class is supported
-               if (!(type.equals(Boolean.class) || type.equals(Integer.class)
-                               || type.equals(String.class) || type.equals(String[].class) || type
-                               .equals(UploadStream.class)))
-                       throw new SystemError("Unsupported variable type: "
-                                       + type.getClass());
-
-               synchronized (mapLock) {
-
-                       // Checks if the variable is already mapped
-                       HashMap nameToIdMap = (HashMap) ownerToNameToIdMap.get(owner);
-                       if (nameToIdMap == null) {
-                               nameToIdMap = new HashMap();
-                               ownerToNameToIdMap.put(owner, nameToIdMap);
-                       }
-                       String id = (String) nameToIdMap.get(name);
-
-                       if (id == null) {
-                               // Generates new id and register it
-
-// ----------
-// TODO This HACK is only included for testing GWT integration                         
-//Original                             id = "v" + String.valueOf(++lastId);
-                               Object pid = AjaxApplicationManager.paintableIdMap.get(owner);
-                               id = pid + "_"+name;
-// ----------
-                               
-                               
-                               nameToIdMap.put(name, id);
-                               idToOwnerMap.put(id, new WeakReference(owner));
-                               idToNameMap.put(id, name);
-                               idToTypeMap.put(id, type);
-                       }
-
-                       idToValueMap.put(id, value);
-
-                       return id;
-               }
-       }
-
-       /**
-        * Unregisters the variable.
-        * 
-        * @param name
-        *            the Variable name.
-        * @param owner
-        *            the Listener for variable changes.
-        */
-       public void unregisterVariable(String name, VariableOwner owner) {
-
-               synchronized (mapLock) {
-
-                       // Get the id
-                       HashMap nameToIdMap = (HashMap) ownerToNameToIdMap.get(owner);
-                       if (nameToIdMap == null)
-                               return;
-                       String id = (String) nameToIdMap.get(name);
-                       if (id != null)
-                               return;
-
-                       // Remove all the mappings
-                       nameToIdMap.remove(name);
-                       if (nameToIdMap.isEmpty())
-                               ownerToNameToIdMap.remove(owner);
-                       idToNameMap.remove(id);
-                       idToTypeMap.remove(id);
-                       idToValueMap.remove(id);
-                       idToOwnerMap.remove(id);
-
-               }
-       }
-
-       /**
-        * @author IT Mill Ltd.
-        * @version
-        * @VERSION@
-        * @since 3.0
-        */
-       private class ParameterContainer {
-
-               /**
-                * Constructs the mapping: listener to set of listened parameter names.
-                */
-               private HashMap parameters = new HashMap();
-
-               /**
-                * Parameter values.
-                */
-               private HashMap values = new HashMap();
-
-               /**
-                * Multipart parser used for parsing the request.
-                */
-               private ServletMultipartRequest parser = null;
-
-               /**
-                * Name - Value mapping of parameters that are not variables.
-                */
-               private HashMap nonVariables = new HashMap();
-
-               /**
-                * Creates a new parameter container and parse the parameters from the
-                * request using GET, POST and POST/MULTIPART parsing
-                * 
-                * @param req
-                *            the Http request to handle.
-                * @throws IOException
-                *             if the writing failed due to input/output error.
-                */
-               public ParameterContainer(HttpServletRequest req) throws IOException {
-                       // Parse GET / POST parameters
-                       for (Enumeration e = req.getParameterNames(); e.hasMoreElements();) {
-                               String paramName = (String) e.nextElement();
-                               String[] paramValues = req.getParameterValues(paramName);
-                               addParam(paramName, paramValues);
-                       }
-
-                       // Parse multipart variables
-                       try {
-                               parser = new ServletMultipartRequest(req,
-                                               MultipartRequest.MAX_READ_BYTES);
-                       } catch (IllegalArgumentException ignored) {
-                               parser = null;
-                       }
-
-                       if (parser != null) {
-                               for (Enumeration e = parser.getFileParameterNames(); e
-                                               .hasMoreElements();) {
-                                       String paramName = (String) e.nextElement();
-                                       addParam(paramName, null);
-                               }
-                               for (Enumeration e = parser.getParameterNames(); e
-                                               .hasMoreElements();) {
-                                       String paramName = (String) e.nextElement();
-                                       Enumeration val = parser.getURLParameters(paramName);
-
-                                       // Create a linked list from enumeration to calculate
-                                       // elements
-                                       LinkedList l = new LinkedList();
-                                       while (val.hasMoreElements())
-                                               l.addLast(val.nextElement());
-
-                                       // String array event constructor
-                                       String[] s = new String[l.size()];
-                                       Iterator i = l.iterator();
-                                       for (int j = 0; j < s.length; j++)
-                                               s[j] = (String) i.next();
-
-                                       addParam(paramName, s);
-                               }
-                       }
-
-               }
-
-               /**
-                * Adds the parameter to container.
-                * 
-                * @param name
-                *            the Parameter name.
-                * @param value
-                *            the Parameter value.
-                */
-               private void addParam(String name, String[] value) {
-
-                       // Support name="set:name=value" value="ignored" notation
-                       if (name.startsWith("set:")) {
-                               int equalsIndex = name.indexOf('=');
-                               value[0] = name.substring(equalsIndex + 1, name.length());
-                               name = name.substring(4, equalsIndex);
-                               String[] curVal = (String[]) values.get(name);
-                               if (curVal != null) {
-                                       String[] newVal = new String[1 + curVal.length];
-                                       newVal[curVal.length] = value[0];
-                                       for (int i = 0; i < curVal.length; i++)
-                                               newVal[i] = curVal[i];
-                                       value = newVal;
-
-                                       // Special case - if the set:-method is used for
-                                       // declaring array of length 2, where either of the
-                                       // following conditions are true:
-                                       // - the both items are the same
-                                       // - the both items have the same length and
-                                       // - the items only differ on last character
-                                       // - second last character is '.'
-                                       // - last char of one string is 'x' and other is 'y'
-                                       // Browser is unporposely modifying the name.
-                                       if (value.length == 2
-                                                       && value[0].length() == value[1].length()) {
-                                               boolean same = true;
-                                               for (int i = 0; i < value[0].length() - 1 && same; i++)
-                                                       if (value[0].charAt(i) != value[1].charAt(i))
-                                                               same = false;
-                                               if (same
-                                                               && ((value[0].charAt(value[0].length() - 1) == 'x' && value[1]
-                                                                               .charAt(value[1].length() - 1) == 'y') || (value[0]
-                                                                               .charAt(value[0].length() - 1) == 'y' && value[1]
-                                                                               .charAt(value[1].length() - 1) == 'x'))) {
-                                                       value = new String[] { value[0].substring(0,
-                                                                       value[1].length() - 2) };
-                                               } else if (same && value[0].equals(value[1]))
-                                                       value = new String[] { value[0] };
-                                       }
-
-                                       // Special case - if the set:-method is used for
-                                       // declaring array of length 3, where all of the
-                                       // following conditions are true:
-                                       // - two last items have the same length
-                                       // - the first item is 2 chars shorter
-                                       // - the longer items only differ on last character
-                                       // - the shortest item is a prefix of the longer ones
-                                       // - second last character of longer ones is '.'
-                                       // - last char of one long string is 'x' and other is 'y'
-                                       // Browser is unporposely modifying the name. (Mozilla,
-                                       // Firefox, ..)
-                                       if (value.length == 3
-                                                       && value[1].length() == value[2].length()
-                                                       && value[0].length() + 2 == value[1].length()) {
-                                               boolean same = true;
-                                               for (int i = 0; i < value[1].length() - 1 && same; i++)
-                                                       if (value[2].charAt(i) != value[1].charAt(i))
-                                                               same = false;
-                                               for (int i = 0; i < value[0].length() && same; i++)
-                                                       if (value[0].charAt(i) != value[1].charAt(i))
-                                                               same = false;
-                                               if (same
-                                                               && (value[2].charAt(value[2].length() - 1) == 'x' && value[1]
-                                                                               .charAt(value[1].length() - 1) == 'y')
-                                                               || (value[2].charAt(value[2].length() - 1) == 'y' && value[1]
-                                                                               .charAt(value[1].length() - 1) == 'x')) {
-                                                       value = new String[] { value[0] };
-                                               }
-                                       }
-
-                               }
-                       }
-
-                       // Support for setting arrays in format
-                       // set-array:name=value1,value2,value3,...
-                       else if (name.startsWith("set-array:")) {
-                               int equalsIndex = name.indexOf('=');
-                               if (equalsIndex < 0)
-                                       return;
-
-                               StringTokenizer commalist = new StringTokenizer(name
-                                               .substring(equalsIndex + 1), ",");
-                               name = name.substring(10, equalsIndex);
-                               String[] curVal = (String[]) values.get(name);
-                               ArrayList elems = new ArrayList();
-
-                               // Add old values if present.
-                               if (curVal != null) {
-                                       for (int i = 0; i < curVal.length; i++)
-                                               elems.add(curVal[i]);
-                               }
-                               while (commalist.hasMoreTokens()) {
-                                       String token = commalist.nextToken();
-                                       if (token != null && token.length() > 0)
-                                               elems.add(token);
-                               }
-                               value = new String[elems.size()];
-                               for (int i = 0; i < value.length; i++)
-                                       value[i] = (String) elems.get(i);
-
-                       }
-
-                       // Support name="array:name" value="val1,val2,val3" notation
-                       // All the empty elements are ignored
-                       else if (name.startsWith("array:")) {
-
-                               name = name.substring(6);
-                               StringTokenizer commalist = new StringTokenizer(value[0], ",");
-                               String[] curVal = (String[]) values.get(name);
-                               ArrayList elems = new ArrayList();
-
-                               // Add old values if present.
-                               if (curVal != null) {
-                                       for (int i = 0; i < curVal.length; i++)
-                                               elems.add(curVal[i]);
-                               }
-                               while (commalist.hasMoreTokens()) {
-                                       String token = commalist.nextToken();
-                                       if (token != null && token.length() > 0)
-                                               elems.add(token);
-                               }
-                               value = new String[elems.size()];
-                               for (int i = 0; i < value.length; i++)
-                                       value[i] = (String) elems.get(i);
-                       }
-
-                       // Support declaring variables with name="declare:name"
-                       else if (name.startsWith("declare:")) {
-                               name = name.substring(8);
-                               value = (String[]) values.get(name);
-                               if (value == null)
-                                       value = new String[0];
-                       }
-
-                       // Gets the owner
-                       WeakReference ref = (WeakReference) idToOwnerMap.get(name);
-                       VariableOwner owner = null;
-                       if (ref != null)
-                               owner = (VariableOwner) ref.get();
-
-                       // Adds the parameter to mapping only if they have owners
-                       if (owner != null) {
-                               Set p = (Set) parameters.get(owner);
-                               if (p == null)
-                                       parameters.put(owner, p = new HashSet());
-                               p.add(name);
-                               if (value != null)
-                                       values.put(name, value);
-                       }
-
-                       // If the owner can not be found
-                       else {
-
-                               // If parameter has been mapped before, remove the old owner
-                               // mapping
-                               if (ref != null) {
-
-                                       // The owner has been destroyed, so we remove the mappings
-                                       idToNameMap.remove(name);
-                                       idToOwnerMap.remove(name);
-                                       idToTypeMap.remove(name);
-                                       idToValueMap.remove(name);
-                               }
-
-                               // Adds the parameter to set of non-variables
-                               nonVariables.put(name, value);
-                       }
-
-               }
-
-               /**
-                * Gets the set of all parameters connected to given variable owner.
-                * 
-                * @param owner
-                *            the Listener for variable changes.
-                * @return the set of all the parameters.
-                */
-               public Set getParameters(VariableOwner owner) {
-                       if (owner == null)
-                               return null;
-                       return (Set) parameters.get(owner);
-               }
-
-               /**
-                * Gets the set of all variable owners owning parameters in this
-                * request.
-                * 
-                * @return the set of all varaible owners.
-                */
-               public Set getOwners() {
-                       return parameters.keySet();
-               }
-
-               /**
-                * Gets the value of a parameter.
-                * 
-                * @param parameterName
-                *            the name of the parameter.
-                * @return the value of the parameter.
-                */
-               public String[] getValue(String parameterName) {
-                       return (String[]) values.get(parameterName);
-               }
-
-               /**
-                * Gets the servlet multipart parser.
-                * 
-                * @return the parser.
-                */
-               public ServletMultipartRequest getParser() {
-                       return parser;
-               }
-
-               /**
-                * Gets the name - value[] mapping of non variable parameters.
-                * 
-                * @return the mapping of non variable parameters.
-                */
-               public Map getNonVariables() {
-                       return nonVariables;
-               }
-       }
-
-       /**
-        * Handles all variable changes in this request.
-        * 
-        * @param req
-        *            the Http request to handle.
-        * @param errorListener
-        *            the listeners If the list is non null, only the listed
-        *            listeners are served. Otherwise all the listeners are served.
-        * @return Name to Value[] mapping of unhandled variables.
-        * @throws IOException
-        *             if the writing failed due to input/output error.
-        */
-       public Map handleVariables(HttpServletRequest req,
-                       Terminal.ErrorListener errorListener) throws IOException {
-
-               // Gets the parameters
-               ParameterContainer parcon = new ParameterContainer(req);
-
-               // Sorts listeners to dependency order
-               List listeners = getDependencySortedListenerList(parcon.getOwners());
-
-               // Handles all parameters for all listeners
-               while (!listeners.isEmpty()) {
-                       VariableOwner listener = (VariableOwner) listeners.remove(0);
-                       boolean changed = false; // Has any of this owners variabes
-                                                                               // changed
-                       // Handles all parameters for listener
-                       Set params = parcon.getParameters(listener);
-                       if (params != null) { // Name value mapping
-                               Map variables = new HashMap();
-                               for (Iterator pi = params.iterator(); pi.hasNext();) {
-                                       // Gets the name of the parameter
-                                       String param = (String) pi.next();
-                                       // Extracts more information about the parameter
-                                       String varName = (String) idToNameMap.get(param);
-                                       Class varType = (Class) idToTypeMap.get(param);
-                                       Object varOldValue = idToValueMap.get(param);
-                                       if (varName == null || varType == null)
-                                               // TODO Remove this?
-                                               System.err
-                                                               .println("VariableMap: No variable found for parameter "
-                                                                               + param
-                                                                               + " ("
-                                                                               + varName
-                                                                               + ","
-                                                                               + listener + ")");
-                                       else {
-
-                                               ServletMultipartRequest parser = parcon.getParser();
-
-                                               // Uploads events
-                                               if (varType.equals(UploadStream.class)) {
-                                                       if (parser != null
-                                                                       && parser.getFileParameter(param,
-                                                                                       MultipartRequest.FILENAME) != null) {
-                                                               String filename = (String) parser
-                                                                               .getFileParameter(param,
-                                                                                               MultipartRequest.FILENAME);
-                                                               String contentType = (String) parser
-                                                                               .getFileParameter(param,
-                                                                                               MultipartRequest.CONTENT_TYPE);
-                                                               UploadStream upload = new AjaxHttpUploadStream(
-                                                                               varName, parser.getFileContents(param),
-                                                                               filename, contentType);
-                                                               variables.put(varName, upload);
-                                                               changed = true;
-                                                       }
-                                               }
-
-                                               // Normal variable change events
-                                               else {
-                                                       // First try to parse the event without multipart
-                                                       String[] values = parcon.getValue(param);
-                                                       if (values != null) {
-
-                                                               if (varType.equals(String[].class)) {
-                                                                       variables.put(varName, values);
-                                                                       changed |= (!Arrays.equals(values,
-                                                                                       (String[]) varOldValue));
-                                                               } else {
-                                                                       try {
-                                                                               if (values.length == 1) {
-                                                                                       Object val = convert(varType,
-                                                                                                       values[0]);
-                                                                                       variables.put(varName, val);
-                                                                                       changed |= ((val == null && varOldValue != null) || (val != null && !val
-                                                                                                       .equals(varOldValue)));
-                                                                               } else if (values.length == 0
-                                                                                               && varType
-                                                                                                               .equals(Boolean.class)) {
-                                                                                       Object val = new Boolean(false);
-                                                                                       variables.put(varName, val);
-                                                                                       changed |= (!val
-                                                                                                       .equals(varOldValue));
-                                                                               } else {
-                                                                                       // TODO Remove this?
-                                                                                       System.err
-                                                                                                       .println("Empty variable '"
-                                                                                                                       + varName
-                                                                                                                       + "' of type "
-                                                                                                                       + varType
-                                                                                                                                       .toString());
-                                                                               }
-
-                                                                       } catch (java.lang.ClassCastException e) {
-                                                                               // TODO Remove this?
-                                                                               System.err
-                                                                                               .println("WebVariableMap conversion exception");
-                                                                               e.printStackTrace(System.err);
-                                                                               errorListener
-                                                                                               .terminalError(new TerminalErrorImpl(
-                                                                                                               e));
-                                                                       }
-                                                               }
-                                                       }
-                                               }
-                                       }
-                               }
-
-                               // Do the valuechange if the listener is enabled
-                               if (listener.isEnabled() && changed) {
-                                       try {
-                                               listener.changeVariables(req, variables);
-                                       } catch (Throwable t) {
-                                               // Notify the error listener
-                                               errorListener.terminalError(new VariableOwnerErrorImpl(
-                                                               listener, t));
-                                       }
-                               }
-                       }
-               }
-
-               return parcon.getNonVariables();
-       }
-
-       /**
-        * Implementation of VariableOwner.Error interface.
-        */
-       public class TerminalErrorImpl implements Terminal.ErrorEvent {
-               private Throwable throwable;
-
-               /**
-                * 
-                * @param throwable
-                */
-               private TerminalErrorImpl(Throwable throwable) {
-                       this.throwable = throwable;
-               }
-
-               /**
-                * @see com.itmill.toolkit.terminal.Terminal.ErrorEvent#getThrowable()
-                */
-               public Throwable getThrowable() {
-                       return this.throwable;
-               }
-
-       }
-
-       /**
-        * Implementation of VariableOwner.Error interface.
-        */
-       public class VariableOwnerErrorImpl extends TerminalErrorImpl implements
-                       VariableOwner.ErrorEvent {
-
-               private VariableOwner owner;
-
-               /**
-                * 
-                * @param owner
-                *            the Listener for variable changes.
-                * @param throwable
-                */
-               private VariableOwnerErrorImpl(VariableOwner owner, Throwable throwable) {
-                       super(throwable);
-                       this.owner = owner;
-               }
-
-               /**
-                * @see com.itmill.toolkit.terminal.VariableOwner.ErrorEvent#getVariableOwner()
-                */
-               public VariableOwner getVariableOwner() {
-                       return this.owner;
-               }
-
-       }
-
-       /**
-        * Resolves the VariableOwners needed from the request and sort them to
-        * assure that the dependencies are met (as well as possible).
-        * 
-        * @param listeners
-        * @return List of variable list changers, that are needed for handling all
-        *         the variables in the request
-        */
-       private List getDependencySortedListenerList(Set listeners) {
-
-               LinkedList resultNormal = new LinkedList();
-               LinkedList resultImmediate = new LinkedList();
-
-               // Go trough the listeners and either add them to result or resolve
-               // their dependencies
-               HashMap deepdeps = new HashMap();
-               LinkedList unresolved = new LinkedList();
-               for (Iterator li = listeners.iterator(); li.hasNext();) {
-
-                       VariableOwner listener = (VariableOwner) li.next();
-                       if (listener != null) {
-                               Set dependencies = listener.getDirectDependencies();
-
-                               // The listeners with no dependencies are added to the front of
-                               // the
-                               // list directly
-                               if (dependencies == null || dependencies.isEmpty()) {
-                                       if (listener.isImmediate())
-                                               resultImmediate.addFirst(listener);
-                                       else
-                                               resultNormal.addFirst(listener);
-                               }
-
-                               // Resolve deep dependencies for the listeners with dependencies
-                               // (the listeners will be added to the end of results in correct
-                               // dependency order later). Also the dependencies of all the
-                               // depended listeners are resolved.
-                               else if (deepdeps.get(listener) == null) {
-
-                                       // Set the fifo for unresolved parents to contain only the
-                                       // listener to be resolved
-                                       unresolved.clear();
-                                       unresolved.add(listener);
-
-                                       // Resolve dependencies
-                                       HashSet tmpdeepdeps = new HashSet();
-                                       while (!unresolved.isEmpty()) {
-
-                                               VariableOwner l = (VariableOwner) unresolved
-                                                               .removeFirst();
-                                               if (!tmpdeepdeps.contains(l)) {
-                                                       tmpdeepdeps.add(l);
-                                                       if (deepdeps.containsKey(l)) {
-                                                               tmpdeepdeps.addAll((Set) deepdeps.get(l));
-                                                       } else {
-                                                               Set deps = l.getDirectDependencies();
-                                                               if (deps != null && !deps.isEmpty())
-                                                                       for (Iterator di = deps.iterator(); di
-                                                                                       .hasNext();) {
-                                                                               Object d = di.next();
-                                                                               if (d != null
-                                                                                               && !tmpdeepdeps.contains(d))
-                                                                                       unresolved.addLast(d);
-                                                                       }
-                                                       }
-                                               }
-                                       }
-
-                                       tmpdeepdeps.remove(listener);
-                                       deepdeps.put(listener, tmpdeepdeps);
-                               }
-                       }
-               }
-
-               // Adds the listeners with dependencies in sane order to the result
-               for (Iterator li = deepdeps.keySet().iterator(); li.hasNext();) {
-                       VariableOwner l = (VariableOwner) li.next();
-                       boolean immediate = l.isImmediate();
-
-                       // Adds each listener after the last depended listener already in
-                       // the list
-                       int index = -1;
-                       for (Iterator di = ((Set) deepdeps.get(l)).iterator(); di.hasNext();) {
-                               int k;
-                               Object depended = di.next();
-                               if (immediate) {
-                                       k = resultImmediate.lastIndexOf(depended);
-                               } else {
-                                       k = resultNormal.lastIndexOf(depended);
-                               }
-                               if (k > index)
-                                       index = k;
-                       }
-                       if (immediate) {
-                               resultImmediate.add(index + 1, l);
-                       } else {
-                               resultNormal.add(index + 1, l);
-                       }
-               }
-
-               // Appends immediate listeners to normal listeners
-               // This way the normal handlers are always called before
-               // immediate ones
-               resultNormal.addAll(resultImmediate);
-               return resultNormal;
-       }
-}
diff --git a/src/com/itmill/toolkit/terminal/web/AjaxXmlPaintTarget.java b/src/com/itmill/toolkit/terminal/web/AjaxXmlPaintTarget.java
deleted file mode 100644 (file)
index dc175f7..0000000
+++ /dev/null
@@ -1,608 +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 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;
-       }
-
-       public void addAttribute(String string, String[] keys) {
-               // TODO Auto-generated method stub
-               
-       }
-
-       public void addAttribute(String string, Object[] keys) {
-               // TODO Auto-generated method stub
-               
-       }
-
-}
diff --git a/src/com/itmill/toolkit/terminal/web/ApplicationServlet.java b/src/com/itmill/toolkit/terminal/web/ApplicationServlet.java
deleted file mode 100644 (file)
index 525d9f9..0000000
+++ /dev/null
@@ -1,2186 +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 java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Date;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import java.util.StringTokenizer;
-import java.util.Vector;
-import java.util.WeakHashMap;
-
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-import javax.servlet.http.HttpSessionBindingEvent;
-import javax.servlet.http.HttpSessionBindingListener;
-
-import org.xml.sax.SAXException;
-
-import com.itmill.toolkit.Application;
-import com.itmill.toolkit.Application.WindowAttachEvent;
-import com.itmill.toolkit.Application.WindowDetachEvent;
-import com.itmill.toolkit.service.FileTypeResolver;
-import com.itmill.toolkit.service.License;
-import com.itmill.toolkit.service.License.InvalidLicenseFile;
-import com.itmill.toolkit.service.License.LicenseFileHasNotBeenRead;
-import com.itmill.toolkit.service.License.LicenseSignatureIsInvalid;
-import com.itmill.toolkit.service.License.LicenseViolation;
-import com.itmill.toolkit.terminal.DownloadStream;
-import com.itmill.toolkit.terminal.Paintable;
-import com.itmill.toolkit.terminal.ParameterHandler;
-import com.itmill.toolkit.terminal.ThemeResource;
-import com.itmill.toolkit.terminal.URIHandler;
-import com.itmill.toolkit.terminal.Paintable.RepaintRequestEvent;
-import com.itmill.toolkit.terminal.web.ThemeSource.ThemeException;
-import com.itmill.toolkit.terminal.web.WebBrowser;
-import com.itmill.toolkit.ui.Window;
-
-/**
- * This servlet connects IT Mill Toolkit Application to Web. This servlet
- * replaces both WebAdapterServlet and AjaxAdapterServlet.
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 4.0
- */
-
-public class ApplicationServlet extends HttpServlet implements
-               Application.WindowAttachListener, Application.WindowDetachListener,
-               Paintable.RepaintRequestListener {
-
-       private static final long serialVersionUID = -4937882979845826574L;
-
-       /**
-        * Version number of this release. For example "4.0.0".
-        */
-       public static final String VERSION;
-
-       /**
-        * Major version number. For example 4 in 4.1.0.
-        */
-       public static final int VERSION_MAJOR;
-
-       /**
-        * Minor version number. For example 1 in 4.1.0.
-        */
-       public static final int VERSION_MINOR;
-
-       /**
-        * Builds number. For example 0-beta1 in 4.0.0-beta1.
-        */
-       public static final String VERSION_BUILD;
-
-       /* Initialize version numbers from string replaced by build-script. */
-       static {
-               if ("@VERSION@".equals("@" + "VERSION" + "@"))
-                       VERSION = "4.0.0-INTERNAL-NONVERSIONED-DEBUG-BUILD";
-               else
-                       VERSION = "@VERSION@";
-               String[] digits = VERSION.split("\\.");
-               VERSION_MAJOR = Integer.parseInt(digits[0]);
-               VERSION_MINOR = Integer.parseInt(digits[1]);
-               VERSION_BUILD = digits[2];
-       }
-
-       // Configurable parameter names
-       private static final String PARAMETER_DEBUG = "Debug";
-
-       private static final String PARAMETER_DEFAULT_THEME_JAR = "DefaultThemeJar";
-
-       private static final String PARAMETER_THEMESOURCE = "ThemeSource";
-
-       private static final String PARAMETER_THEME_CACHETIME = "ThemeCacheTime";
-
-       private static final String PARAMETER_MAX_TRANSFORMERS = "MaxTransformers";
-
-       private static final String PARAMETER_TRANSFORMER_CACHETIME = "TransformerCacheTime";
-
-       private static final int DEFAULT_THEME_CACHETIME = 1000 * 60 * 60 * 24;
-
-       private static final int DEFAULT_BUFFER_SIZE = 32 * 1024;
-
-       private static final int DEFAULT_MAX_TRANSFORMERS = 1;
-
-       private static final int MAX_BUFFER_SIZE = 64 * 1024;
-
-       // TODO: these should be moved to session object and stored directly into
-       // session
-       private static final String SESSION_ATTR_VARMAP = "itmill-toolkit-varmap";
-
-       private static final String SESSION_ATTR_CONTEXT = "itmill-toolkit-context";
-
-       protected static final String SESSION_ATTR_APPS = "itmill-toolkit-apps";
-
-       private static final String SESSION_BINDING_LISTENER = "itmill-toolkit-bindinglistener";
-
-       private static HashMap applicationToDirtyWindowSetMap = new HashMap();
-
-       private static HashMap applicationToServerCommandStreamLock = new HashMap();
-
-       private static HashMap applicationToLastRequestDate = new HashMap();
-
-       private static HashMap applicationToAjaxAppMgrMap = new HashMap();
-
-       // License for ApplicationServlets
-       private static HashMap licenseForApplicationClass = new HashMap();
-
-       private static HashMap licensePrintedForApplicationClass = new HashMap();
-
-       // TODO Should default or base theme be the default?
-       protected static final String DEFAULT_THEME = "base";
-
-       private static final String RESOURCE_URI = "/RES/";
-
-       private static final String AJAX_UIDL_URI = "/UIDL/";
-
-       private static final String THEME_DIRECTORY_PATH = "/theme/";
-
-       private static final String THEME_LISTING_FILE = THEME_DIRECTORY_PATH
-                       + "themes.txt";
-
-       private static final String DEFAULT_THEME_JAR_PREFIX = "itmill-toolkit-themes";
-
-       private static final String DEFAULT_THEME_JAR = "/WEB-INF/lib/"
-                       + DEFAULT_THEME_JAR_PREFIX + "-" + VERSION + ".jar";
-
-       private static final String DEFAULT_THEME_TEMP_FILE_PREFIX = "ITMILL_TMP_";
-
-       private static final String SERVER_COMMAND_PARAM = "SERVER_COMMANDS";
-
-       private static final int SERVER_COMMAND_STREAM_MAINTAIN_PERIOD = 15000;
-
-       private static final int SERVER_COMMAND_HEADER_PADDING = 2000;
-
-       // Maximum delay between request for an user to be considered active (in ms)
-       private static final long ACTIVE_USER_REQUEST_INTERVAL = 1000 * 45;
-
-       // Private fields
-       private Class applicationClass;
-
-       private Properties applicationProperties;
-
-       private UIDLTransformerFactory transformerFactory;
-
-       private CollectionThemeSource themeSource;
-
-       private String resourcePath = null;
-
-       private String debugMode = "";
-
-       private int maxConcurrentTransformers;
-
-       private long transformerCacheTime;
-
-       private long themeCacheTime;
-
-       /**
-        * Called by the servlet container to indicate to a servlet that the servlet
-        * is being placed into service.
-        * 
-        * @param servletConfig
-        *            the object containing the servlet's configuration and
-        *            initialization parameters
-        * @throws javax.servlet.ServletException
-        *             if an exception has occurred that interferes with the
-        *             servlet's normal operation.
-        */
-       public void init(javax.servlet.ServletConfig servletConfig)
-                       throws javax.servlet.ServletException {
-               super.init(servletConfig);
-
-               // Gets the application class name
-               String applicationClassName = servletConfig
-                               .getInitParameter("application");
-               if (applicationClassName == null) {
-                       Log.error("Application not specified in servlet parameters");
-               }
-
-               // Stores the application parameters into Properties object
-               this.applicationProperties = new Properties();
-               for (Enumeration e = servletConfig.getInitParameterNames(); e
-                               .hasMoreElements();) {
-                       String name = (String) e.nextElement();
-                       this.applicationProperties.setProperty(name, servletConfig
-                                       .getInitParameter(name));
-               }
-
-               // Overrides with server.xml parameters
-               ServletContext context = servletConfig.getServletContext();
-               for (Enumeration e = context.getInitParameterNames(); e
-                               .hasMoreElements();) {
-                       String name = (String) e.nextElement();
-                       this.applicationProperties.setProperty(name, context
-                                       .getInitParameter(name));
-               }
-
-               // Gets the debug window parameter
-               String debug = getApplicationOrSystemProperty(PARAMETER_DEBUG, "")
-                               .toLowerCase();
-
-               // Enables application specific debug
-               if (!"".equals(debug) && !"true".equals(debug)
-                               && !"false".equals(debug))
-                       throw new ServletException(
-                                       "If debug parameter is given for an application, it must be 'true' or 'false'");
-               this.debugMode = debug;
-
-               // Gets the maximum number of simultaneous transformers
-               this.maxConcurrentTransformers = Integer
-                               .parseInt(getApplicationOrSystemProperty(
-                                               PARAMETER_MAX_TRANSFORMERS, "-1"));
-               if (this.maxConcurrentTransformers < 1)
-                       this.maxConcurrentTransformers = DEFAULT_MAX_TRANSFORMERS;
-
-               // Gets cache time for transformers
-               this.transformerCacheTime = Integer
-                               .parseInt(getApplicationOrSystemProperty(
-
-                               PARAMETER_TRANSFORMER_CACHETIME, "-1")) * 1000;
-
-               // Gets cache time for theme resources
-               this.themeCacheTime = Integer.parseInt(getApplicationOrSystemProperty(
-                               PARAMETER_THEME_CACHETIME, "-1")) * 1000;
-               if (this.themeCacheTime < 0) {
-                       this.themeCacheTime = DEFAULT_THEME_CACHETIME;
-               }
-
-               // Adds all specified theme sources
-               this.themeSource = new CollectionThemeSource();
-               List directorySources = getThemeSources();
-               for (Iterator i = directorySources.iterator(); i.hasNext();) {
-                       this.themeSource.add((ThemeSource) i.next());
-               }
-
-               // Adds the default theme source
-               String[] defaultThemeFiles = new String[] { getApplicationOrSystemProperty(
-                               PARAMETER_DEFAULT_THEME_JAR, DEFAULT_THEME_JAR) };
-               File f = findDefaultThemeJar(defaultThemeFiles);
-               boolean defaultThemeFound = false;
-               try {
-                       // Adds themes.jar if exists
-                       if (f != null && f.exists()) {
-                               this.themeSource.add(new JarThemeSource(f, this, ""));
-                               defaultThemeFound = true;
-                       }
-               } catch (Exception e) {
-                       throw new ServletException("Failed to load default theme from "
-                                       + Arrays.asList(defaultThemeFiles), e);
-               }
-
-               // Checks that at least one themesource was loaded
-               if (this.themeSource.getThemes().size() <= 0) {
-                       throw new ServletException(
-                                       "No themes found in specified themesources. "
-                                                       + Theme.MESSAGE_CONFIGURE_HELP);
-               }
-
-               // Warn if default theme not found
-               if (this.themeSource.getThemeByName(DEFAULT_THEME) == null) {
-                       if (!defaultThemeFound)
-                               Log.warn("Default theme JAR not found in: "
-                                               + Arrays.asList(defaultThemeFiles));
-               }
-
-               // Initializes the transformer factory, if not initialized
-               if (this.transformerFactory == null) {
-                       this.transformerFactory = new UIDLTransformerFactory(
-                                       this.themeSource, this, this.maxConcurrentTransformers,
-                                       this.transformerCacheTime);
-               }
-
-               // Loads the application class using the same class loader
-               // as the servlet itself
-               ClassLoader loader = this.getClass().getClassLoader();
-               try {
-                       this.applicationClass = loader.loadClass(applicationClassName);
-               } catch (ClassNotFoundException e) {
-                       throw new ServletException("Failed to load application class: "
-                                       + applicationClassName);
-               }
-       }
-
-       /**
-        * Gets an application or system property value.
-        * 
-        * @param parameterName
-        *            the Name or the parameter.
-        * @param defaultValue
-        *            the Default to be used.
-        * @return String value or default if not found
-        */
-       private String getApplicationOrSystemProperty(String parameterName,
-                       String defaultValue) {
-
-               // Try application properties
-               String val = this.applicationProperties.getProperty(parameterName);
-               if (val != null) {
-                       return val;
-               }
-
-               // Try lowercased application properties for backward compability with
-               // 3.0.2 and earlier
-               val = this.applicationProperties.getProperty(parameterName
-                               .toLowerCase());
-               if (val != null) {
-                       return val;
-               }
-
-               // Try system properties
-               String pkgName;
-               Package pkg = this.getClass().getPackage();
-               if (pkg != null) {
-                       pkgName = pkg.getName();
-               } else {
-                       String className = this.getClass().getName();
-                       pkgName = new String(className.toCharArray(), 0, className
-                                       .lastIndexOf('.'));
-               }
-               val = System.getProperty(pkgName + "." + parameterName);
-               if (val != null) {
-                       return val;
-               }
-
-               // Try lowercased system properties
-               val = System.getProperty(pkgName + "." + parameterName.toLowerCase());
-               if (val != null) {
-                       return val;
-               }
-
-               return defaultValue;
-       }
-
-       /**
-        * Gets ThemeSources from given path. Construct the list of avalable themes
-        * in path using the following sources:
-        * <p>
-        * 1. Content of <code>THEME_PATH</code> directory (if available).
-        * </p>
-        * <p>
-        * 2. The themes listed in <code>THEME_LIST_FILE</code>.
-        * </p>
-        * <p>
-        * 3. "themesource" application parameter - "ThemeSource" system property.
-        * </p>
-        * 
-        * @return the List
-        * @throws ServletException
-        *             if an exception has occurred that interferes with the
-        *             servlet's normal operation.
-        */
-       private List getThemeSources() throws ServletException {
-
-               List returnValue = new LinkedList();
-
-               // Check the list file in theme directory
-               List sourcePaths = new LinkedList();
-               try {
-                       BufferedReader reader = new BufferedReader(new InputStreamReader(
-                                       this.getServletContext().getResourceAsStream(
-                                                       THEME_LISTING_FILE)));
-                       String line = null;
-                       while ((line = reader.readLine()) != null) {
-                               sourcePaths.add(THEME_DIRECTORY_PATH + line.trim());
-                       }
-                       if (this.isDebugMode(null)) {
-                               Log.debug("Listed " + sourcePaths.size() + " themes in "
-                                               + THEME_LISTING_FILE + ". Loading " + sourcePaths);
-                       }
-               } catch (Exception ignored) {
-                       // If the file reading fails, just skip to next method
-               }
-
-               // If no file was found or it was empty,
-               // try to add themes filesystem directory if it is accessible
-               if (sourcePaths.size() <= 0) {
-                       if (this.isDebugMode(null)) {
-                               Log.debug("No themes listed in " + THEME_LISTING_FILE
-                                               + ". Trying to read the content of directory "
-                                               + THEME_DIRECTORY_PATH);
-                       }
-
-                       try {
-                               String path = getResourcePath(getServletContext(),
-                                               THEME_DIRECTORY_PATH);
-                               if (path != null) {
-                                       File f = new File(path);
-                                       if (f != null && f.exists())
-                                               returnValue.add(new DirectoryThemeSource(f, this));
-                               }
-                       } catch (java.io.IOException je) {
-                               Log.info("Theme directory " + THEME_DIRECTORY_PATH
-                                               + " not available. Skipped.");
-                       } catch (ThemeException e) {
-                               throw new ServletException("Failed to load themes from "
-                                               + THEME_DIRECTORY_PATH, e);
-                       }
-               }
-
-               // Adds the theme sources from application properties
-               String paramValue = getApplicationOrSystemProperty(
-                               PARAMETER_THEMESOURCE, null);
-               if (paramValue != null) {
-                       StringTokenizer st = new StringTokenizer(paramValue, ";");
-                       while (st.hasMoreTokens()) {
-                               sourcePaths.add(st.nextToken());
-                       }
-               }
-
-               // Constructs appropriate theme source instances for each path
-               for (Iterator i = sourcePaths.iterator(); i.hasNext();) {
-                       String source = (String) i.next();
-                       File sourceFile = new File(source);
-                       try {
-                               // Relative files are treated as streams (to support
-                               // resource inside WAR files)
-                               if (!sourceFile.isAbsolute()) {
-                                       returnValue.add(new ServletThemeSource(this
-                                                       .getServletContext(), this, source));
-                               } else if (sourceFile.isDirectory()) {
-                                       // Absolute directories are read from filesystem
-                                       returnValue.add(new DirectoryThemeSource(sourceFile, this));
-                               } else {
-                                       // Absolute JAR-files are read from filesystem
-                                       returnValue.add(new JarThemeSource(sourceFile, this, ""));
-                               }
-                       } catch (Exception e) {
-                               // Any exception breaks the the init
-                               throw new ServletException("Invalid theme source: " + source, e);
-                       }
-               }
-
-               // Returns the constructed list of theme sources
-               return returnValue;
-       }
-
-       /**
-        * Receives standard HTTP requests from the public service method and
-        * dispatches them.
-        * 
-        * @param request
-        *            the object that contains the request the client made of the
-        *            servlet.
-        * @param response
-        *            the object that contains the response the servlet returns to
-        *            the client.
-        * @throws ServletException
-        *             if an input or output error occurs while the servlet is
-        *             handling the TRACE request.
-        * @throws IOException
-        *             if the request for the TRACE cannot be handled.
-        */
-       protected void service(HttpServletRequest request,
-                       HttpServletResponse response) throws ServletException, IOException {
-
-               // Transformer and output stream for the result
-               UIDLTransformer transformer = null;
-               HttpVariableMap variableMap = null;
-               OutputStream out = response.getOutputStream();
-               HashMap currentlyDirtyWindowsForThisApplication = new HashMap();
-               Application application = null;
-               try {
-
-                       // Handles resource requests
-                       if (handleResourceRequest(request, response))
-                               return;
-
-                       // Handles server commands
-                       if (handleServerCommands(request, response))
-                               return;
-
-                       // Gets the application
-                       application = getApplication(request);
-
-                       // Creates application if it doesn't exist
-                       if (application == null)
-                               application = createApplication(request);
-
-                       // Sets the last application request date
-                       synchronized (applicationToLastRequestDate) {
-                               applicationToLastRequestDate.put(application, new Date());
-                       }
-
-                       // Invokes context transaction listeners
-                       ((WebApplicationContext) application.getContext())
-                                       .startTransaction(application, request);
-
-                       // Is this a download request from application
-                       DownloadStream download = null;
-
-                       // The rest of the process is synchronized with the application
-                       // in order to guarantee that no parallel variable handling is
-                       // made
-                       synchronized (application) {
-
-                               // Handles AJAX UIDL requests
-                               String resourceId = request.getPathInfo();
-                               if (resourceId != null && resourceId.startsWith(AJAX_UIDL_URI)) {
-                                       getApplicationManager(application).handleUidlRequest(
-                                                       request, response, themeSource, true);
-                                       return;
-                               }
-
-                               // Gets the variable map
-                               variableMap = getVariableMap(application, request);
-                               if (variableMap == null)
-                                       return;
-
-                               // Change all variables based on request parameters
-                               Map unhandledParameters = variableMap.handleVariables(request,
-                                               application);
-
-                               // Check/handle client side feature checks
-                               WebBrowserProbe
-                                               .handleProbeRequest(request, unhandledParameters);
-
-                               // If rendering mode is not defined or detecting requested
-                               // try to detect it
-                               WebBrowser wb = WebBrowserProbe.getTerminalType(request
-                                               .getSession());
-
-                               boolean detect = false;
-                               if (unhandledParameters.get("renderingMode") != null) {
-                                       detect = ((String) ((Object[]) unhandledParameters
-                                                       .get("renderingMode"))[0]).equals("detect");
-                               }
-                               if (detect
-                                               || wb.getRenderingMode() == WebBrowser.RENDERING_MODE_UNDEFINED) {
-                                       String themeName = application.getTheme();
-                                       if (themeName == null)
-                                               themeName = DEFAULT_THEME;
-                                       if (unhandledParameters.get("theme") != null) {
-                                               themeName = (String) ((Object[]) unhandledParameters
-                                                               .get("theme"))[0];
-                                       }
-
-                                       Theme theme = themeSource.getThemeByName(themeName);
-                                       if (theme == null)
-                                               throw new ServletException(
-                                                               "Failed to load theme with name " + themeName
-                                                                               + ". " + Theme.MESSAGE_CONFIGURE_HELP);
-
-                                       String renderingMode = theme.getPreferredMode(wb,
-                                                       themeSource);
-                                       if (Theme.MODE_AJAX.equals(renderingMode)) {
-                                               wb.setRenderingMode(WebBrowser.RENDERING_MODE_AJAX);
-                                       } else {
-                                               wb.setRenderingMode(WebBrowser.RENDERING_MODE_HTML);
-                                       }
-                               }
-                               if (unhandledParameters.get("renderingMode") != null) {
-                                       String renderingMode = (String) ((Object[]) unhandledParameters
-                                                       .get("renderingMode"))[0];
-                                       if (renderingMode.equals("html")) {
-                                               wb.setRenderingMode(WebBrowser.RENDERING_MODE_HTML);
-                                       } else if (renderingMode.equals("ajax")) {
-                                               wb.setRenderingMode(WebBrowser.RENDERING_MODE_AJAX);
-                                       }
-                               }
-
-                               // Handles the URI if the application is still running
-                               if (application.isRunning())
-                                       download = handleURI(application, request, response);
-
-                               // If this is not a download request
-                               if (download == null) {
-
-                                       // Window renders are not cacheable
-                                       response.setHeader("Cache-Control", "no-cache");
-                                       response.setHeader("Pragma", "no-cache");
-                                       response.setDateHeader("Expires", 0);
-
-                                       // Finds the window within the application
-                                       Window window = null;
-                                       if (application.isRunning())
-                                               window = getApplicationWindow(request, application,
-                                                               unhandledParameters);
-
-                                       // Handles the unhandled parameters if the application is
-                                       // still running
-                                       if (window != null && unhandledParameters != null
-                                                       && !unhandledParameters.isEmpty()) {
-                                               try {
-                                                       window.handleParameters(unhandledParameters);
-                                               } catch (Throwable t) {
-                                                       application
-                                                                       .terminalError(new ParameterHandlerErrorImpl(
-                                                                                       window, t));
-                                               }
-                                       }
-
-                                       // Removes application if it has stopped
-                                       if (!application.isRunning()) {
-                                               endApplication(request, response, application);
-                                               return;
-                                       }
-
-                                       // Returns blank page, if no window found
-                                       if (window == null) {
-                                               response.setContentType("text/html");
-                                               BufferedWriter page = new BufferedWriter(
-                                                               new OutputStreamWriter(out));
-                                               page.write("<html><head><script>");
-                                               page
-                                                               .write(ThemeFunctionLibrary
-                                                                               .generateWindowScript(
-                                                                                               null,
-                                                                                               application,
-                                                                                               this,
-                                                                                               WebBrowserProbe
-                                                                                                               .getTerminalType(request
-                                                                                                                               .getSession())));
-                                               page.write("</script></head><body>");
-                                               page
-                                                               .write("The requested window has been removed from application.");
-                                               page.write("</body></html>");
-                                               page.close();
-
-                                               return;
-                                       }
-
-                                       // Sets terminal type for the window, if not already set
-                                       if (window.getTerminal() == null) {
-                                               window.setTerminal(wb);
-                                       }
-
-                                       // Finds theme
-                                       String themeName = window.getTheme() != null ? window
-                                                       .getTheme() : DEFAULT_THEME;
-                                       if (unhandledParameters.get("theme") != null) {
-                                               themeName = (String) ((Object[]) unhandledParameters
-                                                               .get("theme"))[0];
-                                       }
-                                       Theme theme = themeSource.getThemeByName(themeName);
-                                       if (theme == null)
-                                               throw new ServletException("Theme (named '" + themeName
-                                                               + "') can not be found");
-
-                                       // If in ajax rendering mode, print an html page for it
-                                       if (wb.getRenderingMode() == WebBrowser.RENDERING_MODE_AJAX) {
-                                               writeAjaxPage(request, response, out,
-                                                               unhandledParameters, window, wb, theme);
-                                               return;
-                                       }
-
-                                       // If other than html or ajax mode is requested
-                                       if (wb.getRenderingMode() == WebBrowser.RENDERING_MODE_UNDEFINED
-                                                       && !(window instanceof DebugWindow)) {
-                                               // TODO More informal message should be given to browser
-                                               response.setContentType("text/html");
-                                               BufferedWriter page = new BufferedWriter(
-                                                               new OutputStreamWriter(out));
-                                               page.write("<html><head></head><body>");
-                                               page.write("Unsupported browser.");
-                                               page.write("</body></html>");
-                                               page.close();
-
-                                               return;
-                                       }
-
-                                       // Initialize Transformer
-                                       UIDLTransformerType transformerType = new UIDLTransformerType(
-                                                       wb, theme);
-
-                                       transformer = this.transformerFactory
-                                                       .getTransformer(transformerType);
-
-                                       // Sets the response type
-                                       response.setContentType(wb.getContentType());
-
-                                       // Creates UIDL writer
-                                       WebPaintTarget paintTarget = transformer
-                                                       .getPaintTarget(variableMap);
-
-                                       // Assures that the correspoding debug window will be
-                                       // repainted property
-                                       // by clearing it before the actual paint.
-                                       DebugWindow debugWindow = (DebugWindow) application
-                                                       .getWindow(DebugWindow.WINDOW_NAME);
-                                       if (debugWindow != null && debugWindow != window) {
-                                               debugWindow.setWindowUIDL(window, "Painting...");
-                                       }
-
-                                       // Paints window
-                                       window.paint(paintTarget);
-                                       paintTarget.close();
-
-                                       // For exception handling, memorize the current dirty status
-                                       HashMap dirtyWindows = (HashMap) applicationToDirtyWindowSetMap
-                                                       .get(application);
-
-                                       if (dirtyWindows == null) {
-                                               dirtyWindows = new HashMap();
-                                               applicationToDirtyWindowSetMap.put(application,
-                                                               dirtyWindows);
-                                       }
-                                       currentlyDirtyWindowsForThisApplication
-                                                       .putAll((Map) dirtyWindows);
-
-                                       // Window is now painted
-                                       windowPainted(application, window);
-
-                                       // Debug
-                                       if (debugWindow != null && debugWindow != window) {
-                                               debugWindow
-                                                               .setWindowUIDL(window, paintTarget.getUIDL());
-                                       }
-
-                                       // Sets the function library state for this thread
-                                       ThemeFunctionLibrary.setState(application, window,
-                                                       transformerType.getWebBrowser(), request
-                                                                       .getSession(), this, transformerType
-                                                                       .getTheme().getName());
-
-                               }
-                       }
-
-                       // For normal requests, transform the window
-                       if (download == null) {
-
-                               // Transform and output the result to browser
-                               // Note that the transform and transfer of the result is
-                               // not synchronized with the variable map. This allows
-                               // parallel transfers and transforms for better performance,
-                               // but requires that all calls from the XSL to java are
-                               // thread-safe
-                               transformer.transform(out);
-                       }
-
-                       // For download request, transfer the downloaded data
-                       else {
-
-                               handleDownload(download, request, response);
-                       }
-
-               } catch (UIDLTransformerException te) {
-                       // Print stacktrace
-                       te.printStackTrace();
-
-                       try {
-                               // Writes the error report to client
-                               response.setContentType("text/html");
-                               BufferedWriter err = new BufferedWriter(new OutputStreamWriter(
-                                               out));
-                               err
-                                               .write("<html><head><title>Application Internal Error</title></head><body>");
-                               err.write("<h1>" + te.getMessage() + "</h1>");
-                               err.write(te.getHTMLDescription());
-                               err.write("</body></html>");
-                               err.close();
-                       } catch (Throwable t) {
-                               Log.except("Failed to write error page: " + t
-                                               + ". Original exception was: ", te);
-                       }
-
-                       // Adds previously dirty windows to dirtyWindowList in order
-                       // to make sure that eventually they are repainted
-                       Application currentApplication = getApplication(request);
-                       for (Iterator iter = currentlyDirtyWindowsForThisApplication
-                                       .keySet().iterator(); iter.hasNext();) {
-                               Window dirtyWindow = (Window) iter.next();
-                               addDirtyWindow(currentApplication, dirtyWindow);
-                       }
-
-               } catch (Throwable e) {
-                       // Print stacktrace
-                       e.printStackTrace();
-                       // Re-throw other exceptions
-                       throw new ServletException(e);
-               } finally {
-
-                       // Releases transformer
-                       if (transformer != null)
-                               transformerFactory.releaseTransformer(transformer);
-
-                       // Notifies transaction end
-                       if (application != null)
-                               ((WebApplicationContext) application.getContext())
-                                               .endTransaction(application, request);
-
-                       // Cleans the function library state for this thread
-                       // for security reasons
-                       ThemeFunctionLibrary.cleanState();
-               }
-       }
-
-       /**
-        * 
-        * @param request
-        *            the HTTP request.
-        * @param response
-        *            the HTTP response to write to.
-        * @param out
-        * @param unhandledParameters
-        * @param window
-        * @param terminalType
-        * @param theme
-        * @throws IOException
-        *             if the writing failed due to input/output error.
-        * @throws MalformedURLException
-        *             if the application is denied access the persistent data store
-        *             represented by the given URL.
-        */
-       private void writeAjaxPage(HttpServletRequest request,
-                       HttpServletResponse response, OutputStream out,
-                       Map unhandledParameters, Window window, WebBrowser terminalType,
-                       Theme theme) throws IOException, MalformedURLException {
-               response.setContentType("text/html");
-               BufferedWriter page = new BufferedWriter(new OutputStreamWriter(out));
-
-               page
-                               .write("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" "
-                                               + "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n");
-
-               
-               
-               page.write("<html>\n<head>\n<title>IT Mill Toolkit 5</title>\n" +
-                               "<meta name='gwt:module' content='../com.itmill.toolkit.terminal.gwt.Client=com.itmill.toolkit.terminal.gwt.Client'>\n" +
-                               "<script type=\"text/javascript\">\n" +
-                               "       var itmtk = {\n" +
-                               "               appUri:'");
-               
-               String[] urlParts = getApplicationUrl(request).toString().split("\\/");
-               String appUrl = "";
-               // don't use server and port in uri. It may cause problems with some
-               // virtual server configurations which lose the server name
-               for (int i = 3; i < urlParts.length; i++)
-                       appUrl += "/" + urlParts[i];
-               if (appUrl.endsWith("/"))
-                       appUrl = appUrl.substring(0, appUrl.length() - 1);
-               
-               page.write(appUrl);
-               
-               page.write("'\n};\n" +
-                               "</script>\n" +
-                               "<link REL=\"stylesheet\" TYPE=\"text/css\" HREF=\""+request.getContextPath() + "/theme/"+theme.getName()+"/style.css\">" + 
-                               "</head>\n<body>\n<script language=\"javascript\" src=\"/tk/com.itmill.toolkit.terminal.gwt.Client/gwt.js\"></script>\n" +
-                               "       <iframe id=\"__gwt_historyFrame\" style=\"width:0;height:0;border:0\"></iframe>\n" +
-                               "       <div id=\"itmtk-ajax-window\"></div>" +
-                               "       <div id=\"itmtk-loki\" style=\"width: 100%; position: absolute; left: 0px; bottom: 0; height: 0px; border-top: 1px solid gray; background-color: #f6f6f6; overflow: scroll; font-size: x-small;color:red !important;\"" +
-                               "></div>\n" +
-                               "<div id='itm-loki-exp' style='right: 0; bottom: 0px; position: absolute; padding-left: 5px; padding-right: 5px; border-left: 1px solid gray; border-top: 1px solid gray; background-color: #f6f6f6;' onclick='itm_loki_exp()'>console</div><script language='JavaScript'>itm_loki_exp = function() {var l=document.getElementById('itmtk-loki'); var e=document.getElementById('itm-loki-exp'); if (e.style.bottom=='400px') {e.style.bottom='0px'; l.style.height='0px'; e.innerHTML='console';} else {e.style.bottom='400px'; l.style.height='400px'; e.innerHTML='-';}}</script>"+
-                               "       <div style=\"position: absolute; right: 5px; top: 5px; color: gray;\"><strong>IT Mill Toolkit 5 Prototype</strong></div>\n" + 
-                               "       </body>\n" + 
-                               "</html>\n");
-               
-               
-               
-//             Theme t = theme;
-//             Vector themes = new Vector();
-//             themes.add(t);
-//             while (t.getParent() != null) {
-//                     String parentName = t.getParent();
-//                     t = themeSource.getThemeByName(parentName);
-//                     themes.add(t);
-//             }
-//             for (int k = themes.size() - 1; k >= 0; k--) {
-//                     t = (Theme) themes.get(k);
-//                     Collection files = t.getFileNames(terminalType, Theme.MODE_AJAX);
-//                     for (Iterator i = files.iterator(); i.hasNext();) {
-//                             String file = (String) i.next();
-//                             if (file.endsWith(".css"))
-//                                     page.write("<link rel=\"stylesheet\" href=\""
-//                                                     + getResourceLocation(t.getName(),
-//                                                                     new ThemeResource(file))
-//                                                     + "\" type=\"text/css\" />\n");
-//                             else if (file.endsWith(".js")) {
-//                                     page.write("<script src=\"");
-//
-//                                     // TODO remove this and implement behaviour in themes
-//                                     // description.xml files
-//                                     if (file.endsWith("firebug.js")
-//                                                     && !isDebugMode(unhandledParameters)) {
-//                                             file = file.replaceFirst("bug.js", "bugx.js");
-//                                     }
-//                                     page.write(getResourceLocation(t.getName(),
-//                                                     new ThemeResource(file)));
-//                                     page.write("\" type=\"text/javascript\"></script>\n");
-//                             }
-//                     }
-//
-//             }
-
-
-//             page.write("itmill.tmp = new itmill.Client("
-//                             + "document.getElementById('ajax-window')," + "\"" + appUrl
-//                             + "/UIDL/" + "\",\"" + resourcePath
-//                             + ((Theme) themes.get(themes.size() - 1)).getName() + "/"
-//
-//                             + "client/\",document.getElementById('ajax-wait'));\n");
-
-               // TODO Only current theme is registered to the client
-               // for (int k = themes.size() - 1; k >= 0; k--) {
-               // t = (Theme) themes.get(k);
-//             t = theme;
-//             String themeObjName = "itmill.themes."
-//                             + t.getName().substring(0, 1).toUpperCase()
-//                             + t.getName().substring(1);
-//             page.write(" (new " + themeObjName + "(\"" + resourcePath + t.getName()
-//                             + "/\")).registerTo(itmill.tmp);\n");
-               // }
-
-               page.close();
-       }
-
-       /**
-        * Handles the requested URI. An application can add handlers to do special
-        * processing, when a certain URI is requested. The handlers are invoked
-        * before any windows URIs are processed and if a DownloadStream is returned
-        * it is sent to the client.
-        * 
-        * @param application
-        *            the Application owning the URI.
-        * @param request
-        *            the HTTP request instance.
-        * @param response
-        *            the HTTP response to write to.
-        * @return boolean <code>true</code> if the request was handled and
-        *         further processing should be suppressed, <code>false</code>
-        *         otherwise.
-        * @see com.itmill.toolkit.terminal.URIHandler
-        */
-       private DownloadStream handleURI(Application application,
-                       HttpServletRequest request, HttpServletResponse response) {
-
-               String uri = request.getPathInfo();
-
-               // If no URI is available
-               if (uri == null || uri.length() == 0 || uri.equals("/"))
-                       return null;
-
-               // Removes the leading /
-               while (uri.startsWith("/") && uri.length() > 0)
-                       uri = uri.substring(1);
-
-               // Handles the uri
-               DownloadStream stream = null;
-               try {
-                       stream = application.handleURI(application.getURL(), uri);
-               } catch (Throwable t) {
-                       application.terminalError(new URIHandlerErrorImpl(application, t));
-               }
-
-               return stream;
-       }
-
-       /**
-        * Handles the requested URI. An application can add handlers to do special
-        * processing, when a certain URI is requested. The handlers are invoked
-        * before any windows URIs are processed and if a DownloadStream is returned
-        * it is sent to the client.
-        * 
-        * @param stream
-        *            the download stream.
-        * 
-        * @param request
-        *            the HTTP request instance.
-        * @param response
-        *            the HTTP response to write to.
-        * 
-        * @see com.itmill.toolkit.terminal.URIHandler
-        */
-       private void handleDownload(DownloadStream stream,
-                       HttpServletRequest request, HttpServletResponse response) {
-
-               // Download from given stream
-               InputStream data = stream.getStream();
-               if (data != null) {
-
-                       // Sets content type
-                       response.setContentType(stream.getContentType());
-
-                       // Sets cache headers
-                       long cacheTime = stream.getCacheTime();
-                       if (cacheTime <= 0) {
-                               response.setHeader("Cache-Control", "no-cache");
-                               response.setHeader("Pragma", "no-cache");
-                               response.setDateHeader("Expires", 0);
-                       } else {
-                               response.setHeader("Cache-Control", "max-age=" + cacheTime
-                                               / 1000);
-                               response.setDateHeader("Expires", System.currentTimeMillis()
-                                               + cacheTime);
-                               response.setHeader("Pragma", "cache"); // Required to apply
-                               // caching in some
-                               // Tomcats
-                       }
-
-                       // Copy download stream parameters directly
-                       // to HTTP headers.
-                       Iterator i = stream.getParameterNames();
-                       if (i != null) {
-                               while (i.hasNext()) {
-                                       String param = (String) i.next();
-                                       response.setHeader((String) param, stream
-                                                       .getParameter(param));
-                               }
-                       }
-
-                       int bufferSize = stream.getBufferSize();
-                       if (bufferSize <= 0 || bufferSize > MAX_BUFFER_SIZE)
-                               bufferSize = DEFAULT_BUFFER_SIZE;
-                       byte[] buffer = new byte[bufferSize];
-                       int bytesRead = 0;
-
-                       try {
-                               OutputStream out = response.getOutputStream();
-
-                               while ((bytesRead = data.read(buffer)) > 0) {
-                                       out.write(buffer, 0, bytesRead);
-                                       out.flush();
-                               }
-                               out.close();
-                       } catch (IOException ignored) {
-                       }
-
-               }
-
-       }
-
-       /**
-        * Looks for default theme JAR file.
-        * 
-        * @param fileList
-        * @return Jar file or null if not found.
-        */
-       private File findDefaultThemeJar(String[] fileList) {
-
-               // Try to find the default theme JAR file based on the given path
-               for (int i = 0; i < fileList.length; i++) {
-                       String path = getResourcePath(getServletContext(), fileList[i]);
-                       File file = null;
-                       if (path != null && (file = new File(path)).exists()) {
-                               return file;
-                       }
-               }
-
-               // If we do not have access to individual files, create a temporary
-               // file from named resource.
-               for (int i = 0; i < fileList.length; i++) {
-                       InputStream defaultTheme = this.getServletContext()
-                                       .getResourceAsStream(fileList[i]);
-                       // Read the content to temporary file and return it
-                       if (defaultTheme != null) {
-                               return createTemporaryFile(defaultTheme, ".jar");
-                       }
-               }
-
-               // Try to find the default theme JAR file based on file naming scheme
-               // NOTE: This is for backward compability with 3.0.2 and earlier.
-               String path = getResourcePath(getServletContext(), "/WEB-INF/lib");
-               if (path != null) {
-                       File lib = new File(path);
-                       String[] files = lib.list();
-                       if (files != null) {
-                               for (int i = 0; i < files.length; i++) {
-                                       if (files[i].toLowerCase().endsWith(".jar")
-                                                       && files[i].startsWith(DEFAULT_THEME_JAR_PREFIX)) {
-                                               return new File(lib, files[i]);
-                                       }
-                               }
-                       }
-               }
-
-               // If no file was found return null
-               return null;
-       }
-
-       /**
-        * Creates a temporary file for given stream.
-        * 
-        * @param stream
-        *            the Stream to be stored into temporary file.
-        * @param extension
-        *            the File type extension.
-        * @return the temporary File.
-        */
-       private File createTemporaryFile(InputStream stream, String extension) {
-               File tmpFile;
-               try {
-                       tmpFile = File.createTempFile(DEFAULT_THEME_TEMP_FILE_PREFIX,
-                                       extension);
-                       FileOutputStream out = new FileOutputStream(tmpFile);
-                       byte[] buf = new byte[1024];
-                       int bytes = 0;
-                       while ((bytes = stream.read(buf)) > 0) {
-                               out.write(buf, 0, bytes);
-                       }
-                       out.close();
-               } catch (IOException e) {
-                       System.err
-                                       .println("Failed to create temporary file for default theme: "
-                                                       + e);
-                       tmpFile = null;
-               }
-
-               return tmpFile;
-       }
-
-       /**
-        * Handles theme resource file requests. Resources supplied with the themes
-        * are provided by the WebAdapterServlet.
-        * 
-        * @param request
-        *            the HTTP request.
-        * @param response
-        *            the HTTP response.
-        * @return boolean <code>true</code> if the request was handled and
-        *         further processing should be suppressed, <code>false</code>
-        *         otherwise.
-        * @throws ServletException
-        *             if an exception has occurred that interferes with the
-        *             servlet's normal operation.
-        */
-       private boolean handleResourceRequest(HttpServletRequest request,
-                       HttpServletResponse response) throws ServletException {
-
-               // If the resource path is unassigned, initialize it
-               if (resourcePath == null) {
-                       resourcePath = request.getContextPath() + request.getServletPath()
-                                       + RESOURCE_URI;
-                       // WebSphere Application Server related fix
-                       resourcePath = resourcePath.replaceAll("//", "/");
-               }
-
-               String resourceId = request.getPathInfo();
-
-               // Checks if this really is a resource request
-               if (resourceId == null || !resourceId.startsWith(RESOURCE_URI))
-                       return false;
-
-               // Checks the resource type
-               resourceId = resourceId.substring(RESOURCE_URI.length());
-               InputStream data = null;
-               // Gets theme resources
-               try {
-                       data = themeSource.getResource(resourceId);
-               } catch (ThemeSource.ThemeException e) {
-                       Log.info(e.getMessage());
-                       data = null;
-               }
-
-               // Writes the response
-               try {
-                       if (data != null) {
-                               response.setContentType(FileTypeResolver
-                                               .getMIMEType(resourceId));
-
-                               // Use default cache time for theme resources
-                               if (this.themeCacheTime > 0) {
-                                       response.setHeader("Cache-Control", "max-age="
-                                                       + this.themeCacheTime / 1000);
-                                       response.setDateHeader("Expires", System
-                                                       .currentTimeMillis()
-                                                       + this.themeCacheTime);
-                                       response.setHeader("Pragma", "cache"); // Required to apply
-                                       // caching in some
-                                       // Tomcats
-                               }
-                               // Writes the data to client
-                               byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
-                               int bytesRead = 0;
-                               OutputStream out = response.getOutputStream();
-                               while ((bytesRead = data.read(buffer)) > 0) {
-                                       out.write(buffer, 0, bytesRead);
-                               }
-                               out.close();
-                               data.close();
-                       } else {
-                               response.sendError(HttpServletResponse.SC_NOT_FOUND);
-                       }
-
-               } catch (java.io.IOException e) {
-                       Log.info("Resource transfer failed:  " + request.getRequestURI()
-                                       + ". (" + e.getMessage() + ")");
-               }
-
-               return true;
-       }
-
-       /**
-        * Gets the variable map for the session.
-        * 
-        * @param application
-        * @param request
-        *            the HTTP request.
-        * @return the variable map.
-        * 
-        */
-       private static synchronized HttpVariableMap getVariableMap(
-                       Application application, HttpServletRequest request) {
-
-               HttpSession session = request.getSession();
-
-               // Gets the application to variablemap map
-               Map varMapMap = (Map) session.getAttribute(SESSION_ATTR_VARMAP);
-               if (varMapMap == null) {
-                       varMapMap = new WeakHashMap();
-                       session.setAttribute(SESSION_ATTR_VARMAP, varMapMap);
-               }
-
-               // Creates a variable map, if it does not exists.
-               HttpVariableMap variableMap = (HttpVariableMap) varMapMap
-                               .get(application);
-               if (variableMap == null) {
-                       variableMap = new HttpVariableMap();
-                       varMapMap.put(application, variableMap);
-               }
-
-               return variableMap;
-       }
-
-       /**
-        * Gets the current application URL from request.
-        * 
-        * @param request
-        *            the HTTP request.
-        * @throws MalformedURLException
-        *             if the application is denied access to the persistent data
-        *             store represented by the given URL.
-        */
-       private URL getApplicationUrl(HttpServletRequest request)
-                       throws MalformedURLException {
-
-               URL applicationUrl;
-               try {
-                       URL reqURL = new URL(
-                                       (request.isSecure() ? "https://" : "http://")
-                                                       + request.getServerName()
-                                                       + ((request.isSecure() && request.getServerPort() == 443)
-                                                                       || (!request.isSecure() && request
-                                                                                       .getServerPort() == 80) ? "" : ":"
-                                                                       + request.getServerPort())
-                                                       + request.getRequestURI());
-                       String servletPath = request.getContextPath()
-                                       + request.getServletPath();
-                       if (servletPath.length() == 0
-                                       || servletPath.charAt(servletPath.length() - 1) != '/')
-                               servletPath = servletPath + "/";
-                       applicationUrl = new URL(reqURL, servletPath);
-               } catch (MalformedURLException e) {
-                       Log.error("Error constructing application url "
-                                       + request.getRequestURI() + " (" + e + ")");
-                       throw e;
-               }
-
-               return applicationUrl;
-       }
-
-       /**
-        * Gets the existing application for given request. Looks for application
-        * instance for given request based on the requested URL.
-        * 
-        * @param request
-        *            the HTTP request.
-        * @return Application instance, or null if the URL does not map to valid
-        *         application.
-        * @throws MalformedURLException
-        *             if the application is denied access to the persistent data
-        *             store represented by the given URL.
-        */
-       private Application getApplication(HttpServletRequest request)
-                       throws MalformedURLException {
-
-               // Ensures that the session is still valid
-               HttpSession session = request.getSession(false);
-               if (session == null)
-                       return null;
-
-               // Gets application list for the session.
-               LinkedList applications = (LinkedList) session
-                               .getAttribute(SESSION_ATTR_APPS);
-               if (applications == null)
-                       return null;
-
-               // Search for the application (using the application URI) from the list
-               Application application = null;
-               for (Iterator i = applications.iterator(); i.hasNext()
-                               && application == null;) {
-                       Application a = (Application) i.next();
-                       String aPath = a.getURL().getPath();
-                       String servletPath = request.getContextPath()
-                                       + request.getServletPath();
-                       if (servletPath.length() < aPath.length())
-                               servletPath += "/";
-                       if (servletPath.equals(aPath))
-                               application = a;
-               }
-
-               // Removes stopped applications from the list
-               if (application != null && !application.isRunning()) {
-                       applications.remove(application);
-                       application = null;
-               }
-
-               return application;
-       }
-
-       /**
-        * Creates a new application.
-        * 
-        * @param request
-        *            the HTTP request.
-        * @return the New application instance.
-        * @throws MalformedURLException
-        *             if the application is denied access to the persistent data
-        *             store represented by the given URL.
-        * @throws InstantiationException
-        *             if a new instance of the class cannot be instantiated.
-        * @throws IllegalAccessException
-        *             if it does not have access to the property accessor method.
-        * @throws LicenseFileHasNotBeenRead
-        *             if the license file has not been read.
-        * @throws LicenseSignatureIsInvalid
-        *             if the license file has been changed or signature is
-        *             otherwise invalid.
-        * @throws InvalidLicenseFile
-        *             if the license file is not of correct XML format.
-        * @throws LicenseViolation
-        * 
-        * @throws SAXException
-        *             the Error parsing the license file.
-        */
-       private Application createApplication(HttpServletRequest request)
-                       throws MalformedURLException, InstantiationException,
-                       IllegalAccessException, LicenseFileHasNotBeenRead,
-                       LicenseSignatureIsInvalid, InvalidLicenseFile, LicenseViolation,
-                       SAXException {
-
-               Application application = null;
-
-               // Gets the application url
-               URL applicationUrl = getApplicationUrl(request);
-
-               // Gets application list.
-               HttpSession session = request.getSession();
-               if (session == null)
-                       return null;
-               LinkedList applications = (LinkedList) session
-                               .getAttribute(SESSION_ATTR_APPS);
-               if (applications == null) {
-                       applications = new LinkedList();
-                       session.setAttribute(SESSION_ATTR_APPS, applications);
-                       HttpSessionBindingListener sessionBindingListener = new SessionBindingListener(
-                                       applications);
-                       session.setAttribute(SESSION_BINDING_LISTENER,
-                                       sessionBindingListener);
-               }
-
-               // Creates new application and start it
-               try {
-                       application = (Application) this.applicationClass.newInstance();
-                       applications.add(application);
-
-                       // Listens to window add/removes (for web mode)
-                       application.addListener((Application.WindowAttachListener) this);
-                       application.addListener((Application.WindowDetachListener) this);
-
-                       // Sets locale
-                       application.setLocale(request.getLocale());
-
-                       // Gets application context for this session
-                       WebApplicationContext context = (WebApplicationContext) session
-                                       .getAttribute(SESSION_ATTR_CONTEXT);
-                       if (context == null) {
-                               context = new WebApplicationContext(session);
-                               session.setAttribute(SESSION_ATTR_CONTEXT, context);
-                       }
-
-                       // Starts application and check license
-                       initializeLicense(application);
-                       application.start(applicationUrl, this.applicationProperties,
-                                       context);
-                       checkLicense(application);
-
-               } catch (IllegalAccessException e) {
-                       Log.error("Illegal access to application class "
-                                       + this.applicationClass.getName());
-                       throw e;
-               } catch (InstantiationException e) {
-                       Log.error("Failed to instantiate application class: "
-                                       + this.applicationClass.getName());
-                       throw e;
-               }
-
-               return application;
-       }
-
-       /**
-        * 
-        * @param application
-        */
-       private void initializeLicense(Application application) {
-               License license;
-               synchronized (licenseForApplicationClass) {
-                       license = (License) licenseForApplicationClass.get(application
-                                       .getClass());
-                       if (license == null) {
-                               license = new License();
-                               licenseForApplicationClass.put(application.getClass(), license);
-                       }
-               }
-               application.setToolkitLicense(license);
-       }
-
-       /**
-        * 
-        * @param application
-        * @throws LicenseFileHasNotBeenRead
-        *             if the license file has not been read.
-        * @throws LicenseSignatureIsInvalid
-        *             if the license file has been changed or signature is
-        *             otherwise invalid.
-        * @throws InvalidLicenseFile
-        *             if the license file is not of correct XML format.
-        * @throws LicenseViolation
-        * 
-        * @throws SAXException
-        *             the Error parsing the license file.
-        */
-       private void checkLicense(Application application)
-                       throws LicenseFileHasNotBeenRead, LicenseSignatureIsInvalid,
-                       InvalidLicenseFile, LicenseViolation, SAXException {
-               License license = application.getToolkitLicense();
-
-               if (!license.hasBeenRead())
-                       // Lock threads that have not yet read license
-                       synchronized (license) {
-                               if (!license.hasBeenRead()) {
-                                       InputStream lis;
-                                       try {
-                                               URL url = getServletContext().getResource(
-                                                               "/WEB-INF/itmill-toolkit-license.xml");
-                                               if (url == null) {
-                                                       throw new RuntimeException(
-                                                                       "License file could not be read. "
-                                                                                       + "You can install it to "
-                                                                                       + "WEB-INF/itmill-toolkit-license.xml.");
-                                               }
-                                               lis = url.openStream();
-                                               license.readLicenseFile(lis);
-                                       } catch (MalformedURLException e) {
-                                               // This should not happen
-                                               throw new RuntimeException(e);
-                                       } catch (IOException e) {
-                                               // This should not happen
-                                               throw new RuntimeException(e);
-                                       }
-
-                                       // For each application class, print license description -
-                                       // once
-                                       if (!licensePrintedForApplicationClass
-                                                       .containsKey(applicationClass)) {
-                                               licensePrintedForApplicationClass.put(applicationClass,
-                                                               Boolean.TRUE);
-                                               if (license.shouldLimitsBePrintedOnInit()) {
-                                                       System.out.println(license
-                                                                       .getDescription(application.getClass()
-                                                                                       .toString()));
-                                               }
-                                       }
-
-                                       // Checks license validity
-                                       try {
-                                               license.check(applicationClass, VERSION_MAJOR,
-                                                               VERSION_MINOR, "IT Mill Toolkit", null);
-                                       } catch (LicenseFileHasNotBeenRead e) {
-                                               application.close();
-                                               throw e;
-                                       } catch (LicenseSignatureIsInvalid e) {
-                                               application.close();
-                                               throw e;
-                                       } catch (InvalidLicenseFile e) {
-                                               application.close();
-                                               throw e;
-                                       } catch (LicenseViolation e) {
-                                               application.close();
-                                               throw e;
-                                       }
-                               }
-                       }
-
-               // Checks concurrent user limit
-               try {
-                       license.checkConcurrentUsers(getNumberOfActiveUsers() + 1);
-               } catch (LicenseViolation e) {
-                       application.close();
-                       throw e;
-               }
-       }
-
-       /**
-        * Gets the number of active application-user pairs.
-        * 
-        * This returns total number of all applications in the server that are
-        * considered to be active. For an application to be active, it must have
-        * been accessed less than ACTIVE_USER_REQUEST_INTERVAL ms.
-        * 
-        * @return the Number of active application instances in the server.
-        */
-       private int getNumberOfActiveUsers() {
-               int active = 0;
-
-               synchronized (applicationToLastRequestDate) {
-                       Set apps = applicationToLastRequestDate.keySet();
-                       long now = System.currentTimeMillis();
-                       for (Iterator i = apps.iterator(); i.hasNext();) {
-                               Date lastReq = (Date) applicationToLastRequestDate
-                                               .get(i.next());
-                               if (now - lastReq.getTime() < ACTIVE_USER_REQUEST_INTERVAL)
-                                       active++;
-                       }
-               }
-
-               return active;
-       }
-
-       /**
-        * Ends the application.
-        * 
-        * @param request
-        *            the HTTP request.
-        * @param response
-        *            the HTTP response to write to.
-        * @param application
-        *            the application to end.
-        * @throws IOException
-        *             if the writing failed due to input/output error.
-        */
-       private void endApplication(HttpServletRequest request,
-                       HttpServletResponse response, Application application)
-                       throws IOException {
-
-               String logoutUrl = application.getLogoutURL();
-               if (logoutUrl == null)
-                       logoutUrl = application.getURL().toString();
-
-               HttpSession session = request.getSession();
-               if (session != null) {
-                       LinkedList applications = (LinkedList) session
-                                       .getAttribute(SESSION_ATTR_APPS);
-                       if (applications != null)
-                               applications.remove(application);
-               }
-
-               response.sendRedirect(response.encodeRedirectURL(logoutUrl));
-       }
-
-       /**
-        * Gets the existing application or create a new one. Get a window within an
-        * application based on the requested URI.
-        * 
-        * @param request
-        *            the HTTP Request.
-        * @param application
-        *            the Application to query for window.
-        * @return Window mathing the given URI or null if not found.
-        * @throws ServletException
-        *             if an exception has occurred that interferes with the
-        *             servlet's normal operation.
-        */
-       private Window getApplicationWindow(HttpServletRequest request,
-                       Application application, Map params) throws ServletException {
-
-               Window window = null;
-
-               // Finds the window where the request is handled
-               String path = request.getPathInfo();
-
-               // Main window as the URI is empty
-               if (path == null || path.length() == 0 || path.equals("/"))
-                       window = application.getMainWindow();
-
-               // Try to search by window name
-               else {
-                       String windowName = null;
-                       if (path.charAt(0) == '/')
-                               path = path.substring(1);
-                       int index = path.indexOf('/');
-                       if (index < 0) {
-                               windowName = path;
-                               path = "";
-                       } else {
-                               windowName = path.substring(0, index);
-                               path = path.substring(index + 1);
-                       }
-                       window = application.getWindow(windowName);
-
-                       if (window == null) {
-                               // By default, we use main window
-                               window = application.getMainWindow();
-                       } else if (!window.isVisible()) {
-                               // Implicitly painting without actually invoking paint()
-                               window.requestRepaintRequests();
-
-                               // If the window is invisible send a blank page
-                               return null;
-                       }
-               }
-               // Creates and open new debug window for application if requested
-               Window debugWindow = application.getWindow(DebugWindow.WINDOW_NAME);
-               if (debugWindow == null) {
-                       if (isDebugMode(params)
-                                       && WebBrowserProbe.getTerminalType(request.getSession())
-                                                       .getRenderingMode() != WebBrowser.RENDERING_MODE_AJAX) {
-                               try {
-                                       debugWindow = new DebugWindow(application, request
-                                                       .getSession(false), this);
-                                       debugWindow.setWidth(370);
-                                       debugWindow.setHeight(480);
-                                       application.addWindow(debugWindow);
-                               } catch (Exception e) {
-                                       throw new ServletException(
-                                                       "Failed to create debug window for application", e);
-                               }
-                       }
-               } else if (window != debugWindow) {
-                       if (isDebugMode(params))
-                               debugWindow.requestRepaint();
-                       else
-                               application.removeWindow(debugWindow);
-               }
-
-               return window;
-       }
-
-       /**
-        * Gets relative location of a theme resource.
-        * 
-        * @param theme
-        *            the Theme name.
-        * @param resource
-        *            the Theme resource.
-        * @return External URI specifying the resource
-        */
-       public String getResourceLocation(String theme, ThemeResource resource) {
-
-               if (resourcePath == null)
-                       return resource.getResourceId();
-               return resourcePath + theme + "/" + resource.getResourceId();
-       }
-
-       /**
-        * Checks if web adapter is in debug mode. Extra output is generated to log
-        * when debug mode is enabled.
-        * 
-        * @param parameters
-        * @return <code>true</code> if the web adapter is in debug mode.
-        *         otherwise <code>false</code>.
-        */
-       public boolean isDebugMode(Map parameters) {
-               if (parameters != null) {
-                       Object[] debug = (Object[]) parameters.get("debug");
-                       if (debug != null && !"false".equals(debug[0].toString())
-                                       && !"false".equals(debugMode))
-                               return true;
-               }
-               return "true".equals(debugMode);
-       }
-
-       /**
-        * Returns the theme source.
-        * 
-        * @return ThemeSource
-        */
-       public ThemeSource getThemeSource() {
-               return themeSource;
-       }
-
-       /**
-        * 
-        * @param application
-        * @param window
-        */
-       protected void addDirtyWindow(Application application, Window window) {
-               synchronized (applicationToDirtyWindowSetMap) {
-                       HashMap dirtyWindows = (HashMap) applicationToDirtyWindowSetMap
-                                       .get(application);
-                       if (dirtyWindows == null) {
-                               dirtyWindows = new HashMap();
-                               applicationToDirtyWindowSetMap.put(application, dirtyWindows);
-                       }
-                       dirtyWindows.put(window, Boolean.TRUE);
-               }
-       }
-
-       /**
-        * 
-        * @param application
-        * @param window
-        */
-       protected void removeDirtyWindow(Application application, Window window) {
-               synchronized (applicationToDirtyWindowSetMap) {
-                       HashMap dirtyWindows = (HashMap) applicationToDirtyWindowSetMap
-                                       .get(application);
-                       if (dirtyWindows != null)
-                               dirtyWindows.remove(window);
-               }
-       }
-
-       /**
-        * @see com.itmill.toolkit.Application.WindowAttachListener#windowAttached(Application.WindowAttachEvent)
-        */
-       public void windowAttached(WindowAttachEvent event) {
-               Window win = event.getWindow();
-               win.addListener((Paintable.RepaintRequestListener) this);
-
-               // Add window to dirty window references if it is visible
-               // Or request the window to pass on the repaint requests
-               if (win.isVisible())
-                       addDirtyWindow(event.getApplication(), win);
-               else
-                       win.requestRepaintRequests();
-
-       }
-
-       /**
-        * @see com.itmill.toolkit.Application.WindowDetachListener#windowDetached(Application.WindowDetachEvent)
-        */
-       public void windowDetached(WindowDetachEvent event) {
-               event.getWindow().removeListener(
-                               (Paintable.RepaintRequestListener) this);
-
-               // Adds dirty window reference for closing the window
-               addDirtyWindow(event.getApplication(), event.getWindow());
-       }
-
-       /**
-        * Receives repaint request events.
-        * 
-        * @see com.itmill.toolkit.terminal.Paintable.RepaintRequestListener#repaintRequested(Paintable.RepaintRequestEvent)
-        */
-       public void repaintRequested(RepaintRequestEvent event) {
-
-               Paintable p = event.getPaintable();
-               Application app = null;
-               if (p instanceof Window)
-                       app = ((Window) p).getApplication();
-
-               if (app != null)
-                       addDirtyWindow(app, ((Window) p));
-
-               Object lock = applicationToServerCommandStreamLock.get(app);
-               if (lock != null)
-                       synchronized (lock) {
-                               lock.notifyAll();
-                       }
-       }
-
-       /**
-        * Gets the list of dirty windows in application.
-        * 
-        * @param app
-        * @return
-        */
-       protected Map getDirtyWindows(Application app) {
-               HashMap dirtyWindows;
-               synchronized (applicationToDirtyWindowSetMap) {
-                       dirtyWindows = (HashMap) applicationToDirtyWindowSetMap.get(app);
-               }
-               return (Map) dirtyWindows;
-       }
-
-       /**
-        * Removes a window from the list of dirty windows.
-        * 
-        * @param app
-        * @param window
-        */
-       private void windowPainted(Application app, Window window) {
-               removeDirtyWindow(app, window);
-       }
-
-       /**
-        * Generates server commands stream. If the server commands are not
-        * requested, return false.
-        * 
-        * @param request
-        *            the HTTP request instance.
-        * @param response
-        *            the HTTP response to write to.
-        */
-       private boolean handleServerCommands(HttpServletRequest request,
-                       HttpServletResponse response) {
-
-               // Server commands are allways requested with certain parameter
-               if (request.getParameter(SERVER_COMMAND_PARAM) == null)
-                       return false;
-
-               // Gets the application
-               Application application;
-               try {
-                       application = getApplication(request);
-               } catch (MalformedURLException e) {
-                       return false;
-               }
-               if (application == null)
-                       return false;
-
-               // Creates continuous server commands stream
-               try {
-
-                       // Writer for writing the stream
-                       PrintWriter w = new PrintWriter(response.getOutputStream());
-
-                       // Prints necessary http page headers and padding
-                       w.println("<html><head></head><body>");
-                       for (int i = 0; i < SERVER_COMMAND_HEADER_PADDING; i++)
-                               w.print(' ');
-
-                       // Clock for synchronizing the stream
-                       Object lock = new Object();
-                       synchronized (applicationToServerCommandStreamLock) {
-                               Object oldlock = applicationToServerCommandStreamLock
-                                               .get(application);
-                               if (oldlock != null)
-                                       synchronized (oldlock) {
-                                               oldlock.notifyAll();
-                                       }
-                               applicationToServerCommandStreamLock.put(application, lock);
-                       }
-                       while (applicationToServerCommandStreamLock.get(application) == lock
-                                       && application.isRunning()) {
-                               synchronized (application) {
-
-                                       // Session expiration
-                                       Date lastRequest;
-                                       synchronized (applicationToLastRequestDate) {
-                                               lastRequest = (Date) applicationToLastRequestDate
-                                                               .get(application);
-                                       }
-                                       if (lastRequest != null
-                                                       && lastRequest.getTime()
-                                                                       + request.getSession()
-                                                                                       .getMaxInactiveInterval() * 1000 < System
-                                                                       .currentTimeMillis()) {
-
-                                               // Session expired, close application
-                                               application.close();
-                                       } else {
-
-                                               // Application still alive - keep updating windows
-                                               Map dws = getDirtyWindows(application);
-                                               if (dws != null && !dws.isEmpty()) {
-
-                                                       // For one of the dirty windows (in each
-                                                       // application)
-                                                       // request redraw
-                                                       Window win = (Window) dws.keySet().iterator()
-                                                                       .next();
-                                                       w
-                                                                       .println("<script>\n"
-                                                                                       + ThemeFunctionLibrary
-                                                                                                       .getWindowRefreshScript(
-                                                                                                                       application,
-                                                                                                                       win,
-                                                                                                                       WebBrowserProbe
-                                                                                                                                       .getTerminalType(request
-                                                                                                                                                       .getSession()))
-                                                                                       + "</script>");
-
-                                                       removeDirtyWindow(application, win);
-
-                                                       // Windows that are closed immediately are "painted"
-                                                       // now
-                                                       if (win.getApplication() == null
-                                                                       || !win.isVisible())
-                                                               win.requestRepaintRequests();
-                                               }
-                                       }
-                               }
-
-                               // Sends the generated commands and newline immediately to
-                               // browser
-                               // TODO why space in here? why not plain ln?
-                               w.println(" ");
-                               w.flush();
-                               response.flushBuffer();
-
-                               synchronized (lock) {
-                                       try {
-                                               lock.wait(SERVER_COMMAND_STREAM_MAINTAIN_PERIOD);
-                                       } catch (InterruptedException ignored) {
-                                       }
-                               }
-                       }
-               } catch (IOException ignore) {
-
-                       // In case of an Exceptions the server command stream is
-                       // terminated
-                       synchronized (applicationToServerCommandStreamLock) {
-                               if (applicationToServerCommandStreamLock.get(application) == application)
-                                       applicationToServerCommandStreamLock.remove(application);
-                       }
-               }
-
-               return true;
-       }
-
-       /**
-        * 
-        * SessionBindingListener performs Application cleanups after sessions are
-        * expired. For each session exists one SessionBindingListener. It contains
-        * references to all applications related to single session.
-        * 
-        * @author IT Mill Ltd.
-        * @version
-        * @VERSION@
-        * @since 4.0
-        */
-
-       private class SessionBindingListener implements HttpSessionBindingListener {
-               private LinkedList applications;
-
-               /**
-                * 
-                * @param applications
-                */
-               protected SessionBindingListener(LinkedList applications) {
-                       this.applications = applications;
-               }
-
-               /**
-                * @see javax.servlet.http.HttpSessionBindingListener#valueBound(HttpSessionBindingEvent)
-                */
-               public void valueBound(HttpSessionBindingEvent arg0) {
-                       // We are not interested in bindings
-               }
-
-               /**
-                * @see javax.servlet.http.HttpSessionBindingListener#valueUnbound(HttpSessionBindingEvent)
-                */
-               public void valueUnbound(HttpSessionBindingEvent event) {
-                       // If the binding listener is unbound from the session, the
-                       // session must be closing
-                       if (event.getName().equals(SESSION_BINDING_LISTENER)) {
-                               // Close all applications related to given session
-                               Object[] apps = applications.toArray();
-                               for (int i = 0; i < apps.length; i++) {
-                                       if (apps[i] != null) {
-                                               // Close application
-                                               ((Application) apps[i]).close();
-
-                                               // Stops application server commands stream
-                                               Object lock = applicationToServerCommandStreamLock
-                                                               .get(apps[i]);
-                                               if (lock != null)
-                                                       synchronized (lock) {
-                                                               lock.notifyAll();
-                                                       }
-
-                                               // Remove application from hashmaps
-                                               synchronized (applicationToServerCommandStreamLock) {
-                                                       applicationToServerCommandStreamLock
-                                                                       .remove(apps[i]);
-                                               }
-                                               synchronized (applicationToDirtyWindowSetMap) {
-                                                       applicationToDirtyWindowSetMap.remove(apps[i]);
-                                               }
-                                               synchronized (applicationToLastRequestDate) {
-                                                       applicationToLastRequestDate.remove(apps[i]);
-                                               }
-                                               synchronized (applicationToAjaxAppMgrMap) {
-                                                       applicationToAjaxAppMgrMap.remove(apps[i]);
-                                               }
-                                               // Remove application from applications list
-                                               applications.remove(apps[i]);
-                                       }
-                               }
-                       }
-               }
-       }
-
-       /**
-        * Implementation of ParameterHandler.ErrorEvent interface.
-        */
-       public class ParameterHandlerErrorImpl implements
-                       ParameterHandler.ErrorEvent {
-
-               private ParameterHandler owner;
-
-               private Throwable throwable;
-
-               /**
-                * 
-                * @param owner
-                * @param throwable
-                */
-               private ParameterHandlerErrorImpl(ParameterHandler owner,
-                               Throwable throwable) {
-                       this.owner = owner;
-                       this.throwable = throwable;
-               }
-
-               /**
-                * Gets the contained throwable.
-                * 
-                * @see com.itmill.toolkit.terminal.Terminal.ErrorEvent#getThrowable()
-                */
-               public Throwable getThrowable() {
-                       return this.throwable;
-               }
-
-               /**
-                * Gets the source ParameterHandler.
-                * 
-                * @see com.itmill.toolkit.terminal.ParameterHandler.ErrorEvent#getParameterHandler()
-                */
-               public ParameterHandler getParameterHandler() {
-                       return this.owner;
-               }
-
-       }
-
-       /**
-        * Implementation of URIHandler.ErrorEvent interface.
-        */
-       public class URIHandlerErrorImpl implements URIHandler.ErrorEvent {
-
-               private URIHandler owner;
-
-               private Throwable throwable;
-
-               /**
-                * 
-                * @param owner
-                * @param throwable
-                */
-               private URIHandlerErrorImpl(URIHandler owner, Throwable throwable) {
-                       this.owner = owner;
-                       this.throwable = throwable;
-               }
-
-               /**
-                * Gets the contained throwable.
-                * 
-                * @see com.itmill.toolkit.terminal.Terminal.ErrorEvent#getThrowable()
-                */
-               public Throwable getThrowable() {
-                       return this.throwable;
-               }
-
-               /**
-                * Gets the source URIHandler.
-                * 
-                * @see com.itmill.toolkit.terminal.URIHandler.ErrorEvent#getURIHandler()
-                */
-               public URIHandler getURIHandler() {
-                       return this.owner;
-               }
-       }
-
-       /**
-        * Gets AJAX application manager for an application.
-        * 
-        * If this application has not been running in ajax mode before, new manager
-        * is created and web adapter stops listening to changes.
-        * 
-        * @param application
-        * @return AJAX Application Manager
-        */
-       private AjaxApplicationManager getApplicationManager(Application application) {
-               AjaxApplicationManager mgr = (AjaxApplicationManager) applicationToAjaxAppMgrMap
-                               .get(application);
-
-               // This application is going from Web to AJAX mode, create new manager
-               if (mgr == null) {
-                       // Creates new manager
-                       mgr = new AjaxApplicationManager(application);
-                       applicationToAjaxAppMgrMap.put(application, mgr);
-
-                       // Stops sending changes to this servlet because manager will take
-                       // control
-                       application.removeListener((Application.WindowAttachListener) this);
-                       application.removeListener((Application.WindowDetachListener) this);
-
-                       // Deregister all window listeners
-                       for (Iterator wins = application.getWindows().iterator(); wins
-                                       .hasNext();)
-                               ((Window) wins.next())
-                                               .removeListener((Paintable.RepaintRequestListener) this);
-
-                       // Manager takes control over the application
-                       mgr.takeControl();
-               }
-
-               return mgr;
-       }
-
-       /**
-        * Gets resource path using different implementations. Required fo
-        * supporting different servlet container implementations (application
-        * servers).
-        * 
-        * @param servletContext
-        * @param path
-        *            the resource path.
-        * @return the resource path.
-        */
-       protected static String getResourcePath(ServletContext servletContext,
-                       String path) {
-               String resultPath = null;
-               resultPath = servletContext.getRealPath(path);
-               if (resultPath != null) {
-                       return resultPath;
-               } else {
-                       try {
-                               URL url = servletContext.getResource(path);
-                               resultPath = url.getFile();
-                       } catch (Exception e) {
-                               // ignored
-                       }
-               }
-               return resultPath;
-       }
-
-}
\ No newline at end of file
diff --git a/src/com/itmill/toolkit/terminal/web/CollectionThemeSource.java b/src/com/itmill/toolkit/terminal/web/CollectionThemeSource.java
deleted file mode 100644 (file)
index 047b787..0000000
+++ /dev/null
@@ -1,210 +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 java.io.InputStream;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * Theme source for consisting of collection of other theme sources. This class
- * is used to implement the retrieval of themes from multiple sources. Also this
- * class implements the inheritance of themes by first retrieving the relevant
- * parent theme information.
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
-public class CollectionThemeSource implements ThemeSource {
-
-       private List sources = new LinkedList();
-
-       /**
-        * Gets the name of the ThemeSource.
-        * 
-        * @see com.itmill.toolkit.terminal.web.ThemeSource#getName()
-        */
-       public String getName() {
-               return "THEMES";
-       }
-
-       /**
-        * Gets the XSL stream for the specified theme and web-browser type.
-        * 
-        * @see com.itmill.toolkit.terminal.web.ThemeSource#getXSLStreams(Theme,
-        *      WebBrowser)
-        */
-       public Collection getXSLStreams(Theme theme, WebBrowser type)
-                       throws ThemeException {
-               Collection xslFiles = new LinkedList();
-
-               // Adds parent theme XSL
-               xslFiles.addAll(this.getParentXSLStreams(theme, type));
-
-               // Adds theme XSL, Handle subdirectories: return the first match
-               for (Iterator i = this.sources.iterator(); i.hasNext();) {
-                       ThemeSource source = (ThemeSource) i.next();
-                       if (source.getThemes().contains(theme))
-                               xslFiles.addAll(source.getXSLStreams(theme, type));
-               }
-
-               return xslFiles;
-       }
-
-       /**
-        * 
-        * @param theme
-        * @param type
-        * @return
-        * @throws ThemeException
-        *             If the resource is not found or there was some problem
-        *             finding the resource.
-        */
-       private Collection getParentXSLStreams(Theme theme, WebBrowser type)
-                       throws ThemeException {
-               Collection xslFiles = new LinkedList();
-               String parentName = theme.getParent();
-               if (parentName != null) {
-                       Theme parent = this.getThemeByName(parentName);
-                       if (parent != null) {
-                               xslFiles.addAll(this.getXSLStreams(parent, type));
-                       } else {
-                               throw new ThemeSource.ThemeException(
-                                               "Parent theme not found for name: " + parentName);
-                       }
-               }
-               return xslFiles;
-       }
-
-       /**
-        * Gets the last modification time, used to reload theme on changes.
-        * 
-        * @see com.itmill.toolkit.terminal.web.ThemeSource#getModificationTime()
-        */
-       public long getModificationTime() {
-               long modTime = 0;
-               for (Iterator i = this.sources.iterator(); i.hasNext();) {
-                       long t = ((ThemeSource) i.next()).getModificationTime();
-                       if (t > modTime)
-                               modTime = t;
-               }
-               return modTime;
-       }
-
-       /**
-        * Gets the input stream for the resource with the specified resource id.
-        * 
-        * @see com.itmill.toolkit.terminal.web.ThemeSource#getResource(String)
-        */
-       public InputStream getResource(String resourceId) throws ThemeException {
-
-               // Resolves theme name and resource name
-               int delim = resourceId.indexOf("/");
-               String subResourceId = "";
-               String themeName = "";
-               if (delim >= 0 && delim < resourceId.length() - 1) {
-                       subResourceId = resourceId.substring(delim + 1);
-                       themeName = resourceId.substring(0, delim);
-               }
-
-               // Gets the list of themes to look for the resource
-               List themes = new LinkedList();
-               while (themeName != null && themeName.length() > 0) {
-                       Theme t = this.getThemeByName(themeName);
-                       if (t != null)
-                               themes.add(themeName);
-                       themeName = t.getParent();
-               }
-
-               // Iterate all themes in list
-               for (Iterator ti = themes.iterator(); ti.hasNext();) {
-                       String name = (String) ti.next();
-                       String resource = name + "/" + subResourceId;
-                       // Search all sources
-                       for (Iterator i = this.sources.iterator(); i.hasNext();) {
-                               try {
-                                       InputStream in = ((ThemeSource) i.next())
-                                                       .getResource(resource);
-                                       if (in != null)
-                                               return in;
-                               } catch (ThemeException e) {
-                                       // Ignore and continue to next source
-                               }
-                       }
-               }
-
-               throw new ThemeException("Theme resource not found:" + subResourceId
-                               + " in themes " + themes);
-       }
-
-       /**
-        * Gets the list of themes in the theme source.
-        * 
-        * @see com.itmill.toolkit.terminal.web.ThemeSource#getThemes()
-        */
-       public Collection getThemes() {
-               Collection themes = new LinkedList();
-               for (Iterator i = this.sources.iterator(); i.hasNext();) {
-                       Collection c = ((ThemeSource) i.next()).getThemes();
-                       themes.addAll(c);
-               }
-               return themes;
-       }
-
-       /**
-        * Gets the theme instance by name.
-        * 
-        * @param name
-        *            the theme name.
-        * @see com.itmill.toolkit.terminal.web.ThemeSource#getThemeByName(String)
-        */
-       public Theme getThemeByName(String name) {
-               for (Iterator i = this.sources.iterator(); i.hasNext();) {
-                       Theme t = ((ThemeSource) i.next()).getThemeByName(name);
-                       if (t != null)
-                               return t;
-               }
-               return null;
-       }
-
-       /**
-        * Adds new theme source to this collection.
-        * 
-        * @param source
-        *            the Theme source to be added.
-        */
-       public void add(ThemeSource source) {
-               this.sources.add(source);
-       }
-
-}
diff --git a/src/com/itmill/toolkit/terminal/web/DebugWindow.java b/src/com/itmill/toolkit/terminal/web/DebugWindow.java
deleted file mode 100644 (file)
index 42d9f11..0000000
+++ /dev/null
@@ -1,446 +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 java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-
-import javax.servlet.http.HttpSession;
-
-import com.itmill.toolkit.Application;
-import com.itmill.toolkit.data.util.BeanItem;
-import com.itmill.toolkit.data.util.MethodProperty;
-import com.itmill.toolkit.terminal.FileResource;
-import com.itmill.toolkit.ui.*;
-
-/**
- * This class provides a debugging window where one may view the UIDL of the
- * current window, or in a tabset the UIDL of an active frameset.
- * 
- * It is primarily intended for creating and debugging themes.
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
-public class DebugWindow extends Window {
-
-       protected static String WINDOW_NAME = "debug";
-
-       private Application debuggedApplication;
-
-       private HashMap rawUIDL = new HashMap();
-
-       private ApplicationServlet servlet;
-
-       private HttpSession session;
-
-       private TabSheet tabs = new TabSheet();
-
-       private Select themeSelector;
-
-       private Label applicationInfo = new Label("", Label.CONTENT_XHTML);
-
-       /**
-        * Creates a new debug window for an application.
-        * 
-        * @param debuggedApplication
-        *            the Application to be debugged.
-        * @param session
-        *            the Session to be debugged.
-        * @param servlet
-        *            the Servlet to be debugged.
-        */
-       protected DebugWindow(Application debuggedApplication, HttpSession session,
-                       ApplicationServlet servlet) {
-
-               super("Debug window");
-               setName(WINDOW_NAME);
-               setServlet(servlet);
-               setSession(session);
-               setBorder(Window.BORDER_NONE);
-
-               // Creates control buttons
-               OrderedLayout controls = new OrderedLayout(
-                               OrderedLayout.ORIENTATION_HORIZONTAL);
-               controls.addComponent(new Button("Restart Application", this,
-                               "restartApplication"));
-               controls
-                               .addComponent(new Button("Clear Session", this, "clearSession"));
-               Collection themes = servlet.getThemeSource().getThemes();
-               Collection names = new LinkedList();
-               for (Iterator i = themes.iterator(); i.hasNext();) {
-                       names.add(((Theme) i.next()).getName());
-               }
-
-               // Creates theme selector
-               themeSelector = new Select("Application Theme", names);
-               themeSelector.setWriteThrough(false);
-
-               // Terminal type editor
-               Label terminal = new Label("<h2>Terminal Information</h2> ",
-                               Label.CONTENT_XHTML);
-               Form browser = new Form();
-               browser.setItemDataSource(new BeanItem(WebBrowserProbe
-                               .getTerminalType(session)));
-               browser.removeItemProperty("class");
-               browser.replaceWithSelect("javaScriptVersion",
-                               WebBrowser.JAVASCRIPT_VERSIONS, WebBrowser.JAVASCRIPT_VERSIONS);
-               browser.replaceWithSelect("markupVersion", WebBrowser.MARKUP_VERSIONS,
-                               WebBrowser.MARKUP_VERSIONS);
-               browser.setWriteThrough(false);
-               Button setbrowser = new Button("Set terminal information", browser,
-                               "commit");
-               setbrowser.dependsOn(browser);
-
-               // Arrange the UI in tabsheet
-               TabSheet infoTabs = new TabSheet();
-               addComponent(infoTabs);
-
-               OrderedLayout appInfo = new OrderedLayout();
-               infoTabs.addTab(appInfo, "Application", null);
-               appInfo.addComponent(applicationInfo);
-               appInfo.addComponent(controls);
-               appInfo.addComponent(themeSelector);
-               appInfo.addComponent(new Button("Change theme", this, "commitTheme"));
-
-               OrderedLayout winInfo = new OrderedLayout();
-               infoTabs.addTab(winInfo, "Windows", null);
-               winInfo.addComponent(tabs);
-               winInfo.addComponent(new Button("Save UIDL", this, "saveUIDL"));
-
-               OrderedLayout termInfo = new OrderedLayout();
-               infoTabs.addTab(termInfo, "Terminal", null);
-               termInfo.addComponent(terminal);
-               termInfo.addComponent(browser);
-               termInfo.addComponent(setbrowser);
-
-               // Sets the debugged application
-               setDebuggedApplication(debuggedApplication);
-
-       }
-
-       /**
-        * 
-        * @param caption
-        * @param keys
-        * @param names
-        * @return
-        */
-       protected Select createSelect(String caption, Object[] keys, String[] names) {
-               Select s = new Select(caption);
-               s.addContainerProperty("name", String.class, "");
-               for (int i = 0; i < keys.length; i++) {
-                       s.addItem(keys[i]).getItemProperty("name").setValue(names[i]);
-               }
-               s.setItemCaptionPropertyId("name");
-               return s;
-       }
-
-       /**
-        * Saves the UIDL.
-        */
-       public void saveUIDL() {
-
-               synchronized (rawUIDL) {
-
-                       String currentUIDL = (String) rawUIDL.get(tabs.getSelectedTab());
-
-                       if (currentUIDL == null)
-                               return;
-
-                       DateFormat df = new SimpleDateFormat("yyyyMMdd-HHmmss");
-                       File file = new File("/uidl-debug"
-                                       + df.format(new Date(System.currentTimeMillis())) + ".xml");
-                       try {
-                               BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
-                                               new FileOutputStream(file)));
-                               out.write(currentUIDL);
-                               out.close();
-
-                               // Open the UIDL also
-                               open(new FileResource(file, this.getApplication()));
-                               Log.info("UIDL written to file " + file);
-                       } catch (FileNotFoundException e) {
-                               Log.info("Failed to write debug to " + file + ": " + e);
-                       } catch (IOException e) {
-                               Log.info("Failed to write debug to " + file + ": " + e);
-                       }
-               }
-       }
-
-       /**
-        * Commits the theme.
-        * 
-        */
-       public void commitTheme() {
-               themeSelector.commit();
-       }
-
-       /**
-        * Clears the session.
-        */
-       public void clearSession() {
-               session.invalidate();
-       }
-
-       /**
-        * Restarts the Application.
-        * 
-        */
-       public void restartApplication() {
-               if (debuggedApplication != null)
-                       debuggedApplication.close();
-       }
-
-       /**
-        * 
-        * @param window
-        * @param uidl
-        */
-       protected void setWindowUIDL(Window window, String uidl) {
-               String caption = "UIDL:" + window.getName();
-               synchronized (tabs) {
-                       for (Iterator i = tabs.getComponentIterator(); i.hasNext();) {
-                               Component c = (Component) i.next();
-                               if (tabs.getTabCaption(c).equals(caption)) {
-                                       ((Label) c).setValue(getHTMLFormattedUIDL(caption, uidl));
-                                       ((Label) c).setContentMode(Label.CONTENT_XHTML);
-                                       rawUIDL.put(c, uidl);
-                                       caption = null;
-                               }
-                       }
-
-                       // Add new tab
-                       if (caption != null) {
-                               Label l = new Label(getHTMLFormattedUIDL(caption, uidl));
-                               l.setContentMode(Label.CONTENT_XHTML);
-                               rawUIDL.put(l, uidl);
-                               tabs.addTab(l, caption, null);
-                       }
-               }
-       }
-
-       /**
-        * 
-        * @param caption
-        * @param uidl
-        * @return
-        */
-       protected String getHTMLFormattedUIDL(String caption, String uidl) {
-               StringBuffer sb = new StringBuffer();
-
-               // Print formatted UIDL with errors embedded
-               // Perl5Util util = new Perl5Util();
-
-               int row = 0;
-               int prev = 0;
-               int index = 0;
-               boolean lastLineWasEmpty = false;
-
-               sb
-                               .append("<TABLE WIDTH=\"100%\" STYLE=\"border-left: 1px solid black; "
-                                               + "border-right: 1px solid black; border-bottom: "
-                                               + "1px solid black; border-top: 1px solid black\""
-                                               + " cellpadding=\"0\" cellspacing=\"0\" BORDER=\"0\">");
-
-               if (caption != null)
-                       sb.append("<TR><TH BGCOLOR=\"#ddddff\" COLSPAN=\"2\">"
-                                       + "<FONT SIZE=\"+2\">" + caption + "</FONT></TH></TR>\n");
-
-               boolean unfinished = true;
-               while (unfinished) {
-                       row++;
-
-                       // Get individual line
-                       index = uidl.indexOf('\n', prev);
-                       String line;
-                       if (index < 0) {
-                               unfinished = false;
-                               line = uidl.substring(prev);
-                       } else {
-                               line = uidl.substring(prev, index);
-                               prev = index + 1;
-                       }
-
-                       // Escape the XML
-                       line = WebPaintTarget.escapeXML(line);
-
-                       // Code beautification : Comment lines
-                       line = replaceAll(line, "&lt;!--",
-                                       "<SPAN STYLE = \"color: #00dd00\">&lt;!--");
-                       line = replaceAll(line, "--&gt;", "--&gt;</SPAN>");
-
-                       while (line.length() > 0 && line.charAt(0) == ' ') {
-                               line = line.substring(1);
-                       }
-                       boolean isEmpty = (line.length() == 0 || line.equals("\r"));
-                       line = " " + line;
-
-                       if (!(isEmpty && lastLineWasEmpty))
-                               sb
-                                               .append("<TR"
-                                                               + ((row % 10) > 4 ? " BGCOLOR=\"#eeeeff\"" : "")
-                                                               + ">"
-                                                               + "<TD VALIGN=\"top\" ALIGN=\"rigth\" STYLE=\"border-right: 1px solid gray\"> "
-                                                               + String.valueOf(row) + " </TD><TD>" + line
-                                                               + "</TD></TR>\n");
-
-                       lastLineWasEmpty = isEmpty;
-
-               }
-
-               sb.append("</TABLE>\n");
-
-               return sb.toString();
-       }
-
-       /**
-        * Replaces the characters in a substring of this <code>String</code> with
-        * characters in the specified <code>String</code>. The substring begins
-        * at the specified <code>start</code> and extends to the character at
-        * index <code>end - 1</code> or to the end of the <code>String</code>
-        * if no such character exists.
-        * <p>
-        * First the characters in the substring are removed and then the specified
-        * <code>String</code> is inserted at <code>start</code>. (The
-        * <code>StringBuffer</code> will be lengthened to accommodate the
-        * specified String if necessary.)
-        * </p>
-        * <p>
-        * NOTE: This operation is slow.
-        * </p>
-        * 
-        * @param text
-        * @param start
-        *            the beginning index, inclusive.
-        * @param end
-        *            the ending index, exclusive.
-        * @param str
-        *            the String that will replace previous contents.
-        * @return This string buffer.
-        */
-       protected static String replace(String text, int start, int end, String str) {
-               return new StringBuffer(text).replace(start, end, str).toString();
-       }
-
-       /**
-        * 
-        * @param text
-        * @param oldStr
-        * @param newStr
-        * @return
-        */
-       protected static String replaceAll(String text, String oldStr, String newStr) {
-               StringBuffer sb = new StringBuffer(text);
-
-               int newStrLen = newStr.length();
-               int oldStrLen = oldStr.length();
-               if (oldStrLen <= 0)
-                       return text;
-
-               int i = 0;
-               while (i <= sb.length() - oldStrLen) {
-                       if (sb.substring(i, i + oldStrLen).equals(oldStr)) {
-                               sb.replace(i, i + oldStrLen, newStr);
-                               i += newStrLen;
-                       } else {
-                               i++;
-                       }
-               }
-               return sb.toString();
-       }
-
-       /**
-        * Sets the application.
-        * 
-        * @param application
-        *            the application to set.
-        */
-       protected void setDebuggedApplication(Application application) {
-               this.debuggedApplication = application;
-               if (application != null) {
-                       applicationInfo.setValue("<h2>Application Class</h2> "
-                                       + application.getClass().getName());
-                       themeSelector.setPropertyDataSource(new MethodProperty(application,
-                                       "theme"));
-               }
-       }
-
-       /**
-        * Returns the servlet.
-        * 
-        * @return the WebAdapterServlet.
-        */
-       protected ApplicationServlet getServlet() {
-               return servlet;
-       }
-
-       /**
-        * Returns the session.
-        * 
-        * @return the HttpSession.
-        */
-       protected HttpSession getSession() {
-               return session;
-       }
-
-       /**
-        * Sets the servlet.
-        * 
-        * @param servlet
-        *            the servlet to set.
-        */
-       protected void setServlet(ApplicationServlet servlet) {
-               this.servlet = servlet;
-       }
-
-       /**
-        * Sets the session.
-        * 
-        * @param session
-        *            the session to set.
-        */
-       protected void setSession(HttpSession session) {
-               this.session = session;
-       }
-
-}
diff --git a/src/com/itmill/toolkit/terminal/web/DirectoryThemeSource.java b/src/com/itmill/toolkit/terminal/web/DirectoryThemeSource.java
deleted file mode 100644 (file)
index 7130d4c..0000000
+++ /dev/null
@@ -1,312 +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 java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.LinkedList;
-
-/**
- * Theme source for reading themes from a directory on the Filesystem.
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
-public class DirectoryThemeSource implements ThemeSource {
-
-       private File path;
-
-       private Theme theme;
-
-       private ApplicationServlet webAdapterServlet;
-
-       /**
-        * Collection of subdirectory entries.
-        */
-       private Collection subdirs = new LinkedList();
-
-       /**
-        * Creates a new instance of ThemeRepository by reading the themes from a
-        * local directory.
-        * 
-        * @param path
-        *            the Path to the source directory .
-        * @param webAdapterServlet
-        * @throws ThemeException
-        *             If the resource is not found or there was some problem
-        *             finding the resource.
-        * @throws FileNotFoundException
-        *             if no theme files are found.
-        * @throws IOException
-        *             if the writing failed due to input/output error.
-        */
-       public DirectoryThemeSource(File path, ApplicationServlet webAdapterServlet)
-                       throws ThemeException, FileNotFoundException, IOException {
-
-               this.path = path;
-               this.theme = null;
-               this.webAdapterServlet = webAdapterServlet;
-
-               if (!this.path.isDirectory())
-                       throw new java.io.FileNotFoundException(
-                                       "Theme path must be a directory ('" + this.path + "')");
-
-               // Loads description file
-               File description = new File(path, Theme.DESCRIPTIONFILE);
-               if (description.exists()) {
-                       try {
-                               this.theme = new Theme(description);
-                       } catch (Exception e) {
-                               throw new ThemeException("ServletThemeSource: Failed to load '"
-                                               + path, e);
-                       }
-
-                       // Debug info
-                       if (webAdapterServlet.isDebugMode(null)) {
-                               Log.info("Added DirectoryThemeSource: " + this.path);
-                       }
-
-               } else {
-                       // There was no description file found.
-                       // Handle subdirectories recursively
-                       File[] files = this.path.listFiles();
-                       for (int i = 0; i < files.length; i++) {
-                               if (files[i].isDirectory()) {
-                                       this.subdirs.add(new DirectoryThemeSource(files[i],
-                                                       webAdapterServlet));
-                               } else if (files[i].getName().toLowerCase().endsWith(".jar")) {
-                                       this.subdirs.add(new JarThemeSource(files[i],
-                                                       webAdapterServlet, ""));
-                               }
-                       }
-
-                       if (this.subdirs.isEmpty()) {
-                               if (webAdapterServlet.isDebugMode(null)) {
-                                       Log
-                                                       .debug("DirectoryThemeSource: Ignoring empty directory: "
-                                                                       + path);
-                               }
-                       }
-               }
-       }
-
-       /**
-        * Gets the XSL stream for the specified theme and web-browser type.
-        * 
-        * @see com.itmill.toolkit.terminal.web.ThemeSource#getXSLStreams(Theme,
-        *      WebBrowser)
-        */
-       public Collection getXSLStreams(Theme theme, WebBrowser type)
-                       throws ThemeException {
-               Collection xslFiles = new LinkedList();
-
-               // If this directory contains a theme
-               // return XSL from this theme
-               if (this.theme != null) {
-
-                       if (webAdapterServlet.isDebugMode(null)) {
-                               Log.info("DirectoryThemeSource: Loading XSL from: " + theme);
-                       }
-
-                       // Reloads the description file
-                       File description = new File(path, Theme.DESCRIPTIONFILE);
-                       if (description.exists()) {
-                               try {
-                                       this.theme = new Theme(description);
-                               } catch (IOException e) {
-                                       throw new ThemeException(
-                                                       "Failed to reload theme description" + e);
-                               }
-                       }
-
-                       Collection fileNames = theme.getFileNames(type, Theme.MODE_HTML);
-
-                       // Adds all XSL file streams
-                       for (Iterator i = fileNames.iterator(); i.hasNext();) {
-                               File f = new File(this.path, (String) i.next());
-                               if (f.getName().endsWith(".xsl"))
-                                       try {
-                                               xslFiles.add(new XSLStream(f.getName(),
-                                                               new FileInputStream(f)));
-                                       } catch (FileNotFoundException e) {
-                                               throw new ThemeException("XSL File not found: " + f);
-                                       }
-                       }
-
-               } else {
-
-                       // Handles subdirectories: return the first match
-                       for (Iterator i = this.subdirs.iterator(); i.hasNext();) {
-                               ThemeSource source = (ThemeSource) i.next();
-                               if (source.getThemes().contains(theme))
-                                       xslFiles.addAll(source.getXSLStreams(theme, type));
-                       }
-               }
-
-               // Returns the concatenated stream
-               return xslFiles;
-
-       }
-
-       /**
-        * Gets the last modification time, used to reload theme on changes.
-        * 
-        * @see com.itmill.toolkit.terminal.web.ThemeSource#getModificationTime()
-        */
-       public long getModificationTime() {
-
-               long modTime = 0;
-
-               // If this directory contains a theme
-               // returns XSL from this theme
-               if (this.theme != null) {
-
-                       // Gets modification time of the description file
-                       modTime = new File(this.path, Theme.DESCRIPTIONFILE).lastModified();
-
-                       // Gets modification time of the themes directory itself
-                       if (this.path.lastModified() > modTime) {
-                               modTime = this.path.lastModified();
-                       }
-
-                       // Check modification time for all files
-                       Collection fileNames = theme.getFileNames();
-                       for (Iterator i = fileNames.iterator(); i.hasNext();) {
-                               File f = new File(this.path, (String) i.next());
-                               if (f.lastModified() > modTime) {
-                                       modTime = f.lastModified();
-                               }
-                       }
-               } else {
-                       // Handles subdirectories
-                       for (Iterator i = this.subdirs.iterator(); i.hasNext();) {
-                               ThemeSource source = (ThemeSource) i.next();
-                               long t = source.getModificationTime();
-                               if (t > modTime)
-                                       modTime = t;
-                       }
-               }
-
-               return modTime;
-
-       }
-
-       /**
-        * Gets the input stream for the resource with the specified resource id.
-        * 
-        * @see com.itmill.toolkit.terminal.web.ThemeSource#getResource(String)
-        */
-       public InputStream getResource(String resourceId)
-                       throws ThemeSource.ThemeException {
-
-               // If this directory contains a theme
-               // return resource from this theme
-               if (this.theme != null) {
-
-                       try {
-                               return new FileInputStream(new File(this.path, resourceId));
-                       } catch (FileNotFoundException e) {
-                               throw new ThemeSource.ThemeException("Resource " + resourceId
-                                               + " not found.");
-                       }
-
-               } else {
-                       int delim = resourceId.indexOf("/");
-                       String subResourceName = "";
-                       if (delim < resourceId.length() - 1)
-                               subResourceName = resourceId.substring(delim + 1);
-                       String subSourceName = resourceId.substring(0, delim);
-                       for (Iterator i = this.subdirs.iterator(); i.hasNext();) {
-                               ThemeSource source = (ThemeSource) i.next();
-                               if (source.getName().equals(subSourceName)) {
-                                       return source.getResource(subResourceName);
-                               }
-                       }
-               }
-
-               throw new ThemeSource.ThemeException("Resource " + resourceId
-                               + " not found.");
-
-       }
-
-       /**
-        * Gets the list of themes in the theme source.
-        * 
-        * @see com.itmill.toolkit.terminal.web.ThemeSource#getThemes()
-        */
-       public Collection getThemes() {
-               Collection themes = new LinkedList();
-               if (this.theme != null) {
-                       themes.add(this.theme);
-               } else {
-                       for (Iterator i = this.subdirs.iterator(); i.hasNext();) {
-                               ThemeSource source = (ThemeSource) i.next();
-                               themes.addAll(source.getThemes());
-                       }
-
-               }
-               return themes;
-       }
-
-       /**
-        * Gets the name of the ThemeSource.
-        * 
-        * @see com.itmill.toolkit.terminal.web.ThemeSource#getName()
-        */
-       public String getName() {
-               if (this.theme != null) {
-                       return this.theme.getName();
-               } else {
-                       return this.path.getName();
-               }
-       }
-
-       /**
-        * Gets the Theme instance by name.
-        * 
-        * @see com.itmill.toolkit.terminal.web.ThemeSource#getThemeByName(String)
-        */
-       public Theme getThemeByName(String name) {
-               Collection themes = this.getThemes();
-               for (Iterator i = themes.iterator(); i.hasNext();) {
-                       Theme t = (Theme) i.next();
-                       if (name != null && name.equals(t.getName()))
-                               return t;
-               }
-               return null;
-       }
-
-}
diff --git a/src/com/itmill/toolkit/terminal/web/HttpUploadStream.java b/src/com/itmill/toolkit/terminal/web/HttpUploadStream.java
deleted file mode 100644 (file)
index deaeaea..0000000
+++ /dev/null
@@ -1,114 +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 java.io.InputStream;
-
-/**
- * WebAdapter implementation of the UploadStream interface.
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
-public class HttpUploadStream implements
-               com.itmill.toolkit.terminal.UploadStream {
-
-       /**
-        * Holds value of property variableName.
-        */
-       private String streamName;
-
-       private String contentName;
-
-       private String contentType;
-
-       /**
-        * Holds value of property variableValue.
-        */
-       private InputStream stream;
-
-       /**
-        * Creates a new instance of UploadStreamImpl
-        * 
-        * @param name
-        *            the name of the stream.
-        * @param stream
-        *            the input stream.
-        * @param contentName
-        *            the name of the content.
-        * @param contentType
-        *            the type of the content.
-        */
-       public HttpUploadStream(String name, InputStream stream,
-                       String contentName, String contentType) {
-               this.streamName = name;
-               this.stream = stream;
-               this.contentName = contentName;
-               this.contentType = contentType;
-       }
-
-       /**
-        * Gets the name of the stream.
-        * 
-        * @return the name of the stream.
-        */
-       public String getStreamName() {
-               return this.streamName;
-       }
-
-       /**
-        * Gets the input stream.
-        * 
-        * @return the Input stream.
-        */
-       public InputStream getStream() {
-               return this.stream;
-       }
-
-       /**
-        * Gets the input stream content type.
-        * 
-        * @return the content type of the input stream.
-        */
-       public String getContentType() {
-               return this.contentType;
-       }
-
-       /**
-        * Gets the stream content name. Stream content name usually differs from
-        * the actual stream name. It is used to identify the content of the stream.
-        * 
-        * @return the Name of the stream content.
-        */
-       public String getContentName() {
-               return this.contentName;
-       }
-}
diff --git a/src/com/itmill/toolkit/terminal/web/HttpVariableMap.java b/src/com/itmill/toolkit/terminal/web/HttpVariableMap.java
deleted file mode 100644 (file)
index a22d1a3..0000000
+++ /dev/null
@@ -1,791 +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.terminal.SystemError;
-import com.itmill.toolkit.terminal.Terminal;
-import com.itmill.toolkit.terminal.UploadStream;
-import com.itmill.toolkit.terminal.VariableOwner;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.List;
-import java.util.StringTokenizer;
-import java.util.Enumeration;
-import java.util.WeakHashMap;
-import java.io.IOException;
-import java.lang.ref.WeakReference;
-
-import javax.servlet.http.HttpServletRequest;
-import java.util.LinkedList;
-import java.util.Iterator;
-
-/**
- * Class implementing the variable mappings.
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
-public class HttpVariableMap {
-
-       // Id <-> (Owner,Name) mapping
-       private Map idToNameMap = new HashMap();
-
-       private Map idToTypeMap = new HashMap();
-
-       private Map idToOwnerMap = new HashMap();
-
-       private Map idToValueMap = new HashMap();
-
-       private Map ownerToNameToIdMap = new WeakHashMap();
-
-       private Object mapLock = new Object();
-
-       // Id generator
-       private long lastId = 0;
-
-       /**
-        * Converts the string to a supported class.
-        * 
-        * @param type
-        * @param value
-        * @throws java.lang.ClassCastException
-        */
-       private static Object convert(Class type, String value)
-                       throws java.lang.ClassCastException {
-               try {
-
-                       // Boolean typed variables
-                       if (type.equals(Boolean.class))
-                               return new Boolean(!(value.equals("") || value.equals("false")));
-
-                       // Integer typed variables
-                       if (type.equals(Integer.class))
-                               return new Integer(value.trim());
-
-                       // String typed variables
-                       if (type.equals(String.class))
-                               return value;
-
-                       throw new ClassCastException("Unsupported type: " + type.getName());
-               } catch (NumberFormatException e) {
-                       return null;
-               }
-       }
-
-       /**
-        * Registers a new variable.
-        * 
-        * @param name
-        *            the name of the variable.
-        * @param type
-        * @param value
-        * @param owner
-        *            the Listener for variable changes.
-        * 
-        * @return id to assigned for this variable.
-        */
-       public String registerVariable(String name, Class type, Object value,
-                       VariableOwner owner) {
-
-               // Checks that the type of the class is supported
-               if (!(type.equals(Boolean.class) || type.equals(Integer.class)
-                               || type.equals(String.class) || type.equals(String[].class) || type
-                               .equals(UploadStream.class)))
-                       throw new SystemError("Unsupported variable type: "
-                                       + type.getClass());
-
-               synchronized (mapLock) {
-
-                       // Checks if the variable is already mapped
-                       HashMap nameToIdMap = (HashMap) ownerToNameToIdMap.get(owner);
-                       if (nameToIdMap == null) {
-                               nameToIdMap = new HashMap();
-                               ownerToNameToIdMap.put(owner, nameToIdMap);
-                       }
-                       String id = (String) nameToIdMap.get(name);
-
-                       if (id == null) {
-                               // Generates new id and register it
-                               id = "v" + String.valueOf(++lastId);
-                               nameToIdMap.put(name, id);
-                               idToOwnerMap.put(id, new WeakReference(owner));
-                               idToNameMap.put(id, name);
-                               idToTypeMap.put(id, type);
-                       }
-
-                       idToValueMap.put(id, value);
-
-                       return id;
-               }
-       }
-
-       /**
-        * Unregisters the variable.
-        * 
-        * @param name
-        *            the name of the variable.
-        * @param owner
-        *            the Listener for variable changes.
-        */
-       public void unregisterVariable(String name, VariableOwner owner) {
-
-               synchronized (mapLock) {
-
-                       // Gets the id
-                       HashMap nameToIdMap = (HashMap) ownerToNameToIdMap.get(owner);
-                       if (nameToIdMap == null)
-                               return;
-                       String id = (String) nameToIdMap.get(name);
-                       if (id != null)
-                               return;
-
-                       // Removes all the mappings
-                       nameToIdMap.remove(name);
-                       if (nameToIdMap.isEmpty())
-                               ownerToNameToIdMap.remove(owner);
-                       idToNameMap.remove(id);
-                       idToTypeMap.remove(id);
-                       idToValueMap.remove(id);
-                       idToOwnerMap.remove(id);
-
-               }
-       }
-
-       /**
-        * @author IT Mill Ltd.
-        * @version
-        * @VERSION@
-        * @since 3.0
-        */
-       private class ParameterContainer {
-
-               /**
-                * Constructs the mapping: listener to set of listened parameter names.
-                */
-               private HashMap parameters = new HashMap();
-
-               /**
-                * Parameter values.
-                */
-               private HashMap values = new HashMap();
-
-               /**
-                * Multipart parser used for parsing the request.
-                */
-               private ServletMultipartRequest parser = null;
-
-               /**
-                * Name - Value mapping of parameters that are not variables.
-                */
-               private HashMap nonVariables = new HashMap();
-
-               /**
-                * Creates a new parameter container and parse the parameters from the
-                * request using GET, POST and POST/MULTIPART parsing.
-                * 
-                * @param req
-                *            the HTTP request.
-                * @throws IOException
-                *             if the writing failed due to input/output error.
-                */
-               public ParameterContainer(HttpServletRequest req) throws IOException {
-                       // Parse GET / POST parameters
-                       for (Enumeration e = req.getParameterNames(); e.hasMoreElements();) {
-                               String paramName = (String) e.nextElement();
-                               String[] paramValues = req.getParameterValues(paramName);
-                               addParam(paramName, paramValues);
-                       }
-
-                       // Parse multipart variables
-                       try {
-                               parser = new ServletMultipartRequest(req,
-                                               MultipartRequest.MAX_READ_BYTES);
-                       } catch (IllegalArgumentException ignored) {
-                               parser = null;
-                       }
-
-                       if (parser != null) {
-                               for (Enumeration e = parser.getFileParameterNames(); e
-                                               .hasMoreElements();) {
-                                       String paramName = (String) e.nextElement();
-                                       addParam(paramName, null);
-                               }
-                               for (Enumeration e = parser.getParameterNames(); e
-                                               .hasMoreElements();) {
-                                       String paramName = (String) e.nextElement();
-                                       Enumeration val = parser.getURLParameters(paramName);
-
-                                       // Create a linked list from enumeration to calculate
-                                       // elements
-                                       LinkedList l = new LinkedList();
-                                       while (val.hasMoreElements())
-                                               l.addLast(val.nextElement());
-
-                                       // String array event constructor
-                                       String[] s = new String[l.size()];
-                                       Iterator i = l.iterator();
-                                       for (int j = 0; j < s.length; j++)
-                                               s[j] = (String) i.next();
-
-                                       addParam(paramName, s);
-                               }
-                       }
-
-               }
-
-               /**
-                * Adds the parameter to container.
-                * 
-                * @param name
-                *            the name of the parameter.
-                * @param value
-                */
-               private void addParam(String name, String[] value) {
-
-                       // Support name="set:name=value" value="ignored" notation
-                       if (name.startsWith("set:")) {
-                               int equalsIndex = name.indexOf('=');
-                               value[0] = name.substring(equalsIndex + 1, name.length());
-                               name = name.substring(4, equalsIndex);
-                               String[] curVal = (String[]) values.get(name);
-                               if (curVal != null) {
-                                       String[] newVal = new String[1 + curVal.length];
-                                       newVal[curVal.length] = value[0];
-                                       for (int i = 0; i < curVal.length; i++)
-                                               newVal[i] = curVal[i];
-                                       value = newVal;
-
-                                       // Special case - if the set:-method is used for
-                                       // declaring array of length 2, where either of the
-                                       // following conditions are true:
-                                       // - the both items are the same
-                                       // - the both items have the same length and
-                                       // - the items only differ on last character
-                                       // - second last character is '.'
-                                       // - last char of one string is 'x' and other is 'y'
-                                       // Browser is unporposely modifying the name.
-                                       if (value.length == 2
-                                                       && value[0].length() == value[1].length()) {
-                                               boolean same = true;
-                                               for (int i = 0; i < value[0].length() - 1 && same; i++)
-                                                       if (value[0].charAt(i) != value[1].charAt(i))
-                                                               same = false;
-                                               if (same
-                                                               && ((value[0].charAt(value[0].length() - 1) == 'x' && value[1]
-                                                                               .charAt(value[1].length() - 1) == 'y') || (value[0]
-                                                                               .charAt(value[0].length() - 1) == 'y' && value[1]
-                                                                               .charAt(value[1].length() - 1) == 'x'))) {
-                                                       value = new String[] { value[0].substring(0,
-                                                                       value[1].length() - 2) };
-                                               } else if (same && value[0].equals(value[1]))
-                                                       value = new String[] { value[0] };
-                                       }
-
-                                       // Special case - if the set:-method is used for
-                                       // declaring array of length 3, where all of the
-                                       // following conditions are true:
-                                       // - two last items have the same length
-                                       // - the first item is 2 chars shorter
-                                       // - the longer items only differ on last character
-                                       // - the shortest item is a prefix of the longer ones
-                                       // - second last character of longer ones is '.'
-                                       // - last char of one long string is 'x' and other is 'y'
-                                       // Browser is unporposely modifying the name. (Mozilla,
-                                       // Firefox, ..)
-                                       if (value.length == 3
-                                                       && value[1].length() == value[2].length()
-                                                       && value[0].length() + 2 == value[1].length()) {
-                                               boolean same = true;
-                                               for (int i = 0; i < value[1].length() - 1 && same; i++)
-                                                       if (value[2].charAt(i) != value[1].charAt(i))
-                                                               same = false;
-                                               for (int i = 0; i < value[0].length() && same; i++)
-                                                       if (value[0].charAt(i) != value[1].charAt(i))
-                                                               same = false;
-                                               if (same
-                                                               && (value[2].charAt(value[2].length() - 1) == 'x' && value[1]
-                                                                               .charAt(value[1].length() - 1) == 'y')
-                                                               || (value[2].charAt(value[2].length() - 1) == 'y' && value[1]
-                                                                               .charAt(value[1].length() - 1) == 'x')) {
-                                                       value = new String[] { value[0] };
-                                               }
-                                       }
-
-                               }
-                       }
-
-                       // Support for setting arrays in format
-                       // set-array:name=value1,value2,value3,...
-                       else if (name.startsWith("set-array:")) {
-                               int equalsIndex = name.indexOf('=');
-                               if (equalsIndex < 0)
-                                       return;
-
-                               StringTokenizer commalist = new StringTokenizer(name
-                                               .substring(equalsIndex + 1), ",");
-                               name = name.substring(10, equalsIndex);
-                               String[] curVal = (String[]) values.get(name);
-                               ArrayList elems = new ArrayList();
-
-                               // Adds old values if present.
-                               if (curVal != null) {
-                                       for (int i = 0; i < curVal.length; i++)
-                                               elems.add(curVal[i]);
-                               }
-                               while (commalist.hasMoreTokens()) {
-                                       String token = commalist.nextToken();
-                                       if (token != null && token.length() > 0)
-                                               elems.add(token);
-                               }
-                               value = new String[elems.size()];
-                               for (int i = 0; i < value.length; i++)
-                                       value[i] = (String) elems.get(i);
-
-                       }
-
-                       // Support name="array:name" value="val1,val2,val3" notation
-                       // All the empty elements are ignored
-                       else if (name.startsWith("array:")) {
-
-                               name = name.substring(6);
-                               StringTokenizer commalist = new StringTokenizer(value[0], ",");
-                               String[] curVal = (String[]) values.get(name);
-                               ArrayList elems = new ArrayList();
-
-                               // Adds old values if present.
-                               if (curVal != null) {
-                                       for (int i = 0; i < curVal.length; i++)
-                                               elems.add(curVal[i]);
-                               }
-                               while (commalist.hasMoreTokens()) {
-                                       String token = commalist.nextToken();
-                                       if (token != null && token.length() > 0)
-                                               elems.add(token);
-                               }
-                               value = new String[elems.size()];
-                               for (int i = 0; i < value.length; i++)
-                                       value[i] = (String) elems.get(i);
-                       }
-
-                       // Support declaring variables with name="declare:name"
-                       else if (name.startsWith("declare:")) {
-                               name = name.substring(8);
-                               value = (String[]) values.get(name);
-                               if (value == null)
-                                       value = new String[0];
-                       }
-
-                       // Gets the owner
-                       WeakReference ref = (WeakReference) idToOwnerMap.get(name);
-                       VariableOwner owner = null;
-                       if (ref != null)
-                               owner = (VariableOwner) ref.get();
-
-                       // Adds the parameter to mapping only if they have owners
-                       if (owner != null) {
-                               Set p = (Set) parameters.get(owner);
-                               if (p == null)
-                                       parameters.put(owner, p = new HashSet());
-                               p.add(name);
-                               if (value != null)
-                                       values.put(name, value);
-                       }
-
-                       // If the owner can not be found
-                       else {
-
-                               // If parameter has been mapped before, remove the old owner
-                               // mapping
-                               if (ref != null) {
-
-                                       // The owner has been destroyed, so we remove the mappings
-                                       idToNameMap.remove(name);
-                                       idToOwnerMap.remove(name);
-                                       idToTypeMap.remove(name);
-                                       idToValueMap.remove(name);
-                               }
-
-                               // Adds the parameter to set of non-variables
-                               nonVariables.put(name, value);
-                       }
-
-               }
-
-               /**
-                * Gets the set of all parameters connected to given variable owner.
-                * 
-                * @param owner
-                *            the Listener for variable changes.
-                * @return the set of all parameters connected to variable owner.
-                */
-               public Set getParameters(VariableOwner owner) {
-                       if (owner == null)
-                               return null;
-                       return (Set) parameters.get(owner);
-               }
-
-               /**
-                * Gets the set of all variable owners owning parameters in this
-                * request.
-                * 
-                * @return
-                */
-               public Set getOwners() {
-                       return parameters.keySet();
-               }
-
-               /**
-                * Gets the value of a parameter.
-                * 
-                * @param parameterName
-                *            the name of the parameter.
-                * @return the value of the parameter.
-                */
-               public String[] getValue(String parameterName) {
-                       return (String[]) values.get(parameterName);
-               }
-
-               /**
-                * Gets the servlet multipart parser.
-                * 
-                * @return the parser.
-                */
-               public ServletMultipartRequest getParser() {
-                       return parser;
-               }
-
-               /**
-                * Gets the name - value[] mapping of non variable paramteres.
-                * 
-                * @return
-                */
-               public Map getNonVariables() {
-                       return nonVariables;
-               }
-       }
-
-       /**
-        * Handles all variable changes in this request.
-        * 
-        * @param req
-        *            the Http request to handle.
-        * @param errorListener
-        *            If the list is non null, only the listed listeners are served.
-        *            Otherwise all the listeners are served.
-        * @return Name to Value[] mapping of unhandled variables.
-        * @throws IOException
-        *             if the writing failed due to input/output error.
-        */
-       public Map handleVariables(HttpServletRequest req,
-                       Terminal.ErrorListener errorListener) throws IOException {
-
-               // Gets the parameters
-               ParameterContainer parcon = new ParameterContainer(req);
-
-               // Sorts listeners to dependency order
-               List listeners = getDependencySortedListenerList(parcon.getOwners());
-
-               // Handles all parameters for all listeners
-               while (!listeners.isEmpty()) {
-                       VariableOwner listener = (VariableOwner) listeners.remove(0);
-                       boolean changed = false; // Has any of this owners variabes
-                                                                               // changed
-                       // Handle all parameters for listener
-                       Set params = parcon.getParameters(listener);
-                       if (params != null) { // Name value mapping
-                               Map variables = new HashMap();
-                               for (Iterator pi = params.iterator(); pi.hasNext();) {
-                                       // Gets the name of the parameter
-                                       String param = (String) pi.next();
-                                       // Extracts more information about the parameter
-                                       String varName = (String) idToNameMap.get(param);
-                                       Class varType = (Class) idToTypeMap.get(param);
-                                       Object varOldValue = idToValueMap.get(param);
-                                       if (varName == null || varType == null)
-                                               Log
-                                                               .warn("VariableMap: No variable found for parameter "
-                                                                               + param
-                                                                               + " ("
-                                                                               + varName
-                                                                               + ","
-                                                                               + listener + ")");
-                                       else {
-
-                                               ServletMultipartRequest parser = parcon.getParser();
-
-                                               // Upload events
-                                               if (varType.equals(UploadStream.class)) {
-                                                       if (parser != null
-                                                                       && parser.getFileParameter(param,
-                                                                                       MultipartRequest.FILENAME) != null) {
-                                                               String filename = (String) parser
-                                                                               .getFileParameter(param,
-                                                                                               MultipartRequest.FILENAME);
-                                                               String contentType = (String) parser
-                                                                               .getFileParameter(param,
-                                                                                               MultipartRequest.CONTENT_TYPE);
-                                                               UploadStream upload = new HttpUploadStream(
-                                                                               varName, parser.getFileContents(param),
-                                                                               filename, contentType);
-                                                               variables.put(varName, upload);
-                                                               changed = true;
-                                                       }
-                                               }
-
-                                               // Normal variable change events
-                                               else {
-                                                       // First try to parse the event without multipart
-                                                       String[] values = parcon.getValue(param);
-                                                       if (values != null) {
-
-                                                               if (varType.equals(String[].class)) {
-                                                                       variables.put(varName, values);
-                                                                       changed |= (!Arrays.equals(values,
-                                                                                       (String[]) varOldValue));
-                                                               } else {
-                                                                       try {
-                                                                               if (values.length == 1) {
-                                                                                       Object val = convert(varType,
-                                                                                                       values[0]);
-                                                                                       variables.put(varName, val);
-                                                                                       changed |= ((val == null && varOldValue != null) || (val != null && !val
-                                                                                                       .equals(varOldValue)));
-                                                                               } else if (values.length == 0
-                                                                                               && varType
-                                                                                                               .equals(Boolean.class)) {
-                                                                                       Object val = new Boolean(false);
-                                                                                       variables.put(varName, val);
-                                                                                       changed |= (!val
-                                                                                                       .equals(varOldValue));
-                                                                               } else {
-                                                                                       Log.warn("Empty variable '"
-                                                                                                       + varName + "' of type "
-                                                                                                       + varType.toString());
-                                                                               }
-
-                                                                       } catch (java.lang.ClassCastException e) {
-                                                                               Log
-                                                                                               .except(
-                                                                                                               "WebVariableMap conversion exception",
-                                                                                                               e);
-                                                                               errorListener
-                                                                                               .terminalError(new TerminalErrorImpl(
-                                                                                                               e));
-                                                                       }
-                                                               }
-                                                       }
-                                               }
-                                       }
-                               }
-
-                               // Do the valuechange if the listener is enabled
-                               if (listener.isEnabled() && changed) {
-                                       try {
-                                               listener.changeVariables(req, variables);
-                                       } catch (Throwable t) {
-                                               // Notify the error listener
-                                               errorListener.terminalError(new VariableOwnerErrorImpl(
-                                                               listener, t));
-                                       }
-                               }
-                       }
-               }
-
-               return parcon.getNonVariables();
-       }
-
-       /**
-        * Implementation of VariableOwner.Error interface.
-        */
-       public class TerminalErrorImpl implements Terminal.ErrorEvent {
-               private Throwable throwable;
-
-               /**
-                * 
-                * @param throwable
-                */
-               private TerminalErrorImpl(Throwable throwable) {
-                       this.throwable = throwable;
-               }
-
-               /**
-                * Gets the contained throwable.
-                * 
-                * @see com.itmill.toolkit.terminal.Terminal.ErrorEvent#getThrowable()
-                */
-               public Throwable getThrowable() {
-                       return this.throwable;
-               }
-
-       }
-
-       /**
-        * Implementation of VariableOwner.Error interface.
-        */
-       public class VariableOwnerErrorImpl extends TerminalErrorImpl implements
-                       VariableOwner.ErrorEvent {
-
-               private VariableOwner owner;
-
-               /**
-                * 
-                * @param owner
-                *            the Listener for variable changes.
-                * @param throwable
-                */
-               private VariableOwnerErrorImpl(VariableOwner owner, Throwable throwable) {
-                       super(throwable);
-                       this.owner = owner;
-               }
-
-               /**
-                * Gets the source VariableOwner.
-                * 
-                * @see com.itmill.toolkit.terminal.VariableOwner.ErrorEvent#getVariableOwner()
-                */
-               public VariableOwner getVariableOwner() {
-                       return this.owner;
-               }
-
-       }
-
-       /**
-        * Resolves the VariableOwners needed from the request and sort them to
-        * assure that the dependencies are met (as well as possible).
-        * 
-        * @param listeners
-        * @return List of variable list changers, that are needed for handling all
-        *         the variables in the request
-        */
-       private List getDependencySortedListenerList(Set listeners) {
-
-               LinkedList resultNormal = new LinkedList();
-               LinkedList resultImmediate = new LinkedList();
-
-               // Go trough the listeners and either add them to result or resolve
-               // their dependencies
-               HashMap deepdeps = new HashMap();
-               LinkedList unresolved = new LinkedList();
-               for (Iterator li = listeners.iterator(); li.hasNext();) {
-
-                       VariableOwner listener = (VariableOwner) li.next();
-                       if (listener != null) {
-                               Set dependencies = listener.getDirectDependencies();
-
-                               // The listeners with no dependencies are added to the front of
-                               // the
-                               // list directly
-                               if (dependencies == null || dependencies.isEmpty()) {
-                                       if (listener.isImmediate())
-                                               resultImmediate.addFirst(listener);
-                                       else
-                                               resultNormal.addFirst(listener);
-                               }
-
-                               // Resolve deep dependencies for the listeners with dependencies
-                               // (the listeners will be added to the end of results in correct
-                               // dependency order later). Also the dependencies of all the
-                               // depended listeners are resolved.
-                               else if (deepdeps.get(listener) == null) {
-
-                                       // Set the fifo for unresolved parents to contain only the
-                                       // listener to be resolved
-                                       unresolved.clear();
-                                       unresolved.add(listener);
-
-                                       // Resolve dependencies
-                                       HashSet tmpdeepdeps = new HashSet();
-                                       while (!unresolved.isEmpty()) {
-
-                                               VariableOwner l = (VariableOwner) unresolved
-                                                               .removeFirst();
-                                               if (!tmpdeepdeps.contains(l)) {
-                                                       tmpdeepdeps.add(l);
-                                                       if (deepdeps.containsKey(l)) {
-                                                               tmpdeepdeps.addAll((Set) deepdeps.get(l));
-                                                       } else {
-                                                               Set deps = l.getDirectDependencies();
-                                                               if (deps != null && !deps.isEmpty())
-                                                                       for (Iterator di = deps.iterator(); di
-                                                                                       .hasNext();) {
-                                                                               Object d = di.next();
-                                                                               if (d != null
-                                                                                               && !tmpdeepdeps.contains(d))
-                                                                                       unresolved.addLast(d);
-                                                                       }
-                                                       }
-                                               }
-                                       }
-
-                                       tmpdeepdeps.remove(listener);
-                                       deepdeps.put(listener, tmpdeepdeps);
-                               }
-                       }
-               }
-
-               // Adds the listeners with dependencies in sane order to the result
-               for (Iterator li = deepdeps.keySet().iterator(); li.hasNext();) {
-                       VariableOwner l = (VariableOwner) li.next();
-                       boolean immediate = l.isImmediate();
-
-                       // Adds each listener after the last depended listener already in
-                       // the list
-                       int index = -1;
-                       for (Iterator di = ((Set) deepdeps.get(l)).iterator(); di.hasNext();) {
-                               int k;
-                               Object depended = di.next();
-                               if (immediate) {
-                                       k = resultImmediate.lastIndexOf(depended);
-                               } else {
-                                       k = resultNormal.lastIndexOf(depended);
-                               }
-                               if (k > index)
-                                       index = k;
-                       }
-                       if (immediate) {
-                               resultImmediate.add(index + 1, l);
-                       } else {
-                               resultNormal.add(index + 1, l);
-                       }
-               }
-
-               // Appends immediate listeners to normal listeners
-               // This way the normal handlers are always called before
-               // immediate ones
-               resultNormal.addAll(resultImmediate);
-               return resultNormal;
-       }
-}
diff --git a/src/com/itmill/toolkit/terminal/web/JarThemeSource.java b/src/com/itmill/toolkit/terminal/web/JarThemeSource.java
deleted file mode 100644 (file)
index 2761f79..0000000
+++ /dev/null
@@ -1,406 +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 java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.ref.SoftReference;
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Map;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-
-/**
- * Theme source for reading themes from a JAR archive. At this time only jar
- * files are supported and an archive may not contain any recursive archives.
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
-public class JarThemeSource implements ThemeSource {
-
-       private File file;
-
-       private JarFile jar;
-
-       private Theme theme;
-
-       private String path;
-
-       private String name;
-
-       private ApplicationServlet webAdapterServlet;
-
-       private Cache resourceCache = new Cache();
-
-       /**
-        * Collection of subdirectory entries.
-        */
-       private Collection subdirs = new LinkedList();
-
-       /**
-        * Creates a new instance of ThemeRepository by reading the themes from a
-        * local directory.
-        * 
-        * @param file
-        *            the Path to the JAR archive .
-        * @param webAdapterServlet
-        * @param path
-        *            the Path inside the archive to be processed.
-        * @throws ThemeException
-        *             If the resource is not found or there was some problem
-        *             finding the resource.
-        * 
-        * @throws FileNotFoundException
-        *             if no theme files are found.
-        * @throws IOException
-        *             if the writing failed due to input/output error.
-        */
-       public JarThemeSource(File file, ApplicationServlet webAdapterServlet,
-                       String path) throws ThemeException, FileNotFoundException,
-                       IOException {
-
-               this.file = file;
-               this.jar = new JarFile(file);
-               this.theme = null;
-               this.path = path;
-               if (this.path.length() > 0 && !this.path.endsWith("/")) {
-                       this.path = this.path + "/";
-               }
-               this.name = file.getName();
-               if (this.name.toLowerCase().endsWith(".jar")) {
-                       this.name = this.name.substring(0, this.name.length() - 4);
-               }
-
-               this.webAdapterServlet = webAdapterServlet;
-
-               // Loads description file
-               JarEntry entry = jar.getJarEntry(this.path + Theme.DESCRIPTIONFILE);
-               if (entry != null) {
-                       try {
-                               this.theme = new Theme(jar.getInputStream(entry));
-                       } catch (Exception e) {
-                               throw new ThemeException("JarThemeSource: Failed to load '"
-                                               + path + "': ", e);
-                       }
-
-                       // Debug info
-                       if (webAdapterServlet.isDebugMode(null)) {
-                               Log.debug("Added JarThemeSource: " + this.file + ":"
-                                               + this.path);
-                       }
-
-               } else {
-                       // There was no description file found.
-                       // Handle subdirectories recursively
-                       for (Enumeration entries = jar.entries(); entries.hasMoreElements();) {
-                               JarEntry e = (JarEntry) entries.nextElement();
-                               if (e.getName().startsWith(this.path)) {
-                                       if (e.getName().endsWith("/")
-                                                       && e.getName().indexOf('/', this.path.length()) == (e
-                                                                       .getName().length() - 1)) {
-                                               this.subdirs.add(new JarThemeSource(this.file,
-                                                               this.webAdapterServlet, e.getName()));
-                                       }
-                               }
-                       }
-
-                       if (this.subdirs.isEmpty()) {
-                               if (webAdapterServlet.isDebugMode(null)) {
-                                       Log.info("JarThemeSource: Ignoring empty JAR path: "
-                                                       + this.file + " path: " + this.path);
-                               }
-                       }
-               }
-       }
-
-       /**
-        * Gets the XSL stream for the specified theme and web-browser type.
-        * 
-        * @see com.itmill.toolkit.terminal.web.ThemeSource#getXSLStreams(Theme,
-        *      WebBrowser)
-        */
-       public Collection getXSLStreams(Theme theme, WebBrowser type)
-                       throws ThemeException {
-               Collection xslFiles = new LinkedList();
-               // If this directory contains a theme
-               // return XSL from this theme
-               if (this.theme != null) {
-
-                       if (webAdapterServlet.isDebugMode(null)) {
-                               Log.info("JarThemeSource: Loading XSL from: " + theme);
-                       }
-
-                       // Reload the theme if JAR has been modified
-                       JarEntry entry = jar.getJarEntry(this.path + Theme.DESCRIPTIONFILE);
-                       if (entry != null) {
-                               try {
-                                       this.theme = new Theme(jar.getInputStream(entry));
-                               } catch (IOException e) {
-                                       throw new ThemeException("Failed to read description: "
-                                                       + this.file + ":" + this.path
-                                                       + Theme.DESCRIPTIONFILE);
-                               }
-                       }
-
-                       Collection fileNames = theme.getFileNames(type, Theme.MODE_HTML);
-                       // Add all XSL file streams
-                       for (Iterator i = fileNames.iterator(); i.hasNext();) {
-                               entry = jar.getJarEntry(this.path + (String) i.next());
-                               if (entry.getName().endsWith(".xsl"))
-                                       try {
-                                               xslFiles.add(new XSLStream(entry.getName(), jar
-                                                               .getInputStream(entry)));
-                                       } catch (java.io.FileNotFoundException e) {
-                                               throw new ThemeException("XSL File not found: "
-                                                               + this.file + ": " + entry);
-                                       } catch (java.io.IOException e) {
-                                               throw new ThemeException("Failed to read XSL file. "
-                                                               + this.file + ": " + entry);
-                                       }
-                       }
-
-               } else {
-
-                       // Handle subdirectories in archive: return the first match
-                       for (Iterator i = this.subdirs.iterator(); i.hasNext();) {
-                               ThemeSource source = (ThemeSource) i.next();
-                               if (source.getThemes().contains(theme))
-                                       xslFiles.addAll(source.getXSLStreams(theme, type));
-                       }
-               }
-
-               return xslFiles;
-       }
-
-       /**
-        * Returns modication time of the jar file.
-        * 
-        * @see com.itmill.toolkit.terminal.web.ThemeSource#getModificationTime()
-        */
-       public long getModificationTime() {
-               return this.file.lastModified();
-       }
-
-       /**
-        * Gets the input stream for the resource with the specified resource id.
-        * 
-        * @see com.itmill.toolkit.terminal.web.ThemeSource#getResource(String)
-        */
-       public InputStream getResource(String resourceId)
-                       throws ThemeSource.ThemeException {
-
-               // Strip off the theme name prefix from resource id
-               if (this.theme != null && this.theme.getName() != null
-                               && resourceId.startsWith(this.theme.getName() + "/")) {
-                       resourceId = resourceId
-                                       .substring(this.theme.getName().length() + 1);
-               }
-
-               // Returns the resource inside the jar file
-               JarEntry entry = jar.getJarEntry(resourceId);
-               if (entry != null)
-                       try {
-
-                               // Try cache
-                               byte[] data = (byte[]) resourceCache.get(entry);
-                               if (data != null)
-                                       return new ByteArrayInputStream(data);
-
-                               // Reads data
-                               int bufSize = 1024;
-                               ByteArrayOutputStream out = new ByteArrayOutputStream(bufSize);
-                               InputStream in = jar.getInputStream(entry);
-                               byte[] buf = new byte[bufSize];
-                               int n = 0;
-                               while ((n = in.read(buf)) >= 0) {
-                                       out.write(buf, 0, n);
-                               }
-                               in.close();
-                               data = out.toByteArray();
-
-                               // Cache data
-                               resourceCache.put(entry, data);
-                               return new ByteArrayInputStream(data);
-                       } catch (IOException e) {
-                       }
-
-               throw new ThemeSource.ThemeException("Resource " + resourceId
-                               + " not found.");
-       }
-
-       /**
-        * Gets the list of themes in the theme source.
-        * 
-        * @see com.itmill.toolkit.terminal.web.ThemeSource#getThemes()
-        */
-       public Collection getThemes() {
-               Collection themes = new LinkedList();
-               if (this.theme != null) {
-                       themes.add(this.theme);
-               } else {
-                       for (Iterator i = this.subdirs.iterator(); i.hasNext();) {
-                               ThemeSource source = (ThemeSource) i.next();
-                               themes.addAll(source.getThemes());
-                       }
-               }
-               return themes;
-       }
-
-       /**
-        * Gets the name of the ThemeSource.
-        * 
-        * @see com.itmill.toolkit.terminal.web.ThemeSource#getName()
-        */
-       public String getName() {
-               if (this.theme != null) {
-                       return this.theme.getName();
-               } else {
-                       return this.name;
-               }
-       }
-
-       /**
-        * Gets the Theme instance by name.
-        * 
-        * @see com.itmill.toolkit.terminal.web.ThemeSource#getThemeByName(String)
-        */
-       public Theme getThemeByName(String name) {
-               Collection themes = this.getThemes();
-               for (Iterator i = themes.iterator(); i.hasNext();) {
-                       Theme t = (Theme) i.next();
-                       if (name != null && name.equals(t.getName()))
-                               return t;
-               }
-               return null;
-       }
-
-       /**
-        * @author IT Mill Ltd.
-        * @version
-        * @VERSION@
-        * @since 3.0
-        */
-       private class Cache {
-
-               private Map data = new HashMap();
-
-               /**
-                * Associates the specified value with the specified key in this map. If
-                * the map previously contained a mapping for this key, the old value is
-                * replaced by the specified value.
-                * 
-                * @param key
-                *            the key with which the specified value is to be
-                *            associated.
-                * @param value
-                *            the value to be associated with the specified key.
-                */
-               public void put(Object key, Object value) {
-                       data.put(key, new SoftReference(new CacheItem(value)));
-               }
-
-               /**
-                * Returns the value to which this map maps the specified key. Returns
-                * null if the map contains no mapping for this key.
-                * <p>
-                * A return value of null does not necessarily indicate that the map
-                * contains no mapping for the key; it's also possible that the map
-                * explicitly maps the key to null. The containsKey operation may be
-                * used to distinguish these two cases.
-                * </p>
-                * 
-                * @param key
-                *            the key whose associated value is to be returned.
-                * @return the value to which this map maps the specified key, or null
-                *         if the map contains no mapping for this key.
-                */
-               public Object get(Object key) {
-                       SoftReference ref = (SoftReference) data.get(key);
-                       if (ref != null)
-                               return ((CacheItem) ref.get()).getData();
-                       return null;
-               }
-
-               /**
-                * Clears the data.
-                * 
-                */
-               public void clear() {
-                       data.clear();
-               }
-       }
-
-       /**
-        * @author IT Mill Ltd.
-        * @version
-        * @VERSION@
-        * @since 3.0
-        */
-       private class CacheItem {
-
-               private Object data;
-
-               /**
-                * 
-                * @param data
-                */
-               public CacheItem(Object data) {
-                       this.data = data;
-               }
-
-               /**
-                * 
-                * @return
-                */
-               public Object getData() {
-                       return this.data;
-               };
-
-               /**
-                * @see java.lang.Object#finalize()
-                */
-               public void finalize() throws Throwable {
-                       this.data = null;
-                       super.finalize();
-               }
-
-       }
-
-}
diff --git a/src/com/itmill/toolkit/terminal/web/Log.java b/src/com/itmill/toolkit/terminal/web/Log.java
deleted file mode 100644 (file)
index ddc6ec2..0000000
+++ /dev/null
@@ -1,133 +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;
-
-/**
- * <p>
- * Class providing centralized logging services. The logger defines five message
- * types, and provides methods to create messages of those types. These types
- * are:
- * </p>
- * 
- * <ul>
- * <li> <code>info</code> - Useful information generated during normal
- * operation of the application.
- * <li> <code>warning</code> - An error situation has occurred, but the
- * operation was able to finish succesfully.
- * <li> <code>error</code> - An error situation which prevented the operation
- * from finishing succesfully.
- * <li> <code>debug</code> - Internal information from the application meant
- * for developers.
- * <li> <code>exception</code> - A Java exception reported using the logger.
- * Includes the exception stack trace and a possible free-form message.
- * </ul>
- * 
- * <p>
- * Currently the class offers logging only to the standard output.
- * </p>
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
-public class Log {
-
-       private static boolean useStdOut = true;
-
-       private static String LOG_MSG_INFO = "[INFO]";
-
-       private static String LOG_MSG_ERROR = "[ERROR]";
-
-       private static String LOG_MSG_WARN = "[WARNING]";
-
-       private static String LOG_MSG_DEBUG = "[DEBUG]";
-
-       private static String LOG_MSG_EXCEPT = "[EXCEPTION]";
-
-       /**
-        * Logs the <code>warning</code> message.
-        * 
-        * @param message
-        *            the Message String to be logged.
-        */
-       protected static synchronized void warn(java.lang.String message) {
-               if (Log.useStdOut)
-                       System.out.println(LOG_MSG_WARN + " " + message);
-       }
-
-       /**
-        * Logs the <code>debug</code> message.
-        * 
-        * @param message
-        *            the Message String to be logged.
-        */
-       protected static synchronized void debug(java.lang.String message) {
-               if (Log.useStdOut)
-                       System.out.println(LOG_MSG_DEBUG + " " + message);
-       }
-
-       /**
-        * Logs an <code>info</code> message.
-        * 
-        * @param message
-        *            the Message String to be logged.
-        */
-       protected static synchronized void info(java.lang.String message) {
-               if (Log.useStdOut)
-                       System.out.println(LOG_MSG_INFO + " " + message);
-       }
-
-       /**
-        * Logs the Java exception and an accompanying error message.
-        * 
-        * @param message
-        *            the Message String to be logged.
-        * @param e
-        *            the Exception to be logged.
-        */
-       protected static synchronized void except(java.lang.String message,
-                       Exception e) {
-               if (Log.useStdOut) {
-                       System.out.println(LOG_MSG_EXCEPT + " " + message);
-                       e.printStackTrace();
-               }
-       }
-
-       /**
-        * Logs the <code>error</code> message.
-        * 
-        * @param message
-        *            the Message String to be logged.
-        */
-       protected static synchronized void error(java.lang.String message) {
-               if (Log.useStdOut)
-                       System.out.println(LOG_MSG_ERROR + " " + message);
-       }
-}
diff --git a/src/com/itmill/toolkit/terminal/web/MultipartRequest.java b/src/com/itmill/toolkit/terminal/web/MultipartRequest.java
deleted file mode 100644 (file)
index 3b2620c..0000000
+++ /dev/null
@@ -1,1332 +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 java.util.Hashtable;
-import java.io.BufferedOutputStream;
-import java.io.BufferedInputStream;
-import java.io.OutputStream;
-import java.io.InputStream;
-import java.io.PrintWriter;
-import java.io.ByteArrayOutputStream;
-import java.io.ByteArrayInputStream;
-import java.io.FileOutputStream;
-import java.io.UnsupportedEncodingException;
-import java.io.IOException;
-import java.util.Enumeration;
-import java.util.Vector;
-import java.io.File;
-
-/**
- * A Multipart form data parser. Parses an input stream and writes out any files
- * found, making available a hashtable of other url parameters. As of version
- * 1.17 the files can be saved to memory, and optionally written to a database,
- * etc.
- * 
- * <BR>
- * <BR>
- * Copyright (C)2001 Jason Pell. <BR>
- * 
- * <PRE>
- * 
- * This library is free software; you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License as published by the Free
- * Software Foundation; either version 2.1 of the License, or (at your option)
- * any later version. <BR>
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
- * details. <BR>
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA <BR>
- * Email: jasonpell@hotmail.com Url: http://www.geocities.com/jasonpell
- * 
- * </PRE>
- * 
- * @author Jason Pell
- * 
- * @version 1.18 Fixed some serious bugs. A new method readAndWrite(InputStream
- *          in, OutputStream out) which now does the generic processing in
- *          common for readAndWriteFile and readFile. The differences are that
- *          now the two extra bytes at the end of a file upload are processed
- *          once, instead of after each line. Also if an empty file is
- *          encountered, an outputstream is opened, but then deleted if no data
- *          written to it. The <code>getCharArray</code> method has been
- *          removed. Replaced by the new String(bytes, encoding) method using a
- *          specific encoding (Defaults to ISO-8859-1) to ensure that extended
- *          characters are supported. All strings are processed using this
- *          encoding. The addition of static methods setEncoding(String) and
- *          <code>getEncoding</code> method to allow the use of
- *          <code>MultipartRequest</code> with a specific encoding type. All
- *          instances of MultipartRequest will utilise the static charEncoding
- *          variable value, that the <code>setEncoding</code> method can be
- *          used to set. Started to introduce support for multiple file uploads
- *          with the same form field name, but not completed for v1.18.
- *          26/06/2001
- * 
- * @version 1.17 A few _very_ minor fixes. Plus a cool new feature added. The
- *          ability to save files into memory. <b>Thanks to Mark Latham for the
- *          idea and some of the code.</b> 11/04/2001
- * @version 1.16 Added support for multiple parameter values. Also fixed
- *          getCharArray(...) method to support parameters with non-english
- *          ascii values (ascii above 127). Thanks to Stefan Schmidt & Michael
- *          Elvers for this. (No fix yet for reported problems with Tomcat 3.2
- *          or a single extra byte appended to uploads of certain files). By
- *          1.17 hopefully will have a resolution for the second problem.
- *          14/03/2001
- * @version 1.15 A new parameter added, intMaxReadBytes, to allow arbitrary
- *          length files. Released under the LGPL (Lesser General Public
- *          License). 03/02/2001
- * @version 1.14 Fix for IE problem with filename being empty. This is because
- *          IE includes a default Content-Type even when no file is uploaded.
- *          16/02/2001
- * @version 1.13 If an upload directory is not specified, then all file contents
- *          are sent into oblivion, but the rest of the parsing works as normal.
- * @version 1.12 Fix, was allowing zero length files. Will not even create the
- *          output file until there is something to write. getFile(String) now
- *          returns null, if a zero length file was specified. 06/11/2000
- * @version 1.11 Fix, in case Content-type is not specified.
- * @version 1.1 Removed dependence on Servlets. Now passes in a generic
- *          InputStream instead. "Borrowed" readLine from Tomcat 3.1
- *          ServletInputStream class, so we can remove some of the dependencies
- *          on ServletInputStream. Fixed bug where a empty INPUT TYPE="FILE"
- *          value, would cause an exception.
- * @version 1.0 Initial Release.
- */
-
-public class MultipartRequest {
-       /**
-        * Defines Character Encoding method here.
-        */
-       private String charEncoding = "UTF-8";
-
-       // If not null, send debugging out here.
-       private PrintWriter debug = null;
-
-       private Hashtable htParameters = null;
-
-       private Hashtable htFiles = null;
-
-       private String strBoundary = null;
-
-       // If this Directory spec remains null, writing of files will be disabled...
-       private File fileOutPutDirectory = null;
-
-       private boolean loadIntoMemory = false;
-
-       private long intContentLength = -1;
-
-       private long intTotalRead = -1;
-
-       /**
-        * Prevent a denial of service by defining this, will never read more data.
-        * If Content-Length is specified to be more than this, will throw an
-        * exception.
-        * 
-        * This limits the maximum number of bytes to the value of an int, which is
-        * 2 Gigabytes.
-        */
-       public static final int MAX_READ_BYTES = Integer.MAX_VALUE;
-
-       /**
-        * Defines the number of bytes to read per readLine call. 128K
-        */
-       public static final int READ_LINE_BLOCK = 1024 * 128;
-
-       /**
-        * Store a read from the input stream here. Global so we do not keep
-        * creating new arrays each read.
-        */
-       private byte[] blockOfBytes = null;
-
-       /**
-        * Type constant for File FILENAME.
-        */
-       public static final int FILENAME = 0;
-
-       /**
-        * Type constant for the File CONTENT_TYPE.
-        */
-       public static final int CONTENT_TYPE = 1;
-
-       /**
-        * Type constant for the File SIZE.
-        */
-       public static final int SIZE = 2;
-
-       /**
-        * Type constant for the File CONTENTS.
-        * 
-        * <b>Note: </b>Only used for file upload to memory.
-        */
-       public static final int CONTENTS = 3;
-
-       /**
-        * This method should be called on the <code>MultipartRequest</code>
-        * itself, not on any instances of <code>MultipartRequest</code>, because
-        * this sets up the encoding for all instances of multipartrequest. You can
-        * set the encoding to null, in which case the default encoding will be
-        * applied. The default encoding if this method is not called has been set
-        * to ISO-8859-1, which seems to offer the best hope of support for
-        * international characters, such as german "Umlaut" characters.
-        * 
-        * <p>
-        * <b>Warning:</b> In multithreaded environments it is the responsibility
-        * of the implementer to make sure that this method is not called while
-        * another instance is being constructed. When an instance of
-        * MultipartRequest is constructed, it parses the input data, and uses the
-        * result of <code>getEncoding</code> method to convert between bytes and
-        * strings. If <code>setEncoding</code> method is called by another
-        * thread, while the private <code>parse</code> method is executing, the
-        * method will utilise this new encoding, which may cause serious problems.
-        * </p>
-        */
-       public void setEncoding(String enc) throws UnsupportedEncodingException {
-               if (enc == null || enc.trim() == "")
-                       charEncoding = System.getProperty("file.encoding");
-               else {
-                       // This will test the encoding for validity.
-                       new String(new byte[] { '\n' }, enc);
-
-                       charEncoding = enc;
-               }
-       }
-
-       /**
-        * Gets the current encoding method.
-        * 
-        * @return the encoding method.
-        */
-       public String getEncoding() {
-               return charEncoding;
-       }
-
-       /**
-        * Constructor.
-        * 
-        * @param strContentTypeText
-        *            the &quot;Content-Type&quot; HTTP header value.
-        * @param intContentLength
-        *            the &quot;Content-Length&quot; HTTP header value.
-        * @param in
-        *            the InputStream to read and parse.
-        * @param strSaveDirectory
-        *            the temporary directory to save the file from where they can
-        *            then be moved to wherever by the calling process. <b>If you
-        *            specify <u>null</u> for this parameter, then any files
-        *            uploaded will be silently ignored.</b>
-        * 
-        * @exception IllegalArgumentException
-        *                If the strContentTypeText does not contain a Content-Type
-        *                of "multipart/form-data" or the boundary is not found.
-        * @exception IOException
-        *                If the intContentLength is higher than MAX_READ_BYTES or
-        *                strSaveDirectory is invalid or cannot be written to.
-        * 
-        * @see #MAX_READ_BYTES
-        */
-       public MultipartRequest(String strContentTypeText, int intContentLength,
-                       InputStream in, String strSaveDirectory)
-                       throws IllegalArgumentException, IOException {
-               this(null, strContentTypeText, intContentLength, in, strSaveDirectory,
-                               MAX_READ_BYTES);
-       }
-
-       /**
-        * Constructor.
-        * 
-        * @param strContentTypeText
-        *            the &quot;Content-Type&quot; HTTP header value.
-        * @param intContentLength
-        *            the &quot;Content-Length&quot; HTTP header value.
-        * @param in
-        *            the InputStream to read and parse.
-        * @param strSaveDirectory
-        *            the temporary directory to save the file from where they can
-        *            then be moved to wherever by the calling process. <b>If you
-        *            specify <u>null</u> for this parameter, then any files
-        *            uploaded will be silently ignored.</B>
-        * @param intMaxReadBytes
-        *            Overrides the MAX_BYTES_READ value, to allow arbitrarily long
-        *            files.
-        * 
-        * @exception IllegalArgumentException
-        *                If the strContentTypeText does not contain a Content-Type
-        *                of "multipart/form-data" or the boundary is not found.
-        * @exception IOException
-        *                If the intContentLength is higher than MAX_READ_BYTES or
-        *                strSaveDirectory is invalid or cannot be written to.
-        * 
-        * @see #MAX_READ_BYTES
-        */
-       public MultipartRequest(String strContentTypeText, int intContentLength,
-                       InputStream in, String strSaveDirectory, int intMaxReadBytes)
-                       throws IllegalArgumentException, IOException {
-               this(null, strContentTypeText, intContentLength, in, strSaveDirectory,
-                               intMaxReadBytes);
-       }
-
-       /**
-        * Constructor.
-        * 
-        * @param debug
-        *            A PrintWriter that can be used for debugging.
-        * @param strContentTypeText
-        *            the &quot;Content-Type&quot; HTTP header value.
-        * @param intContentLength
-        *            the &quot;Content-Length&quot; HTTP header value.
-        * @param in
-        *            the InputStream to read and parse.
-        * @param strSaveDirectory
-        *            the temporary directory to save the file from where they can
-        *            then be moved to wherever by the calling process. <b>If you
-        *            specify <u>null</u> for this parameter, then any files
-        *            uploaded will be silently ignored.</B>
-        * 
-        * @exception IllegalArgumentException
-        *                If the strContentTypeText does not contain a Content-Type
-        *                of "multipart/form-data" or the boundary is not found.
-        * @exception IOException
-        *                If the intContentLength is higher than MAX_READ_BYTES or
-        *                strSaveDirectory is invalid or cannot be written to.
-        * 
-        * @see #MAX_READ_BYTES
-        * @deprecated Replaced by MultipartRequest(PrintWriter, String, int,
-        *             InputStream, int) You can specify
-        *             MultipartRequest.MAX_READ_BYTES for the intMaxReadBytes
-        *             parameter
-        */
-       public MultipartRequest(PrintWriter debug, String strContentTypeText,
-                       int intContentLength, InputStream in, String strSaveDirectory)
-                       throws IllegalArgumentException, IOException {
-               this(debug, strContentTypeText, intContentLength, in, strSaveDirectory,
-                               MAX_READ_BYTES);
-
-       }
-
-       /**
-        * Constructor - load into memory constructor
-        * 
-        * @param debug
-        *            A PrintWriter that can be used for debugging.
-        * @param strContentTypeText
-        *            the &quot;Content-Type&quot; HTTP header value.
-        * @param intContentLength
-        *            the &quot;Content-Length&quot; HTTP header value.
-        * @param in
-        *            the InputStream to read and parse.
-        * @param intMaxReadBytes
-        *            Overrides the MAX_BYTES_READ value, to allow arbitrarily long
-        *            files.
-        * 
-        * @exception IllegalArgumentException
-        *                If the strContentTypeText does not contain a Content-Type
-        *                of "multipart/form-data" or the boundary is not found.
-        * @exception IOException
-        *                If the intContentLength is higher than MAX_READ_BYTES or
-        *                strSaveDirectory is invalid or cannot be written to.
-        * 
-        * @see #MAX_READ_BYTES
-        */
-       public MultipartRequest(PrintWriter debug, String strContentTypeText,
-                       int intContentLength, InputStream in, int intMaxReadBytes)
-                       throws IllegalArgumentException, IOException {
-               this.loadIntoMemory = true;
-
-               // Now initialise the object, which will actually call the parse method
-               // to parse multipart stream.
-               init(debug, strContentTypeText, intContentLength, in, intMaxReadBytes);
-       }
-
-       /**
-        * Constructor.
-        * 
-        * @param debug
-        *            A PrintWriter that can be used for debugging.
-        * @param strContentTypeText
-        *            the &quot;Content-Type&quot; HTTP header value.
-        * @param intContentLength
-        *            the &quot;Content-Length&quot; HTTP header value.
-        * @param in
-        *            the InputStream to read and parse.
-        * @param strSaveDirectory
-        *            the temporary directory to save the file from where they can
-        *            then be moved to wherever by the calling process. <b>If you
-        *            specify <u>null</u> for this parameter, then any files
-        *            uploaded will be silently ignored.</B>
-        * @param intMaxReadBytes
-        *            Overrides the MAX_BYTES_READ value, to allow arbitrarily long
-        *            files.
-        * 
-        * @exception IllegalArgumentException
-        *                If the strContentTypeText does not contain a Content-Type
-        *                of "multipart/form-data" or the boundary is not found.
-        * @exception IOException
-        *                If the intContentLength is higher than MAX_READ_BYTES or
-        *                strSaveDirectory is invalid or cannot be written to.
-        * 
-        * @see #MAX_READ_BYTES
-        */
-       public MultipartRequest(PrintWriter debug, String strContentTypeText,
-                       int intContentLength, InputStream in, String strSaveDirectory,
-                       int intMaxReadBytes) throws IllegalArgumentException, IOException {
-               // IF strSaveDirectory == NULL, then we should ignore any files
-               // uploaded.
-               if (strSaveDirectory != null) {
-                       fileOutPutDirectory = new File(strSaveDirectory);
-                       if (!fileOutPutDirectory.exists())
-                               throw new IOException("Directory [" + strSaveDirectory
-                                               + "] is invalid.");
-                       else if (!fileOutPutDirectory.canWrite())
-                               throw new IOException("Directory [" + strSaveDirectory
-                                               + "] is readonly.");
-               }
-
-               // Now initialise the object, which will actually call the parse method
-               // to parse multipart stream.
-               init(debug, strContentTypeText, intContentLength, in, intMaxReadBytes);
-       }
-
-       /**
-        * Initialise the parser.
-        * 
-        * @param debug
-        *            A PrintWriter that can be used for debugging.
-        * @param strContentTypeText
-        *            the &quot;Content-Type&quot; HTTP header value.
-        * @param intContentLength
-        *            the &quot;Content-Length&quot; HTTP header value.
-        * @param in
-        *            the InputStream to read and parse.
-        * @param strSaveDirectory
-        *            the temporary directory to save the file from where they can
-        *            then be moved to wherever by the calling process. <b>If you
-        *            specify <u>null</u> for this parameter, then any files
-        *            uploaded will be silently ignored.</B>
-        * @param intMaxReadBytes
-        *            Overrides the MAX_BYTES_READ value, to allow arbitrarily long
-        *            files.
-        * 
-        * @exception IllegalArgumentException
-        *                If the strContentTypeText does not contain a Content-Type
-        *                of "multipart/form-data" or the boundary is not found.
-        * @exception IOException
-        *                If the intContentLength is higher than MAX_READ_BYTES or
-        *                strSaveDirectory is invalid or cannot be written to.
-        * 
-        * @see #MAX_READ_BYTES
-        */
-       private void init(PrintWriter debug, String strContentTypeText,
-                       int intContentLength, InputStream in, int intMaxReadBytes)
-                       throws IllegalArgumentException, IOException {
-               // saves reference to debug stream for later.
-               this.debug = debug;
-
-               if (strContentTypeText != null
-                               && strContentTypeText.startsWith("multipart/form-data")
-                               && strContentTypeText.indexOf("boundary=") != -1)
-                       strBoundary = strContentTypeText.substring(
-                                       strContentTypeText.indexOf("boundary=")
-                                                       + "boundary=".length()).trim();
-               else {
-                       // <mtl,jpell>
-                       debug("ContentType = " + strContentTypeText);
-                       throw new IllegalArgumentException("Invalid Content Type.");
-               }
-
-               this.intContentLength = intContentLength;
-               // FIX: 115
-               if (intContentLength > intMaxReadBytes)
-                       throw new IOException("Content Length Error (" + intContentLength
-                                       + " > " + intMaxReadBytes + ")");
-
-               // Instantiate the hashtable...
-               htParameters = new Hashtable();
-               htFiles = new Hashtable();
-               blockOfBytes = new byte[READ_LINE_BLOCK];
-
-               // Now parse the data.
-               parse(new BufferedInputStream(in));
-
-               // No need for this once parse is complete.
-               this.blockOfBytes = null;
-               this.debug = null;
-               this.strBoundary = null;
-       }
-
-       /**
-        * Gets the value of the strName URLParameter. If more than one value for a
-        * particular Parameter, will return the first. If an error occurs will
-        * return null.
-        * 
-        * @param strName
-        *            the form field name, used to upload the file. This identifies
-        *            the formfield location in the storage facility.
-        * @return the value of the URL Parameter.
-        */
-       public String getURLParameter(String strName) {
-               Object value = htParameters.get(strName);
-               if (value instanceof Vector)
-                       return (String) ((Vector) value).firstElement();
-               else
-                       return (String) htParameters.get(strName);
-       }
-
-       /**
-        * Gets an enumeration of all values for the strName parameter. Even if a
-        * single value for, will always return an enumeration, although it may
-        * actually be empty if no value was encountered for strName or it is an
-        * invalid parameter name.
-        * 
-        * @param strName
-        *            the form field name, used to upload the file. This identifies
-        *            the formfield location in the storage facility.
-        * @return the enumeration of all values.
-        */
-       public Enumeration getURLParameters(String strName) {
-               Object value = htParameters.get(strName);
-               if (value instanceof Vector)
-                       return ((Vector) value).elements();
-               else {
-                       Vector vector = new Vector();
-                       if (value != null)
-                               vector.addElement(value);
-                       return vector.elements();
-               }
-       }
-
-       /**
-        * Gets the enumeration of all URL Parameters for the current HTTP Request.
-        * 
-        * @return the enumeration of URl Parameters.
-        */
-       public Enumeration getParameterNames() {
-               return htParameters.keys();
-       }
-
-       /**
-        * Gets the enumeration of all INPUT TYPE=FILE parameter NAMES as
-        * encountered during the upload.
-        * 
-        * @return
-        */
-       public Enumeration getFileParameterNames() {
-               return htFiles.keys();
-       }
-
-       /**
-        * Returns the Content-Type of a file.
-        * 
-        * @see #getFileParameter(java.lang.String, int)
-        */
-       public String getContentType(String strName) {
-               // Can cast null, it will be ignored.
-               return (String) getFileParameter(strName, CONTENT_TYPE);
-       }
-
-       /**
-        * If files were uploaded into memory, this method will retrieve the
-        * contents of the file as a InputStream.
-        * 
-        * @param strName
-        *            the form field name, used to upload the file. This identifies
-        *            the formfield location in the storage facility.
-        * @return the contents of the file as a InputStream, or null if not file
-        *         uploaded, or file uploaded to file system directory.
-        * @see #getFileParameter(java.lang.String, int)
-        */
-       public InputStream getFileContents(String strName) {
-               Object obj = getFileParameter(strName, CONTENTS);
-               if (obj != null)
-                       return new ByteArrayInputStream((byte[]) obj);
-               else
-                       return null;
-       }
-
-       /**
-        * Returns a File reference to the uploaded file. This reference is to the
-        * files uploaded location, and allows you to read/move/delete the file.
-        * This method is only of use, if files were uploaded to the file system.
-        * Will return null if uploaded to memory, in which case you should use
-        * getFileContents(strName) instead.
-        * 
-        * @param strName
-        *            the form field name, used to upload the file. This identifies
-        *            the formfield location in the storage facility.
-        * @return a null file reference if a call to getFileSize(strName) returns
-        *         zero or files were uploaded to memory.
-        * @see #getFileSize(java.lang.String)
-        * @see #getFileContents(java.lang.String)
-        * @see #getFileSystemName(java.lang.String)
-        */
-       public File getFile(String strName) {
-               String filename = getFileSystemName(strName);
-               // Fix: If fileOutPutDirectory is null, then we are ignoring any file
-               // contents, so we must return null.
-               if (filename != null && getFileSize(strName) > 0
-                               && fileOutPutDirectory != null)
-                       return new File(fileOutPutDirectory, filename);
-               else
-                       return null;
-       }
-
-       /**
-        * Gets the file system basename of an uploaded file.
-        * 
-        * @param strName
-        *            the form field name, used to upload the file. This identifies
-        *            the formfield location in the storage facility.
-        * @return null if strName not found.
-        * 
-        * @see #getFileParameter(java.lang.String, int)
-        */
-       public String getFileSystemName(String strName) {
-               // Can cast null, it will be ignored.
-               return (String) getFileParameter(strName, FILENAME);
-       }
-
-       /**
-        * Returns the File Size of a uploaded file.
-        * 
-        * @param strName
-        *            the form field name, used to upload the file. This identifies
-        *            the formfield location in the storage facility.
-        * @return -1 if file size not defined.
-        * 
-        * @see #getFileParameter(java.lang.String, int)
-        */
-       public long getFileSize(String strName) {
-               Object obj = getFileParameter(strName, SIZE);
-               if (obj != null)
-                       return ((Long) obj).longValue();
-               else
-                       return (long) -1;
-       }
-
-       /**
-        * Access an attribute of a file upload parameter record.
-        * <p>
-        * The getFileSystemName(String strName),getFileSize(String
-        * strName),getContentType(String strName), getContents(String strName)
-        * methods all use this method passing in a different type argument.
-        * </p>
-        * 
-        * <p>
-        * <b>Note: </b>This class has been changed to provide for future
-        * functionality where you will be able to access all files uploaded, even
-        * if they are uploaded using the same form field name. At this point
-        * however, only the first file uploaded via a form field name is
-        * accessible.
-        * </p>
-        * 
-        * @param strName
-        *            the form field name, used to upload the file. This identifies
-        *            the formfield location in the storage facility.
-        * 
-        * @param type
-        *            What attribute you want from the File Parameter. The following
-        *            types are supported: MultipartRequest.FILENAME,
-        *            MultipartRequest.CONTENT_TYPE, MultipartRequest.SIZE,
-        *            MultipartRequest.CONTENTS
-        * 
-        * @see #getContentType(java.lang.String)
-        * @see #getFileSize(java.lang.String)
-        * @see #getFileContents(java.lang.String)
-        * @see #getFileSystemName(java.lang.String)
-        */
-       public Object getFileParameter(String strName, int type) {
-               Object[] objArray = null;
-               Object value = htFiles.get(strName);
-               if (value instanceof Vector)
-                       objArray = (Object[]) ((Vector) value).firstElement();
-               else
-                       objArray = (Object[]) htFiles.get(strName);
-
-               // Now ensure valid value.
-               if (objArray != null && type >= FILENAME && type <= CONTENTS)
-                       return objArray[type];
-               else
-                       return null;
-       }
-
-       /**
-        * This is the main parse method.
-        * 
-        * @param in
-        *            the InputStream to read and parse.
-        * @throws IOException
-        *             If the intContentLength is higher than MAX_READ_BYTES or
-        *             strSaveDirectory is invalid or cannot be written to.
-        */
-       private void parse(InputStream in) throws IOException {
-               String strContentType = null;
-               String strName = null;
-               String strFilename = null;
-               String strLine = null;
-               int read = -1;
-
-               // First run through, check that the first line is a boundary, otherwise
-               // throw a exception as format incorrect.
-               read = readLine(in, blockOfBytes);
-               strLine = read > 0 ? new String(blockOfBytes, 0, read, charEncoding)
-                               : null;
-
-               // Must be boundary at top of loop, otherwise we have finished.
-               if (strLine == null || strLine.indexOf(this.strBoundary) == -1)
-                       // Just exit. Exception would be overkill
-                       return;
-               // throw new IOException("Invalid Form Data, no boundary encountered.");
-
-               // At the top of loop, we assume that the Content-Disposition line is
-               // next, otherwise we are at the end.
-               while (true) {
-                       // Get Content-Disposition line.
-                       read = readLine(in, blockOfBytes);
-                       if (read <= 0)
-                               break; // Nothing to do.
-                       else {
-                               strLine = new String(blockOfBytes, 0, read, charEncoding);
-
-                               // Mac IE4 adds extra line after last boundary - 1.21
-                               if (strLine == null || strLine.length() == 0
-                                               || strLine.trim().length() == 0)
-                                       break;
-
-                               strName = trimQuotes(getValue("name", strLine));
-                               // If this is not null, it indicates that we are processing a
-                               // filename.
-                               strFilename = trimQuotes(getValue("filename", strLine));
-                               // Now if not null, strip it of any directory information.
-
-                               if (strFilename != null) {
-                                       // Fix: did not check whether filename was empty string
-                                       // indicating FILE contents were not passed.
-                                       if (strFilename.length() > 0) {
-                                               // Need to get the content type.
-                                               read = readLine(in, blockOfBytes);
-                                               strLine = read > 0 ? new String(blockOfBytes, 0, read,
-                                                               charEncoding) : null;
-
-                                               strContentType = "application/octet-stream";
-                                               // Fix 1.11: If not null AND strLine.length() is long
-                                               // enough.
-                                               if (strLine != null
-                                                               && strLine.length() > "Content-Type: ".length())
-                                                       strContentType = strLine.substring("Content-Type: "
-                                                                       .length());// Changed 1.13
-                                       } else {
-                                               // FIX 1.14: IE problem with empty filename.
-                                               read = readLine(in, blockOfBytes);
-                                               strLine = read > 0 ? new String(blockOfBytes, 0, read,
-                                                               charEncoding) : null;
-
-                                               if (strLine != null
-                                                               && strLine.startsWith("Content-Type:"))
-                                                       readLine(in, blockOfBytes);
-                                       }
-                               }
-
-                               // Ignore next line, as it should be blank.
-                               readLine(in, blockOfBytes);
-
-                               // No filename specified at all.
-                               if (strFilename == null) {
-                                       String param = readParameter(in);
-                                       addParameter(strName, param);
-                               } else {
-                                       if (strFilename.length() > 0) {
-                                               long filesize = -1;
-                                               // Will remain null for read onto file system uploads.
-                                               byte[] contentsOfFile = null;
-
-                                               // Get the BASENAME version of strFilename.
-                                               strFilename = getBasename(strFilename);
-
-                                               // Are we loading files into memory instead of the
-                                               // filesystem?
-                                               if (loadIntoMemory) {
-                                                       contentsOfFile = readFile(in);
-                                                       if (contentsOfFile != null)
-                                                               filesize = contentsOfFile.length;
-                                               } else
-                                                       // Read the file onto file system.
-                                                       filesize = readAndWriteFile(in, strFilename);
-
-                                               // Fix 1.18 for multiple FILE parameter values.
-                                               if (filesize > 0)
-                                                       addFileParameter(strName, new Object[] {
-                                                                       strFilename, strContentType,
-                                                                       new Long(filesize), contentsOfFile });
-                                               else
-                                                       // Zero length file.
-                                                       addFileParameter(strName, new Object[] {
-                                                                       strFilename, null, new Long(0), null });
-                                       } else // Fix: FILE INPUT TYPE, but no file passed as
-                                                       // input...
-                                       {
-                                               addFileParameter(strName, new Object[] { null, null,
-                                                               null, null });
-                                               readLine(in, blockOfBytes);
-                                       }
-                               }
-                       }
-               }// while
-       }
-
-       /**
-        * So we can put the logic for supporting multiple parameters with the same
-        * form field name in the one location.
-        * 
-        * @param strName
-        *            the form field name, used to upload the file. This identifies
-        *            the formfield location in the storage facility.
-        * @param value
-        *            the form field value.
-        */
-       private void addParameter(String strName, String value) {
-               // Fix NPE in case of null name
-               if (strName == null)
-                       return;
-
-               // Fix 1.16: for multiple parameter values.
-               Object objParms = htParameters.get(strName);
-
-               // Adds an new entry to the param vector.
-               if (objParms instanceof Vector)
-                       ((Vector) objParms).addElement(value);
-               else if (objParms instanceof String)// There is only one entry, so we
-                                                                                       // create a vector!
-               {
-                       Vector vecParms = new Vector();
-                       vecParms.addElement(objParms);
-                       vecParms.addElement(value);
-
-                       htParameters.put(strName, vecParms);
-               } else
-                       // first entry for strName.
-                       htParameters.put(strName, value);
-       }
-
-       /**
-        * So we can put the logic for supporting multiple files with the same form
-        * field name in the one location.
-        * 
-        * Assumes that this method will never be called with a null fileObj or
-        * strFilename.
-        * 
-        * @param strName
-        *            the form field name, used to upload the file. This identifies
-        *            the formfield location in the storage facility.
-        * @param fileObj
-        */
-       private void addFileParameter(String strName, Object[] fileObj) {
-               Object objParms = htFiles.get(strName);
-
-               // Add an new entry to the param vector.
-               if (objParms instanceof Vector)
-                       ((Vector) objParms).addElement(fileObj);
-               else if (objParms instanceof Object[])// There is only one entry, so
-                                                                                               // we create a vector!
-               {
-                       Vector vecParms = new Vector();
-                       vecParms.addElement(objParms);
-                       vecParms.addElement(fileObj);
-
-                       htFiles.put(strName, vecParms);
-               } else
-                       // first entry for strName.
-                       htFiles.put(strName, fileObj);
-       }
-
-       /**
-        * Reads the parameters, assume already passed Content-Disposition and blank
-        * line.
-        * 
-        * @param in
-        *            the InputStream to read and parse.
-        * @return the value read in.
-        * @throws IOException
-        *             if an error occurs writing the file.
-        */
-       private String readParameter(InputStream in) throws IOException {
-               StringBuffer buf = new StringBuffer();
-               int read = -1;
-
-               String line = null;
-               while (true) {
-                       read = readLine(in, blockOfBytes);
-                       if (read < 0)
-                               throw new IOException("Stream ended prematurely.");
-
-                       // Change v1.18: Only instantiate string once for performance
-                       // reasons.
-                       line = new String(blockOfBytes, 0, read, charEncoding);
-                       if (read < blockOfBytes.length
-                                       && line.indexOf(this.strBoundary) != -1)
-                               break; // Boundary found, we need to finish up.
-                       else
-                               buf.append(line);
-               }
-
-               if (buf.length() > 0)
-                       buf.setLength(getLengthMinusEnding(buf));
-               return buf.toString();
-       }
-
-       /**
-        * Read from in, write to out, minus last two line ending bytes.
-        * 
-        * @param in
-        *            the InputStream to read and parse.
-        * @param out
-        *            the OutputStream.
-        * @throws IOException
-        *             if an error occurs writing the file.
-        */
-       private long readAndWrite(InputStream in, OutputStream out)
-                       throws IOException {
-               long fileSize = 0;
-               int read = -1;
-
-               // This variable will be assigned the bytes actually read.
-               byte[] secondLineOfBytes = new byte[blockOfBytes.length];
-               // So we do not have to keep creating the second array.
-               int sizeOfSecondArray = 0;
-
-               while (true) {
-                       read = readLine(in, blockOfBytes);
-                       if (read < 0)
-                               throw new IOException("Stream ended prematurely.");
-
-                       // Found boundary.
-                       if (read < blockOfBytes.length
-                                       && new String(blockOfBytes, 0, read, charEncoding)
-                                                       .indexOf(this.strBoundary) != -1) {
-                               // Writes the line, minus any line ending bytes.
-                               // The secondLineOfBytes will NEVER BE NON-NULL if out==null, so
-                               // there is no need to included this in the test
-                               if (sizeOfSecondArray != 0) {
-                                       // Only used once, so declare here.
-                                       int actualLength = getLengthMinusEnding(secondLineOfBytes,
-                                                       sizeOfSecondArray);
-                                       if (actualLength > 0 && out != null) {
-                                               out.write(secondLineOfBytes, 0, actualLength);
-                                               // Updates the file size.
-                                               fileSize += actualLength;
-                                       }
-                               }
-                               break;
-                       } else {
-                               // Writes the out previous line.
-                               // The sizeOfSecondArray will NEVER BE ZERO if out==null, so
-                               // there is no need to included this in the test
-                               if (sizeOfSecondArray != 0) {
-                                       out.write(secondLineOfBytes, 0, sizeOfSecondArray);
-                                       // Updates the file size.
-                                       fileSize += sizeOfSecondArray;
-                               }
-
-                               // out will always be null, so there is no need to reset
-                               // sizeOfSecondArray to zero each time.
-                               if (out != null) {
-                                       // Copy the read bytes into the array.
-                                       System.arraycopy(blockOfBytes, 0, secondLineOfBytes, 0,
-                                                       read);
-                                       // That is how many bytes to read from the secondLineOfBytes
-                                       sizeOfSecondArray = read;
-                               }
-                       }
-               }
-
-               // Returns the number of bytes written to outstream.
-               return fileSize;
-       }
-
-       /**
-        * Reads a Multipart section that is a file type. Assumes that the
-        * Content-Disposition/Content-Type and blank line have already been
-        * processed. So we read until we hit a boundary, then close file and
-        * return.
-        * 
-        * @param in
-        *            the InputStream to read and parse.
-        * @param strFilename
-        *            the FileSystemName of the file.
-        * @return the number of bytes read.
-        * @throws IOException
-        *             if an error occurs writing the file.
-        */
-       private long readAndWriteFile(InputStream in, String strFilename)
-                       throws IOException {
-               // Stores a reference to this, as we may need to delete it later.
-               File outFile = new File(fileOutPutDirectory, strFilename);
-
-               BufferedOutputStream out = null;
-               // Do not bother opening a OutputStream, if we cannot even write the
-               // file.
-               if (fileOutPutDirectory != null)
-                       out = new BufferedOutputStream(new FileOutputStream(outFile));
-
-               long count = readAndWrite(in, out);
-               // Count would NOT be larger than zero if out was null.
-               if (count > 0) {
-                       out.flush();
-                       out.close();
-               } else {
-                       out.close();
-                       // Deletes the file as empty. We should be able to delete it, if we
-                       // can open it!
-                       outFile.delete();
-               }
-               return count;
-       }
-
-       /**
-        * If the fileOutPutDirectory wasn't specified, just read the file to
-        * memory.
-        * 
-        * @param in
-        *            the InputStream to read and parse.
-        * @return contents of file, from which you can garner the size as well.
-        * @throws IOException
-        *             if the writing failed due to input/output error.
-        */
-       private byte[] readFile(InputStream in) throws IOException {
-               // In this case, we do not need to worry about a outputdirectory.
-               ByteArrayOutputStream out = new ByteArrayOutputStream();
-
-               long count = readAndWrite(in, out);
-               // Count would NOT be larger than zero if out was null.
-               if (count > 0) {
-                       // Return contents of file to parse method for inclusion in htFiles
-                       // object.
-                       return out.toByteArray();
-               } else
-                       return null;
-       }
-
-       /**
-        * Gets the length of the line minus line ending.
-        * 
-        * @param byteLine
-        * @param endOfArray
-        *            This is because in many cases the byteLine will have garbage
-        *            data at the end, so we act as though the actual end of the
-        *            array is this parameter. If you want to process the complete
-        *            byteLine, specify byteLine.length as the endOfArray parameter.
-        * @return the length.
-        */
-       private static final int getLengthMinusEnding(byte byteLine[],
-                       int endOfArray) {
-               if (byteLine == null)
-                       return 0;
-
-               if (endOfArray >= 2 && byteLine[endOfArray - 2] == '\r'
-                               && byteLine[endOfArray - 1] == '\n')
-                       return endOfArray - 2;
-               else if (endOfArray >= 1 && byteLine[endOfArray - 1] == '\n'
-                               || byteLine[endOfArray - 1] == '\r')
-                       return endOfArray - 1;
-               else
-                       return endOfArray;
-       }
-
-       /**
-        * 
-        * @param buf
-        * @return
-        */
-       private static final int getLengthMinusEnding(StringBuffer buf) {
-               if (buf.length() >= 2 && buf.charAt(buf.length() - 2) == '\r'
-                               && buf.charAt(buf.length() - 1) == '\n')
-                       return buf.length() - 2;
-               else if (buf.length() >= 1 && buf.charAt(buf.length() - 1) == '\n'
-                               || buf.charAt(buf.length() - 1) == '\r')
-                       return buf.length() - 1;
-               else
-                       return buf.length();
-       }
-
-       /**
-        * Reads at most READ_BLOCK blocks of data, or a single line whichever is
-        * smaller. Returns -1, if nothing to read, or we have reached the specified
-        * content-length.
-        * 
-        * Assumes that bytToBeRead.length indicates the block size to read.
-        * 
-        * @param in
-        *            the InputStream to read and parse.
-        * @param bytesToBeRead
-        *            the bytes to be read.
-        * @return -1 if stream has ended, before a newline encountered (should
-        *         never happen) OR we have read past the Content-Length specified.
-        *         (Should also not happen). Otherwise return the number of
-        *         characters read. You can test whether the number returned is less
-        *         than bytesToBeRead.length, which indicates that we have read the
-        *         last line of a file or parameter or a border line, or some other
-        *         formatting stuff.
-        * @throws IOException
-        *             if the writing failed due to input/output error.
-        */
-       private int readLine(InputStream in, byte[] bytesToBeRead)
-                       throws IOException {
-               // Ensure that there is still stuff to read...
-               if (intTotalRead >= intContentLength)
-                       return -1;
-
-               // Get the length of what we are wanting to read.
-               int length = bytesToBeRead.length;
-
-               // End of content, but some servers (apparently) may not realise this
-               // and end the InputStream, so
-               // we cover ourselves this way.
-               if (length > (intContentLength - intTotalRead))
-                       length = (int) (intContentLength - intTotalRead); // So we only
-                                                                                                                               // read the data
-                                                                                                                               // that is left.
-
-               int result = readLine(in, bytesToBeRead, 0, length);
-               // Only if we get actually read something, otherwise something weird has
-               // happened, such as the end of stream.
-               if (result > 0)
-                       intTotalRead += result;
-
-               return result;
-       }
-
-       /**
-        * This needs to support the possibility of a / or a \ separator.
-        * 
-        * @param strFilename
-        *            the FileSystemName of the file.
-        * @return the strFilename after removing all characters before the last
-        *         occurence of / or \.
-        */
-       private static final String getBasename(String strFilename) {
-               if (strFilename == null)
-                       return strFilename;
-
-               int intIndex = strFilename.lastIndexOf("/");
-               if (intIndex == -1 || strFilename.lastIndexOf("\\") > intIndex)
-                       intIndex = strFilename.lastIndexOf("\\");
-
-               if (intIndex != -1)
-                       return strFilename.substring(intIndex + 1);
-               else
-                       return strFilename;
-       }
-
-       /**
-        * Trims any quotes from the start and end of a string.
-        * 
-        * @param strItem
-        * @return the trimmed string.
-        */
-       private static final String trimQuotes(String strItem) {
-               // Saves having to go any further....
-               if (strItem == null || strItem.indexOf("\"") == -1)
-                       return strItem;
-
-               // Gets the rid of any whitespace..
-               strItem = strItem.trim();
-
-               if (strItem.charAt(0) == '\"')
-                       strItem = strItem.substring(1);
-
-               if (strItem.charAt(strItem.length() - 1) == '\"')
-                       strItem = strItem.substring(0, strItem.length() - 1);
-
-               return strItem;
-       }
-
-       /**
-        * Format of string name=value; name=value; If not found, will return null.
-        * 
-        * @param strName
-        *            the form field name, used to upload the file. This identifies
-        *            the formfield location in the storage facility.
-        * @param strToDecode
-        * 
-        */
-       private static final String getValue(String strName, String strToDecode) {
-               strName = strName + "=";
-
-               int startIndexOf = 0;
-               while (startIndexOf < strToDecode.length()) {
-                       int indexOf = strToDecode.indexOf(strName, startIndexOf);
-                       // Ensure either first name, or a space or ; precedes it.
-                       if (indexOf != -1) {
-                               if (indexOf == 0
-                                               || Character.isWhitespace(strToDecode
-                                                               .charAt(indexOf - 1))
-                                               || strToDecode.charAt(indexOf - 1) == ';') {
-                                       int endIndexOf = strToDecode.indexOf(";", indexOf
-                                                       + strName.length());
-                                       if (endIndexOf == -1) // May return an empty string...
-                                               return strToDecode
-                                                               .substring(indexOf + strName.length());
-                                       else
-                                               return strToDecode.substring(
-                                                               indexOf + strName.length(), endIndexOf);
-                               } else
-                                       startIndexOf = indexOf + strName.length();
-                       } else
-                               return null;
-               }
-               return null;
-       }
-
-       /**
-        * <I>Tomcat's ServletInputStream.readLine(byte[],int,int) Slightly Modified
-        * to utilise in.read()</I> <BR>
-        * Reads the input stream, one line at a time. Starting at an offset, reads
-        * bytes into an array, until it reads a certain number of bytes or reaches
-        * a newline character, which it reads into the array as well.
-        * 
-        * <p>
-        * This method <u><b>does not</b></u> returns -1 if it reaches the end of
-        * the input stream before reading the maximum number of bytes, it returns
-        * -1, if no bytes read.
-        * 
-        * @param in
-        *            the InputStream to read and parse.
-        * @param b
-        *            an array of bytes into which data is read.
-        * 
-        * @param off
-        *            an integer specifying the character at which this method
-        *            begins reading.
-        * 
-        * @param len
-        *            an integer specifying the maximum number of bytes to read.
-        * 
-        * @return an integer specifying the actual number of bytes read, or -1 if
-        *         the end of the stream is reached.
-        * 
-        * @throws IOException
-        *             if an input or output exception has occurred
-        * 
-        * 
-        * Note: We have a problem with Tomcat reporting an erroneous number of
-        * bytes, so we need to check this. This is the method where we get an
-        * infinite loop, but only with binary files.
-        */
-       private int readLine(InputStream in, byte[] b, int off, int len)
-                       throws IOException {
-               if (len <= 0)
-                       return 0;
-
-               int count = 0, c;
-
-               while ((c = in.read()) != -1) {
-                       b[off++] = (byte) c;
-                       count++;
-                       if (c == '\n' || count == len)
-                               break;
-               }
-
-               return count > 0 ? count : -1;
-       }
-
-       /**
-        * Prints the given debugging message.
-        * 
-        * @param x
-        *            the message to print.
-        */
-       protected void debug(String x) {
-               if (debug != null) {
-                       debug.println(x);
-                       debug.flush();
-               }
-       }
-
-       /**
-        * Gets the Html Table.For debugging.
-        */
-       public String getHtmlTable() {
-               StringBuffer sbReturn = new StringBuffer();
-
-               sbReturn.append("<h2>Parameters</h2>");
-               sbReturn
-                               .append("\n<table border=3><tr><td><b>Name</b></td><td><b>Value</b></td></tr>");
-               for (Enumeration e = getParameterNames(); e.hasMoreElements();) {
-                       String strName = (String) e.nextElement();
-                       sbReturn.append("\n<tr>" + "<td>" + strName + "</td>");
-
-                       sbReturn.append("<td><table border=1><tr>");
-                       for (Enumeration f = getURLParameters(strName); f.hasMoreElements();) {
-                               String value = (String) f.nextElement();
-                               sbReturn.append("<td>" + value + "</td>");
-                       }
-                       sbReturn.append("</tr></table></td></tr>");
-               }
-               sbReturn.append("</table>");
-
-               sbReturn.append("<h2>File Parameters</h2>");
-
-               sbReturn
-                               .append("\n<table border=2><tr><td><b>Name</b></td><td><b>Filename</b></td><td><b>Path</b></td><td><b>Content Type</b></td><td><b>Size</b></td></tr>");
-               for (Enumeration e = getFileParameterNames(); e.hasMoreElements();) {
-                       String strName = (String) e.nextElement();
-
-                       sbReturn
-                                       .append("\n<tr>"
-                                                       + "<td>"
-                                                       + strName
-                                                       + "</td>"
-                                                       + "<td>"
-                                                       + (getFileSystemName(strName) != null ? getFileSystemName(strName)
-                                                                       : "") + "</td>");
-
-                       if (loadIntoMemory)
-                               sbReturn.append("<td>"
-                                               + (getFileSize(strName) > 0 ? "<i>in memory</i>" : "")
-                                               + "</td>");
-                       else
-                               sbReturn.append("<td>"
-                                               + (getFile(strName) != null ? getFile(strName)
-                                                               .getAbsolutePath() : "") + "</td>");
-
-                       sbReturn
-                                       .append("<td>"
-                                                       + (getContentType(strName) != null ? getContentType(strName)
-                                                                       : "")
-                                                       + "</td>"
-                                                       + "<td>"
-                                                       + (getFileSize(strName) != -1 ? getFileSize(strName)
-                                                                       + ""
-                                                                       : "") + "</td>" + "</tr>");
-               }
-               sbReturn.append("</table>");
-
-               return sbReturn.toString();
-       }
-}
diff --git a/src/com/itmill/toolkit/terminal/web/ServletMultipartRequest.java b/src/com/itmill/toolkit/terminal/web/ServletMultipartRequest.java
deleted file mode 100644 (file)
index 1980b0e..0000000
+++ /dev/null
@@ -1,139 +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 java.io.IOException;
-
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * This class wraps the MultipartRequest class by Jason Pell for the Servlet
- * environment.
- * 
- * @author IT Mill Ltd
- * @version
- * @VERSION@
- * @since 3.0
- */
-public class ServletMultipartRequest extends MultipartRequest {
-       /**
-        * Constructor wrapper, unwraps the InputStream, content type and content
-        * length from the servlet request object.
-        * 
-        * @param request
-        *            the HttpServletRequest will be used to initialise the
-        *            MultipartRequest super class.
-        * @param strSaveDirectory
-        *            the temporary directory to save the file from where they can
-        *            then be moved to wherever by the calling process. <b>If you
-        *            specify <u>null</u> for this parameter, then any files
-        *            uploaded will be silently ignored.</B>
-        * 
-        * @throws IllegalArgumentException
-        *             If the request.getContentType() does not contain a
-        *             Content-Type of "multipart/form-data" or the boundary is not
-        *             found.
-        * @throws IOException
-        *             If the request.getContentLength() is higher than
-        *             MAX_READ_BYTES or strSaveDirectory is invalid or cannot be
-        *             written to.
-        * 
-        * @see MultipartRequest#MAX_READ_BYTES
-        */
-       public ServletMultipartRequest(HttpServletRequest request,
-                       String strSaveDirectory) throws IllegalArgumentException,
-                       IOException {
-               super(null, request.getContentType(), request.getContentLength(),
-                               request.getInputStream(), strSaveDirectory,
-                               MultipartRequest.MAX_READ_BYTES);
-       }
-
-       /**
-        * Constructor wrapper, unwraps the InputStream, content type and content
-        * lenght from the servlet request object. Also allow to explicitly set the
-        * max permissable length of the request.
-        * 
-        * @param request
-        *            the HttpServletRequest will be used to initialise the
-        *            MultipartRequest super class.
-        * @param strSaveDirectory
-        *            the temporary directory to save the file from where they can
-        *            then be moved to wherever by the calling process. <b>If you
-        *            specify <u>null</u> for this parameter, then any files
-        *            uploaded will be silently ignored.</B>
-        * @param intMaxReadBytes
-        *            Overrides the MAX_BYTES_READ value, to allow arbitrarily long
-        *            files.
-        * 
-        * @throws IllegalArgumentException
-        *             If the request.getContentType() does not contain a
-        *             Content-Type of "multipart/form-data" or the boundary is not
-        *             found.
-        * @throws IOException
-        *             If the request.getContentLength() is higher than
-        *             MAX_READ_BYTES or strSaveDirectory is invalid or cannot be
-        *             written to.
-        * 
-        * @see MultipartRequest#MAX_READ_BYTES
-        */
-       public ServletMultipartRequest(HttpServletRequest request,
-                       String strSaveDirectory, int intMaxReadBytes)
-                       throws IllegalArgumentException, IOException {
-               super(null, request.getContentType(), request.getContentLength(),
-                               request.getInputStream(), strSaveDirectory, intMaxReadBytes);
-       }
-
-       /**
-        * Constructor wrapper for loading the request into memory rather than
-        * temp-file.
-        * 
-        * @param request
-        *            the HttpServletRequest will be used to initialise the
-        *            MultipartRequest super class.
-        * @param intMaxReadBytes
-        *            Overrides the MAX_BYTES_READ value, to allow arbitrarily long
-        *            files.
-        * 
-        * @throws IllegalArgumentException
-        *             If the request.getContentType() does not contain a
-        *             Content-Type of "multipart/form-data" or the boundary is not
-        *             found.
-        * @throws IOException
-        *             If the request.getContentLength() is higher than
-        *             MAX_READ_BYTES or strSaveDirectory is invalid or cannot be
-        *             written to.
-        * 
-        * @see MultipartRequest#MAX_READ_BYTES
-        */
-       public ServletMultipartRequest(HttpServletRequest request,
-                       int intMaxReadBytes) throws IllegalArgumentException, IOException {
-               super(null, request.getContentType(), request.getContentLength(),
-                               request.getInputStream(), intMaxReadBytes);
-       }
-}
diff --git a/src/com/itmill/toolkit/terminal/web/ServletThemeSource.java b/src/com/itmill/toolkit/terminal/web/ServletThemeSource.java
deleted file mode 100644 (file)
index 8221d04..0000000
+++ /dev/null
@@ -1,392 +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 java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.ref.SoftReference;
-import java.net.URL;
-import java.net.URLConnection;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Map;
-
-import javax.servlet.ServletContext;
-
-/**
- * Theme source for reading themes from a JAR archive. At this time only jar
- * files are supported and an archive may not contain any recursive archives.
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
-public class ServletThemeSource implements ThemeSource {
-
-       private ServletContext context;
-
-       private Theme theme;
-
-       private String path;
-
-       private ApplicationServlet webAdapterServlet;
-
-       private Cache resourceCache = new Cache();
-
-       /**
-        * Collection of subdirectory entries.
-        */
-       private URL descFile;
-
-       /**
-        * Creates a new instance of ThemeRepository by reading the themes from a
-        * local directory.
-        * 
-        * @param file
-        *            the Path to the JAR archive .
-        * @param path
-        *            the Path inside the archive to be processed.
-        * @throws IOException
-        *             if the writing failed due to input/output error.
-        * @throws ThemeException
-        *             If the resource is not found or there was some problem
-        *             finding the resource.
-        */
-       public ServletThemeSource(ServletContext context,
-                       ApplicationServlet webAdapterServlet, String path)
-                       throws IOException, ThemeException {
-
-               this.theme = null;
-               this.webAdapterServlet = webAdapterServlet;
-               this.context = context;
-
-               // Formats path
-               this.path = path;
-               if ((this.path.length() > 0) && !this.path.endsWith("/")) {
-                       this.path = this.path + "/";
-               }
-               if ((this.path.length() > 0) && !this.path.startsWith("/")) {
-                       this.path = "/" + this.path;
-               }
-
-               // Loads description file
-               this.descFile = context.getResource(this.path + Theme.DESCRIPTIONFILE);
-               InputStream entry = context.getResourceAsStream(this.path
-                               + Theme.DESCRIPTIONFILE);
-               try {
-                       if (entry != null) {
-                               try {
-                                       this.theme = new Theme(entry);
-                               } catch (Exception e) {
-                                       throw new ThemeException(
-                                                       "ServletThemeSource: Failed to load '" + path
-                                                                       + "': " + e);
-                               }
-                               entry.close();
-
-                               // Debug info
-                               if (webAdapterServlet.isDebugMode(null)) {
-                                       Log.debug("Added ServletThemeSource: " + this.path);
-                               }
-
-                       } else {
-                               throw new IllegalArgumentException(
-                                               "ServletThemeSource: Invalid theme resource: " + path);
-                       }
-               } finally {
-                       if (entry != null)
-                               entry.close();
-               }
-       }
-
-       /**
-        * Gets the XSL stream for the specified theme and web-browser type.
-        * 
-        * @see com.itmill.toolkit.terminal.web.ThemeSource#getXSLStreams(Theme,
-        *      WebBrowser)
-        */
-       public Collection getXSLStreams(Theme theme, WebBrowser type)
-                       throws ThemeException {
-               Collection xslFiles = new LinkedList();
-
-               // If this directory contains a theme
-               // return XSL from this theme
-               if (this.theme != null) {
-
-                       if (webAdapterServlet.isDebugMode(null)) {
-                               Log.info("ServletThemeSource: Loading theme: " + theme);
-                       }
-
-                       // Reloads the description file
-                       InputStream entry = context.getResourceAsStream(this.path
-                                       + Theme.DESCRIPTIONFILE);
-                       try {
-                               if (entry != null) {
-                                       this.theme = new Theme(entry);
-                               }
-                       } catch (Exception e) {
-                               throw new ThemeException("ServletThemeSource: Failed to load '"
-                                               + path + "': " + e);
-                       } finally {
-                               if (entry != null)
-                                       try {
-                                               entry.close();
-                                       } catch (IOException ignored) {
-                                       }
-                       }
-
-                       Collection fileNames = theme.getFileNames(type, Theme.MODE_HTML);
-                       // Adds all XSL file streams
-                       for (Iterator i = fileNames.iterator(); i.hasNext();) {
-                               String entryName = (String) i.next();
-                               if (entryName.endsWith(".xsl")) {
-
-                                       entry = context
-                                                       .getResourceAsStream((this.path + entryName));
-                                       xslFiles.add(new XSLStream(entryName, entry));
-                               }
-                       }
-
-               }
-               return xslFiles;
-       }
-
-       /**
-        * Returns the modification time of the description file.
-        * 
-        * @see com.itmill.toolkit.terminal.web.ThemeSource#getModificationTime()
-        */
-       public long getModificationTime() {
-               long modTime = 0;
-               try {
-                       URLConnection conn = this.descFile.openConnection();
-                       modTime = conn.getLastModified();
-               } catch (Exception ignored) {
-                       // In case of exceptions, return zero
-               }
-               return modTime;
-       }
-
-       /**
-        * Gets the input stream for the resource with the specified resource id.
-        * 
-        * @see com.itmill.toolkit.terminal.web.ThemeSource#getResource(String)
-        */
-       public InputStream getResource(String resourceId)
-                       throws ThemeSource.ThemeException {
-
-               // Checks the id
-               String name = this.getName();
-               int namelen = name.length();
-               if (resourceId == null || !resourceId.startsWith(name + "/")
-                               || resourceId.length() <= (namelen + 1)) {
-                       return null;
-               }
-
-               // Finds the resource
-               String streamName = this.path + resourceId.substring(namelen + 1);
-               InputStream stream = context.getResourceAsStream(streamName);
-               if (stream != null)
-                       try {
-
-                               // Try cache
-                               byte[] data = (byte[]) resourceCache.get(stream);
-                               if (data != null)
-                                       return new ByteArrayInputStream(data);
-
-                               // Read data
-                               int bufSize = 1024;
-                               ByteArrayOutputStream out = new ByteArrayOutputStream(bufSize);
-                               byte[] buf = new byte[bufSize];
-                               int n = 0;
-                               while ((n = stream.read(buf)) >= 0) {
-                                       out.write(buf, 0, n);
-                               }
-                               try {
-                                       stream.close();
-                               } catch (IOException ignored) {
-                               }
-                               data = out.toByteArray();
-
-                               // Cache data
-                               resourceCache.put(stream, data);
-                               return new ByteArrayInputStream(data);
-                       } catch (IOException e) {
-                       }
-
-               throw new ThemeSource.ThemeException("Resource " + resourceId
-                               + " not found.");
-       }
-
-       /**
-        * Gets the list of themes in the theme source.
-        * 
-        * @see com.itmill.toolkit.terminal.web.ThemeSource#getThemes()
-        */
-       public Collection getThemes() {
-               Collection themes = new LinkedList();
-               if (this.theme != null) {
-                       themes.add(this.theme);
-               }
-               return themes;
-       }
-
-       /**
-        * Gets the name of the ThemeSource.
-        * 
-        * @see com.itmill.toolkit.terminal.web.ThemeSource#getName()
-        */
-       public String getName() {
-               return this.theme.getName();
-       }
-
-       /**
-        * Gets the Theme instance by name.
-        * 
-        * @see com.itmill.toolkit.terminal.web.ThemeSource#getThemeByName(String)
-        */
-       public Theme getThemeByName(String name) {
-               Collection themes = this.getThemes();
-               for (Iterator i = themes.iterator(); i.hasNext();) {
-                       Theme t = (Theme) i.next();
-                       if (name != null && name.equals(t.getName()))
-                               return t;
-               }
-               return null;
-       }
-
-       /**
-        * @author IT Mill Ltd.
-        * @version
-        * @VERSION@
-        * @since 3.0
-        */
-       private class Cache {
-
-               private Map data = new HashMap();
-
-               /**
-                * Associates the specified value with the specified key in this map. If
-                * the map previously contained a mapping for this key, the old value is
-                * replaced by the specified value.
-                * 
-                * @param key
-                *            the key with which the specified value is to be
-                *            associated.
-                * @param value
-                *            the value to be associated with the specified key.
-                */
-               public void put(Object key, Object value) {
-                       data.put(key, new SoftReference(new CacheItem(value)));
-               }
-
-               /**
-                * Returns the value to which this map maps the specified key. Returns
-                * null if the map contains no mapping for this key.
-                * <p>
-                * A return value of null does not necessarily indicate that the map
-                * contains no mapping for the key; it's also possible that the map
-                * explicitly maps the key to null. The containsKey operation may be
-                * used to distinguish these two cases.
-                * </p>
-                * 
-                * @param key
-                *            the key whose associated value is to be returned.
-                * @return the value to which this map maps the specified key, or null
-                *         if the map contains no mapping for this key.
-                */
-               public Object get(Object key) {
-                       SoftReference ref = (SoftReference) data.get(key);
-                       if (ref != null)
-                               return ((CacheItem) ref.get()).getData();
-                       return null;
-               }
-
-               /**
-                * Clears the data and removes all mappings from this map .
-                */
-               public void clear() {
-                       data.clear();
-               }
-       }
-
-       /**
-        * @author IT Mill Ltd.
-        * @version
-        * @VERSION@
-        * @since 3.0
-        */
-       private class CacheItem {
-
-               private Object data;
-
-               /**
-                * 
-                * @param data
-                */
-               public CacheItem(Object data) {
-                       this.data = data;
-               }
-
-               /**
-                * Gets the data.
-                * 
-                * @return the data.
-                */
-               public Object getData() {
-                       return this.data;
-               };
-
-               /**
-                * Called by the garbage collector on an object when garbage collection
-                * determines that there are no more references to the object. A
-                * subclass overrides the finalize method to dispose of system resources
-                * or to perform other cleanup.
-                * <p>
-                * The finalize method is never invoked more than once by a Java virtual
-                * machine for any given object.
-                * </p>
-                * 
-                * @throws Throwable
-                *             the Exception raised by this method
-                * @see java.lang.Object#finalize()
-                */
-               public void finalize() throws Throwable {
-                       this.data = null;
-                       super.finalize();
-               }
-
-       }
-
-}
diff --git a/src/com/itmill/toolkit/terminal/web/TO BE DEPRECATED FROM 5.0 b/src/com/itmill/toolkit/terminal/web/TO BE DEPRECATED FROM 5.0
deleted file mode 100644 (file)
index 6a4a7bc..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-
-We'll selectively copy resources from "web/ajax-adapter" to gwt and deprecate web from 4.0
-
-Although this directory will probably be deleted in future, please DO NOT YET delete resource from 
-this directory
\ No newline at end of file
diff --git a/src/com/itmill/toolkit/terminal/web/Theme.java b/src/com/itmill/toolkit/terminal/web/Theme.java
deleted file mode 100644 (file)
index dbc879e..0000000
+++ /dev/null
@@ -1,1243 +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 java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Stack;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParserFactory;
-import org.xml.sax.helpers.DefaultHandler;
-import org.xml.sax.SAXException;
-import org.xml.sax.InputSource;
-import org.xml.sax.XMLReader;
-import org.xml.sax.Attributes;
-
-/**
- * This class provides an interface to the meta-information regarding a
- * particular theme. This entails for instanace the inheritance tree of the
- * various xsl-template files, the different requirments that the theme imposes
- * on the client browser, etc.
- * <p>
- * The WebAdapter uses themes to convert the UIDL description into client
- * representation, typically HTML or XHTML. A theme consists of set of XSL
- * template files which are used to perform XSL transform.
- * </p>
- * <p>
- * XSL files are divided into sets, which can have requirements. A file set is
- * included in transformation only if the given requirements are met. Following
- * requirements are supported:
- * <ul>
- * <li>User-Agent HTTP header substring matching</li>
- * <li>Markup language version</li>
- * <li>JavaScript version</li>
- * </ul>
- * Additionally following boolean operators may be applied to above
- * requirements:
- * <ul>
- * <li>NOT</li>
- * <li>AND</li>
- * <li>OR</li>
- * </ul>
- * The requirements are introduced in XML description file. See example below.
- * </p>
- * <p>
- * The theme description is XML data, and it can be loaded from file or stream.
- * The default filename is specified by <code>Theme.DESCRIPTIONFILE</code>.
- * 
- * </p>
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
-public class Theme extends DefaultHandler {
-
-       /**
-        * Default description file name.
-        */
-       public static final String DESCRIPTIONFILE = "description.xml";
-
-       private static final String TAG_THEME = "theme";
-
-       private static final String TAG_EXTENDS = "extends";
-
-       private static final String TAG_DESCRIPTION = "description";
-
-       private static final String TAG_FILE = "file";
-
-       private static final String TAG_FILESET = "fileset";
-
-       private static final String TAG_MODE = "mode";
-
-       private static final String TAG_MODES = "modes";
-
-       private static final String TAG_REQUIRE = "require";
-
-       private static final String TAG_SUPPORTS = "supports";
-
-       private static final String TAG_AUTHOR = "author";
-
-       private static final String TAG_AND = "and";
-
-       private static final String TAG_OR = "or";
-
-       private static final String TAG_NOT = "not";
-
-       private static final String ATTR_NAME = "name";
-
-       private static final String ATTR_THEME = "theme";
-
-       private static final String ATTR_EMAIL = "email";
-
-       private static final String ATTR_MODE = "mode";
-
-       private static final String ATTR_JAVASCRIPT = "javascript";
-
-       private static final String ATTR_AGENT = "agent";
-
-       private static final String ATTR_MARKUP = "markup";
-
-       public static final String MODE_AJAX = "ajax";
-
-       public static final String MODE_HTML = "html";
-
-       public static final String MODE_FALLBACK = MODE_HTML;
-
-       public static final String MESSAGE_CONFIGURE_HELP = "You can provide themes by adding "
-                       + "itmill-toolkit-x.y.z-themes.jar "
-                       + "to WEB-INF/lib directory or adding "
-                       + "theme files under WEB-INF/lib/themes directory."
-                       + " Check also theme's description.xml.";
-
-       /**
-        * Name of the theme.
-        */
-       private String name;
-
-       /**
-        * Theme description.
-        */
-       private String description;
-
-       /**
-        * Author of the theme.
-        */
-       private Author author;
-
-       /**
-        * Name of the theme, which this theme extends.
-        */
-       private String parentTheme = null;
-
-       /**
-        * Fileset of included XSL files.
-        */
-       private Fileset files = null;
-
-       /**
-        * Stack of fileset used while parsing XML.
-        */
-       private Stack openFilesets = new Stack();
-
-       /**
-        * Stack of string buffers used while parsing XML.
-        */
-       private Stack openStrings = new Stack();
-
-       /**
-        * Supported modes name-to-requirements.
-        */
-       private LinkedHashMap supportedModes = new LinkedHashMap();
-
-       /**
-        * Currently open mode.
-        */
-       private String currentlyOpenMode = null;
-
-       /**
-        * Are we processing modes.
-        */
-       private boolean modesListCurrentlyOpen = false;
-
-       /**
-        * Is a NOT requirement element open.
-        */
-       private boolean isNOTRequirementOpen = false;
-
-       /**
-        * Currently open requirements while parsing.
-        */
-       private Stack openRequirements = new Stack();
-
-       /**
-        * Creates a new instance using XML description file. Instantiate new theme,
-        * by loading the description from given File.
-        * 
-        * @param descriptionFile
-        *            the Description file.
-        * @throws FileNotFoundException
-        *             Thrown if the given file is not found.
-        */
-       public Theme(java.io.File descriptionFile) throws FileNotFoundException {
-               parse(new InputSource(new FileInputStream(descriptionFile)));
-       }
-
-       /**
-        * Creates a new instance using XML description stream. Instantiate new
-        * theme, by loading the description from given InputSource.
-        * 
-        * @param descriptionStream
-        *            the XML input to parse
-        */
-       public Theme(InputStream descriptionStream) {
-               try {
-                       parse(new InputSource(descriptionStream));
-               } finally {
-                       try {
-                               descriptionStream.close();
-                       } catch (IOException ignored) {
-                       }
-               }
-       }
-
-       /**
-        * Gets the preferred operating mode supported by this theme for given
-        * terminal.
-        * 
-        * @param terminal
-        *            the type of the web browser.
-        * @param themeSource
-        */
-       public String getPreferredMode(WebBrowser terminal, ThemeSource themeSource) {
-
-               // If no supported modes are declared, then we use parents preferred
-               // mode
-               if (parentTheme != null && supportedModes.keySet().isEmpty()) {
-                       Theme parent = themeSource.getThemeByName(parentTheme);
-                       if (parent == null)
-                               throw new IllegalStateException("Parent theme '" + parentTheme
-                                               + "' is not found for theme '" + getName() + "'.");
-                       return parent.getPreferredMode(terminal, themeSource);
-               }
-
-               // Iterate and test the modes in order
-               for (Iterator i = supportedModes.keySet().iterator(); i.hasNext();) {
-                       String mode = (String) i.next();
-                       if (supportsMode(mode, terminal, themeSource))
-                               return mode;
-               }
-
-               return null;
-       }
-
-       /**
-        * Tests if this theme suppors given mode.
-        * 
-        * @param mode
-        * @param terminal
-        *            the type of the web browser.
-        * @param themeSource
-        */
-       public boolean supportsMode(String mode, WebBrowser terminal,
-                       ThemeSource themeSource) {
-
-               // Theme must explicitly support the given mode
-               RequirementCollection rc = (RequirementCollection) supportedModes
-                               .get(mode);
-
-               if (rc == null || !rc.isMet(terminal))
-                       return false;
-
-               // All parents must also support the mode
-               if (parentTheme != null) {
-                       Theme parent = themeSource.getThemeByName(parentTheme);
-                       if (parent == null)
-                               throw new IllegalStateException("Parent theme '" + parentTheme
-                                               + "' is not found for theme '" + getName() + "'. "
-                                               + MESSAGE_CONFIGURE_HELP);
-                       if (!parent.supportsMode(mode, terminal, themeSource))
-                               return false;
-               }
-
-               return true;
-       }
-
-       /**
-        * Parses the XML data.
-        * 
-        * @param descriptionSource
-        *            the XML input source to parse.
-        */
-       private synchronized void parse(InputSource descriptionSource) {
-
-               // Clean-up parse time data
-               this.openStrings.clear();
-               this.openFilesets.clear();
-               this.openRequirements.clear();
-               this.files = null;
-
-               // Parse the Document
-               try {
-                       XMLReader xr = SAXParserFactory.newInstance().newSAXParser()
-                                       .getXMLReader();
-
-                       xr.setContentHandler(this);
-                       xr.setErrorHandler(this);
-
-                       xr.parse(descriptionSource);
-
-                       return;
-               } catch (ParserConfigurationException e) {
-                       e.printStackTrace();
-               } catch (SAXException e) {
-                       e.getException().printStackTrace();
-               } catch (IOException e) {
-                       e.printStackTrace();
-               } finally {
-               }
-
-       }
-
-       /**
-        * Parses start tag in XML stream.
-        * 
-        * @see org.xml.sax.ContentHandler#startElement(java.lang.String,
-        *      java.lang.String, java.lang.String, org.xml.sax.Attributes)
-        */
-       public void startElement(String uri, String local, String qName,
-                       Attributes atts) {
-
-               if (TAG_THEME.equals(qName)) {
-                       this.name = atts.getValue(ATTR_NAME);
-               } else if (TAG_DESCRIPTION.equals(qName)) {
-                       this.description = "(none)";
-                       this.openStrings.push(new StringBuffer());
-               } else if (TAG_EXTENDS.equals(qName)) {
-                       String themeName = atts.getValue(ATTR_THEME);
-                       if (this.name.equals(themeName))
-                               throw new IllegalArgumentException("Theme " + this.name
-                                               + " extends itself.");
-                       if (parentTheme != null)
-                               throw new IllegalArgumentException(
-                                               "Only one extends statement is allowed");
-                       this.parentTheme = themeName;
-               } else if (TAG_FILE.equals(qName)) {
-                       File f = new File(atts.getValue(ATTR_NAME));
-                       if (this.openFilesets.isEmpty()) {
-                               throw new IllegalStateException("Element '" + TAG_FILE
-                                               + "' must be within '" + TAG_FILESET + "' element.");
-                       }
-                       Fileset fs = (Fileset) this.openFilesets.peek();
-                       fs.addFile(f);
-               } else if (TAG_FILESET.equals(qName)) {
-                       Fileset fs;
-                       String mode = atts.getValue(ATTR_MODE);
-                       if (mode != null && mode.length() == 0)
-                               mode = null;
-                       if (mode != null && !mode.equals(MODE_AJAX)
-                                       && !mode.equals(MODE_HTML))
-                               throw new IllegalStateException("Given mode '" + mode
-                                               + "' is not supported. (This version only supports '"
-                                               + MODE_HTML + "' and '" + MODE_AJAX + "')");
-                       fs = new Fileset(mode);
-
-                       // Uses the first fileset as root fileset
-                       if (this.files == null) {
-                               this.files = fs;
-                       }
-
-                       // Adds inner filesets to parent
-                       if (!this.openFilesets.isEmpty()) {
-                               ((Fileset) this.openFilesets.peek()).addFile(fs);
-                       }
-
-                       this.openFilesets.push(fs);
-               } else if (TAG_AUTHOR.equals(qName)) {
-                       this.author = new Author(atts.getValue(ATTR_NAME), atts
-                                       .getValue(ATTR_EMAIL));
-               } else if (TAG_MODES.equals(qName)) {
-                       if (modesListCurrentlyOpen)
-                               throw new IllegalStateException(
-                                               "Modes element can not be inside another modes element");
-                       modesListCurrentlyOpen = true;
-               } else if (TAG_MODE.equals(qName)) {
-                       if (!modesListCurrentlyOpen)
-                               throw new IllegalStateException(
-                                               "Mode elements must be placed inside modes element");
-                       if (currentlyOpenMode != null)
-                               throw new IllegalStateException(
-                                               "No mode is allowed inside mode");
-                       String name = atts.getValue(ATTR_NAME);
-                       if (name == null || name.length() == 0)
-                               throw new IllegalStateException(
-                                               "Name is required for mode elements");
-                       this.currentlyOpenMode = name;
-                       RequirementCollection rc = new AndRequirement();
-                       supportedModes.put(name, rc);
-               }
-               // Requirements
-               else if (TAG_REQUIRE.equals(qName)) {
-                       if (currentlyOpenMode != null) {
-                               RequirementCollection rc = (RequirementCollection) supportedModes
-                                               .get(this.currentlyOpenMode);
-                               if (rc == null)
-                                       throw new IllegalStateException(
-                                                       "Tried to add requirements to mode '"
-                                                                       + name
-                                                                       + "', but requirements set was not properly created. (internal error)");
-                               this.openRequirements.push(rc);
-                       } else {
-                               if (this.openFilesets.isEmpty()) {
-                                       throw new IllegalStateException("Element '" + TAG_REQUIRE
-                                                       + "' must be within '" + TAG_FILESET + "' element.");
-                               }
-                               Fileset fs = (Fileset) this.openFilesets.peek();
-                               this.openRequirements.push(fs.getRequirements());
-                       }
-               } else if (TAG_SUPPORTS.equals(qName)) {
-                       if (this.openFilesets.isEmpty() && currentlyOpenMode == null) {
-                               throw new IllegalStateException("Element '" + TAG_REQUIRE
-                                               + "' must be within '" + TAG_FILESET + "' element.");
-                       }
-                       if (this.openRequirements.isEmpty()) {
-                               throw new IllegalStateException("Element '" + TAG_SUPPORTS
-                                               + "' must be within '" + TAG_REQUIRE + "' element.");
-                       }
-                       this.addRequirements(atts,
-                                       (RequirementCollection) this.openRequirements.peek(),
-                                       this.isNOTRequirementOpen);
-               } else if (TAG_NOT.equals(qName)) {
-                       this.isNOTRequirementOpen = true;
-               } else if (TAG_AND.equals(qName)) {
-                       this.openRequirements.push(new AndRequirement());
-               } else if (TAG_OR.equals(qName)) {
-                       this.openRequirements.push(new OrRequirement());
-               }
-       }
-
-       /**
-        * Parses the end tag in XML stream.
-        * 
-        * @see org.xml.sax.ContentHandler#endElement(String, String, String)
-        */
-       public void endElement(String namespaceURI, String localName, String qName)
-                       throws SAXException {
-
-               if (TAG_FILESET.equals(qName)) {
-                       this.openFilesets.pop();
-               } else if (TAG_DESCRIPTION.equals(qName)) {
-                       this.description = ((StringBuffer) this.openStrings.pop())
-                                       .toString();
-               } else if (TAG_REQUIRE.equals(qName)) {
-                       this.openRequirements.pop();
-               } else if (TAG_NOT.equals(qName)) {
-                       this.isNOTRequirementOpen = false;
-               } else if (TAG_MODES.equals(qName)) {
-                       this.modesListCurrentlyOpen = false;
-               } else if (TAG_MODE.equals(qName)) {
-                       this.currentlyOpenMode = null;
-               } else if (TAG_OR.equals(qName) || TAG_AND.equals(qName)) {
-                       RequirementCollection r = (RequirementCollection) openRequirements
-                                       .pop();
-                       if (openRequirements.size() < 1)
-                               throw new IllegalStateException();
-                       ((RequirementCollection) openRequirements.peek()).addRequirement(r);
-               }
-       }
-
-       /**
-        * Parses the character data in XML stream.
-        * 
-        * @see org.xml.sax.ContentHandler#characters(char[], int, int)
-        */
-       public void characters(char[] data, int start, int length) {
-
-               // if stack is not ready, data is not content of recognized element
-               if (!this.openStrings.isEmpty()) {
-                       ((StringBuffer) this.openStrings.peek())
-                                       .append(data, start, length);
-               } else {
-                       // read data which is not part of recognized element
-               }
-       }
-
-       /**
-        * Adds all requirements specified in attributes to fileset.
-        * 
-        * @param atts
-        *            the Attribute set.
-        * @param requirements
-        *            the Collection where to add requirement rules.
-        * @param applyNot
-        *            the Should the meaning of these requirement be negated.
-        */
-       private void addRequirements(Attributes atts,
-                       RequirementCollection requirements, boolean applyNot) {
-
-               // Creates temporary collection for requirements
-               Collection tmpReqs = new LinkedList();
-               Requirement req = null;
-
-               for (int i = 0; i < atts.getLength(); i++) {
-                       req = null;
-                       if (ATTR_JAVASCRIPT.equals(atts.getQName(i))) {
-                               req = new JavaScriptRequirement(WebBrowser
-                                               .parseJavaScriptVersion(atts.getValue(i)));
-                       } else if (ATTR_AGENT.equals(atts.getQName(i))) {
-                               req = new AgentRequirement(atts.getValue(i));
-                       } else if (ATTR_MARKUP.equals(atts.getQName(i))) {
-                               req = new MarkupLanguageRequirement(WebBrowser
-                                               .parseHTMLVersion(atts.getValue(i)));
-                       }
-                       // Adds to temporary requirement collection and clear reference
-                       if (req != null)
-                               tmpReqs.add(req);
-               }
-
-               // Creates implicit AND requirement if more than one
-               // Rrequirements were specified in attributes
-               if (tmpReqs.size() > 1) {
-                       req = new AndRequirement(tmpReqs);
-               }
-
-               // Apply NOT rule if requested
-               if (applyNot) {
-                       req = new NotRequirement(req);
-               }
-
-               // Adds to requirements
-               requirements.addRequirement(req);
-       }
-
-       /**
-        * Gets the list of all files in this theme.
-        * 
-        * @return the List of filenames belonging to this theme.
-        */
-       public List getFileNames() {
-               if (files == null)
-                       return new LinkedList();
-               return files.getFileNames();
-       }
-
-       /**
-        * Gets the list of file names matching WebBrowserType.
-        * 
-        * @param terminal
-        *            the type of the web browser.
-        * @param mode
-        * @return the list of filenames in this theme supporting the given
-        *         terminal.
-        */
-       public List getFileNames(WebBrowser terminal, String mode) {
-               if (files == null)
-                       return new LinkedList();
-               return this.files.getFileNames(terminal, mode);
-       }
-
-       /**
-        * String representation of Theme object. Used for debugging purposes only.
-        * 
-        * @see java.lang.Object#toString()
-        */
-       public String toString() {
-               return this.name
-                               + " author='"
-                               + this.author
-                               + "'"
-                               + (parentTheme != null ? " inherits='" + parentTheme + "'" : "")
-                               + " files={" + (files != null ? files.toString() : "null")
-                               + "}";
-       }
-
-       /**
-        * Author information class. This class represents an single author of a
-        * theme package. Authors have name and contact email address properties.
-        * 
-        * @author IT Mill Ltd.
-        * @version
-        * @VERSION@
-        * @since 3.0
-        */
-       public class Author {
-               // name of the author.
-               private String name;
-
-               // email address of the author.
-               private String email;
-
-               /**
-                * Constructor for Author Information Class.
-                * 
-                * @param name
-                *            the name of the author.
-                * @param email
-                *            the email address of the author.
-                */
-               public Author(String name, String email) {
-                       this.name = name;
-                       this.email = email;
-               }
-
-               /**
-                * Gets the name of the author.
-                * 
-                * @return the Name of the author.
-                */
-               public String getName() {
-                       return this.name;
-               }
-
-               /**
-                * Gets the email address of the author.
-                * 
-                * @return the Email address of the author.
-                */
-               public String getEmail() {
-                       return this.email;
-               }
-
-               /**
-                * @see java.lang.Object#toString()
-                */
-               public String toString() {
-                       return name + "(" + email + ")";
-               }
-       }
-
-       /**
-        * Generic requirement. Interface implemented by requirements introducing
-        * method for checking compability with given terminal.
-        * 
-        * @author IT Mill Ltd.
-        * @version
-        * @VERSION@
-        * @since 3.0
-        */
-       public interface Requirement {
-
-               /**
-                * Checks that this requirement is met by given type of browser.
-                * 
-                * @param terminal
-                *            the type of the web browser.
-                * @return <code>true</code> if terminal is compatible with this
-                *         rule,otherwise <code>false</code>.
-                * 
-                */
-               public boolean isMet(WebBrowser terminal);
-
-       }
-
-       /**
-        * Generic requirement collection interface. Requirement collection
-        * introducing methods for combining requirements into single requirement.
-        * 
-        * @author IT Mill Ltd.
-        * @version
-        * @VERSION@
-        * @since 3.0
-        */
-       public interface RequirementCollection extends Requirement {
-
-               /**
-                * Adds the new requirement to this collection.
-                * 
-                * @param requirement
-                *            the Requirement to be added.
-                */
-               public void addRequirement(Requirement requirement);
-
-               /**
-                * Removes the requirement from this collection.
-                * 
-                * @param requirement
-                *            the Requirement to be removed.
-                */
-               public void removeRequirement(Requirement requirement);
-       }
-
-       /**
-        * Logical NOT requirement. Requirement implementing logical NOT operation.
-        * Wraps an another requirement and negates the meaning of it.
-        * 
-        * @author IT Mill Ltd.
-        * @version
-        * @VERSION@
-        * @since 3.0
-        */
-       public class NotRequirement implements Requirement {
-               private Requirement requirement;
-
-               /**
-                * Create a new NOT requirement based on another requirement.
-                * 
-                * @param requirement
-                *            the requirement to be negated.
-                */
-               public NotRequirement(Requirement requirement) {
-                       this.requirement = requirement;
-               }
-
-               /**
-                * Check that this requirement is met by given type of browser.
-                * 
-                * @param terminal
-                *            the type of the web browser.
-                * @return <code>true</code> if terminal is compatible with this
-                *         rule,otherwise <code>false</code>.
-                * 
-                */
-               public boolean isMet(WebBrowser terminal) {
-                       return !this.requirement.isMet(terminal);
-               }
-
-               /**
-                * @see java.lang.Object#toString()
-                */
-               public String toString() {
-                       return "not(" + requirement + ")";
-               }
-
-       }
-
-       /**
-        * Logical AND requirement. Implements a collection of requirements
-        * combining the included requirements using logical AND operation.
-        * 
-        * @author IT Mill Ltd.
-        * @version
-        * @VERSION@
-        * @since 3.0
-        */
-       public class AndRequirement implements RequirementCollection {
-
-               private Collection requirements = new LinkedList();
-
-               public AndRequirement() {
-               }
-
-               /**
-                * 
-                * @param requirements
-                */
-               public AndRequirement(Collection requirements) {
-                       this.requirements.addAll(requirements);
-               }
-
-               /**
-                * 
-                * @param req1
-                * @param req2
-                */
-               public AndRequirement(Requirement req1, Requirement req2) {
-                       this.addRequirement(req1);
-                       this.addRequirement(req2);
-               }
-
-               /**
-                * Adds the new requirement to this collection.
-                * 
-                * @see com.itmill.toolkit.terminal.web.Theme.RequirementCollection#addRequirement(com.itmill.toolkit.terminal.web.Theme.Requirement)
-                */
-               public void addRequirement(Requirement requirement) {
-                       this.requirements.add(requirement);
-               }
-
-               /**
-                * Removes the requirement from this collection.
-                * 
-                * @see com.itmill.toolkit.terminal.web.Theme.RequirementCollection#removeRequirement(com.itmill.toolkit.terminal.web.Theme.Requirement)
-                */
-               public void removeRequirement(Requirement requirement) {
-                       this.requirements.remove(requirement);
-               }
-
-               /**
-                * Checks that all os the requirements in this collection are met.
-                * 
-                * @param terminal
-                *            the type of the web browser.
-                * @see Theme.Requirement#isMet(WebBrowser)
-                */
-               public boolean isMet(WebBrowser terminal) {
-                       for (Iterator i = this.requirements.iterator(); i.hasNext();) {
-                               if (!((Requirement) i.next()).isMet(terminal)) {
-                                       return false;
-                               }
-                       }
-                       return true;
-               }
-
-               /**
-                * @see java.lang.Object#toString()
-                */
-               public String toString() {
-                       String str = "";
-                       for (Iterator i = this.requirements.iterator(); i.hasNext();) {
-                               if (!"".equals(str))
-                                       str += " AND ";
-                               str += "(" + ((Requirement) i.next()).toString() + ")";
-                       }
-                       return str;
-               }
-
-       }
-
-       /**
-        * Logical OR requirement. Implements a collection of requirements combining
-        * the included requirements using logical AND operation.
-        * 
-        * @author IT Mill Ltd.
-        * @version
-        * @VERSION@
-        * @since 3.0
-        */
-       public class OrRequirement implements RequirementCollection {
-
-               private Collection requirements = new LinkedList();
-
-               public OrRequirement() {
-               }
-
-               /**
-                * 
-                * @param requirements
-                */
-               public OrRequirement(Collection requirements) {
-                       this.requirements.addAll(requirements);
-               }
-
-               /**
-                * 
-                * @param req1
-                * @param req2
-                */
-               public OrRequirement(Requirement req1, Requirement req2) {
-                       this.addRequirement(req1);
-                       this.addRequirement(req2);
-               }
-
-               /**
-                * Adds the new requirement to this collection.
-                * 
-                * @see com.itmill.toolkit.terminal.web.Theme.RequirementCollection#addRequirement(com.itmill.toolkit.terminal.web.Theme.Requirement)
-                */
-               public void addRequirement(Requirement requirement) {
-                       this.requirements.add(requirement);
-               }
-
-               /**
-                * Removes the requirement from this collection.
-                * 
-                * @see com.itmill.toolkit.terminal.web.Theme.RequirementCollection#removeRequirement(com.itmill.toolkit.terminal.web.Theme.Requirement)
-                */
-               public void removeRequirement(Requirement requirement) {
-                       this.requirements.remove(requirement);
-               }
-
-               /**
-                * Checks that some of the requirements in this collection is met.
-                * 
-                * @param terminal
-                *            the type of the web browser.
-                * @see Theme.Requirement#isMet(WebBrowser)
-                */
-               public boolean isMet(WebBrowser terminal) {
-                       for (Iterator i = this.requirements.iterator(); i.hasNext();) {
-                               if (((Requirement) i.next()).isMet(terminal)) {
-                                       return true;
-                               }
-                       }
-                       return false;
-               }
-
-               /**
-                * @see java.lang.Object#toString()
-                */
-               public String toString() {
-                       String str = "";
-                       for (Iterator i = this.requirements.iterator(); i.hasNext();) {
-                               if (!"".equals(str))
-                                       str += " OR ";
-                               str += "(" + ((Requirement) i.next()).toString() + ")";
-                       }
-                       return str;
-               }
-       }
-
-       /**
-        * HTTP user agent requirement This requirements is used to ensure that the
-        * User-Agent string provided in HTTP request headers contains given
-        * substring.
-        * 
-        * @author IT Mill Ltd.
-        * @version
-        * @VERSION@
-        * @since 3.0
-        */
-       public class AgentRequirement implements Requirement {
-
-               private String agentSubstring;
-
-               /**
-                * 
-                * @param agentSubString
-                */
-               public AgentRequirement(String agentSubString) {
-                       this.agentSubstring = agentSubString;
-               }
-
-               /**
-                * Checks that this requirement is met by given type of browser.
-                * 
-                * @see com.itmill.toolkit.terminal.web.Theme.Requirement#isMet(com.itmill.toolkit.terminal.web.WebBrowser)
-                */
-               public boolean isMet(WebBrowser terminal) {
-                       return terminal.getBrowserApplication()
-                                       .indexOf(this.agentSubstring) >= 0;
-               }
-
-               /**
-                * @see java.lang.Object#toString()
-                */
-               public String toString() {
-                       return this.agentSubstring;
-               }
-       }
-
-       /**
-        * Javascript version requirement This requirement is used to ensure a
-        * certain level of JavaScript version support.
-        * 
-        * @author IT Mill Ltd.
-        * @version
-        * @VERSION@
-        * @since 3.0
-        */
-       public class JavaScriptRequirement implements Requirement {
-
-               private WebBrowser.JavaScriptVersion requiredVersion;
-
-               /**
-                * 
-                * @param requiredVersion
-                */
-               public JavaScriptRequirement(
-                               WebBrowser.JavaScriptVersion requiredVersion) {
-                       this.requiredVersion = requiredVersion;
-               }
-
-               /**
-                * Checks that this requirement is met by given type of browser.
-                * 
-                * @see com.itmill.toolkit.terminal.web.Theme.Requirement#isMet(com.itmill.toolkit.terminal.web.WebBrowser)
-                */
-               public boolean isMet(WebBrowser terminal) {
-                       if (terminal.getJavaScriptVersion().supports(this.requiredVersion))
-                               return true;
-                       return false;
-               }
-
-               /**
-                * @see java.lang.Object#toString()
-                */
-               public String toString() {
-                       return this.requiredVersion.toString();
-               }
-       }
-
-       /**
-        * Markup language version requirement. This requirement is used to ensure a
-        * certain level of Markup language version support.
-        * 
-        * @author IT Mill Ltd.
-        * @version
-        * @VERSION@
-        * @since 3.0
-        */
-       public class MarkupLanguageRequirement implements Requirement {
-
-               private WebBrowser.MarkupVersion requiredVersion;
-
-               /**
-                * 
-                * @param requiredVersion
-                */
-               public MarkupLanguageRequirement(
-                               WebBrowser.MarkupVersion requiredVersion) {
-                       this.requiredVersion = requiredVersion;
-               }
-
-               /**
-                * Checks that this requirement is met by given type of browser.
-                * 
-                * @see com.itmill.toolkit.terminal.web.Theme.Requirement#isMet(com.itmill.toolkit.terminal.web.WebBrowser)
-                */
-               public boolean isMet(WebBrowser terminal) {
-                       if (terminal.getMarkupVersion().supports(this.requiredVersion))
-                               return true;
-                       return false;
-
-               }
-
-               /**
-                * @see java.lang.Object#toString()
-                */
-               public String toString() {
-                       return this.requiredVersion.toString();
-               }
-
-       }
-
-       /**
-        * Theme XSL file description Description of a single XSL file included a
-        * theme.
-        * 
-        * @author IT Mill Ltd.
-        * @version
-        * @VERSION@
-        * @since 3.0
-        */
-       public class File {
-
-               private String name;
-
-               /**
-                * Creates a new file.
-                * 
-                * @param name
-                *            the Name of the file.
-                */
-               public File(String name) {
-                       this.name = name;
-               }
-
-               /**
-                * Gets the name of the file. The file name is relative and unique
-                * within a theme.
-                * 
-                * @return the Name of the file.
-                */
-               public String getName() {
-                       return this.name;
-               }
-
-               /**
-                * Does this file support the given terminal. Single file requirements
-                * are not supported and therefore this always returns true.
-                * 
-                * @param terminal
-                *            the type of the web browser.
-                * @return Always returns true.
-                * @see Theme.Fileset
-                */
-               public boolean supports(WebBrowser terminal) {
-                       return true;
-               }
-
-               /**
-                * @see java.lang.Object#toString()
-                */
-               public String toString() {
-                       return this.getName();
-               }
-
-       }
-
-       /**
-        * A recursive set of files sharing the same requirements.
-        * 
-        * @author IT Mill Ltd.
-        * @version
-        * @VERSION@
-        * @since 3.0
-        */
-       public class Fileset extends File {
-
-               private RequirementCollection requirements = new AndRequirement();
-
-               private Collection files = new LinkedList();
-
-               private String mode;
-
-               /**
-                * Creates a new empty fileset.
-                * 
-                * @param mode
-                * 
-                */
-               public Fileset(String mode) {
-                       super(null);
-                       this.mode = mode;
-               }
-
-               /**
-                * Adds a file into fileset.
-                * 
-                * @param file
-                *            the file to add.
-                */
-               private void addFile(File file) {
-                       this.files.add(file);
-               }
-
-               /**
-                * Gets the requirements in this fileset.
-                * 
-                * @return the requirements.
-                */
-               private RequirementCollection getRequirements() {
-                       return this.requirements;
-               }
-
-               /**
-                * Gets the list of all files in this theme.
-                * 
-                * @return the list of filenames.
-                */
-               public List getFileNames() {
-
-                       List list = new LinkedList();
-
-                       for (Iterator i = this.files.iterator(); i.hasNext();) {
-                               File f = (File) i.next();
-
-                               // Recursively add included filesets
-                               if (f instanceof Fileset) {
-                                       list.addAll(((Fileset) f).getFileNames());
-                               } else {
-                                       list.add(f.getName());
-                               }
-                       }
-                       return list;
-
-               }
-
-               /**
-                * Gets the list of file names matching WebBrowserType.
-                * 
-                * @param terminal
-                *            the type of the web browser.
-                * @param mode
-                * @return the list of filenames supporting the given terminal.
-                */
-               public List getFileNames(WebBrowser terminal, String mode) {
-
-                       List list = new LinkedList();
-
-                       // If this set is not supported by the terminal or is explicitly set
-                       // into
-                       // another mode, no files are given
-                       if (!this.supports(terminal)
-                                       || (this.mode != null && !this.mode.equals(mode)))
-                               return list;
-
-                       for (Iterator i = this.files.iterator(); i.hasNext();) {
-                               File f = (File) i.next();
-
-                               // Recursively add included filesets if they are
-                               // supported
-                               if (f instanceof Fileset) {
-                                       list.addAll(((Fileset) f).getFileNames(terminal, mode));
-
-                               } else {
-                                       list.add(f.getName());
-                               }
-                       }
-                       return list;
-               }
-
-               /**
-                * Does this file support the given terminal.
-                * 
-                * @terminal the type of the web browser.
-                * @return True if fileset supports the given browser. False otherwise.
-                */
-               public boolean supports(WebBrowser terminal) {
-                       if (requirements.isMet(terminal))
-                               return true;
-                       return false;
-               }
-
-               /**
-                * @see java.lang.Object#toString()
-                */
-               public String toString() {
-                       return "name=[" + this.getName() + "] requires=["
-                                       + this.requirements + "] files=[" + files + "]";
-               }
-       }
-
-       /**
-        * Gets the author of this theme.
-        * 
-        * @return the Author of the theme.
-        */
-       public Author getAuthor() {
-               return author;
-       }
-
-       /**
-        * Gets the name of this theme.
-        * 
-        * @return the Name of the theme.
-        */
-       public String getName() {
-               return name;
-       }
-
-       /**
-        * Gets the name of the parent theme.
-        * 
-        * @return the name of the parent theme.
-        */
-       public String getParent() {
-               return parentTheme;
-       }
-
-       /**
-        * Gets the theme description.
-        * 
-        * @return the theme description.
-        */
-       public String getDescription() {
-               return description;
-       }
-
-}
diff --git a/src/com/itmill/toolkit/terminal/web/ThemeFunctionLibrary.java b/src/com/itmill/toolkit/terminal/web/ThemeFunctionLibrary.java
deleted file mode 100644 (file)
index e03f6b3..0000000
+++ /dev/null
@@ -1,606 +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.ThemeResource;
-import com.itmill.toolkit.ui.FrameWindow;
-import com.itmill.toolkit.ui.Window;
-
-import java.text.DateFormatSymbols;
-import java.util.Calendar;
-import java.util.Collection;
-import java.util.GregorianCalendar;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Map;
-import java.util.Vector;
-
-import javax.servlet.http.HttpSession;
-
-/**
- * This a function library that can be used from the theme XSL-files. It
- * provides easy access to current application, window, theme, webbrowser and
- * session. The internal threadlocal state must be maintained by the webadapter
- * in order to guarantee that it works.
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
-
-public class ThemeFunctionLibrary {
-
-       static private final int APPLICATION = 0;
-
-       static private final int WINDOW = 1;
-
-       static private final int WEBBROWSER = 2;
-
-       static private final int SESSION = 3;
-
-       static private final int WEBADAPTERSERVLET = 4;
-
-       static private final int THEME = 5;
-
-       static private ThreadLocal state = new ThreadLocal();
-
-       /**
-        * 
-        * @param application
-        * @param window
-        * @param webBrowser
-        * @param session
-        * @param webAdapterServlet
-        * @param theme
-        */
-       static protected void setState(Application application, Window window,
-                       WebBrowser webBrowser, HttpSession session,
-                       ApplicationServlet webAdapterServlet, String theme) {
-               state.set(new Object[] { application, window, webBrowser, session,
-                               webAdapterServlet, theme });
-       }
-
-       static protected void cleanState() {
-               state.set(null);
-       }
-
-       /**
-        * Returns a reference to the application object associated with the session
-        * that the call came from.
-        */
-       static public Application application() {
-               try {
-                       return (Application) ((Object[]) state.get())[APPLICATION];
-               } catch (NullPointerException e) {
-                       throw new IllegalStateException();
-               }
-       }
-
-       /**
-        * Returns a reference to the current window object associated with the
-        * session that the call came from.
-        */
-       static public Window window() {
-               try {
-                       return (Window) ((Object[]) state.get())[WINDOW];
-               } catch (NullPointerException e) {
-                       throw new IllegalStateException();
-               }
-       }
-
-       /**
-        * Returns a reference to the browser object associated with the session
-        * that the call came from.
-        */
-       static public WebBrowser browser() {
-               try {
-                       return (WebBrowser) ((Object[]) state.get())[WEBBROWSER];
-               } catch (NullPointerException e) {
-                       throw new IllegalStateException();
-               }
-       }
-
-       /**
-        * Returns a reference to the current servlet http session object that is
-        * associated with the session that the call came from.
-        */
-       static public HttpSession session() {
-               try {
-                       return (HttpSession) ((Object[]) state.get())[SESSION];
-               } catch (NullPointerException e) {
-                       throw new IllegalStateException();
-               }
-       }
-
-       /**
-        * Returns a reference to the current theme name that is associated with the
-        * session that the call came from.
-        */
-       static public String theme() {
-               try {
-                       return (String) ((Object[]) state.get())[THEME];
-               } catch (NullPointerException e) {
-                       throw new IllegalStateException();
-               }
-       }
-
-       /**
-        * Returns an URI to the named resource from the named theme.
-        * 
-        * @param resource
-        * @param theme
-        */
-       static public String resource(String resource, String theme) {
-               try {
-                       return ((ApplicationServlet) ((Object[]) state.get())[WEBADAPTERSERVLET])
-                                       .getResourceLocation(theme, new ThemeResource(resource));
-               } catch (NullPointerException e) {
-                       throw new IllegalStateException();
-               }
-       }
-
-       /**
-        * Returns an URI to the named resource.
-        * 
-        * @param resource
-        */
-       static public String resource(String resource) {
-               try {
-                       return ((ApplicationServlet) ((Object[]) state.get())[WEBADAPTERSERVLET])
-                                       .getResourceLocation(theme(), new ThemeResource(resource));
-               } catch (NullPointerException e) {
-                       throw new IllegalStateException();
-               }
-       }
-
-       /**
-        * Generates the JavaScript for page that performs client-side combility
-        * checks.
-        */
-       static public boolean probeClient() {
-               return (browser().performClientCheck() && !browser()
-                               .isClientSideChecked());
-       }
-
-       /**
-        * Generates the JavaScript for page header that handles window refreshing,
-        * opening and closing.
-        * 
-        * Generates script that:
-        * <ul>
-        * <li>Requests that all windows that need repaint be reloaded</li>
-        * <li>Sets the window name</li>
-        * <li>Closes window if it is set to be closed </li>
-        * <ul>
-        * 
-        * @return
-        */
-       static public String windowScript() {
-               return generateWindowScript(
-                               window(),
-                               application(),
-                               (ApplicationServlet) ((Object[]) state.get())[WEBADAPTERSERVLET],
-                               browser());
-       }
-
-       /**
-        * 
-        * @param window
-        * @param app
-        * @param wa
-        * @param browser
-        * @return
-        */
-       static protected String generateWindowScript(Window window,
-                       Application app, ApplicationServlet wa, WebBrowser browser) {
-
-               StringBuffer script = new StringBuffer();
-               LinkedList update = new LinkedList();
-
-               // Adds all the windows needto update list
-               Map dirtyWindows = wa != null ? wa.getDirtyWindows(app) : null;
-               if (dirtyWindows != null)
-                       for (Iterator i = dirtyWindows.keySet().iterator(); i.hasNext();) {
-                               Window w = (Window) i.next();
-                               if (w != window) {
-                                       if (w instanceof FrameWindow)
-                                               update.addFirst(w);
-                                       else
-                                               update.addLast(w);
-                               }
-                       }
-
-               // Removes all windows that are in frames, of such frame windows that
-               // will be updated anyway
-               Object[] u = update.toArray();
-               if (u.length > 0 && (window != null && window instanceof FrameWindow))
-                       u[u.length - 1] = window;
-               for (int i = 0; i < u.length; i++) {
-                       try {
-                               FrameWindow w = (FrameWindow) u[i];
-                               LinkedList framesets = new LinkedList();
-                               framesets.add(w.getFrameset());
-                               while (!framesets.isEmpty()) {
-                                       FrameWindow.Frameset fs = (FrameWindow.Frameset) framesets
-                                                       .removeFirst();
-                                       for (Iterator j = fs.getFrames().iterator(); j.hasNext();) {
-                                               FrameWindow.Frame f = (FrameWindow.Frame) j.next();
-                                               if (f instanceof FrameWindow.Frameset)
-                                                       framesets.add(f);
-                                               else if (f.getWindow() != null) {
-                                                       update.remove(f.getWindow());
-                                                       wa.removeDirtyWindow(app, f.getWindow());
-                                               }
-                                       }
-                               }
-                       } catch (ClassCastException ignored) {
-                       }
-               }
-
-               // Sets window name
-               if (window != null) {
-                       script.append("window.name = \"" + getWindowTargetName(app, window)
-                                       + "\";\n");
-               }
-
-               // Generates window updatescript
-               for (Iterator i = update.iterator(); i.hasNext();) {
-                       Window w = (Window) i.next();
-                       script.append(getWindowRefreshScript(app, w, browser));
-
-                       wa.removeDirtyWindow(app, w);
-
-                       // Windows that are closed immediately are "painted" now
-                       if (w.getApplication() == null || !w.isVisible())
-                               w.requestRepaintRequests();
-               }
-
-               // Closes current window if it is not visible
-               if (window == null || !window.isVisible())
-                       script.append("window.close();\n");
-
-               return script.toString();
-       }
-
-       /**
-        * Returns an unique target name for a given window name.
-        * 
-        * @param application
-        * @param window
-        *            the Name of the window.
-        * @return An unique ID for window target.
-        */
-       static public String getWindowTargetName(Application application,
-                       Window window) {
-               try {
-                       return "" + application.hashCode() + "_" + window.getName();
-               } catch (NullPointerException e) {
-                       throw new IllegalStateException();
-               }
-       }
-
-       /**
-        * Returns an unique target name for current window.
-        * 
-        * @return An unique ID for window target.
-        */
-       static public String getWindowTargetName() {
-               return getWindowTargetName(application(), window());
-       }
-
-       /**
-        * Returns an unique target name for current window.
-        * 
-        * @param name
-        *            the name of the window.
-        * @return An unique ID for window target.
-        */
-       static public String getWindowTargetName(String name) {
-               Window w = application().getWindow(name);
-               if (w != null)
-                       return getWindowTargetName(application(), w);
-               else
-                       return name;
-       }
-
-       /* Static mapping for 0 to be sunday. */
-       private static int[] weekdays = new int[] { Calendar.SUNDAY,
-                       Calendar.MONDAY, Calendar.TUESDAY, Calendar.WEDNESDAY,
-                       Calendar.THURSDAY, Calendar.FRIDAY, Calendar.SATURDAY };
-
-       /**
-        * Returns the country and region code for current application locale.
-        * 
-        * @return the language Country code of the current application locale.
-        * @see Locale#getCountry()
-        */
-       static public String getLocaleCountryId() {
-               try {
-                       Application app = (Application) ((Object[]) state.get())[APPLICATION];
-                       return app.getLocale().getCountry();
-               } catch (NullPointerException e) {
-                       throw new IllegalStateException();
-               }
-       }
-
-       /**
-        * Returns the language code for current application locale.
-        * 
-        * @return the Language code for current application locale.
-        * @see Locale#getLanguage()
-        */
-       static public String getLocaleLanguageId() {
-               try {
-                       Application app = (Application) ((Object[]) state.get())[APPLICATION];
-                       return app.getLocale().getLanguage();
-               } catch (NullPointerException e) {
-                       throw new IllegalStateException();
-               }
-       }
-
-       /**
-        * Gets the name of first day of the week.
-        * 
-        * @return
-        */
-       static public int getFirstDayOfWeek() {
-               try {
-                       Application app = (Application) ((Object[]) state.get())[APPLICATION];
-                       Calendar cal = new GregorianCalendar(app.getLocale());
-                       int first = cal.getFirstDayOfWeek();
-                       for (int i = 0; i < 7; i++) {
-                               if (first == weekdays[i])
-                                       return i;
-                       }
-                       return 0; // default to sunday
-               } catch (NullPointerException e) {
-                       throw new IllegalStateException();
-               }
-       }
-
-       /**
-        * Gets the name for week day.
-        * 
-        * @param dayOfWeek
-        *            the Number of week day. 0 sunday, 1 monday, ...
-        * @return the Name of week day in applications current locale.
-        */
-       static public String getShortWeekday(int dayOfWeek) {
-               try {
-                       Application app = (Application) ((Object[]) state.get())[APPLICATION];
-                       DateFormatSymbols df = new DateFormatSymbols(app.getLocale());
-                       return df.getShortWeekdays()[weekdays[dayOfWeek]];
-               } catch (NullPointerException e) {
-                       throw new IllegalStateException();
-               }
-       }
-
-       /**
-        * Gets the short name for month.
-        * 
-        * @param month
-        *            the Number of month. 0 is January, 1 is February, and so on.
-        * @return the Name of month in applications current locale.
-        */
-       static public String getShortMonth(int month) {
-               try {
-                       Application app = (Application) ((Object[]) state.get())[APPLICATION];
-                       DateFormatSymbols df = new DateFormatSymbols(app.getLocale());
-                       String monthName = df.getShortMonths()[month];
-                       return monthName;
-               } catch (NullPointerException e) {
-                       throw new IllegalStateException();
-               }
-       }
-
-       /**
-        * Gets the name for month.
-        * 
-        * @param month
-        *            the Number of month. 0 is January, 1 is February, and so on.
-        * @return the Name of month in applications current locale.
-        */
-       static public String getMonth(int month) {
-               try {
-                       Application app = (Application) ((Object[]) state.get())[APPLICATION];
-                       DateFormatSymbols df = new DateFormatSymbols(app.getLocale());
-                       String monthName = df.getMonths()[month];
-                       return monthName;
-               } catch (NullPointerException e) {
-                       throw new IllegalStateException();
-               }
-       }
-
-       /**
-        * Gets Form Action URL for the requested window.
-        * 
-        * <p>
-        * This returns the action for the window main form. This action can be set
-        * through WebApplicationContect setWindowFormAction method..
-        * </p>
-        * 
-        * @return the Form action for the current window.
-        */
-       static public String getFormAction() {
-
-               Window win = window();
-               Application app = application();
-
-               return ((WebApplicationContext) app.getContext())
-                               .getWindowFormAction(win);
-       }
-
-       /**
-        * Generates the links for CSS files to be included in html head.
-        * 
-        * @return
-        */
-       static public String getCssLinksForHead() {
-               ApplicationServlet as = (ApplicationServlet) ((Object[]) state.get())[WEBADAPTERSERVLET];
-               Theme t = as.getThemeSource().getThemeByName(theme());
-
-               // Also iterate parent themes
-               Vector themes = new Vector();
-               themes.add(t);
-               while (t.getParent() != null) {
-                       String parentName = t.getParent();
-                       t = as.getThemeSource().getThemeByName(parentName);
-                       themes.add(t);
-               }
-
-               // Generates links
-               StringBuffer links = new StringBuffer();
-               for (int k = themes.size() - 1; k >= 0; k--) {
-                       Collection allFiles = ((Theme) themes.get(k)).getFileNames(
-                                       browser(), Theme.MODE_HTML);
-                       for (Iterator i = allFiles.iterator(); i.hasNext();) {
-                               String file = (String) i.next();
-                               if (file.endsWith(".css")) {
-                                       links
-                                                       .append("<LINK REL=\"STYLESHEET\" TYPE=\"text/css\" HREF=\""
-                                                                       + resource(file) + "\"/>\n");
-                               }
-                       }
-               }
-
-               return links.toString();
-       }
-
-       /**
-        * Generates the links for JavaScript files to be included in html head.
-        * 
-        * @return
-        */
-       static public String getJavaScriptLinksForHead() {
-               ApplicationServlet as = (ApplicationServlet) ((Object[]) state.get())[WEBADAPTERSERVLET];
-               Theme t = as.getThemeSource().getThemeByName(theme());
-
-               // Also iterate parent themes
-               Vector themes = new Vector();
-               themes.add(t);
-               while (t.getParent() != null) {
-                       String parentName = t.getParent();
-                       t = as.getThemeSource().getThemeByName(parentName);
-                       themes.add(t);
-               }
-
-               // Generates links
-               StringBuffer links = new StringBuffer();
-               for (int k = themes.size() - 1; k >= 0; k--) {
-                       Collection allFiles = ((Theme) themes.get(k)).getFileNames(
-                                       browser(), Theme.MODE_HTML);
-                       for (Iterator i = allFiles.iterator(); i.hasNext();) {
-                               String file = (String) i.next();
-                               if (file.endsWith(".js")) {
-                                       links.append("<SCRIPT LANGUAGE=\"Javascript\" SRC=\""
-                                                       + resource(file) + "\"></SCRIPT>\n");
-                               }
-                       }
-               }
-
-               return links.toString();
-       }
-
-       /**
-        * Generates the JavaScript for updating given window.
-        * 
-        * @param application
-        * @param window
-        * @param browser
-        * @return
-        */
-       static protected String getWindowRefreshScript(Application application,
-                       Window window, WebBrowser browser) {
-
-               if (application == null)
-                       return "";
-
-               if (window == null)
-                       return "";
-
-               if (window == null)
-                       return "";
-
-               // If window is closed or hidden
-               if (window.getApplication() == null || !window.isVisible())
-                       return "win = window.open(\"\",\""
-                                       + getWindowTargetName(application, window) + "\");\n  "
-                                       + "if (win != null) { win.close(); }\n";
-
-               String url = window.getURL().toString();
-
-               String features = "dependent=yes,";
-               int width = window.getWidth();
-               int height = window.getHeight();
-               if (width >= 0)
-                       features += "width=" + width;
-               if (height >= 0)
-                       features += ((features.length() > 0) ? "," : "") + "height="
-                                       + height;
-               switch (window.getBorder()) {
-               case Window.BORDER_NONE:
-                       features += ((features.length() > 0) ? "," : "")
-                                       + "toolbar=0,location=0,menubar=0,status=0,resizable=1,scrollbars="
-                                       + (window.isScrollable() ? "1" : "0");
-                       break;
-               case Window.BORDER_MINIMAL:
-                       features += ((features.length() > 0) ? "," : "")
-                                       + "toolbar=1,location=0,menubar=0,status=1,resizable=1,scrollbars="
-                                       + (window.isScrollable() ? "1" : "0");
-                       break;
-               case Window.BORDER_DEFAULT:
-                       features += ((features.length() > 0) ? "," : "")
-                                       + "toolbar=1,location=1,menubar=1,status=1,resizable=1,scrollbars="
-                                       + (window.isScrollable() ? "1" : "0");
-                       break;
-               }
-
-               String script = "win = window.open(\"\",\""
-                               + getWindowTargetName(application, window) + "\",\"" + features
-                               + "\");\n" + "if (win != null) {" + "var form = null;";
-
-               if (browser != null
-                               && (browser.getJavaScriptVersion().supports(
-                                               WebBrowser.JAVASCRIPT_1_5) || browser
-                                               .getJavaScriptVersion()
-                                               .supports(WebBrowser.JSCRIPT_1_0))) {
-                       script += "try { form = win.document.forms[\"itmill\"]; if (typeof form == 'undefined') form = win.document.forms[\"millstone\"];"
-                                       + "} catch (e) { form = null;}";
-               } else {
-                       script += "form = win.document.forms[\"itmill\"]; if (typeof form == 'undefined') form = win.document.forms[\"millstone\"];";
-               }
-
-               script += "if (form != null) {" + "form.submit();"
-                               + "} else {win.location.href = \"" + url + "\";}}";
-
-               return script;
-       }
-}
diff --git a/src/com/itmill/toolkit/terminal/web/ThemeSource.java b/src/com/itmill/toolkit/terminal/web/ThemeSource.java
deleted file mode 100644 (file)
index c2ff054..0000000
+++ /dev/null
@@ -1,183 +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 java.io.InputStream;
-import java.util.Collection;
-
-/**
- * Interface implemented by theme sources.
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
-public interface ThemeSource {
-
-       /**
-        * Gets the name of the ThemeSource.
-        * 
-        * @return the Name of the theme source.
-        */
-       public String getName();
-
-       /**
-        * Gets the XSL stream for the specified theme and web-browser type. Returns
-        * the XSL templates, which are used to process the UIDL data. The
-        * <code>type</code> parameter is used to limit the templates, which are
-        * returned based on the theme fileset requirements.
-        * <p>
-        * Note : This implicitly operates in xslt mode.
-        * </p>
-        * 
-        * @param theme
-        *            the Theme, which XSL should be returned.
-        * @param type
-        *            the type of the current client.
-        * @return Collection of ThemeSource.XSLStream objects.
-        * @throws ThemeException
-        *             If the resource is not found or there was some problem
-        *             finding the resource.
-        * @see Theme
-        */
-       public Collection getXSLStreams(Theme theme, WebBrowser type)
-                       throws ThemeException;
-
-       /**
-        * Gets the last modification time, used to reload theme on changes.
-        * 
-        * @return the Last modification time of the theme source.
-        */
-       public long getModificationTime();
-
-       /**
-        * Gets the input stream for the resource with the specified resource id.
-        * 
-        * @param resourceId
-        *            the resource id.
-        * @return Stream where the resource can be read.
-        * @throws ThemeException
-        *             If the resource is not found or there was some problem
-        *             finding the resource.
-        */
-       public InputStream getResource(String resourceId) throws ThemeException;
-
-       /**
-        * Gets the list of themes in the theme source.
-        * 
-        * @return the List of themes included in the theme source.
-        */
-       public Collection getThemes();
-
-       /**
-        * Returns the Theme instance by name.
-        * 
-        * @param name
-        *            the Theme name.
-        * @return the Theme instance matching the name, or null if not found.
-        */
-       public Theme getThemeByName(String name);
-
-       /**
-        * <code>ThemeException</code> is thrown by classes implementing the
-        * <code>ThemeSource</code> interface if some error occurs during
-        * processing.
-        * 
-        * @author IT Mill Ltd.
-        * @version
-        * @VERSION@
-        * @since 3.0
-        */
-       public class ThemeException extends Exception {
-
-               private static final long serialVersionUID = -7823850742197580285L;
-
-               /**
-                * Creates a new theme exception.
-                * 
-                * @param message
-                *            the Error message.
-                */
-               public ThemeException(String message) {
-                       super(message);
-               }
-
-               /**
-                * Creates a new theme exception.
-                * 
-                * @param message
-                *            the error message.
-                * @param cause
-                *            the cause of the exception.
-                */
-               public ThemeException(String message, Throwable cause) {
-                       super(message, cause);
-               }
-       }
-
-       /**
-        * Wrapper class for XSL InputStreams.
-        */
-       public class XSLStream {
-               private String id;
-
-               private InputStream stream;
-
-               /**
-                * 
-                * @param id
-                * @param stream
-                *            the input stream.
-                */
-               public XSLStream(String id, InputStream stream) {
-                       this.id = id;
-                       this.stream = stream;
-               }
-
-               /**
-                * Returns id of this stream.
-                * 
-                * @return the id of the stream.
-                */
-               public String getId() {
-                       return id;
-               }
-
-               /**
-                * Returns the actual XSL Stream.
-                * 
-                * @return the XSL Stream.
-                */
-               public InputStream getStream() {
-                       return stream;
-               }
-
-       }
-}
diff --git a/src/com/itmill/toolkit/terminal/web/UIDLTransformer.java b/src/com/itmill/toolkit/terminal/web/UIDLTransformer.java
deleted file mode 100644 (file)
index 694f068..0000000
+++ /dev/null
@@ -1,670 +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 org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXParseException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.helpers.XMLReaderFactory;
-
-import com.itmill.toolkit.terminal.PaintException;
-
-import java.io.BufferedOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.StringReader;
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.Hashtable;
-import java.util.Iterator;
-
-import javax.xml.transform.sax.SAXSource;
-import javax.xml.transform.stream.StreamResult;
-import javax.xml.transform.ErrorListener;
-import javax.xml.transform.SourceLocator;
-import javax.xml.transform.OutputKeys;
-
-/**
- * Class implementing the UIDLTransformer.
- * 
- * The transformer should not be created directly; it should be contructed using
- * <code>getTransformer</code> provided by <code>UIDLTransformerFactory</code>.
- * 
- * After the transform has been done, the transformer can be recycled with
- * <code>releaseTransformer</code> by <code>UIDLTransformerFactory</code>.
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
-
-public class UIDLTransformer {
-
-       /**
-        * XSLT factory.
-        */
-       protected static javax.xml.transform.TransformerFactory xsltFactory;
-       static {
-               xsltFactory = javax.xml.transform.TransformerFactory.newInstance();
-               if (xsltFactory == null)
-                       throw new RuntimeException("Could not instantiate "
-                                       + "transformer factory. Maybe XSLT processor is "
-                                       + "not included in classpath.");
-       }
-
-       /**
-        * Source of the transform containing UIDL.
-        */
-       private WebPaintTarget paintTarget;
-
-       /**
-        * Holds the type of the transformer.
-        */
-       private UIDLTransformerType transformerType;
-
-       /**
-        * Prepared XSLT transformer for UIDL transformations.
-        */
-       private javax.xml.transform.Transformer uidlTransformer;
-
-       /**
-        * Error handled used.
-        */
-       private TransformerErrorHandler errorHandler;
-
-       /**
-        * Theme repository used for late error reporting.
-        */
-       private ThemeSource themeSource;
-
-       private ApplicationServlet webAdapterServlet;
-
-       /**
-        * UIDLTransformer constructor.
-        * 
-        * @param type
-        *            the Type of the transformer.
-        * @param themes
-        *            the theme implemented by the transformer.
-        * @param webAdapterServlet
-        *            the Adapter servlet.
-        * @throws UIDLTransformerException
-        *             UIDLTransformer exception is thrown, if the transform can not
-        *             be created.
-        */
-       public UIDLTransformer(UIDLTransformerType type, ThemeSource themes,
-                       ApplicationServlet webAdapterServlet)
-                       throws UIDLTransformerException {
-               this.transformerType = type;
-               this.themeSource = themes;
-               this.webAdapterServlet = webAdapterServlet;
-
-               // Registers the error handler
-               errorHandler = new TransformerErrorHandler();
-               xsltFactory.setErrorListener(errorHandler);
-
-               try {
-
-                       // Creates XML Reader to be used by
-                       // XSLReader as the actual parser object.
-                       XMLReader parser = XMLReaderFactory.createXMLReader();
-
-                       // Creates XML reader for concatenating
-                       // multiple XSL files as one.
-
-                       XMLReader xmlReader = new XSLReader(parser, themes.getXSLStreams(
-                                       type.getTheme(), type.getWebBrowser()));
-
-                       xmlReader.setErrorHandler(errorHandler);
-
-                       // Creates own SAXSource using a dummy inputSource.
-                       SAXSource source = new SAXSource(xmlReader, new InputSource());
-                       uidlTransformer = xsltFactory.newTransformer(source);
-
-                       if (uidlTransformer != null) {
-
-                               // Registers transformer error handler
-                               uidlTransformer.setErrorListener(errorHandler);
-
-                               // Ensures HTML output
-                               uidlTransformer.setOutputProperty(OutputKeys.METHOD, "html");
-
-                               // Ensures no indent
-                               uidlTransformer.setOutputProperty(OutputKeys.INDENT, "no");
-                       }
-
-                       // Checks if transform itself failed, meaning either
-                       // UIDL error or error in XSL/T semantics (like XPath)
-                       if (errorHandler.hasFatalErrors()) {
-                               throw new UIDLTransformerException(
-                                               "XSL Transformer creation failed", errorHandler
-                                                               .getFirstFatalError(), errorHandler
-                                                               .getUIDLErrorReport()
-                                                               + "<br /><br />"
-                                                               + errorHandler.getXSLErrorReport(themeSource,
-                                                                               transformerType));
-                       }
-
-               } catch (Exception e) {
-                       // Pass the new XHTML coded error forwards
-                       throw new UIDLTransformerException(e.toString(), e, errorHandler
-                                       .getXSLErrorReport(themeSource, transformerType));
-               }
-       }
-
-       /**
-        * Gets the type of the transformer.
-        * 
-        * @return the Type of the transformer.
-        */
-       public UIDLTransformerType getTransformerType() {
-               return this.transformerType;
-       }
-
-       /**
-        * Attaches the output stream to transformer and get corresponding
-        * UIDLStream for writing UI description language trough transform to given
-        * output.
-        * 
-        * @param variableMap
-        *            the variable map used for UIDL creation.
-        * @return returns UI description language stream, that can be used for
-        *         writing UIDL to transformer.
-        */
-       public WebPaintTarget getPaintTarget(HttpVariableMap variableMap) {
-
-               try {
-                       paintTarget = new WebPaintTarget(variableMap, transformerType,
-                                       webAdapterServlet, transformerType.getTheme());
-               } catch (PaintException e) {
-                       throw new IllegalArgumentException(
-                                       "Failed to instantiate new WebPaintTarget: " + e);
-               }
-               return paintTarget;
-       }
-
-       /**
-        * Resets the transformer, before it can be used again. This also interrupts
-        * any ongoing transform and thus should not be called before the transform
-        * is ready. This is automatically called by the UIDLTransformFactory, when
-        * the UIDLTransformer has been released.
-        * 
-        * @see UIDLTransformerFactory#releaseTransformer(UIDLTransformer)
-        */
-       protected void reset() {
-               if (paintTarget != null) {
-                       try {
-                               paintTarget.close();
-                       } catch (PaintException e) {
-                               // Ignore this exception
-                       }
-                       paintTarget = null;
-               }
-               if (errorHandler != null)
-                       errorHandler.clear();
-       }
-
-       /**
-        * Transforms the UIDL to HTML and output to the OutputStream.
-        * 
-        * @param outputStream
-        *            the output stream to render to.
-        * @throws UIDLTransformerException
-        *             UIDLTransformer exception is thrown, if the transform can not
-        *             be created.
-        */
-       public void transform(OutputStream outputStream)
-                       throws UIDLTransformerException {
-
-               StreamResult result = new StreamResult(new BufferedOutputStream(
-                               outputStream));
-
-               // XSL Transform
-               try {
-                       InputSource uidl = new InputSource(new StringReader(paintTarget
-                                       .getUIDL()));
-                       XMLReader reader = org.xml.sax.helpers.XMLReaderFactory
-                                       .createXMLReader();
-                       reader.setErrorHandler(this.errorHandler);
-
-                       // Validates if requested. We validate the UIDL separately,
-                       // toget the SAXExceptions instead of TransformerExceptions.
-                       // This is required to get the line numbers right.
-                       /*
-                        * FIXME: Disable due abnormalities in DTD handling. if
-                        * (webAdapterServlet.isDebugMode()) { reader.setFeature(
-                        * "http://xml.org/sax/features/validation", true);
-                        * reader.parse(uidl); uidl = new InputSource(new
-                        * StringReader(paintTarget.getUIDL())); }
-                        */
-                       SAXSource source = new SAXSource(reader, uidl);
-
-                       // TODO HTML mode under heavy load provides
-                       // java.net.SocketException: broken pipe
-                       uidlTransformer.transform(source, result);
-               } catch (Exception e) {
-                       // XSL parsing failed. Pass the new XHTML coded error forwards
-                       throw new UIDLTransformerException(e.toString(), e, errorHandler
-                                       .getUIDLErrorReport());
-               }
-
-               // Checks if transform itself failed, meaning either
-               // UIDL error or error in XSL/T semantics (like XPath)
-               if (errorHandler.hasFatalErrors()) {
-                       throw new UIDLTransformerException("UIDL Transform failed",
-                                       errorHandler.getFirstFatalError(), errorHandler
-                                                       .getUIDLErrorReport()
-                                                       + "<br /><br />"
-                                                       + errorHandler.getXSLErrorReport(themeSource,
-                                                                       transformerType));
-               }
-       }
-
-       /**
-        * 
-        * 
-        * 
-        */
-       protected class TransformerErrorHandler implements ErrorListener,
-                       org.xml.sax.ErrorHandler {
-
-               LinkedList errors = new LinkedList();
-
-               LinkedList warnings = new LinkedList();
-
-               LinkedList fatals = new LinkedList();
-
-               Hashtable rowToErrorMap = new Hashtable();
-
-               Hashtable errorToRowMap = new Hashtable();
-
-               /**
-                * 
-                * @return
-                */
-               public boolean hasNoErrors() {
-                       return errors.isEmpty() && warnings.isEmpty() && fatals.isEmpty();
-               }
-
-               /**
-                * 
-                * @return
-                */
-               public boolean hasFatalErrors() {
-                       return !fatals.isEmpty();
-               }
-
-               /**
-                * 
-                * 
-                */
-               public void clear() {
-                       errors.clear();
-                       warnings.clear();
-                       fatals.clear();
-               }
-
-               /**
-                * @see java.lang.Object#toString()
-                */
-               public String toString() {
-                       return getHTMLErrors("Fatal Errors", fatals) + "<br />"
-                                       + getHTMLErrors("Errors", errors) + "<br />"
-                                       + getHTMLErrors("Warnings", warnings) + "<br />";
-               }
-
-               /**
-                * 
-                * @param title
-                * @param l
-                * @return
-                */
-               private String getHTMLErrors(String title, LinkedList l) {
-                       String r = "";
-                       r = "<b>" + title + "</b><br />";
-                       if (l.size() > 0) {
-                               for (Iterator i = l.iterator(); i.hasNext();) {
-                                       Exception e = (Exception) i.next();
-                                       if (e instanceof javax.xml.transform.TransformerException) {
-                                               Integer line = (Integer) errorToRowMap.get(e);
-                                               r += " - "
-                                                               + WebPaintTarget
-                                                                               .escapeXML(((javax.xml.transform.TransformerException) e)
-                                                                                               .getMessage());
-                                               Throwable cause = ((javax.xml.transform.TransformerException) e)
-                                                               .getException();
-
-                                               // Append cause if available
-                                               if (cause != null) {
-                                                       r += ": "
-                                                                       + WebPaintTarget.escapeXML(cause
-                                                                                       .getMessage());
-                                               }
-                                               r += line != null ? " (line:" + line.intValue() + ")"
-                                                               : " (line unknown)";
-                                               r += "<br />\n";
-                                       } else {
-                                               Integer line = (Integer) errorToRowMap.get(e);
-                                               r += " - " + WebPaintTarget.escapeXML(e.toString());
-                                               r += line != null ? " (line:" + line.intValue() + ")"
-                                                               : " (line unknown)";
-                                               r += "<br />\n";
-
-                                       }
-                               }
-                       }
-                       return r;
-               }
-
-               /**
-                * @see javax.xml.transform.ErrorListener#error(TransformerException)
-                */
-               public void error(javax.xml.transform.TransformerException exception) {
-                       if (exception != null) {
-                               errors.addLast(exception);
-                               SourceLocator l = exception.getLocator();
-                               if (l != null) {
-                                       rowToErrorMap.put(new Integer(
-                                                       ((XSLReader.XSLStreamLocator) l).getLineNumber()),
-                                                       exception);
-                                       errorToRowMap.put(exception, new Integer(
-                                                       ((XSLReader.XSLStreamLocator) l).getLineNumber()));
-                               }
-                       }
-               }
-
-               /**
-                * @see javax.xml.transform.ErrorListener#fatalError(TransformerException)
-                */
-               public void fatalError(
-                               javax.xml.transform.TransformerException exception) {
-                       if (exception != null) {
-                               fatals.addLast(exception);
-                               SourceLocator l = exception.getLocator();
-                               if (l != null) {
-                                       rowToErrorMap
-                                                       .put(new Integer(l.getLineNumber()), exception);
-                                       errorToRowMap
-                                                       .put(exception, new Integer(l.getLineNumber()));
-                               }
-                       }
-               }
-
-               /**
-                * @see javax.xml.transform.ErrorListener#warning(TransformerException)
-                */
-               public void warning(javax.xml.transform.TransformerException exception) {
-                       if (exception != null) {
-                               warnings.addLast(exception);
-                               SourceLocator l = exception.getLocator();
-                               if (l != null) {
-                                       rowToErrorMap
-                                                       .put(new Integer(l.getLineNumber()), exception);
-                                       errorToRowMap
-                                                       .put(exception, new Integer(l.getLineNumber()));
-                               }
-                       }
-               }
-
-               /**
-                * Gets the formated error report on XSL.
-                * 
-                * @param themes
-                * @param type
-                */
-               public String getXSLErrorReport(ThemeSource themes,
-                               UIDLTransformerType type) {
-
-                       // Recreates the XSL for error reporting
-                       StringBuffer readBuffer = new StringBuffer();
-                       try {
-                               Collection c = themes.getXSLStreams(type.getTheme(), type
-                                               .getWebBrowser());
-                               for (Iterator i = c.iterator(); i.hasNext();) {
-
-                                       java.io.InputStream is = ((ThemeSource.XSLStream) i.next())
-                                                       .getStream();
-                                       byte[] buffer = new byte[1024];
-                                       int read = 0;
-                                       while ((read = is.read(buffer)) >= 0)
-                                               readBuffer.append(new String(buffer, 0, read));
-                               }
-                       } catch (IOException ignored) {
-
-                       } catch (ThemeSource.ThemeException ignored) {
-
-                       }
-
-                       String xsl = "XSL Source not avaialable";
-                       if (readBuffer != null)
-                               xsl = readBuffer.toString();
-
-                       StringBuffer sb = new StringBuffer();
-
-                       // Print formatted UIDL with errors embedded
-
-                       int row = 0;
-                       int prev = 0;
-                       int index = 0;
-                       int errornro = 0;
-                       boolean lastLineWasEmpty = false;
-
-                       sb.append(toString());
-                       sb
-                                       .append("<font size=\"+1\"><a href=\"#err1\">"
-                                                       + "Go to first error</a></font>"
-                                                       + "<table width=\"100%\" style=\"border-left: 1px solid black; "
-                                                       + "border-right: 1px solid black; border-bottom: "
-                                                       + "1px solid black; border-top: 1px solid black\""
-                                                       + " cellpadding=\"0\" cellspacing=\"0\" border=\"0\"><tr>"
-                                                       + "<th bgcolor=\"#ddddff\" colspan=\"2\">"
-                                                       + "<font size=\"+2\">XSL</font><br />"
-                                                       + "</th></tr>\n");
-
-                       while ((index = xsl.indexOf('\n', prev)) >= 0) {
-                               String line = xsl.substring(prev, index);
-                               prev = index + 1;
-                               row++;
-
-                               Exception exp = (Exception) rowToErrorMap.get(new Integer(row));
-                               line = WebPaintTarget.escapeXML(line);
-                               boolean isEmpty = (line.length() == 0 || line.equals("\r"));
-
-                               // Code beautification : Comment lines
-                               line = xmlHighlight(line);
-
-                               String head = "";
-                               String tail = "";
-
-                               if (exp != null) {
-                                       errornro++;
-                                       head = "<a name=\"err" + String.valueOf(errornro)
-                                                       + "\"><table width=\"100%\">"
-                                                       + "<tr><th bgcolor=\"#ff3030\">"
-                                                       + exp.getLocalizedMessage() + "</th></tr>"
-                                                       + "<tr><td bgcolor=\"#ffcccc\">";
-                                       tail = "</tr><tr><th bgcolor=\"#ff3030\">"
-                                                       + (errornro > 1 ? "<a href=\"#err"
-                                                                       + String.valueOf(errornro - 1)
-                                                                       + "\">Previous error</a>   " : "")
-                                                       + "<a href=\"#err" + String.valueOf(errornro + 1)
-                                                       + "\">Next error</a>" + "</th></tr></table></a>\n";
-                               }
-
-                               if (!(isEmpty && lastLineWasEmpty))
-                                       sb
-                                                       .append("<tr"
-                                                                       + ((row % 10) > 4 ? " bgcolor=\"#eeeeff\""
-                                                                                       : "")
-                                                                       + "><td style=\"border-right: 1px solid gray\">&nbsp;"
-                                                                       + String.valueOf(row) + "&nbsp;</td><td>"
-                                                                       + head + "<nobr>" + line + "</nobr>" + tail
-                                                                       + "</td></tr>\n");
-
-                               lastLineWasEmpty = isEmpty;
-
-                       }
-
-                       sb.append("</table>\n");
-
-                       return sb.toString();
-               }
-
-               /**
-                * Gets the formated error report on UIDL.
-                * 
-                * @return the formatted error report.
-                */
-               public String getUIDLErrorReport() {
-
-                       String uidl = "UIDL Source Not Available.";
-                       if (paintTarget != null)
-                               uidl = paintTarget.getUIDL();
-                       StringBuffer sb = new StringBuffer();
-
-                       // Prints the formatted UIDL with errors embedded
-                       int row = 0;
-                       int prev = 0;
-                       int index = 0;
-                       boolean lastLineWasEmpty = false;
-
-                       // Appends the error report
-                       sb.append(toString());
-
-                       // Appends UIDL
-                       sb
-                                       .append("<table width=\"100%\" style=\"border-left: 1px solid black; "
-                                                       + "border-right: 1px solid black; border-bottom: "
-                                                       + "1px solid black; border-top: 1px solid black\""
-                                                       + " cellpadding=\"0\" cellspacing=\"0\" border=\"0\"><tr>"
-                                                       + "<th bgcolor=\"#ddddff\" colspan=\"2\">"
-                                                       + "<font size=\"+2\">UIDL</font><br />"
-                                                       + "</th></tr>\n");
-
-                       while ((index = uidl.indexOf('\n', prev)) >= 0) {
-                               String line = uidl.substring(prev, index);
-                               prev = index + 1;
-                               row++;
-
-                               line = WebPaintTarget.escapeXML(line);
-                               boolean isEmpty = (line.length() == 0 || line.equals("\r"));
-
-                               // Highlight source
-                               // line = xmlHighlight(line);
-
-                               if (!(isEmpty && lastLineWasEmpty))
-                                       sb
-                                                       .append("<tr"
-                                                                       + ((row % 10) > 4 ? " bgcolor=\"#eeeeff\""
-                                                                                       : "")
-                                                                       + "><td style=\"border-right: 1px solid gray\">&nbsp;"
-                                                                       + String.valueOf(row) + "&nbsp;</td><td>"
-                                                                       + "<nobr>" + line + "</nobr>"
-                                                                       + "</td></tr>\n");
-
-                               lastLineWasEmpty = isEmpty;
-                       }
-
-                       sb.append("</table>\n");
-
-                       return sb.toString();
-               }
-
-               /**
-                * Highlights the XML source.
-                * 
-                * @param xmlSnippet
-                * @return
-                */
-               private String xmlHighlight(String xmlSnippet) {
-                       String res = xmlSnippet;
-
-                       // Code beautification : Comment lines
-                       DebugWindow.replaceAll(res, "&lt;!--",
-                                       "<SPAN STYLE=\"color: #00dd00\">&lt;!--");
-                       res = DebugWindow.replaceAll(res, "--&gt;", "--&gt;</SPAN>");
-
-                       // nbsp instead of blanks
-                       String l = "&nbsp;";
-                       while (res.startsWith(" ")) {
-                               l += "&nbsp;";
-                               res = res.substring(1, res.length());
-                       }
-                       res = l + res;
-
-                       return res;
-               }
-
-               /**
-                * Gets the first fatal error.
-                * 
-                * @return the fatal error.
-                */
-               public Throwable getFirstFatalError() {
-                       return (Throwable) fatals.iterator().next();
-               }
-
-               /**
-                * @see org.xml.sax.ErrorHandler#error(SAXParseException)
-                */
-               public void error(SAXParseException exception) throws SAXException {
-                       errors.addLast(exception);
-                       rowToErrorMap
-                                       .put(new Integer(exception.getLineNumber()), exception);
-                       errorToRowMap
-                                       .put(exception, new Integer(exception.getLineNumber()));
-               }
-
-               /**
-                * @see org.xml.sax.ErrorHandler#fatalError(SAXParseException)
-                */
-               public void fatalError(SAXParseException exception) throws SAXException {
-                       fatals.addLast(exception);
-                       rowToErrorMap
-                                       .put(new Integer(exception.getLineNumber()), exception);
-                       errorToRowMap
-                                       .put(exception, new Integer(exception.getLineNumber()));
-               }
-
-               /**
-                * @see org.xml.sax.ErrorHandler#warning(SAXParseException)
-                */
-               public void warning(SAXParseException exception) throws SAXException {
-                       warnings.addLast(exception);
-                       rowToErrorMap
-                                       .put(new Integer(exception.getLineNumber()), exception);
-                       errorToRowMap
-                                       .put(exception, new Integer(exception.getLineNumber()));
-               }
-
-       }
-
-}
diff --git a/src/com/itmill/toolkit/terminal/web/UIDLTransformerException.java b/src/com/itmill/toolkit/terminal/web/UIDLTransformerException.java
deleted file mode 100644 (file)
index 2aa9c8b..0000000
+++ /dev/null
@@ -1,89 +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;
-
-/**
- * Exception in the transform process.
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
-public class UIDLTransformerException extends java.lang.Exception {
-
-       private static final long serialVersionUID = 5648982356058143223L;
-
-       private String HTMLDescription = null;
-
-       private Throwable transformException = null;
-
-       /**
-        * Creates a new instance of UIDLTransformerException without detail
-        * message.
-        */
-       public UIDLTransformerException() {
-       }
-
-       /**
-        * Constructs an instance of UIDLTransformerException with the specified
-        * detail message.
-        * 
-        * @param msg
-        *            the description of exception that occurred.
-        * @param te
-        *            the Transform exception that occurred.
-        * @param desc
-        *            the detailed description.
-        */
-       public UIDLTransformerException(String msg, Throwable te, String desc) {
-               super(msg);
-               this.transformException = te;
-               this.HTMLDescription = desc;
-       }
-
-       /**
-        * Returns the detailed description.
-        * 
-        * @return the Detailed description of exception.
-        */
-       public String getHTMLDescription() {
-               return HTMLDescription;
-       }
-
-       /**
-        * Returns the nested transform exception that occurred.
-        * 
-        * @return the transform exception
-        */
-       public Throwable getTransformException() {
-               return transformException;
-       }
-
-}
diff --git a/src/com/itmill/toolkit/terminal/web/UIDLTransformerFactory.java b/src/com/itmill/toolkit/terminal/web/UIDLTransformerFactory.java
deleted file mode 100644 (file)
index abaecd7..0000000
+++ /dev/null
@@ -1,347 +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 java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.Map;
-import java.util.Iterator;
-
-/**
- * Class implementing the UIDLTransformer Factory. The factory creates and
- * maintains a pool of transformers that are used for transforming UIDL to HTML.
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
-
-public class UIDLTransformerFactory {
-
-       /**
-        * Time between repository modified queries.
-        */
-       private static final int CACHE_CHECK_INTERVAL_MILLIS = 5 * 1000;
-
-       /**
-        * The time transformers are cached by default.
-        */
-       private static final long DEFAULT_TRANSFORMER_CACHETIME = 60 * 60 * 1000;
-
-       /**
-        * Maximum number of transformers in use.
-        */
-       private int maxConcurrentTransformers = 1;
-
-       /**
-        * Last time theme modification time was checked.
-        */
-       private long lastModificationCheckTime = 0;
-
-       /**
-        * Last time theme source was modified.
-        */
-       private long themeSourceModificationTime = 0;
-
-       /**
-        * How long to cache transformers.
-        */
-       private long cacheTime = DEFAULT_TRANSFORMER_CACHETIME;
-
-       /**
-        * Spool manager thread.
-        */
-       private SpoolManager spoolManager;
-
-       private Map transformerSpool = new HashMap();
-
-       private ThemeSource themeSource;
-
-       private ApplicationServlet webAdapterServlet;
-
-       private int transformerCount = 0;
-
-       private int transformersInUse = 0;
-
-       /**
-        * Constructor for transformer factory. Method UIDLTransformerFactory.
-        * 
-        * @param themeSource
-        *            the Theme source to be used for themes.
-        * @param webAdapterServlet
-        *            the Adapter servlet.
-        * @param maxConcurrentTransformers
-        *            the Maximum number of concurrent themes in use.
-        * @param cacheTime
-        *            the Time to cache the transformers.
-        */
-       public UIDLTransformerFactory(ThemeSource themeSource,
-                       ApplicationServlet webAdapterServlet,
-                       int maxConcurrentTransformers, long cacheTime) {
-               this.webAdapterServlet = webAdapterServlet;
-               if (themeSource == null)
-                       throw new NullPointerException();
-               this.themeSource = themeSource;
-               this.themeSourceModificationTime = themeSource.getModificationTime();
-               this.maxConcurrentTransformers = maxConcurrentTransformers;
-               if (cacheTime >= 0)
-                       this.cacheTime = cacheTime;
-               this.spoolManager = new SpoolManager(this.cacheTime);
-               this.spoolManager.setDaemon(true);
-               // Enable manager only if time > 0
-               if (this.cacheTime > 0)
-                       this.spoolManager.start();
-       }
-
-       /**
-        * Gets the new transformer of the specified type.
-        * 
-        * @param type
-        *            the Type of the requested transformer.
-        * @return Created new transformer.
-        * @throws UIDLTransformerException
-        *             if the transform can not be created.
-        */
-       public synchronized UIDLTransformer getTransformer(UIDLTransformerType type)
-                       throws UIDLTransformerException {
-
-               while (transformersInUse >= maxConcurrentTransformers) {
-                       try {
-                               this.wait();
-                       } catch (InterruptedException e) {
-                               return null;
-                       }
-               }
-
-               // Gets the list of transformers for this type
-               TransformerList list = (TransformerList) this.transformerSpool
-                               .get(type);
-
-               // Checks the modification time between fixed intervals
-               long now = System.currentTimeMillis();
-               if (now - CACHE_CHECK_INTERVAL_MILLIS > this.lastModificationCheckTime) {
-
-                       this.lastModificationCheckTime = now;
-
-                       // Checks if the theme source has been modified and flush
-                       // list if necessary
-                       long lastmod = this.themeSource.getModificationTime();
-                       if (list != null && this.themeSourceModificationTime < lastmod) {
-                               if (webAdapterServlet.isDebugMode(null)) {
-                                       Log.info("Theme source modified since "
-                                                       + new Date(this.themeSourceModificationTime)
-                                                                       .toString() + ". Reloading...");
-                               }
-                               // Force refresh by removing from spool
-                               this.transformerSpool.clear();
-                               list = null;
-                               this.transformerCount = 0;
-                               this.themeSourceModificationTime = lastmod;
-                       }
-               }
-
-               UIDLTransformer t = null;
-
-               if (list != null && !list.isEmpty()) {
-                       // If available, return the first available transformer
-                       t = (UIDLTransformer) list.removeFirst();
-                       if (webAdapterServlet.isDebugMode(null)) {
-                               Log.info("Reserved existing transformer: " + type);
-                       }
-               } else {
-
-                       // Creates the new transformer and return it. Transformers are added
-                       // to
-                       // spool when they are released.
-                       t = new UIDLTransformer(type, themeSource, webAdapterServlet);
-                       transformerCount++;
-                       if (webAdapterServlet.isDebugMode(null)) {
-                               Log.info("Created new transformer (" + transformerCount + "):"
-                                               + type);
-                       }
-
-                       // Creates the new list, if not found
-                       if (list == null) {
-                               list = new TransformerList();
-                               this.transformerSpool.put(type, list);
-                               if (webAdapterServlet.isDebugMode(null)) {
-                                       Log.info("Created new type: " + type);
-                               }
-                       }
-
-               }
-               transformersInUse++;
-               return t;
-       }
-
-       /**
-        * Recycle a used transformer back to spool. One must guarantee not to use
-        * the transformer after it have been released.
-        * 
-        * @param transformer
-        *            the UIDLTransformer to be recycled.
-        */
-       public synchronized void releaseTransformer(UIDLTransformer transformer) {
-
-               try {
-                       // Resets the transformer before returning it to spool
-                       transformer.reset();
-
-                       // Recycle the transformer back to spool
-                       TransformerList list = (TransformerList) this.transformerSpool
-                                       .get(transformer.getTransformerType());
-                       if (list != null) {
-                               list.add(transformer);
-                               if (webAdapterServlet.isDebugMode(null)) {
-                                       Log.info("Released transformer: "
-                                                       + transformer.getTransformerType() + "(In use: "
-                                                       + transformersInUse + ",Spooled: " + list.size()
-                                                       + ")");
-                               }
-                               list.lastUsed = System.currentTimeMillis();
-                       } else {
-                               Log.info("Tried to release non-existing transformer. Ignoring."
-                                               + " (Type:" + transformer.getTransformerType() + ")");
-                       }
-               } finally {
-                       if (transformersInUse > 0)
-                               transformersInUse--;
-                       notifyAll();
-               }
-       }
-
-       /**
-        * 
-        * 
-        * 
-        */
-       private class TransformerList {
-
-               private LinkedList list = new LinkedList();
-
-               private long lastUsed = 0;
-
-               /**
-                * 
-                * @param transformer
-                */
-               public void add(UIDLTransformer transformer) {
-                       list.add(transformer);
-               }
-
-               /**
-                * 
-                * @return
-                */
-               public UIDLTransformer removeFirst() {
-                       return (UIDLTransformer) ((LinkedList) list).removeFirst();
-               }
-
-               /**
-                * 
-                * @return
-                */
-               public boolean isEmpty() {
-                       return list.isEmpty();
-               }
-
-               /**
-                * 
-                * @return
-                */
-               public int size() {
-                       return list.size();
-               }
-       }
-
-       /**
-        * 
-        * 
-        */
-       private synchronized void removeUnusedTransformers() {
-               long currentTime = System.currentTimeMillis();
-               HashSet keys = new HashSet();
-               keys.addAll(this.transformerSpool.keySet());
-               for (Iterator i = keys.iterator(); i.hasNext();) {
-                       UIDLTransformerType type = (UIDLTransformerType) i.next();
-                       TransformerList l = (TransformerList) this.transformerSpool
-                                       .get(type);
-                       if (l != null) {
-                               if (l.lastUsed > 0
-                                               && l.lastUsed < (currentTime - this.cacheTime)) {
-                                       if (webAdapterServlet.isDebugMode(null)) {
-                                               Log.info("Removed transformer: " + type
-                                                               + " Not used since " + new Date(l.lastUsed));
-                                       }
-                                       this.transformerSpool.remove(type);
-                               }
-                       }
-               }
-       }
-
-       /**
-        * Class for periodically remove unused transformers from memory.
-        * 
-        * @author IT Mill Ltd.
-        * @version
-        * @VERSION@
-        * @since 3.0
-        */
-       protected class SpoolManager extends Thread {
-
-               long refreshTime;
-
-               /**
-                * 
-                * @param refreshTime
-                */
-               public SpoolManager(long refreshTime) {
-                       super("UIDLTransformerFactory.SpoolManager");
-                       this.refreshTime = refreshTime;
-               }
-
-               /**
-                * 
-                * @see java.lang.Thread#run()
-                */
-               public void run() {
-                       while (true) {
-                               try {
-                                       sleep(refreshTime);
-                               } catch (Exception e) {
-                               }
-                               removeUnusedTransformers();
-                       }
-               }
-       }
-
-}
diff --git a/src/com/itmill/toolkit/terminal/web/UIDLTransformerType.java b/src/com/itmill/toolkit/terminal/web/UIDLTransformerType.java
deleted file mode 100644 (file)
index 33ef376..0000000
+++ /dev/null
@@ -1,120 +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;
-
-/**
- * Type of the transformer.
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
-public class UIDLTransformerType {
-
-       /**
-        * Holds the value of property webBrowserType.
-        */
-       private WebBrowser webBrowser;
-
-       /**
-        * Holds the value of property theme.
-        */
-       private Theme theme;
-
-       /**
-        * Creates a new instance of TransformerType.
-        * 
-        * @param webBrowserType
-        *            the web browser type.
-        * @param theme
-        *            the property theme.
-        */
-       public UIDLTransformerType(WebBrowser webBrowserType, Theme theme) {
-               if (webBrowserType == null || theme == null)
-                       throw new IllegalArgumentException(
-                                       "WebBrowserType and Theme must be non-null values");
-               this.webBrowser = webBrowserType;
-               this.theme = theme;
-       }
-
-       /**
-        * Returns the hash code for this string.
-        * 
-        * @return the hash code value.
-        */
-       public int hashCode() {
-
-               return this.toString().hashCode();
-       }
-
-       /**
-        * Gets the web browser type used in the UIDLTransformer of this type.
-        * 
-        * @return the Web browser type used.
-        */
-       public WebBrowser getWebBrowser() {
-               return this.webBrowser;
-       }
-
-       /**
-        * Gets the theme used in the UIDLTransformer of this type.
-        * 
-        * @return the Theme used.
-        */
-       public Theme getTheme() {
-               return this.theme;
-       }
-
-       /**
-        * Two types are equal, if their properties are equal.
-        * 
-        * @see java.lang.Object#equals(java.lang.Object)
-        */
-       public boolean equals(Object obj) {
-               // Checks that the object are of the same class
-               if (!(obj.getClass().equals(this.getClass())))
-                       return false;
-
-               // Checks that the properties of the types are equal
-               return this.toString().equals(obj.toString());
-       }
-
-       /**
-        * Textual representation of the UIDLTransformer type.
-        * 
-        * @see java.lang.Object#toString()
-        */
-       public String toString() {
-               return " theme='" + theme.getName() + "' js="
-                               + webBrowser.getJavaScriptVersion() + "' markup='"
-                               + webBrowser.getMarkupVersion() + "'";
-       }
-
-}
diff --git a/src/com/itmill/toolkit/terminal/web/WebApplicationContext.java b/src/com/itmill/toolkit/terminal/web/WebApplicationContext.java
deleted file mode 100644 (file)
index 09a1279..0000000
+++ /dev/null
@@ -1,261 +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 java.io.File;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.WeakHashMap;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpSession;
-
-import com.itmill.toolkit.Application;
-import com.itmill.toolkit.service.ApplicationContext;
-import com.itmill.toolkit.ui.Window;
-
-/**
- * Web application context for the IT Mill Toolkit applications.
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.1
- */
-public class WebApplicationContext implements ApplicationContext {
-
-       private List listeners;
-
-       private HttpSession session;
-
-       private WeakHashMap formActions = new WeakHashMap();
-
-       /**
-        * Creates a new Web Application Context.
-        * 
-        * @param session
-        *            the HTTP session.
-        */
-       WebApplicationContext(HttpSession session) {
-               this.session = session;
-       }
-
-       /**
-        * Gets the form action for given window.
-        * <p>
-        * By default, this action is "", which preserves the current url. Commonly
-        * this is wanted to be set to <code>application.getUrl.toString</code> or
-        * <code>window.getUrl.toString</code> in order to clean any local links
-        * or parameters set from the action.
-        * </p>
-        * 
-        * @param window
-        *            the Window for which the action is queried.
-        * @return the Action to be set into Form action attribute.
-        */
-       public String getWindowFormAction(Window window) {
-               String action = (String) formActions.get(window);
-               return action == null ? "" : action;
-       }
-
-       /**
-        * Sets the form action for given window.
-        * <p>
-        * By default, this action is "", which preserves the current url. Commonly
-        * this is wanted to be set to <code>application.getUrl.toString</code> or
-        * <code>window.getUrl.toString</code> in order to clean any local links
-        * or parameters set from the action.
-        * </p>
-        * 
-        * @param window
-        *            the Window for which the action is set.
-        * @param action
-        *            the New action for the window.
-        */
-       public void setWindowFormAction(Window window, String action) {
-               if (action == null || action == "")
-                       formActions.remove(window);
-               else
-                       formActions.put(window, action);
-       }
-
-       /**
-        * Gets the application context base directory.
-        * 
-        * @see com.itmill.toolkit.service.ApplicationContext#getBaseDirectory()
-        */
-       public File getBaseDirectory() {
-               String realPath = ApplicationServlet.getResourcePath(session
-                               .getServletContext(), "/");
-               if (realPath == null)
-                       return null;
-               return new File(realPath);
-       }
-
-       /**
-        * Gets the http-session application is running in.
-        * 
-        * @return HttpSession this application context resides in.
-        */
-       public HttpSession getHttpSession() {
-               return session;
-       }
-
-       /**
-        * Gets the applications in this context.
-        * 
-        * @see com.itmill.toolkit.service.ApplicationContext#getApplications()
-        */
-       public Collection getApplications() {
-               LinkedList applications = (LinkedList) session
-                               .getAttribute(ApplicationServlet.SESSION_ATTR_APPS);
-
-               return Collections
-                               .unmodifiableCollection(applications == null ? (new LinkedList())
-                                               : applications);
-       }
-
-       /**
-        * Gets the application context for HttpSession.
-        * 
-        * @param session
-        *            the HTTP session.
-        * @return the application context for HttpSession.
-        */
-       static public WebApplicationContext getApplicationContext(
-                       HttpSession session) {
-               return new WebApplicationContext(session);
-       }
-
-       /**
-        * Returns <code>true</code> if and only if the argument is not
-        * <code>null</code> and is a Boolean object that represents the same
-        * boolean value as this object.
-        * 
-        * @param obj
-        *            the object to compare with.
-        * @see java.lang.Object#equals(java.lang.Object)
-        */
-       public boolean equals(Object obj) {
-               return session.equals(obj);
-       }
-
-       /**
-        * Returns the hash code value .
-        * 
-        * @see java.lang.Object#hashCode()
-        */
-       public int hashCode() {
-               return session.hashCode();
-       }
-
-       /**
-        * Adds the transaction listener to this context.
-        * 
-        * @see com.itmill.toolkit.service.ApplicationContext#addTransactionListener(com.itmill.toolkit.service.ApplicationContext.TransactionListener)
-        */
-       public void addTransactionListener(TransactionListener listener) {
-               if (this.listeners == null)
-                       this.listeners = new LinkedList();
-               this.listeners.add(listener);
-       }
-
-       /**
-        * Removes the transaction listener from this context.
-        * 
-        * @see com.itmill.toolkit.service.ApplicationContext#removeTransactionListener(com.itmill.toolkit.service.ApplicationContext.TransactionListener)
-        */
-       public void removeTransactionListener(TransactionListener listener) {
-               if (this.listeners != null)
-                       this.listeners.remove(listener);
-
-       }
-
-       /**
-        * Notifies the transaction start.
-        * 
-        * @param application
-        * @param request
-        *            the HTTP request.
-        */
-       protected void startTransaction(Application application,
-                       HttpServletRequest request) {
-               if (this.listeners == null)
-                       return;
-               for (Iterator i = this.listeners.iterator(); i.hasNext();) {
-                       ((ApplicationContext.TransactionListener) i.next())
-                                       .transactionStart(application, request);
-               }
-       }
-
-       /**
-        * Notifies the transaction end.
-        * 
-        * @param application
-        * @param request
-        *            the HTTP request.
-        */
-       protected void endTransaction(Application application,
-                       HttpServletRequest request) {
-               if (this.listeners == null)
-                       return;
-
-               LinkedList exceptions = null;
-               for (Iterator i = this.listeners.iterator(); i.hasNext();)
-                       try {
-                               ((ApplicationContext.TransactionListener) i.next())
-                                               .transactionEnd(application, request);
-                       } catch (RuntimeException t) {
-                               if (exceptions == null)
-                                       exceptions = new LinkedList();
-                               exceptions.add(t);
-                       }
-
-               // If any runtime exceptions occurred, throw a combined exception
-               if (exceptions != null) {
-                       StringBuffer msg = new StringBuffer();
-                       for (Iterator i = listeners.iterator(); i.hasNext();) {
-                               RuntimeException e = (RuntimeException) i.next();
-                               if (msg.length() == 0)
-                                       msg.append("\n\n--------------------------\n\n");
-                               msg.append(e.getMessage() + "\n");
-                               StringWriter trace = new StringWriter();
-                               e.printStackTrace(new PrintWriter(trace, true));
-                               msg.append(trace.toString());
-                       }
-                       throw new RuntimeException(msg.toString());
-               }
-       }
-
-}
diff --git a/src/com/itmill/toolkit/terminal/web/WebBrowser.java b/src/com/itmill/toolkit/terminal/web/WebBrowser.java
deleted file mode 100644 (file)
index 9351529..0000000
+++ /dev/null
@@ -1,742 +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.terminal.Terminal;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.Locale;
-
-/**
- * Web browser terminal type.
- * 
- * This class implements web browser properties, which declare the features of
- * the web browser.
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
-public class WebBrowser implements Terminal {
-
-       private static WebBrowser DEFAULT = new WebBrowser();
-
-       /**
-        * Content type.
-        */
-       private String contentType = "text/html; charset=utf-8";
-
-       /**
-        * Holds the collection of accepted locales.
-        */
-       private Collection locales = new ArrayList();
-
-       /**
-        * Holds value of property browserApplication.
-        */
-       private String browserApplication = null;
-
-       /**
-        * Should the client side checkking be done.
-        */
-       private boolean performClientCheck = true;
-
-       /**
-        * Holds value for property isClientSideChecked.
-        */
-       private boolean clientSideChecked = false;
-
-       /**
-        * Holds value of property javaScriptVersion.
-        */
-       private JavaScriptVersion javaScriptVersion = JAVASCRIPT_UNCHECKED;
-
-       /**
-        * Holds value of property javaEnabled.
-        */
-       private boolean javaEnabled = false;
-
-       /**
-        * Holds value of property frameSupport.
-        */
-       private boolean frameSupport = false;
-
-       /**
-        * Holds value of property markup version.
-        */
-       private MarkupVersion markupVersion = MARKUP_HTML_3_2;
-
-       /**
-        * Pixel width of the terminal screen.
-        */
-       private int screenWidth = -1;
-
-       /**
-        * Pixel height of the terminal screen.
-        */
-       private int screenHeight = -1;
-
-       private RenderingMode renderingMode = RENDERING_MODE_UNDEFINED;
-
-       /**
-        * Constuctor with some autorecognition capabilities Retrieves all
-        * capability information reported in http request headers:
-        * <ul>
-        * <li>User web browser (User-Agent)</li>
-        * <li>Supported locale(s)</li>
-        * </ul>
-        */
-
-       /**
-        * Constructor WebBrowserType. Creates a default WebBrowserType instance.
-        */
-       public WebBrowser() {
-       }
-
-       /**
-        * Gets the name of the default theme.
-        * 
-        * @return the Name of the terminal window.
-        */
-       public String getDefaultTheme() {
-               return ApplicationServlet.DEFAULT_THEME;
-       }
-
-       /**
-        * Gets the name and version of the web browser application. This is the
-        * version string reported by the web-browser in http headers.
-        * 
-        * @return the Web browser application.
-        */
-       public String getBrowserApplication() {
-               return this.browserApplication;
-       }
-
-       /**
-        * Gets the version of the supported Java Script by the browser.
-        * 
-        * <code>Null</code> if the Java Script is not supported.
-        * 
-        * @return the Version of the supported Java Script.
-        */
-       public JavaScriptVersion getJavaScriptVersion() {
-               return this.javaScriptVersion;
-       }
-
-       /**
-        * Does the browser support frames ?
-        * 
-        * @return <code>true</code> if the browser supports frames, otherwise
-        *         <code>false</code>.
-        */
-       public boolean isFrameSupport() {
-               return this.frameSupport;
-       }
-
-       /**
-        * Sets the browser frame support.
-        * 
-        * @param frameSupport
-        *            True if the browser supports frames, False if not.
-        */
-       public void setFrameSupport(boolean frameSupport) {
-               this.frameSupport = frameSupport;
-       }
-
-       /**
-        * Gets the supported markup language.
-        * 
-        * @return the Supported markup language
-        */
-       public MarkupVersion getMarkupVersion() {
-               return this.markupVersion;
-       }
-
-       /**
-        * Gets the height of the terminal window in pixels.
-        * 
-        * @return the Height of the terminal window.
-        */
-       public int getScreenHeight() {
-               return this.screenHeight;
-       }
-
-       /**
-        * Gets the width of the terminal window in pixels.
-        * 
-        * @return the Width of the terminal window.
-        */
-       public int getScreenWidth() {
-               return this.screenWidth;
-       }
-
-       /**
-        * Gets the default locale requested by the browser.
-        * 
-        * @return the Default locale.
-        */
-       public Locale getDefaultLocale() {
-               if (this.locales.isEmpty())
-                       return null;
-               return (Locale) this.locales.iterator().next();
-       }
-
-       /**
-        * Hash code composed of the properties of the web browser type.
-        * 
-        * @see java.lang.Object#hashCode()
-        */
-       public int hashCode() {
-               return toString().hashCode();
-       }
-
-       /**
-        * Tests the equality of the properties for two web browser types.
-        * 
-        * @see java.lang.Object#equals(java.lang.Object)
-        */
-       public boolean equals(Object obj) {
-               if (obj != null && obj instanceof WebBrowser) {
-                       return toString().equals(obj.toString());
-               }
-               return false;
-       }
-
-       /**
-        * @see java.lang.Object#toString()
-        */
-       public String toString() {
-
-               String localeString = "[";
-               for (Iterator i = this.locales.iterator(); i.hasNext(); localeString += ",") {
-                       localeString += ((Locale) i.next()).toString();
-               }
-               localeString += "]";
-
-               // Returns catenation of the properties
-               return "Browser:" + this.browserApplication + ", " + "Locales:"
-                               + localeString + ", " + "Frames:" + this.frameSupport + ", "
-                               + "JavaScript:" + this.javaScriptVersion + ", " + "Java: "
-                               + this.javaEnabled + ", " + "Markup:" + this.markupVersion
-                               + ", " + "Height:" + this.screenHeight + ", " + "Width:"
-                               + this.screenWidth + ", ClientCheck:" + this.performClientCheck
-                               + ", ClientCheckDone:" + this.clientSideChecked;
-       }
-
-       /**
-        * Gets the preferred content type.
-        * 
-        * @return the content type.
-        */
-       public String getContentType() {
-               return contentType;
-       }
-
-       /**
-        * Checks if this type supports also given browser.
-        * 
-        * @param browser
-        *            the browser type.
-        * @return true if this type matches the given browser.
-        */
-       public boolean supports(String browser) {
-               return this.getBrowserApplication().indexOf(browser) >= 0;
-       }
-
-       /**
-        * Checks if this type supports given markup language version.
-        * 
-        * @param html
-        *            the markup language version.
-        * @return <code>true</ocde> if this type supports the given markup version,otherwise <code>false</code>.
-        */
-       public boolean supports(MarkupVersion html) {
-               return this.getMarkupVersion().supports(html);
-       }
-
-       /**
-        * Checks if this type supports given javascript version.
-        * 
-        * @param js
-        *            the javascript version to check for.
-        * @return true if this type supports the given javascript version.
-        */
-       public boolean supports(JavaScriptVersion js) {
-               return this.getJavaScriptVersion().supports(js);
-       }
-
-       /**
-        * Parses HTML version from string.
-        * 
-        * @param html
-        * @return HTMLVersion instance.
-        */
-       private MarkupVersion doParseHTMLVersion(String html) {
-               for (int i = 0; i < MARKUP_VERSIONS.length; i++) {
-                       if (MARKUP_VERSIONS[i].name.equals(html))
-                               return MARKUP_VERSIONS[i];
-               }
-               return MARKUP_UNKNOWN;
-       }
-
-       /**
-        * Parses JavaScript version from string.
-        * 
-        * @param js
-        *            the javascript version to check for.
-        * @return HTMLVersion instance.
-        */
-       private JavaScriptVersion doParseJavaScriptVersion(String js) {
-               for (int i = 0; i < JAVASCRIPT_VERSIONS.length; i++) {
-                       if (JAVASCRIPT_VERSIONS[i].name.toLowerCase().startsWith(
-                                       js.toLowerCase()))
-                               return JAVASCRIPT_VERSIONS[i];
-               }
-               return JAVASCRIPT_NONE;
-       }
-
-       /**
-        * Parses HTML version from string.
-        * 
-        * @param html
-        * @return the HTMLVersion instance.
-        */
-       public static MarkupVersion parseHTMLVersion(String html) {
-               return DEFAULT.doParseHTMLVersion(html);
-       }
-
-       /**
-        * Parse JavaScript version from string.
-        * 
-        * @param js
-        *            the javascript version to check for.
-        * @return the HTMLVersion instance.
-        */
-       public static JavaScriptVersion parseJavaScriptVersion(String js) {
-               return DEFAULT.doParseJavaScriptVersion(js);
-       }
-
-       /**
-        * Gets the client side cheked property. Certain terminal features can only
-        * be detected at client side. This property indicates if the client side
-        * detections have been performed for this type.
-        * 
-        * @return <code>true</code> if client has sent information about its
-        *         properties. Default is <code>false</code>.
-        */
-       public boolean isClientSideChecked() {
-               return this.clientSideChecked;
-       }
-
-       /**
-        * Sets the client side checked property. Certain terminal features can only
-        * be detected at client side. This property indicates if the client side
-        * detections have been performed for this type.
-        * 
-        * @param value
-        *            true if client has sent information about its properties,
-        *            false otherweise.
-        */
-       public void setClientSideChecked(boolean value) {
-               this.clientSideChecked = value;
-       }
-
-       /**
-        * Should the client features be checked using remote scripts. Should the
-        * client side terminal feature check be performed.
-        * 
-        * @return <code>true</code> if client side checking should be performed
-        *         for this terminal type. Default is <code>false</code>.
-        */
-       public boolean performClientCheck() {
-               return this.performClientCheck;
-       }
-
-       /**
-        * Should the client features be checked using remote scripts.
-        * 
-        * @param value
-        * @return <code>true</code> if client side checking should be performed
-        *         for this terminal type. Default <code>false</code>.
-        */
-       public void performClientCheck(boolean value) {
-               this.performClientCheck = value;
-       }
-
-       /**
-        * Checks if web browser supports Java.
-        * 
-        * @return <code>true<code> if the browser supports java otherwise <code>false</code>.
-        */
-       public boolean isJavaEnabled() {
-               return javaEnabled;
-       }
-
-       /**
-        * Returns the locales supported by the web browser.
-        * 
-        * @return the Collection.
-        */
-       public Collection getLocales() {
-               return locales;
-       }
-
-       /**
-        * Sets the browser application. This corresponds to User-Agent HTTP header.
-        * 
-        * @param browserApplication
-        *            the browserApplication to set.
-        */
-       public void setBrowserApplication(String browserApplication) {
-               this.browserApplication = browserApplication;
-       }
-
-       /**
-        * Sets the default content type. Default is <code>text/html</code>
-        * 
-        * @param contentType
-        *            the contentType to set.
-        */
-       public void setContentType(String contentType) {
-               this.contentType = contentType;
-       }
-
-       /**
-        * Sets the java enabled property.
-        * 
-        * @param javaEnabled
-        *            the javaEnabled to set.
-        */
-       public void setJavaEnabled(boolean javaEnabled) {
-               this.javaEnabled = javaEnabled;
-       }
-
-       /**
-        * Sets the JavaScript version.
-        * 
-        * @param javaScriptVersion
-        *            the JavaScript version to set.
-        */
-       public void setJavaScriptVersion(JavaScriptVersion javaScriptVersion) {
-               this.javaScriptVersion = javaScriptVersion;
-       }
-
-       /**
-        * Sets the markup language version.
-        * 
-        * @param markupVersion
-        *            the markup language version to set.
-        */
-       public void setMarkupVersion(MarkupVersion markupVersion) {
-               this.markupVersion = markupVersion;
-       }
-
-       /**
-        * Sets the screen height.
-        * 
-        * @param screenHeight
-        *            the screen height to set in pixels.
-        */
-       public void setScreenHeight(int screenHeight) {
-               this.screenHeight = screenHeight;
-       }
-
-       /**
-        * Sets the screen width.
-        * 
-        * @param screenWidth
-        *            the screenWidth to set in pixels.
-        */
-       public void setScreenWidth(int screenWidth) {
-               this.screenWidth = screenWidth;
-       }
-
-       /*
-        * Consts defining the supported markup language versions @author IT Mill
-        * Ltd.
-        * 
-        * @version @VERSION@
-        * @since 3.0
-        */
-       public class MarkupVersion {
-               private String name;
-
-               private int order;
-
-               /**
-                * Returns <code>true</code> if and only if the argument is not
-                * <code>null</code> and is a Boolean object that represents the same
-                * boolean value as this object.
-                * 
-                * @param obj
-                *            the object to compare with.
-                * @see java.lang.Object#equals(Object)
-                */
-               public boolean equals(Object obj) {
-                       if (obj != null && obj instanceof MarkupVersion)
-                               return name.equals(((MarkupVersion) obj).name);
-                       return false;
-               }
-
-               /**
-                * @see java.lang.Object#toString()
-                */
-               public String toString() {
-                       return name;
-               }
-
-               /**
-                * 
-                * @param name
-                * @param order
-                */
-               private MarkupVersion(String name, int order) {
-                       this.name = name;
-                       this.order = order;
-               }
-
-               /**
-                * Checks the compability with other HTML version.
-                * 
-                * @param other
-                *            the HTML version.
-                * @return <code>true</code> if this is compatible with the other,
-                *         otherwise <code>false</code>.
-                */
-               public boolean supports(MarkupVersion other) {
-                       return (this.order >= other.order);
-               }
-
-       }
-
-       public static final MarkupVersion MARKUP_UNKNOWN = DEFAULT.new MarkupVersion(
-                       "HTML unknown", 0);
-
-       public static final MarkupVersion MARKUP_HTML_2_0 = DEFAULT.new MarkupVersion(
-                       "HTML 2.0", 20);
-
-       public static final MarkupVersion MARKUP_HTML_3_2 = DEFAULT.new MarkupVersion(
-                       "HTML 3.2", 32);
-
-       public static final MarkupVersion MARKUP_HTML_4_0 = DEFAULT.new MarkupVersion(
-                       "HTML 4.0", 40);
-
-       public static final MarkupVersion MARKUP_XHTML_1_0 = DEFAULT.new MarkupVersion(
-                       "XHTML 1.0", 110);
-
-       public static final MarkupVersion MARKUP_XHTML_2_0 = DEFAULT.new MarkupVersion(
-                       "XHTML 2.0", 120);
-
-       public static final MarkupVersion MARKUP_WML_1_0 = DEFAULT.new MarkupVersion(
-                       "WML 1.0", 10);
-
-       public static final MarkupVersion MARKUP_WML_1_1 = DEFAULT.new MarkupVersion(
-                       "WML 1.1", 11);
-
-       public static final MarkupVersion MARKUP_WML_1_2 = DEFAULT.new MarkupVersion(
-                       "WML 1.2", 12);
-
-       public static final MarkupVersion[] MARKUP_VERSIONS = new MarkupVersion[] {
-                       MARKUP_UNKNOWN, MARKUP_HTML_2_0, MARKUP_HTML_3_2, MARKUP_HTML_4_0,
-                       MARKUP_XHTML_1_0, MARKUP_XHTML_2_0, MARKUP_WML_1_0, MARKUP_WML_1_1,
-                       MARKUP_WML_1_2 };
-
-       /*
-        * Consts defining the supported JavaScript versions @author IT Mill Ltd.
-        * 
-        * @version @VERSION@
-        * @since 3.0
-        */
-       public class JavaScriptVersion {
-               private String name;
-
-               private int order;
-
-               /**
-                * @see java.lang.Object#equals(Object)
-                */
-               public boolean equals(Object obj) {
-                       if (obj != null && obj instanceof JavaScriptVersion)
-                               return name.equals(((JavaScriptVersion) obj).name);
-                       return false;
-               }
-
-               /**
-                * @see java.lang.Object#toString()
-                */
-               public String toString() {
-                       return name;
-               }
-
-               /**
-                * 
-                * @param name
-                * @param order
-                */
-               private JavaScriptVersion(String name, int order) {
-                       this.name = name;
-                       this.order = order;
-               }
-
-               /**
-                * Checks the compability with other JavaScript version. Use this like:
-                * <code>boolean isEcma = someVersion.supports(ECMA_262);</code>
-                * 
-                * @param other
-                *            the java script version.
-                * @return <code>true</code> if this supports the other, otherwise
-                *         <code>false</code>.
-                */
-               public boolean supports(JavaScriptVersion other) {
-
-                       // ECMA-262 support compare
-                       if (other.equals(ECMA_262)) {
-
-                               // JScript over 5.0 support ECMA-262
-                               if (this.order >= 100) {
-                                       return (this.order >= JSCRIPT_5_0.order);
-                               } else {
-                                       return (this.order >= JAVASCRIPT_1_3.order);
-                               }
-                       }
-
-                       // JavaScript version compare
-                       else if (this.order < 100 && other.order < 100) {
-                               return (this.order >= other.order);
-                       }
-
-                       // JScript version compare
-                       else if (this.order >= 100 && other.order >= 100) {
-                               return (this.order >= other.order);
-                       }
-
-                       return false;
-
-               }
-
-       }
-
-       public static final JavaScriptVersion JAVASCRIPT_UNCHECKED = DEFAULT.new JavaScriptVersion(
-                       "JavaScript unchecked", -1);
-
-       public static final JavaScriptVersion JAVASCRIPT_NONE = DEFAULT.new JavaScriptVersion(
-                       "JavaScript none", -1);
-
-       public static final JavaScriptVersion JAVASCRIPT_1_0 = DEFAULT.new JavaScriptVersion(
-                       "JavaScript 1.0", 10);
-
-       public static final JavaScriptVersion JAVASCRIPT_1_1 = DEFAULT.new JavaScriptVersion(
-                       "JavaScript 1.1", 11);
-
-       public static final JavaScriptVersion JAVASCRIPT_1_2 = DEFAULT.new JavaScriptVersion(
-                       "JavaScript 1.2", 12);
-
-       public static final JavaScriptVersion JAVASCRIPT_1_3 = DEFAULT.new JavaScriptVersion(
-                       "JavaScript 1.3", 13);
-
-       public static final JavaScriptVersion JAVASCRIPT_1_4 = DEFAULT.new JavaScriptVersion(
-                       "JavaScript 1.4", 14);
-
-       public static final JavaScriptVersion JAVASCRIPT_1_5 = DEFAULT.new JavaScriptVersion(
-                       "JavaScript 1.5", 15);
-
-       public static final JavaScriptVersion JSCRIPT_1_0 = DEFAULT.new JavaScriptVersion(
-                       "JScript 1.0", 110);
-
-       public static final JavaScriptVersion JSCRIPT_3_0 = DEFAULT.new JavaScriptVersion(
-                       "JScript 3.0", 130);
-
-       public static final JavaScriptVersion JSCRIPT_4_0 = DEFAULT.new JavaScriptVersion(
-                       "JScript 4.0", 140);
-
-       public static final JavaScriptVersion JSCRIPT_5_0 = DEFAULT.new JavaScriptVersion(
-                       "JScript 5.0", 150);
-
-       public static final JavaScriptVersion JSCRIPT_5_1 = DEFAULT.new JavaScriptVersion(
-                       "JScript 5.1", 151);
-
-       public static final JavaScriptVersion JSCRIPT_5_5 = DEFAULT.new JavaScriptVersion(
-                       "JScript 5.5", 155);
-
-       public static final JavaScriptVersion JSCRIPT_5_6 = DEFAULT.new JavaScriptVersion(
-                       "JScript 5.6", 156);
-
-       public static final JavaScriptVersion JSCRIPT_5_7 = DEFAULT.new JavaScriptVersion(
-                       "JScript 5.7", 157);
-
-       public static final JavaScriptVersion ECMA_262 = DEFAULT.new JavaScriptVersion(
-                       "ECMA-262", 262);
-
-       public static final JavaScriptVersion[] JAVASCRIPT_VERSIONS = new JavaScriptVersion[] {
-                       JAVASCRIPT_UNCHECKED, JAVASCRIPT_NONE, JAVASCRIPT_1_0,
-                       JAVASCRIPT_1_1, JAVASCRIPT_1_2, JAVASCRIPT_1_3, JAVASCRIPT_1_4,
-                       JAVASCRIPT_1_5, JSCRIPT_1_0, JSCRIPT_3_0, JSCRIPT_4_0, JSCRIPT_5_0,
-                       JSCRIPT_5_1, JSCRIPT_5_5, JSCRIPT_5_6, JSCRIPT_5_7, ECMA_262 };
-
-       /*
-        * Consts defining the rendering mode @author IT Mill Ltd.
-        * 
-        * @version @VERSION@
-        * @since 4.0
-        */
-       public class RenderingMode {
-               RenderingMode() {
-
-               }
-       }
-
-       public static final RenderingMode RENDERING_MODE_UNDEFINED = DEFAULT.new RenderingMode();
-
-       public static final RenderingMode RENDERING_MODE_HTML = DEFAULT.new RenderingMode();
-
-       public static final RenderingMode RENDERING_MODE_AJAX = DEFAULT.new RenderingMode();
-
-       /**
-        * Gets the current rendering mode.
-        * 
-        * @return the current rendering mode.
-        */
-       public RenderingMode getRenderingMode() {
-               return renderingMode;
-       }
-
-       /**
-        * Sets the current rendering mode.
-        * 
-        * @param renderingMode
-        *            the rendering mode.
-        */
-       public void setRenderingMode(RenderingMode renderingMode) {
-               this.renderingMode = renderingMode;
-       }
-
-}
diff --git a/src/com/itmill/toolkit/terminal/web/WebBrowserProbe.java b/src/com/itmill/toolkit/terminal/web/WebBrowserProbe.java
deleted file mode 100644 (file)
index 76bcd1f..0000000
+++ /dev/null
@@ -1,349 +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 java.util.Collection;
-import java.util.Enumeration;
-import java.util.Map;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpSession;
-
-/**
- * The <code>WebBrowserProbe</code> uses JavaScript to determine the
- * capabilities of the client browser.
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
-public class WebBrowserProbe {
-
-       private static final String WA_NOSCRIPT = "WA_NOSCRIPT";
-
-       private static final String CLIENT_TYPE = "wa_browser";
-
-       /**
-        * Returns the terminal type from the given session.
-        * 
-        * @param session
-        *            the HTTP session.
-        * @return WebBrowser instance for the given session.
-        */
-       public static WebBrowser getTerminalType(HttpSession session) {
-               if (session != null)
-                       return (WebBrowser) session.getAttribute(CLIENT_TYPE);
-               return null;
-       }
-
-       /**
-        * Sets the terminal type for the given session.
-        * 
-        * @param session
-        *            the HTTP session.
-        * @param terminal
-        *            the web browser.
-        * @return WebBrowser instance for the given session.
-        */
-       public static void setTerminalType(HttpSession session, WebBrowser terminal) {
-               if (session != null)
-                       session.setAttribute(CLIENT_TYPE, terminal);
-       }
-
-       /**
-        * Handles the client checking.
-        * 
-        * @param request
-        *            the HTTP request to process.
-        * @param parameters
-        *            the Parameters to be used as defaults.
-        * @return <code>true</code> if response should include a probe
-        *         script,otherwise <code>false</code>.
-        * @throws ServletException
-        *             if an exception has occurred that interferes with the
-        *             servlet's normal operation.
-        */
-       public static boolean handleProbeRequest(HttpServletRequest request,
-                       Map parameters) throws ServletException {
-
-               HttpSession s = request.getSession();
-               WebBrowser browser = getTerminalType(s);
-               if (browser != null) {
-
-                       // Check if no-script was requested
-                       if (parameters.containsKey(WA_NOSCRIPT)) {
-                               String val = ((String[]) parameters.get(WA_NOSCRIPT))[0];
-                               if (val != null && "1".equals(val)) {
-                                       browser.setJavaScriptVersion(WebBrowser.JAVASCRIPT_NONE);
-                                       browser.setClientSideChecked(true);
-                               } else {
-                                       // Recheck
-                                       browser.setClientSideChecked(false);
-                               }
-                       }
-
-                       // If client is alredy checked disable further checking
-                       if (browser.isClientSideChecked())
-                               return false;
-
-               }
-
-               // Creates new type based on client parameters
-               browser = probe(browser, request, parameters);
-               setTerminalType(s, browser);
-
-               // Sets client as checked if parameters were found
-               if (parameters.containsKey("wa_clientprobe")) {
-                       String val = ((String[]) parameters.get("wa_clientprobe"))[0];
-                       browser.setClientSideChecked(val != null && "1".equals(val));
-               }
-
-               // Include probe script if requested and not alredy probed
-               return browser.performClientCheck() && !browser.isClientSideChecked();
-
-       }
-
-       /**
-        * Determines versions based on user agent string.
-        * 
-        * @param agent
-        *            the HTTP User-Agent request header.
-        * @return new WebBrowser instance initialized based on agent features.
-        */
-       public static WebBrowser probe(String agent) {
-               WebBrowser res = new WebBrowser();
-               if (agent == null)
-                       return res;
-
-               // Set the agent string
-               res.setBrowserApplication(agent);
-
-               // Konqueror
-               if (agent.indexOf("Konqueror") >= 0) {
-                       res.setJavaScriptVersion(WebBrowser.JSCRIPT_5_6);
-                       res.setJavaEnabled(true);
-                       res.setFrameSupport(true);
-               }
-
-               // Opera
-               else if (agent.indexOf("Opera 3.") >= 0) {
-                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_1_3);
-                       res.setJavaEnabled(false);
-                       res.setFrameSupport(true);
-               } else if (agent.indexOf("Opera") >= 0) {
-                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_1_3);
-                       res.setJavaEnabled(true);
-                       res.setFrameSupport(true);
-                       res.setMarkupVersion(WebBrowser.MARKUP_HTML_4_0);
-                       if (agent.indexOf("Opera/9") >= 0)
-                               res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_1_5);
-               }
-
-               // OmniWeb
-               else if (agent.indexOf("OmniWeb") >= 0) {
-                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_1_3);
-                       res.setJavaEnabled(true);
-                       res.setFrameSupport(true);
-               }
-
-               // Mosaic
-               else if (agent.indexOf("Mosaic") >= 0) {
-                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_1_3);
-                       res.setJavaEnabled(true);
-                       res.setFrameSupport(true);
-                       res.setMarkupVersion(WebBrowser.MARKUP_HTML_2_0);
-               }
-
-               // Lynx
-               else if (agent.indexOf("Lynx") >= 0) {
-                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_NONE);
-                       res.setJavaEnabled(false);
-                       res.setFrameSupport(true);
-               }
-
-               // Microsoft Browsers
-               // See Microsoft documentation for details:
-               // http://msdn.microsoft.com/library/default.asp?url=/library/
-               // en-us/script56/html/js56jsoriversioninformation.asp
-               else if (agent.indexOf("MSIE 7.") >= 0) {
-                       res.setJavaScriptVersion(WebBrowser.JSCRIPT_5_7);
-                       res.setJavaEnabled(true);
-                       res.setFrameSupport(true);
-                       res.setMarkupVersion(WebBrowser.MARKUP_HTML_4_0);
-               } else if (agent.indexOf("MSIE 6.") >= 0) {
-                       res.setJavaScriptVersion(WebBrowser.JSCRIPT_5_6);
-                       res.setJavaEnabled(true);
-                       res.setFrameSupport(true);
-                       res.setMarkupVersion(WebBrowser.MARKUP_HTML_4_0);
-               } else if (agent.indexOf("MSIE 5.5") >= 0) {
-                       res.setJavaScriptVersion(WebBrowser.JSCRIPT_5_5);
-                       res.setJavaEnabled(true);
-                       res.setFrameSupport(true);
-                       res.setMarkupVersion(WebBrowser.MARKUP_HTML_4_0);
-               } else if (agent.indexOf("MSIE 5.") >= 0) {
-                       res.setJavaScriptVersion(WebBrowser.JSCRIPT_5_0);
-                       res.setJavaEnabled(true);
-                       res.setFrameSupport(true);
-                       res.setMarkupVersion(WebBrowser.MARKUP_HTML_4_0);
-               } else if (agent.indexOf("MSIE 4.") >= 0) {
-                       res.setJavaScriptVersion(WebBrowser.JSCRIPT_3_0);
-                       res.setJavaEnabled(true);
-                       res.setFrameSupport(true);
-                       res.setMarkupVersion(WebBrowser.MARKUP_HTML_4_0);
-               } else if (agent.indexOf("MSIE 3.") >= 0) {
-                       res.setJavaScriptVersion(WebBrowser.JSCRIPT_3_0);
-                       res.setJavaEnabled(true);
-                       res.setFrameSupport(true);
-               } else if (agent.indexOf("MSIE 2.") >= 0) {
-                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_NONE);
-                       res.setJavaEnabled(false);
-                       if (agent.indexOf("Mac") >= 0) {
-                               res.setFrameSupport(true);
-                       } else {
-                               res.setFrameSupport(false);
-                       }
-               }
-
-               // Netscape browsers
-               else if (agent.indexOf("Netscape6") >= 0) {
-                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_1_5);
-                       res.setJavaEnabled(true);
-                       res.setFrameSupport(true);
-                       res.setMarkupVersion(WebBrowser.MARKUP_HTML_4_0);
-               } else if ((agent.indexOf("Mozilla/4.06") >= 0)
-                               || (agent.indexOf("Mozilla/4.7") >= 0)) {
-                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_1_3);
-                       res.setJavaEnabled(true);
-                       res.setFrameSupport(true);
-                       res.setMarkupVersion(WebBrowser.MARKUP_HTML_4_0);
-               } else if (agent.indexOf("Mozilla/4.") >= 0) {
-                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_1_2);
-                       res.setJavaEnabled(true);
-                       res.setFrameSupport(true);
-               } else if (agent.indexOf("Mozilla/3.") >= 0) {
-                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_1_1);
-                       res.setJavaEnabled(true);
-                       res.setFrameSupport(true);
-               } else if (agent.indexOf("Mozilla/2.") >= 0) {
-                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_1_0);
-                       res.setJavaEnabled(true);
-                       res.setFrameSupport(true);
-               }
-
-               // Mozilla Open-Source Browsers
-               else if (agent.indexOf("Mozilla/5.") >= 0) {
-                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_1_5);
-                       res.setJavaEnabled(true);
-                       res.setFrameSupport(true);
-                       res.setMarkupVersion(WebBrowser.MARKUP_HTML_4_0);
-               }
-
-               // Unknown browser
-               else {
-                       res.setJavaScriptVersion(WebBrowser.JAVASCRIPT_UNCHECKED);
-                       res.setJavaEnabled(false);
-                       res.setMarkupVersion(WebBrowser.MARKUP_UNKNOWN);
-                       res.setFrameSupport(false);
-               }
-
-               return res;
-       }
-
-       /**
-        * Creates new instance of WebBrowser by initializing the values based on
-        * user request.
-        * 
-        * @param browser
-        *            the browser to be updated. If null a new instance is created.
-        * @param request
-        *            the Request to be used as defaults.
-        * @param params
-        *            the Parameters to be used as defaults.
-        * @return new WebBrowser instance initialized based on request parameters.
-        */
-       public static WebBrowser probe(WebBrowser browser,
-                       HttpServletRequest request, Map params) {
-
-               // Initialize defaults based on client features
-               WebBrowser res = browser;
-               if (res == null) {
-                       res = probe(request.getHeader("User-Agent"));
-               }
-
-               // Client locales
-               Collection locales = res.getLocales();
-               locales.clear();
-               for (Enumeration e = request.getLocales(); e.hasMoreElements();) {
-                       locales.add(e.nextElement());
-               }
-
-               // Javascript version
-               if (params.containsKey("wa_jsversion")) {
-                       String val = ((String[]) params.get("wa_jsversion"))[0];
-                       if (val != null) {
-                               res
-                                               .setJavaScriptVersion(WebBrowser
-                                                               .parseJavaScriptVersion(val));
-                       }
-               }
-               // Java support
-               if (params.containsKey("wa_javaenabled")) {
-                       String val = ((String[]) params.get("wa_javaenabled"))[0];
-                       if (val != null) {
-                               res.setJavaEnabled(Boolean.valueOf(val).booleanValue());
-                       }
-               }
-               // Screen width
-               if (params.containsKey("wa_screenwidth")) {
-                       String val = ((String[]) params.get("wa_screenwidth"))[0];
-                       if (val != null) {
-                               try {
-                                       res.setScreenWidth(Integer.parseInt(val));
-                               } catch (NumberFormatException e) {
-                                       res.setScreenWidth(-1);
-                               }
-                       }
-               }
-               // Screen height
-               if (params.containsKey("wa_screenheight")) {
-                       String val = ((String[]) params.get("wa_screenheight"))[0];
-                       if (val != null) {
-                               try {
-                                       res.setScreenHeight(Integer.parseInt(val));
-                               } catch (NumberFormatException e) {
-                                       res.setScreenHeight(-1);
-                               }
-                       }
-               }
-
-               return res;
-       }
-}
\ No newline at end of file
diff --git a/src/com/itmill/toolkit/terminal/web/WebPaintTarget.java b/src/com/itmill/toolkit/terminal/web/WebPaintTarget.java
deleted file mode 100644 (file)
index 3b8564a..0000000
+++ /dev/null
@@ -1,734 +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.util.Stack;
-
-/**
- * User Interface Description Language Target.
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
-public class WebPaintTarget implements PaintTarget {
-
-       /* Document type declarations */
-       private final static String UIDL_XML_DECL = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
-
-       /* commonly used tags and argument names */
-       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 StringBuffer uidlBuffer;
-
-       private StringBuffer tagBuffer;
-
-       private HttpVariableMap variableMap;
-
-       private boolean closed = false;
-
-       private ApplicationServlet webAdapterServlet;
-
-       private Theme theme;
-
-       private static final int TAG_BUFFER_DEFAULT_SIZE = 20;
-
-       private boolean mSuppressOutput = false;
-
-       /**
-        * Creates a new XMLPrintWriter, without automatic line flushing.
-        * 
-        * @param out
-        *            A character-output stream.
-        */
-       public WebPaintTarget(HttpVariableMap variableMap,
-                       UIDLTransformerType type, ApplicationServlet webAdapterServlet,
-                       Theme theme) throws PaintException {
-
-               // Host servlet
-               this.webAdapterServlet = webAdapterServlet;
-
-               // Target theme
-               this.theme = theme;
-
-               // Sets the variable map
-               this.variableMap = variableMap;
-
-               // Sets the target for UIDL writing
-               this.uidlBuffer = new StringBuffer();
-
-               // Sets the target for TAG data
-               this.tagBuffer = new StringBuffer();
-
-               // 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("uidl");
-
-               // Name of the active theme
-               this.addAttribute("theme", type.getTheme().getName());
-
-       }
-
-       /**
-        * Ensures that the currently open element tag is closed.
-        */
-       private void ensureClosedTag() {
-               if (mTagArgumentListOpen) {
-                       tagBuffer.append(">");
-                       mTagArgumentListOpen = false;
-                       append(tagBuffer);
-               }
-       }
-
-       /**
-        * Prints 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();
-
-               // 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();
-
-               // Check tagName and attributes here
-               mOpenTags.push(tagName);
-               tagBuffer = new StringBuffer(TAG_BUFFER_DEFAULT_SIZE);
-
-               // Print the tag with attributes
-               tagBuffer.append("<" + tagName);
-
-               mTagArgumentListOpen = true;
-       }
-
-       /**
-        * Prints element end tag.
-        * 
-        * If the parent tag is closed before every child tag is closed a
-        * PaintException is raised.
-        * 
-        * @param tagName
-        *            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();
-
-               // Ensures 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 + "'.");
-
-               // Makes sure that the open start tag is closed before
-               // anything is written.
-               ensureClosedTag();
-
-               // Writes the end (closing) tag
-               append("</" + lastTag + "\n>");
-
-               // NOTE: We re-enable the output (if it has been disabled)
-               // for subsequent tags. The output is suppressed if tag
-               // contains attribute "invisible" with value true.
-               mSuppressOutput = false;
-       }
-
-       /**
-        * Appends data into UIDL output buffer.
-        * 
-        * @param data
-        *            the String to be appended.
-        */
-       private void append(String data) {
-               if (!mSuppressOutput) {
-                       uidlBuffer.append(data);
-               }
-       }
-
-       /**
-        * Appends data into UIDL output buffer.
-        * 
-        * @param data
-        *            the StringBuffer to be appended.
-        */
-       private void append(StringBuffer data) {
-               if (!mSuppressOutput) {
-                       uidlBuffer.append(data);
-               }
-       }
-
-       /**
-        * Substitutes the XML sensitive characters with predefined XML entities.
-        * 
-        * @param xml
-        * @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
-        */
-       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 {
-               if ("invisible".equals(name) && value) {
-                       // NOTE: If we receive the "invisible attribute
-                       // we filter these tags (and ceontent) from
-                       // them out from the output.
-                       this.mSuppressOutput = true;
-               } else {
-                       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) {
-                       addAttribute(name, webAdapterServlet.getResourceLocation(theme
-                                       .getName(), (ThemeResource) value));
-               } else
-                       throw new PaintException("Web 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 (" + name + "="
-                                                       + value + ")");
-
-               // 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.");
-
-               tagBuffer.append(" " + name + "=\"" + escapeXML(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 {
-               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, Object[] 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", (String) 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.
-        * <p>
-        * Prints full text section. The section data is escaped from XML tags and
-        * surrounded by XML start and end-tags.
-        * </p>
-        * 
-        * @param sectionTagName
-        *            the name of the tag.
-        * @param sectionData
-        *            the section data.
-        * @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.
-        * 
-        * @see com.itmill.toolkit.terminal.PaintTarget#addXMLSection(String,
-        *      String, String)
-        */
-       public void addXMLSection(String sectionTagName, String sectionData,
-                       String namespace) throws PaintException {
-
-               // Ensures 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);
-
-               // Closes that starting tag
-               ensureClosedTag();
-
-               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("uidl");
-                       this.closed = true;
-               }
-       }
-
-       /**
-        * Prints element start tag of a paintable section. Starts a paintable
-        * section using the given tag. The PaintTarget may implement a caching
-        * scheme, that checks the paintable has actually changed or can a cached
-        * version be used instead. This method should call the startTag method.
-        * <p>
-        * If the Paintable is found in cache and this function returns true it may
-        * omit the content and close the tag, in which case cached content should
-        * be used.
-        * </p>
-        * <b>Note:</b> Web adapter does not currently implement caching and this
-        * function always returns false.
-        * 
-        * @param paintable
-        *            the paintable to start.
-        * @param tag
-        *            the name of the start tag.
-        * @return false
-        * @throws PaintException
-        *             if the paint operation failed.
-        * @see com.itmill.toolkit.terminal.PaintTarget#startTag(Paintable, String),
-        *      #startTag(String)
-        * @since 3.1
-        */
-       public boolean startTag(Paintable paintable, String tag)
-                       throws PaintException {
-               startTag(tag);
-               return false;
-       }
-
-       /**
-        * Adds CDATA node to target UIDL-tree.
-        * 
-        * @param text
-        *            the Character data to add.
-        * @throws PaintException
-        *             if the paint operation failed.
-        * @since 3.1
-        */
-       public void addCharacterData(String text) throws PaintException {
-               addUIDL("<![CDATA[" + text + "]]>");
-       }
-
-       public void addAttribute(String string, String[] keys) {
-               // TODO Auto-generated method stub
-               
-       }
-
-       public void addAttribute(String string, Object[] keys) {
-               // TODO Auto-generated method stub
-               
-       }
-
-       public void addVariable(VariableOwner owner, String name, String[] value) throws PaintException {
-               // TODO Auto-generated method stub
-               
-       }
-
-}
diff --git a/src/com/itmill/toolkit/terminal/web/XSLReader.java b/src/com/itmill/toolkit/terminal/web/XSLReader.java
deleted file mode 100644 (file)
index 483bd73..0000000
+++ /dev/null
@@ -1,590 +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 java.io.IOException;
-import java.io.InputStream;
-import java.util.Collection;
-import java.util.Iterator;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.DTDHandler;
-import org.xml.sax.EntityResolver;
-import org.xml.sax.ErrorHandler;
-import org.xml.sax.InputSource;
-import org.xml.sax.Locator;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXNotRecognizedException;
-import org.xml.sax.SAXNotSupportedException;
-import org.xml.sax.SAXParseException;
-import org.xml.sax.XMLReader;
-
-/**
- * Class implementing XMLReader for the UIDLTransformer.
- * 
- * @author IT Mill Ltd.
- * @version
- * @VERSION@
- * @since 3.0
- */
-
-public class XSLReader implements XMLReader, ContentHandler {
-
-       static protected final int XSLT_UNKNOWN = 0;
-
-       static protected final int XSLT_XALAN = 1;
-
-       static protected final int XSLT_SAXON6 = 2;
-
-       static protected final int XSLT_SAXON7 = 3;
-
-       static protected final int XSLT_RESIN = 4;
-
-       static protected final int XSLT_WEBLOGIC = 5;
-
-       static protected int xsltProcessor = XSLT_UNKNOWN;
-       static {
-               String transformerName = UIDLTransformer.xsltFactory.getClass()
-                               .getName();
-
-               // Saxon 7.x
-               if ("net.sf.saxon.TransformerFactoryImpl".equals(transformerName))
-                       xsltProcessor = XSLT_SAXON7;
-
-               // Saxon 6.x
-               else if ("com.icl.saxon.TransformerFactoryImpl".equals(transformerName))
-                       xsltProcessor = XSLT_SAXON6;
-
-               // Xalan
-               else if ("org.apache.xalan.processor.TransformerFactoryImpl"
-                               .equals(transformerName)
-                               || "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"
-                                               .equals(transformerName))
-                       xsltProcessor = XSLT_XALAN;
-               // Resin
-               else if ("com.caucho.xsl.Xsl".equals(transformerName))
-                       xsltProcessor = XSLT_RESIN;
-
-               else if ("weblogic.xml.jaxp.RegistrySAXTransformerFactory"
-                               .equals(transformerName))
-                       xsltProcessor = XSLT_WEBLOGIC;
-               else {
-                       throw new RuntimeException(
-                                       "\nThis version of IT Mill Toolkit "
-                                                       + " does not support the selected XSLT-processer:\n  "
-                                                       + transformerName
-                                                       + "\n"
-                                                       + "You can specify the used XSLT processor with JVM "
-                                                       + "parameter like: \n"
-                                                       + "  -Djavax.xml.transform.TransformerFactory=net.sf.saxon.TransformerFactoryImpl\n"
-                                                       + "  -Dorg.xml.sax.driver=org.apache.crimson.parser.XMLReaderImpl\n");
-               }
-       }
-
-       private static final String[] JAVA_PREFIX = { "java://", "millstone://" };
-
-       private Collection streams;
-
-       private boolean startTagHandled = false;
-
-       private String xslNamespace = "";
-
-       private ContentHandler handler;
-
-       private XMLReader reader;
-
-       private XSLStreamLocator locator = null;
-
-       private Locator streamLocator = null;
-
-       private int streamStartLineNumber = 0;
-
-       public XSLReader(XMLReader reader, Collection streams) {
-               this.reader = reader;
-               reader.setContentHandler(this);
-               this.streams = streams;
-       }
-
-       /**
-        * Parses all streams given for constructor parameter. The input parameter
-        * is ignored.
-        * 
-        * @see org.xml.sax.XMLReader#parse(InputSource)
-        */
-       public synchronized void parse(InputSource input) throws IOException,
-                       SAXException {
-
-               startTagHandled = false;
-               handler.startDocument();
-               // Parse all files
-               for (Iterator i = streams.iterator(); i.hasNext();) {
-                       ThemeSource.XSLStream xslStream = (ThemeSource.XSLStream) i.next();
-                       this.locator = new XSLStreamLocator(xslStream.getId());
-                       InputStream in = (xslStream).getStream();
-
-                       // Parse the stream
-                       reader.parse(new InputSource(in));
-
-               }
-               handler.endElement(xslNamespace, "stylesheet", "xsl:stylesheet");
-               handler.endDocument();
-       }
-
-       /**
-        * @see org.xml.sax.ContentHandler#endElement(String, String, String)
-        */
-       public void endElement(String namespaceURI, String localName, String qName)
-                       throws SAXException {
-               if (localName.equals("stylesheet")) {
-                       return; // Skip
-               }
-               handler.endElement(namespaceURI, localName, qName);
-       }
-
-       /**
-        * @see org.xml.sax.ContentHandler#processingInstruction(String, String)
-        */
-       public void processingInstruction(String target, String data)
-                       throws SAXException {
-               handler.processingInstruction(target, data);
-       }
-
-       /**
-        * @see org.xml.sax.ContentHandler#startElement(String, String, String,
-        *      Attributes)
-        */
-       public void startElement(String namespaceURI, String localName,
-                       String qName, Attributes atts) throws SAXException {
-
-               // Only the first stylesheet is used
-               if (startTagHandled && localName.equals("stylesheet"))
-                       return; // skip
-
-               // Get the namespace that will be used for closing the theme
-               if (localName.equals("stylesheet")) {
-                       startTagHandled = true;
-                       this.xslNamespace = namespaceURI;
-
-                       // Manage calls to external functions in XSLT-processor independent
-                       // way, but still using XSLT 1.0
-                       handler.startElement(namespaceURI, localName, qName,
-                                       new AttributeMapper(atts));
-               } else
-
-                       // Handle the element in superclass directly
-                       handler.startElement(namespaceURI, localName, qName, atts);
-       }
-
-       /**
-        * @see org.xml.sax.ContentHandler#characters(char[], int, int)
-        */
-       public void characters(char[] ch, int start, int length)
-                       throws SAXException {
-               handler.characters(ch, start, length);
-       }
-
-       /**
-        * @see org.xml.sax.ContentHandler#startDocument()
-        */
-       public void startDocument() throws SAXException {
-               // Ignore document starts
-       }
-
-       /**
-        * @see org.xml.sax.ContentHandler#endDocument()
-        */
-       public void endDocument() throws SAXException {
-               // Ignore document ends, but add previous line numbers
-               if (this.streamLocator != null) {
-                       this.streamStartLineNumber += this.streamLocator.getLineNumber();
-               }
-       }
-
-       /**
-        * @see org.xml.sax.ContentHandler#endPrefixMapping(String)
-        */
-       public void endPrefixMapping(String prefix) throws SAXException {
-               handler.endPrefixMapping(prefix);
-       }
-
-       /**
-        * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
-        */
-       public void ignorableWhitespace(char[] ch, int start, int length)
-                       throws SAXException {
-               handler.ignorableWhitespace(ch, start, length);
-       }
-
-       /**
-        * @see org.xml.sax.ContentHandler#setDocumentLocator(Locator)
-        */
-       public void setDocumentLocator(Locator locator) {
-               this.streamLocator = locator;
-               // create new locator combined streams/files
-               if (!startTagHandled) {
-                       handler.setDocumentLocator(this.locator);
-               }
-       }
-
-       /**
-        * @see org.xml.sax.ContentHandler#skippedEntity(String)
-        */
-       public void skippedEntity(String name) throws SAXException {
-               handler.skippedEntity(name);
-       }
-
-       /**
-        * @see org.xml.sax.ContentHandler#startPrefixMapping(String, String)
-        */
-       public void startPrefixMapping(String prefix, String uri)
-                       throws SAXException {
-               handler.startPrefixMapping(prefix, uri);
-       }
-
-       /**
-        * Overrides the default content handler.
-        * 
-        * @see org.xml.sax.XMLReader#getContentHandler()
-        */
-       public ContentHandler getContentHandler() {
-               return this.handler;
-       }
-
-       /**
-        * Overrides the default content handler.
-        * 
-        * @see org.xml.sax.XMLReader#setContentHandler(ContentHandler)
-        */
-       public void setContentHandler(ContentHandler handler) {
-               this.handler = handler;
-       }
-
-       /**
-        * @see org.xml.sax.XMLReader#getDTDHandler()
-        */
-       public DTDHandler getDTDHandler() {
-               return reader.getDTDHandler();
-       }
-
-       /**
-        * @see org.xml.sax.XMLReader#getEntityResolver()
-        */
-       public EntityResolver getEntityResolver() {
-               return reader.getEntityResolver();
-       }
-
-       /**
-        * @see org.xml.sax.XMLReader#getErrorHandler()
-        */
-       public ErrorHandler getErrorHandler() {
-               return reader.getErrorHandler();
-       }
-
-       /**
-        * @see org.xml.sax.XMLReader#getFeature(String)
-        */
-       public boolean getFeature(String name) throws SAXNotRecognizedException,
-                       SAXNotSupportedException {
-               return reader.getFeature(name);
-       }
-
-       /**
-        * @see org.xml.sax.XMLReader#getProperty(String)
-        */
-       public Object getProperty(String name) throws SAXNotRecognizedException,
-                       SAXNotSupportedException {
-               return reader.getProperty(name);
-       }
-
-       /**
-        * Overrides the parse.
-        * 
-        * @see org.xml.sax.XMLReader#parse(String)
-        */
-       public void parse(String systemId) throws IOException, SAXException {
-               this.parse((InputSource) null);
-       }
-
-       /**
-        * @see org.xml.sax.XMLReader#setDTDHandler(DTDHandler)
-        */
-       public void setDTDHandler(DTDHandler handler) {
-               reader.setDTDHandler(handler);
-       }
-
-       /**
-        * @see org.xml.sax.XMLReader#setEntityResolver(EntityResolver)
-        */
-       public void setEntityResolver(EntityResolver resolver) {
-               reader.setEntityResolver(resolver);
-       }
-
-       /**
-        * @see org.xml.sax.XMLReader#setErrorHandler(ErrorHandler)
-        */
-       public void setErrorHandler(ErrorHandler handler) {
-               reader.setErrorHandler(new SAXStreamErrorHandler(handler));
-       }
-
-       /**
-        * @see org.xml.sax.XMLReader#setFeature(String, boolean)
-        */
-       public void setFeature(String name, boolean value)
-                       throws SAXNotRecognizedException, SAXNotSupportedException {
-               reader.setFeature(name, value);
-       }
-
-       /**
-        * @see org.xml.sax.XMLReader#setProperty(String, Object)
-        */
-       public void setProperty(String name, Object value)
-                       throws SAXNotRecognizedException, SAXNotSupportedException {
-               reader.setProperty(name, value);
-       }
-
-       public class AttributeMapper implements Attributes {
-
-               private Attributes original;
-
-               /**
-                * 
-                * @param originalAttributes
-                */
-               public AttributeMapper(Attributes originalAttributes) {
-                       original = originalAttributes;
-               }
-
-               /**
-                * @see org.xml.sax.Attributes#getIndex(String, String)
-                */
-               public int getIndex(String uri, String localName) {
-                       return original.getIndex(uri, localName);
-               }
-
-               /**
-                * @see org.xml.sax.Attributes#getIndex(String)
-                */
-               public int getIndex(String qName) {
-                       return original.getIndex(qName);
-               }
-
-               /**
-                * @see org.xml.sax.Attributes#getLength()
-                */
-               public int getLength() {
-                       return original.getLength();
-               }
-
-               /**
-                * @see org.xml.sax.Attributes#getLocalName(int)
-                */
-               public String getLocalName(int index) {
-                       return original.getLocalName(index);
-               }
-
-               /**
-                * @see org.xml.sax.Attributes#getQName(int)
-                */
-               public String getQName(int index) {
-                       return original.getQName(index);
-               }
-
-               /**
-                * @see org.xml.sax.Attributes#getType(int)
-                */
-               public String getType(int index) {
-                       return original.getType(index);
-               }
-
-               /**
-                * @see org.xml.sax.Attributes#getType(String, String)
-                */
-               public String getType(String uri, String localName) {
-                       return original.getType(uri, localName);
-               }
-
-               /**
-                * @see org.xml.sax.Attributes#getType(String)
-                */
-               public String getType(String qName) {
-                       return original.getType(qName);
-               }
-
-               /**
-                * @see org.xml.sax.Attributes#getURI(int)
-                */
-               public String getURI(int index) {
-                       String uri = original.getURI(index);
-
-                       for (int i = 0; i < JAVA_PREFIX.length; i++)
-                               if (uri != null && uri.startsWith(JAVA_PREFIX[i])) {
-
-                                       System.out.print("DEBUG " + uri + " --> ");
-                                       switch (xsltProcessor) {
-                                       case XSLT_SAXON6:
-                                               uri = "saxon://"
-                                                               + uri.substring(JAVA_PREFIX[i].length());
-                                               break;
-                                       case XSLT_SAXON7:
-                                               uri = "saxon://"
-                                                               + uri.substring(JAVA_PREFIX[i].length());
-                                               break;
-                                       case XSLT_XALAN:
-                                               uri = "xalan://"
-                                                               + uri.substring(JAVA_PREFIX[i].length());
-                                               break;
-                                       default:
-                                               uri = "xalan://"
-                                                               + uri.substring(JAVA_PREFIX[i].length());
-                                               break;
-                                       }
-                                       System.out.println(uri);
-                               }
-
-                       return uri;
-               }
-
-               /**
-                * @see org.xml.sax.Attributes#getValue(int)
-                */
-               public String getValue(int index) {
-                       return original.getValue(index);
-               }
-
-               /**
-                * @see org.xml.sax.Attributes#getValue(String, String)
-                */
-               public String getValue(String uri, String localName) {
-                       return original.getValue(uri, localName);
-               }
-
-               /**
-                * @see org.xml.sax.Attributes#getValue(String)
-                */
-               public String getValue(String qName) {
-                       return original.getValue(qName);
-               }
-       }
-
-       public class XSLStreamLocator implements Locator {
-
-               private String id;
-
-               /**
-                * 
-                * @param id
-                */
-               public XSLStreamLocator(String id) {
-                       this.id = id;
-               }
-
-               /**
-                * 
-                * @see org.xml.sax.Locator#getPublicId()
-                */
-               public String getPublicId() {
-                       return streamLocator.getPublicId();
-               }
-
-               /**
-                * 
-                * @see org.xml.sax.Locator#getSystemId()
-                */
-               public String getSystemId() {
-                       return streamLocator.getSystemId() + "" + id;
-               }
-
-               /**
-                * 
-                * @see org.xml.sax.Locator#getLineNumber()
-                */
-               public int getLineNumber() {
-                       return streamLocator.getLineNumber();
-               }
-
-               public int getCombinedLineNumber() {
-                       return streamLocator.getLineNumber() + streamStartLineNumber;
-               }
-
-               /**
-                * @see org.xml.sax.Locator#getColumnNumber()
-                */
-               public int getColumnNumber() {
-                       return streamLocator.getColumnNumber();
-               }
-
-               /**
-                * Gets the id.
-                * 
-                * @return the id .
-                */
-               public String getId() {
-                       return id;
-               }
-       }
-
-       public class SAXStreamErrorHandler implements ErrorHandler {
-
-               private ErrorHandler handler;
-
-               /**
-                * 
-                * @param origHandler
-                */
-               SAXStreamErrorHandler(ErrorHandler origHandler) {
-                       this.handler = origHandler;
-               }
-
-               /**
-                * @see org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException)
-                */
-               public void warning(SAXParseException exception) throws SAXException {
-                       handler.warning(new SAXParseException("" + exception.getMessage()
-                                       + " in " + locator.getId(), locator, exception));
-               }
-
-               /**
-                * @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException)
-                */
-               public void error(SAXParseException exception) throws SAXException {
-                       handler.error(new SAXParseException("" + exception.getMessage()
-                                       + " in " + locator.getId(), locator, exception));
-               }
-
-               /**
-                * @see org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException)
-                */
-               public void fatalError(SAXParseException exception) throws SAXException {
-                       handler.fatalError(new SAXParseException(""
-                                       + exception.getMessage() + " in " + locator.getId(),
-                                       locator, exception));
-               }
-       }
-}
diff --git a/src/com/itmill/toolkit/terminal/web/package.html b/src/com/itmill/toolkit/terminal/web/package.html
deleted file mode 100644 (file)
index 774ad5f..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
-<html>
-<head>
-
-</head>
-
-<body bgcolor="white">
-
-<!-- Package summary here -->
-
-<p>This package implement web terminal for both AJAX-capable and more limited web browsers.</p>
-
-<h2>Package Specification</h2>
-
-<!-- Package spec here -->
-
-<!-- Put @see and @since tags down here. -->
-
-</body>
-</html>