aboutsummaryrefslogtreecommitdiffstats
path: root/src/com/itmill/toolkit/terminal/ajax/VariableMap.java
diff options
context:
space:
mode:
authorJoonas Lehtinen <joonas.lehtinen@itmill.com>2006-12-01 16:58:44 +0000
committerJoonas Lehtinen <joonas.lehtinen@itmill.com>2006-12-01 16:58:44 +0000
commite8ca89433ada2e9b431b61fde647eb3e24053acb (patch)
treedf8a1b5c13d8e7e96858d94ac3cdd96eb34fad9f /src/com/itmill/toolkit/terminal/ajax/VariableMap.java
parent3c853c991a0e7fa81595980e5a7cdd87fd8d149c (diff)
downloadvaadin-framework-e8ca89433ada2e9b431b61fde647eb3e24053acb.tar.gz
vaadin-framework-e8ca89433ada2e9b431b61fde647eb3e24053acb.zip
MERGED AJAX ADAPTER TO WEB ADAPTER
- Merged all functionality of AJAX adapter inside the web adapter (MAJOR step for making the product more understandable) - Removed "Adapter" alltogether from API level (MAJOR step for making the product more understandable) - Built groundwork for automatic terminal detection based selection of technologies - Built groundwork for integration of theme packaging mechanism by allowing Ajax apps to use theme resourses! - Deployment is now easier - it is enough to deploy only one instance of the application - Now AJAX apps also use WebApplicationContext (and get all the features from them!) (should fix bug #93) - Now AJAX apps also can use WebBrowser class that implements Terminal (fixes bug #74) - Now AJAX and Web-apps use the same session -> you can jump from web to ajax and preserve state! (fixes bug #60) - Built groundwork for easier integration of license control (making solving #89 easier) svn changeset:130/svn branch:toolkit
Diffstat (limited to 'src/com/itmill/toolkit/terminal/ajax/VariableMap.java')
-rw-r--r--src/com/itmill/toolkit/terminal/ajax/VariableMap.java732
1 files changed, 0 insertions, 732 deletions
diff --git a/src/com/itmill/toolkit/terminal/ajax/VariableMap.java b/src/com/itmill/toolkit/terminal/ajax/VariableMap.java
deleted file mode 100644
index 54027ef703..0000000000
--- a/src/com/itmill/toolkit/terminal/ajax/VariableMap.java
+++ /dev/null
@@ -1,732 +0,0 @@
-/* *************************************************************************
-
- IT Mill Toolkit
-
- Development of Browser User Intarfaces 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/license.txt. Use of this product might
- require purchasing a commercial license from IT Mill Ltd. For guidelines
- on usage, see license/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.ajax;
-
-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, Joonas Lehtinen
- * @version @VERSION@
- * @since 3.1
- */
-public class VariableMap {
-
-
- // 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;
-
- /** Convert the string to a supported class */
- 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;
- }
- }
-
- /** Register a new variable.
- *
- * @return id to assigned for this variable.
- */
- public String registerVariable(
- String name,
- Class type,
- Object value,
- VariableOwner owner) {
-
- // Check 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) {
-
- // Check 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) {
- // Generate 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 a variable. */
- 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 {
-
- /** Construct 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();
-
- /** Create new parameter container and parse the parameters from the request using
- * GET, POST and POST/MULTIPART parsing
- */
- 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);
- }
- }
-
- }
-
- /** Add parameter to container */
- 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];
- }
-
- // Get the owner
- WeakReference ref = (WeakReference) idToOwnerMap.get(name);
- VariableOwner owner = null;
- if (ref != null)
- owner = (VariableOwner) ref.get();
-
- // Add 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);
- }
-
- // Add the parameter to set of non-variables
- nonVariables.put(name, value);
- }
-
- }
-
- /** Get the set of all parameters connected to given variable owner */
- public Set getParameters(VariableOwner owner) {
- if (owner == null)
- return null;
- return (Set) parameters.get(owner);
- }
-
- /** Get the set of all variable owners owning parameters in this request */
- public Set getOwners() {
- return parameters.keySet();
- }
-
- /** Get the value of a parameter */
- public String[] getValue(String parameterName) {
- return (String[]) values.get(parameterName);
- }
-
- /** Get the servlet multipart parser */
- public ServletMultipartRequest getParser() {
- return parser;
- }
-
- /** Get the name - value[] mapping of non variable paramteres */
- public Map getNonVariables() {
- return nonVariables;
- }
- }
-
- /** Handle all variable changes in this request.
- * @param req Http request to handle
- * @param 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
- */
- public Map handleVariables(
- HttpServletRequest req,
- Terminal.ErrorListener errorListener)
- throws IOException {
-
- // Get the parameters
- ParameterContainer parcon = new ParameterContainer(req);
-
- // Sort listeners to dependency order
- List listeners = getDependencySortedListenerList(parcon.getOwners());
-
- // Handle 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();) {
- // Get the name of the parameter
- String param = (String) pi.next();
- // Extract 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;
-
- 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;
-
- 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;
- }
-
- }
-
- /** Resolve the VariableOwners needed from the request and sort
- * them to assure that the dependencies are met (as well as possible).
- * @return List of variable list changers, that are needed for handling
- * all the variables in the request
- * @param req request to be handled
- * @param parser multipart parser for 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);
- }
- }
- }
-
- // Add 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();
-
- // Add 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);
- }
- }
-
- // Append immediate listeners to normal listeners
- // This way the normal handlers are always called before
- // immediate ones
- resultNormal.addAll(resultImmediate);
- return resultNormal;
- }
-}