\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
\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
\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
\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
\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
\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
\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
\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
\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
\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
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;
--- /dev/null
+/* *************************************************************************
+
+ 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;
+ }
+}
--- /dev/null
+/* *************************************************************************
+
+ 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;
+ }
+}
--- /dev/null
+/* *************************************************************************
+
+ 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]);
+ }
+}
--- /dev/null
+/* *************************************************************************
+
+ 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
--- /dev/null
+/* *************************************************************************
+
+ 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;
+ }
+}
--- /dev/null
+/* *************************************************************************
+
+ 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;
+ }
+}
+++ /dev/null
-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
-
- }
-
-}
--- /dev/null
+/* *************************************************************************
+
+ 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 "&"; // & => &
+ case '>':
+ return ">"; // > => >
+ case '<':
+ return "<"; // < => <
+ case '"':
+ return """; // " => "
+ case '\'':
+ return "'"; // ' => '
+ 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
+
+ }
+
+}
--- /dev/null
+/* *************************************************************************
+
+ 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);
+ }
+}
--- /dev/null
+/* *************************************************************************
+
+ 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 "Content-Type" HTTP header value.
+ * @param intContentLength
+ * the "Content-Length" 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 "Content-Type" HTTP header value.
+ * @param intContentLength
+ * the "Content-Length" 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 "Content-Type" HTTP header value.
+ * @param intContentLength
+ * the "Content-Length" 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 "Content-Type" HTTP header value.
+ * @param intContentLength
+ * the "Content-Length" 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 "Content-Type" HTTP header value.
+ * @param intContentLength
+ * the "Content-Length" 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 "Content-Type" HTTP header value.
+ * @param intContentLength
+ * the "Content-Length" 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();
+ }
+}
--- /dev/null
+/* *************************************************************************
+
+ 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);
+ }
+}
--- /dev/null
+/* *************************************************************************
+
+ 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());
+ }
+ }
+
+}
--- /dev/null
+/* *************************************************************************
+
+ 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 };
+
+}
--- /dev/null
+/* *************************************************************************
+
+ 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
+++ /dev/null
-/* *************************************************************************
-
- 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]);
- }
-}
+++ /dev/null
-/* *************************************************************************
-
- 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;
- }
-}
+++ /dev/null
-/* *************************************************************************
-
- 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 "&"; // & => &
- case '>':
- return ">"; // > => >
- case '<':
- return "<"; // < => <
- case '"':
- return """; // " => "
- case '\'':
- return "'"; // ' => '
- 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
-
- }
-
-}
+++ /dev/null
-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
+++ /dev/null
-/* *************************************************************************
-
- 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;
- }
-}
+++ /dev/null
-/* *************************************************************************
-
- 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 "&"; // & => &
- case '>':
- return ">"; // > => >
- case '<':
- return "<"; // < => <
- case '"':
- return """; // " => "
- case '\'':
- return "'"; // ' => '
- 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
-
- }
-
-}
+++ /dev/null
-/* *************************************************************************
-
- 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
+++ /dev/null
-/* *************************************************************************
-
- 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);
- }
-
-}
+++ /dev/null
-/* *************************************************************************
-
- 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, "<!--",
- "<SPAN STYLE = \"color: #00dd00\"><!--");
- line = replaceAll(line, "-->", "--></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;
- }
-
-}
+++ /dev/null
-/* *************************************************************************
-
- 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;
- }
-
-}
+++ /dev/null
-/* *************************************************************************
-
- 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;
- }
-}
+++ /dev/null
-/* *************************************************************************
-
- 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;
- }
-}
+++ /dev/null
-/* *************************************************************************
-
- 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();
- }
-
- }
-
-}
+++ /dev/null
-/* *************************************************************************
-
- 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);
- }
-}
+++ /dev/null
-/* *************************************************************************
-
- 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 "Content-Type" HTTP header value.
- * @param intContentLength
- * the "Content-Length" 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 "Content-Type" HTTP header value.
- * @param intContentLength
- * the "Content-Length" 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 "Content-Type" HTTP header value.
- * @param intContentLength
- * the "Content-Length" 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 "Content-Type" HTTP header value.
- * @param intContentLength
- * the "Content-Length" 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 "Content-Type" HTTP header value.
- * @param intContentLength
- * the "Content-Length" 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 "Content-Type" HTTP header value.
- * @param intContentLength
- * the "Content-Length" 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();
- }
-}
+++ /dev/null
-/* *************************************************************************
-
- 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);
- }
-}
+++ /dev/null
-/* *************************************************************************
-
- 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();
- }
-
- }
-
-}
+++ /dev/null
-
-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
+++ /dev/null
-/* *************************************************************************
-
- 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;
- }
-
-}
+++ /dev/null
-/* *************************************************************************
-
- 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;
- }
-}
+++ /dev/null
-/* *************************************************************************
-
- 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;
- }
-
- }
-}
+++ /dev/null
-/* *************************************************************************
-
- 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\"> "
- + String.valueOf(row) + " </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\"> "
- + String.valueOf(row) + " </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, "<!--",
- "<SPAN STYLE=\"color: #00dd00\"><!--");
- res = DebugWindow.replaceAll(res, "-->", "--></SPAN>");
-
- // nbsp instead of blanks
- String l = " ";
- while (res.startsWith(" ")) {
- l += " ";
- 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()));
- }
-
- }
-
-}
+++ /dev/null
-/* *************************************************************************
-
- 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;
- }
-
-}
+++ /dev/null
-/* *************************************************************************
-
- 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();
- }
- }
- }
-
-}
+++ /dev/null
-/* *************************************************************************
-
- 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() + "'";
- }
-
-}
+++ /dev/null
-/* *************************************************************************
-
- 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());
- }
- }
-
-}
+++ /dev/null
-/* *************************************************************************
-
- 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;
- }
-
-}
+++ /dev/null
-/* *************************************************************************
-
- 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
+++ /dev/null
-/* *************************************************************************
-
- 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 "&"; // & => &
- case '>':
- return ">"; // > => >
- case '<':
- return "<"; // < => <
- case '"':
- return """; // " => "
- case '\'':
- return "'"; // ' => '
- 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
-
- }
-
-}
+++ /dev/null
-/* *************************************************************************
-
- 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));
- }
- }
-}
+++ /dev/null
-<!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>