aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/com/itmill/toolkit/terminal/ajax/AjaxAdapterServlet.java271
-rw-r--r--src/com/itmill/toolkit/terminal/ajax/AjaxApplicationContext.java204
-rw-r--r--src/com/itmill/toolkit/terminal/ajax/Log.java107
-rw-r--r--src/com/itmill/toolkit/terminal/ajax/MultipartRequest.java1107
-rw-r--r--src/com/itmill/toolkit/terminal/ajax/ServletMultipartRequest.java113
-rw-r--r--src/com/itmill/toolkit/terminal/web/AjaxApplicationManager.java (renamed from src/com/itmill/toolkit/terminal/ajax/ApplicationManager.java)21
-rw-r--r--src/com/itmill/toolkit/terminal/web/AjaxHttpUploadStream.java (renamed from src/com/itmill/toolkit/terminal/ajax/HttpUploadStream.java)6
-rw-r--r--src/com/itmill/toolkit/terminal/web/AjaxPaintTarget.java (renamed from src/com/itmill/toolkit/terminal/ajax/UIDLPaintTarget.java)10
-rw-r--r--src/com/itmill/toolkit/terminal/web/AjaxVariableMap.java (renamed from src/com/itmill/toolkit/terminal/ajax/VariableMap.java)19
-rw-r--r--src/com/itmill/toolkit/terminal/web/ApplicationServlet.java (renamed from src/com/itmill/toolkit/terminal/web/WebAdapterServlet.java)83
-rw-r--r--src/com/itmill/toolkit/terminal/web/DebugWindow.java8
-rw-r--r--src/com/itmill/toolkit/terminal/web/DirectoryThemeSource.java4
-rw-r--r--src/com/itmill/toolkit/terminal/web/JarThemeSource.java4
-rw-r--r--src/com/itmill/toolkit/terminal/web/ServletThemeSource.java4
-rw-r--r--src/com/itmill/toolkit/terminal/web/ThemeFunctionLibrary.java10
-rw-r--r--src/com/itmill/toolkit/terminal/web/UIDLTransformer.java4
-rw-r--r--src/com/itmill/toolkit/terminal/web/UIDLTransformerFactory.java4
-rw-r--r--src/com/itmill/toolkit/terminal/web/WebApplicationContext.java4
-rw-r--r--src/com/itmill/toolkit/terminal/web/WebPaintTarget.java4
-rw-r--r--src/com/itmill/toolkit/terminal/web/XSLReader.java12
20 files changed, 125 insertions, 1874 deletions
diff --git a/src/com/itmill/toolkit/terminal/ajax/AjaxAdapterServlet.java b/src/com/itmill/toolkit/terminal/ajax/AjaxAdapterServlet.java
deleted file mode 100644
index e001d74468..0000000000
--- a/src/com/itmill/toolkit/terminal/ajax/AjaxAdapterServlet.java
+++ /dev/null
@@ -1,271 +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.net.MalformedURLException;
-import java.net.URL;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Properties;
-
-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 com.itmill.toolkit.Application;
-
-/**
- * Servlet implementing connection between a web-browser and Millstone
- * Application.
- *
- * (stage drafting and planning)
- *
- * <h1>Paintable update format</h1>
- *
- * <changes><change pid="271987">... UIDL XML FRAGMENT HERE ... </change>
- * <change pid="271987">... UIDL XML FRAGMENT HERE ... </change> <change
- * pid="271987">... UIDL XML FRAGMENT HERE ... </change> <change format="HTML"
- * paintableId="271987">. <![CDATA[... SERVER SIDE TRANSFORMED HTML HERE ...]]>
- * </change> </changes>
- *
- * In the first phase, no server side-transforms are supported, so the format
- * attribute is omitted and only UIDL supported.
- *
- * <h1>Request parameters</h1>
- *
- * TBD
- *
- * @author IT Mill Ltd, Joonas Lehtinen, Sami Ekblad
- * @version @VERSION@
- * @since 3.1
- */
-public class AjaxAdapterServlet extends HttpServlet {
-
- /**
- * Session attribute, where to find servlet context to
- * AjaxApplicationContext mapping
- */
- private static String SESSION_ATTR_APPLICATION_CONTEXT = "org.millstone.ajaxadapter.AjaxApplicationContext";
-
- private static String SESSION_BINDING_LISTENER = "bindinglistener";
-
- private Class applicationClass;
-
- private Properties applicationProperties;
-
-
-
- /**
- * Called by the servlet container to indicate to a servlet that the servlet
- * is being placed into service.
- *
- * @param servletConfig
- * object containing the servlet's configuration and
- * initialization parameters
- * @throws 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);
-
- // Get the application class name
- String applicationClassName = servletConfig
- .getInitParameter("application");
- if (applicationClassName == null) {
- Log.error("Application not specified in servlet parameters");
- }
-
- // Store 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));
- }
-
- // Override 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));
- }
-
- // Load 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);
- }
- }
-
- private AjaxApplicationContext getAjaxApplicationContext(
- HttpServletRequest request) {
-
- // Get the session
- HttpSession session = request.getSession(true);
-
- // Get the Map
- Map acmap = (Map) session
- .getAttribute(SESSION_ATTR_APPLICATION_CONTEXT);
- if (acmap == null) {
- acmap = new HashMap();
- session.setAttribute(SESSION_ATTR_APPLICATION_CONTEXT, acmap);
- HttpSessionBindingListener sessionBindingListener = new SessionBindingListener(
- acmap);
- session.setAttribute(SESSION_BINDING_LISTENER,
- sessionBindingListener);
-
- }
-
- // Get the application context
- AjaxApplicationContext ac = (AjaxApplicationContext) acmap
- .get(getServletContext());
- if (ac == null) {
- ac = new AjaxApplicationContext(getServletContext());
- acmap.put(getServletContext(), ac);
- }
-
- return ac;
- }
-
- protected void service(HttpServletRequest request,
- HttpServletResponse response) throws ServletException, IOException {
-
- // Get the context
- AjaxApplicationContext context = getAjaxApplicationContext(request);
-
- try {
-
- // Get the application
- Application application = context.getApplication(
- getApplicationUrl(request), request.getContextPath()
- + request.getServletPath());
-
- // Create application if it doesn't exist
- if (application == null)
- application = context.createApplication(applicationClass,
- getApplicationUrl(request), request.getLocale(),
- applicationProperties);
-
- // Notify transaction start
- if (context != null) {
- context.startTransaction(application, request);
- }
-
- // Uidl
- context.getApplicationManager(application).handleXmlHttpRequest(
- request, response);
-
- // Notify transaction end
- if (context != null) {
- context.endTransaction(application, request);
- }
-
- } catch (InstantiationException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
-
- /** Get the current application URL from request */
- private URL getApplicationUrl(HttpServletRequest request) {
-
- URL applicationUrl;
- try {
- URL reqURL = new URL((request.isSecure() ? "https://" : "http://")
- + request.getServerName() + ":" + 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 new RuntimeException("Error constructing application url", e);
- }
-
- return applicationUrl;
- }
-
-
- private class SessionBindingListener implements HttpSessionBindingListener {
- private Map acmap;
- protected SessionBindingListener(Map acmap) {
- this.acmap = acmap;
- }
-
- /**
- * @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
- for (Iterator i = acmap.values().iterator(); i.hasNext();) {
- AjaxApplicationContext actx = (AjaxApplicationContext) i.next();
- actx.close();
- }
- }
- }
-
- }
-
-}
diff --git a/src/com/itmill/toolkit/terminal/ajax/AjaxApplicationContext.java b/src/com/itmill/toolkit/terminal/ajax/AjaxApplicationContext.java
deleted file mode 100644
index 26e6565fff..0000000000
--- a/src/com/itmill/toolkit/terminal/ajax/AjaxApplicationContext.java
+++ /dev/null
@@ -1,204 +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.File;
-import java.net.URL;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Locale;
-import java.util.Properties;
-import java.util.WeakHashMap;
-
-import javax.servlet.ServletContext;
-import javax.servlet.http.HttpServletRequest;
-
-import com.itmill.toolkit.Application;
-import com.itmill.toolkit.service.ApplicationContext;
-
-/** Application context for ajax applications.
- *
- * @author IT Mill Ltd, Joonas Lehtinen
- * @version @VERSION@
- * @since 3.1
- */
-public class AjaxApplicationContext implements ApplicationContext {
-
- private LinkedList applications = new LinkedList();
-
- private ServletContext servletContext;
-
- private LinkedList transactionListeners = new LinkedList();
-
- private WeakHashMap applicationToManagerMap = new WeakHashMap();
-
- AjaxApplicationContext(ServletContext servletContext) {
- this.servletContext = servletContext;
- }
-
- ApplicationManager getApplicationManager(Application application) {
- ApplicationManager vm = (ApplicationManager) applicationToManagerMap
- .get(application);
- if (vm == null) {
- vm = new ApplicationManager(application);
- applicationToManagerMap.put(application, vm);
- }
- return vm;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.itmill.toolkit.service.ApplicationContext#getBaseDirectory()
- */
- public File getBaseDirectory() {
-
- String path = servletContext.getRealPath("/");
- if (path == null)
- return null;
- return new File(path);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.itmill.toolkit.service.ApplicationContext#getApplications()
- */
- public Collection getApplications() {
- return Collections.unmodifiableCollection(applications);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.itmill.toolkit.service.ApplicationContext#addTransactionListener(com.itmill.toolkit.service.ApplicationContext.TransactionListener)
- */
- public void addTransactionListener(TransactionListener listener) {
- transactionListeners.add(listener);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.itmill.toolkit.service.ApplicationContext#removeTransactionListener(com.itmill.toolkit.service.ApplicationContext.TransactionListener)
- */
- public void removeTransactionListener(TransactionListener listener) {
- transactionListeners.remove(listener);
- }
-
- /**
- * Create a new application.
- *
- * @return New application instance
- */
- Application createApplication(Class applicationClass, URL applicationUrl,
- Locale locale, Properties applicationStartProperties)
- throws InstantiationException, IllegalAccessException {
-
- Application application = null;
-
- // Create new application and start it
- try {
- application = (Application) applicationClass.newInstance();
- applications.add(application);
- application.setLocale(locale);
-
- getApplicationManager(application).takeControl();
-
- application.start(applicationUrl, applicationStartProperties, this);
-
- } catch (IllegalAccessException e) {
- Log.error("Illegal access to application class "
- + applicationClass.getName());
- throw e;
- } catch (InstantiationException e) {
- Log.error("Failed to instantiate application class: "
- + applicationClass.getName());
- throw e;
- }
-
- return application;
- }
-
- void removeApplication(Application application) {
- applications.remove(application);
- }
-
- Application getApplication(URL applicationUrl, String servletPath) {
- // 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();
- if (servletPath.length() < aPath.length())
- servletPath += "/";
- if (servletPath.equals(aPath))
- application = a;
- }
-
- // Remove stopped application from the list
- if (application != null && !application.isRunning()) {
- applications.remove(application);
- application = null;
- }
-
- return application;
- }
-
- /** Notify transaction start */
- protected void startTransaction(Application application, HttpServletRequest request) {
- if (this.transactionListeners == null) return;
- for (Iterator i = this.transactionListeners.iterator(); i.hasNext();) {
- ((ApplicationContext.TransactionListener)i.next()).transactionStart(application,request);
- }
- }
-
- /** Notify transaction end */
- protected void endTransaction(Application application, HttpServletRequest request) {
- if (this.transactionListeners == null) return;
- for (Iterator i = this.transactionListeners.iterator(); i.hasNext();) {
- ((ApplicationContext.TransactionListener)i.next()).transactionEnd(application,request);
- }
- }
-
- /** Closes this application context and all applications bound to it.
- *
- */
- public void close() {
- for (Iterator i = this.applications.iterator(); i.hasNext();) {
- Application app = (Application) i.next();
- app.close();
- }
-
- }
-
-}
diff --git a/src/com/itmill/toolkit/terminal/ajax/Log.java b/src/com/itmill/toolkit/terminal/ajax/Log.java
deleted file mode 100644
index 890dd04d5a..0000000000
--- a/src/com/itmill/toolkit/terminal/ajax/Log.java
+++ /dev/null
@@ -1,107 +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;
-
-/** <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.1
- */
-public class Log {
-
- private static String logFilename;
- 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 a <code>warning</code> message.
- *
- * @param message Message <code>String</code> to be logged.
- */
- protected static synchronized void warn(java.lang.String message) {
- if (Log.useStdOut) System.out.println(LOG_MSG_WARN+ " "+message);
- }
- /** Logs a <code>debug</code> message.
- *
- * @param message Message <code>String</code> 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 Message <code>String</code> to be logged.
- */
- protected static synchronized void info(java.lang.String message) {
- if (Log.useStdOut) System.out.println(LOG_MSG_INFO+ " "+message);
- }
-
- /** Logs a Java exception and an accompanying error message.
- *
- * @param message Message <code>String</code> to be logged.
- * @param e 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 an <code>error</code> message.
- *
- * @param message Message <code>String</code> to be logged.
- */
- protected static synchronized void error(java.lang.String message) {
- if (Log.useStdOut) System.out.println(LOG_MSG_ERROR+ " "+message);
- }
-}
diff --git a/src/com/itmill/toolkit/terminal/ajax/MultipartRequest.java b/src/com/itmill/toolkit/terminal/ajax/MultipartRequest.java
deleted file mode 100644
index 48f86606c2..0000000000
--- a/src/com/itmill/toolkit/terminal/ajax/MultipartRequest.java
+++ /dev/null
@@ -1,1107 +0,0 @@
-package com.itmill.toolkit.terminal.ajax;
-
-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 getCharArray() 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 getEncoding() to allow the use of MultipartRequest with a specific encoding type. All instances
- of MultipartRequest will utilise the static charEncoding variable value, that the setEncoding() 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
-{
- /**
- Define 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 MultipartRequest itself, not on any
- instances of MultipartRequest, 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 getEncoding() to convert between bytes and
- strings. If setEncoding() is called by another thread, while the private parse() 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;
- }
- }
-
- /**
- Returns the current encoding method.
- */
- public String getEncoding()
- {
- return charEncoding;
- }
-
- /**
- * Constructor.
- *
- * @param strContentTypeText The &quot;Content-Type&quot; HTTP header value.
- * @param intContentLength The &quot;Content-Length&quot; HTTP header value.
- * @param in The InputStream to read and parse.
- * @param strSaveDirectory The temporary directory to save the file from where they can then be moved to wherever by the
- * calling process. <b>If you specify <u>null</u> for this parameter, then any files uploaded
- * will be silently ignored.</b>
- *
- * @exception IllegalArgumentException If the strContentTypeText does not contain a Content-Type of "multipart/form-data" or the boundary is not found.
- * @exception IOException If the intContentLength is higher than MAX_READ_BYTES or strSaveDirectory is invalid or cannot be written to.
- *
- * @see #MAX_READ_BYTES
- */
- public MultipartRequest(String strContentTypeText,
- int intContentLength,
- InputStream in,
- String strSaveDirectory) throws IllegalArgumentException, IOException
- {
- this(null, strContentTypeText, intContentLength, in, strSaveDirectory, MAX_READ_BYTES);
- }
-
- /**
- * Constructor.
- *
- * @param strContentTypeText The &quot;Content-Type&quot; HTTP header value.
- * @param intContentLength The &quot;Content-Length&quot; HTTP header value.
- * @param in The InputStream to read and parse.
- * @param strSaveDirectory The temporary directory to save the file from where they can then be moved to wherever by the
- * calling process. <b>If you specify <u>null</u> for this parameter, then any files uploaded
- * will be silently ignored.</B>
- * @param intMaxReadBytes Overrides the MAX_BYTES_READ value, to allow arbitrarily long files.
- *
- * @exception IllegalArgumentException If the strContentTypeText does not contain a Content-Type of "multipart/form-data" or the boundary is not found.
- * @exception IOException If the intContentLength is higher than MAX_READ_BYTES or strSaveDirectory is invalid or cannot be written to.
- *
- * @see #MAX_READ_BYTES
- */
- public MultipartRequest(String strContentTypeText,
- int intContentLength,
- InputStream in,
- String strSaveDirectory,
- int intMaxReadBytes) throws IllegalArgumentException, IOException
- {
- this(null, strContentTypeText, intContentLength, in, strSaveDirectory, intMaxReadBytes);
- }
-
- /**
- * Constructor.
- *
- * @param debug A PrintWriter that can be used for debugging.
- * @param strContentTypeText The &quot;Content-Type&quot; HTTP header value.
- * @param intContentLength The &quot;Content-Length&quot; HTTP header value.
- * @param in The InputStream to read and parse.
- * @param strSaveDirectory The temporary directory to save the file from where they can then be moved to wherever by the
- * calling process. <b>If you specify <u>null</u> for this parameter, then any files uploaded
- * will be silently ignored.</B>
- *
- * @exception IllegalArgumentException If the strContentTypeText does not contain a Content-Type of "multipart/form-data" or the boundary is not found.
- * @exception IOException If the intContentLength is higher than MAX_READ_BYTES or strSaveDirectory is invalid or cannot be written to.
- *
- * @see #MAX_READ_BYTES
- * @deprecated Replaced by MultipartRequest(PrintWriter, String, int, InputStream, int)
- * You can specify MultipartRequest.MAX_READ_BYTES for the intMaxReadBytes parameter
- */
- public MultipartRequest(PrintWriter debug,
- String strContentTypeText,
- int intContentLength,
- InputStream in,
- String strSaveDirectory) throws IllegalArgumentException, IOException
- {
- this(debug, strContentTypeText, intContentLength, in, strSaveDirectory, MAX_READ_BYTES);
-
- }
-
- /**
- * Constructor - load into memory constructor
- *
- * @param debug A PrintWriter that can be used for debugging.
- * @param strContentTypeText The &quot;Content-Type&quot; HTTP header value.
- * @param intContentLength The &quot;Content-Length&quot; HTTP header value.
- * @param in The InputStream to read and parse.
- * @param intMaxReadBytes Overrides the MAX_BYTES_READ value, to allow arbitrarily long files.
- *
- * @exception IllegalArgumentException If the strContentTypeText does not contain a Content-Type of "multipart/form-data" or the boundary is not found.
- * @exception IOException If the intContentLength is higher than MAX_READ_BYTES or strSaveDirectory is invalid or cannot be written to.
- *
- * @see #MAX_READ_BYTES
- */
- public MultipartRequest(PrintWriter debug,
- String strContentTypeText,
- int intContentLength,
- InputStream in,
- int intMaxReadBytes) throws IllegalArgumentException, IOException
- {
- this.loadIntoMemory = true;
-
- // Now initialise the object, which will actually call the parse method to parse multipart stream.
- init(debug, strContentTypeText, intContentLength, in, intMaxReadBytes);
- }
-
- /**
- * Constructor.
- *
- * @param debug A PrintWriter that can be used for debugging.
- * @param strContentTypeText The &quot;Content-Type&quot; HTTP header value.
- * @param intContentLength The &quot;Content-Length&quot; HTTP header value.
- * @param in The InputStream to read and parse.
- * @param strSaveDirectory The temporary directory to save the file from where they can then be moved to wherever by the
- * calling process. <b>If you specify <u>null</u> for this parameter, then any files uploaded
- * will be silently ignored.</B>
- * @param intMaxReadBytes Overrides the MAX_BYTES_READ value, to allow arbitrarily long files.
- *
- * @exception IllegalArgumentException If the strContentTypeText does not contain a Content-Type of "multipart/form-data" or the boundary is not found.
- * @exception IOException If the intContentLength is higher than MAX_READ_BYTES or strSaveDirectory is invalid or cannot be written to.
- *
- * @see #MAX_READ_BYTES
- */
- public MultipartRequest(PrintWriter debug,
- String strContentTypeText,
- int intContentLength,
- InputStream in,
- String strSaveDirectory,
- int intMaxReadBytes) throws IllegalArgumentException, IOException
- {
- // IF strSaveDirectory == NULL, then we should ignore any files uploaded.
- if (strSaveDirectory!=null)
- {
- fileOutPutDirectory = new File(strSaveDirectory);
- if (!fileOutPutDirectory.exists())
- throw new IOException("Directory ["+strSaveDirectory+"] is invalid.");
- else if (!fileOutPutDirectory.canWrite())
- throw new IOException("Directory ["+strSaveDirectory+"] is readonly.");
- }
-
- // Now initialise the object, which will actually call the parse method to parse multipart stream.
- init(debug, strContentTypeText, intContentLength, in, intMaxReadBytes);
- }
-
- /**
- * Initialise the parser.
- *
- * @param debug A PrintWriter that can be used for debugging.
- * @param strContentTypeText The &quot;Content-Type&quot; HTTP header value.
- * @param intContentLength The &quot;Content-Length&quot; HTTP header value.
- * @param in The InputStream to read and parse.
- * @param strSaveDirectory The temporary directory to save the file from where they can then be moved to wherever by the
- * calling process. <b>If you specify <u>null</u> for this parameter, then any files uploaded
- * will be silently ignored.</B>
- * @param intMaxReadBytes Overrides the MAX_BYTES_READ value, to allow arbitrarily long files.
- *
- * @exception IllegalArgumentException If the strContentTypeText does not contain a Content-Type of "multipart/form-data" or the boundary is not found.
- * @exception IOException If the intContentLength is higher than MAX_READ_BYTES or strSaveDirectory is invalid or cannot be written to.
- *
- * @see #MAX_READ_BYTES
- */
- private void init(PrintWriter debug,
- String strContentTypeText,
- int intContentLength,
- InputStream in,
- int intMaxReadBytes) throws IllegalArgumentException, IOException
- {
- // save 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;
- }
-
- /**
- Return 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.
- */
- 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);
- }
-
- /**
- Return 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.
- */
- 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();
- }
- }
-
- /**
- An enumeration of all URL Parameters for the current HTTP Request.
- */
- public Enumeration getParameterNames()
- {
- return htParameters.keys();
- }
-
- /**
- This enumeration will return all INPUT TYPE=FILE parameter NAMES as encountered
- during the upload.
- */
- 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.
-
- @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.
-
- @return Returns 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;
- }
-
- /**
- Get the file system basename of an uploaded file.
-
- @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.
-
- @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.
-
- @param strName is the form field name, used to upload the file. This identifies
- the formfield location in the storage facility.
-
- @param strFilename This is the FileSystemName of the file
- @param type What attribute you want from the File Parameter.
- The following types are supported:
- MultipartRequest.FILENAME,
- MultipartRequest.CONTENT_TYPE,
- MultipartRequest.SIZE,
- MultipartRequest.CONTENTS
-
- <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>
-
- @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.
- */
- 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);
- 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.
- */
- 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);
-
- // Add 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.
- */
- 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);
- }
-
- /**
- Read parameters, assume already passed Content-Disposition and blank line.
-
- @return the value read in.
- */
- 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.
- */
- 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)
- {
- // Write 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);
- // Update file size.
- fileSize+=actualLength;
- }
- }
- break;
- }
- else
- {
- // Write 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);
- // Update 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;
- }
- }
- }
-
- //Return the number of bytes written to outstream.
- return fileSize;
- }
-
- /**
- Read 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.
-
- @exception IOException if an error occurs writing the file.
-
- @return the number of bytes read.
- */
- private long readAndWriteFile(InputStream in, String strFilename) throws IOException
- {
- // Store 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();
- // Delete 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 strName - Url parameter this file was loaded under.
- * @return contents of file, from which you can garner the size as well.
- */
- 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;
- }
-
- /**
- Returns the length of the line minus line ending.
-
- @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.
- */
- 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;
- }
-
- 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.
-
- @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.
- */
- 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.
-
- Returns 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;
- }
-
- /**
- trimQuotes trims any quotes from the start and end of a string and returns the trimmed string...
- */
- private static final String trimQuotes (String strItem)
- {
- // Saves having to go any further....
- if (strItem==null || strItem.indexOf("\"")==-1)
- return strItem;
-
- // Get 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.
- */
- 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 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
- *
- * @exception 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;
- }
-
- /**
- Use when debugging this object.
- */
- protected void debug(String x)
- {
- if (debug!=null)
- {
- debug.println(x);
- debug.flush();
- }
- }
-
- /**
- For debugging.
- */
- public String getHtmlTable()
- {
- StringBuffer sbReturn = new StringBuffer();
-
- sbReturn.append("<h2>Parameters</h2>");
- sbReturn.append("\n<table border=3><tr><td><b>Name</b></td><td><b>Value</b></td></tr>");
- for (Enumeration e = getParameterNames() ; e.hasMoreElements() ;)
- {
- String strName = (String) e.nextElement();
- sbReturn.append("\n<tr>" +
- "<td>" + strName + "</td>");
-
- sbReturn.append("<td><table border=1><tr>");
- for (Enumeration f = getURLParameters(strName); f.hasMoreElements() ;)
- {
- String value = (String)f.nextElement();
- sbReturn.append("<td>"+value+"</td>");
- }
- sbReturn.append("</tr></table></td></tr>");
- }
- sbReturn.append("</table>");
-
- sbReturn.append("<h2>File Parameters</h2>");
-
- sbReturn.append("\n<table border=2><tr><td><b>Name</b></td><td><b>Filename</b></td><td><b>Path</b></td><td><b>Content Type</b></td><td><b>Size</b></td></tr>");
- for (Enumeration e = getFileParameterNames() ; e.hasMoreElements() ;)
- {
- String strName = (String) e.nextElement();
-
- sbReturn.append("\n<tr>" +
- "<td>" + strName + "</td>" +
- "<td>" + (getFileSystemName(strName)!=null?getFileSystemName(strName):"") + "</td>");
-
- if (loadIntoMemory)
- sbReturn.append("<td>" + (getFileSize(strName)>0?"<i>in memory</i>":"") + "</td>");
- else
- sbReturn.append("<td>" + (getFile(strName)!=null?getFile(strName).getAbsolutePath():"") + "</td>");
-
- sbReturn.append("<td>" + (getContentType(strName)!=null?getContentType(strName):"") + "</td>" +
- "<td>" + (getFileSize(strName)!=-1?getFileSize(strName)+"":"") + "</td>" +
- "</tr>");
- }
- sbReturn.append("</table>");
-
- return sbReturn.toString();
- }
-}
diff --git a/src/com/itmill/toolkit/terminal/ajax/ServletMultipartRequest.java b/src/com/itmill/toolkit/terminal/ajax/ServletMultipartRequest.java
deleted file mode 100644
index 54dc518ffd..0000000000
--- a/src/com/itmill/toolkit/terminal/ajax/ServletMultipartRequest.java
+++ /dev/null
@@ -1,113 +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 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 lenght 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>
- *
- * @exception IllegalArgumentException If the request.getContentType() does not contain a Content-Type of "multipart/form-data" or the boundary is not found.
- * @exception 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 lenght 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.
- *
- * @exception IllegalArgumentException If the request.getContentType() does not contain a Content-Type of "multipart/form-data" or the boundary is not found.
- * @exception 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.
- *
- * @exception IllegalArgumentException If the request.getContentType() does not contain a Content-Type of "multipart/form-data" or the boundary is not found.
- * @exception IOException If the request.getContentLength() is higher than MAX_READ_BYTES or strSaveDirectory is invalid or cannot be written to.
- *
- * @see MultipartRequest#MAX_READ_BYTES
- */
- public ServletMultipartRequest(HttpServletRequest request, int intMaxReadBytes) throws IllegalArgumentException, IOException
- {
- super(null,
- request.getContentType(),
- request.getContentLength(),
- request.getInputStream(),
- intMaxReadBytes);
- }
-}
diff --git a/src/com/itmill/toolkit/terminal/ajax/ApplicationManager.java b/src/com/itmill/toolkit/terminal/web/AjaxApplicationManager.java
index 403d6721eb..d54a824e80 100644
--- a/src/com/itmill/toolkit/terminal/ajax/ApplicationManager.java
+++ b/src/com/itmill/toolkit/terminal/web/AjaxApplicationManager.java
@@ -26,7 +26,7 @@
********************************************************************** */
-package com.itmill.toolkit.terminal.ajax;
+package com.itmill.toolkit.terminal.web;
import java.io.IOException;
import java.io.InputStream;
@@ -66,7 +66,7 @@ import com.itmill.toolkit.ui.Window;
* @version @VERSION@
* @since 3.1
*/
-public class ApplicationManager implements Paintable.RepaintRequestListener,
+public class AjaxApplicationManager implements Paintable.RepaintRequestListener,
Application.WindowAttachListener, Application.WindowDetachListener {
private static String GET_PARAM_VARIABLE_CHANGES = "changeVariables";
@@ -91,17 +91,17 @@ public class ApplicationManager implements Paintable.RepaintRequestListener,
private Set removedWindows = new HashSet();
- private UIDLPaintTarget paintTarget;
+ private AjaxPaintTarget paintTarget;
- public ApplicationManager(Application application) {
+ public AjaxApplicationManager(Application application) {
this.application = application;
}
- private VariableMap getVariableMap() {
- VariableMap vm = (VariableMap) applicationToVariableMapMap
+ private AjaxVariableMap getVariableMap() {
+ AjaxVariableMap vm = (AjaxVariableMap) applicationToVariableMapMap
.get(application);
if (vm == null) {
- vm = new VariableMap();
+ vm = new AjaxVariableMap();
applicationToVariableMapMap.put(application, vm);
}
return vm;
@@ -169,7 +169,7 @@ public class ApplicationManager implements Paintable.RepaintRequestListener,
// Set the response type
response.setContentType("application/xml; charset=UTF-8");
- paintTarget = new UIDLPaintTarget(
+ paintTarget = new AjaxPaintTarget(
getVariableMap(), this, out);
// Render the removed windows
@@ -464,11 +464,6 @@ public class ApplicationManager implements Paintable.RepaintRequestListener,
if (logoutUrl == null)
logoutUrl = application.getURL().toString();
- AjaxApplicationContext context = (AjaxApplicationContext) application
- .getContext();
- if (context != null)
- context.removeApplication(application);
-
response.sendRedirect(response.encodeRedirectURL(logoutUrl));
}
diff --git a/src/com/itmill/toolkit/terminal/ajax/HttpUploadStream.java b/src/com/itmill/toolkit/terminal/web/AjaxHttpUploadStream.java
index e76179d5c2..c798002ba9 100644
--- a/src/com/itmill/toolkit/terminal/ajax/HttpUploadStream.java
+++ b/src/com/itmill/toolkit/terminal/web/AjaxHttpUploadStream.java
@@ -26,7 +26,7 @@
********************************************************************** */
-package com.itmill.toolkit.terminal.ajax;
+package com.itmill.toolkit.terminal.web;
import java.io.InputStream;
@@ -36,7 +36,7 @@ import java.io.InputStream;
* @version @VERSION@
* @since 3.1
*/
-public class HttpUploadStream
+public class AjaxHttpUploadStream
implements com.itmill.toolkit.terminal.UploadStream {
/** Holds value of property variableName. */
@@ -56,7 +56,7 @@ public class HttpUploadStream
* (for parallel events (for example in
* same http request), times are equal)
*/
- public HttpUploadStream(
+ public AjaxHttpUploadStream(
String name,
InputStream stream,
String contentName,
diff --git a/src/com/itmill/toolkit/terminal/ajax/UIDLPaintTarget.java b/src/com/itmill/toolkit/terminal/web/AjaxPaintTarget.java
index 69fc162b01..5d5598bb40 100644
--- a/src/com/itmill/toolkit/terminal/ajax/UIDLPaintTarget.java
+++ b/src/com/itmill/toolkit/terminal/web/AjaxPaintTarget.java
@@ -26,7 +26,7 @@
********************************************************************** */
-package com.itmill.toolkit.terminal.ajax;
+package com.itmill.toolkit.terminal.web;
import com.itmill.toolkit.Application;
import com.itmill.toolkit.terminal.ApplicationResource;
@@ -54,7 +54,7 @@ import java.util.Stack;
* @VERSION@
* @since 3.1
*/
-public class UIDLPaintTarget implements PaintTarget {
+public class AjaxPaintTarget implements PaintTarget {
/* Document type declarations */
private final static String UIDL_XML_DECL = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
@@ -78,13 +78,13 @@ public class UIDLPaintTarget implements PaintTarget {
private PrintWriter uidlBuffer;
- private VariableMap variableMap;
+ private AjaxVariableMap variableMap;
private boolean closed = false;
private OutputStream output;
- private ApplicationManager manager;
+ private AjaxApplicationManager manager;
private String paintableId;
@@ -99,7 +99,7 @@ public class UIDLPaintTarget implements PaintTarget {
* @param out
* A character-output stream.
*/
- public UIDLPaintTarget(VariableMap variableMap, ApplicationManager manager,
+ public AjaxPaintTarget(AjaxVariableMap variableMap, AjaxApplicationManager manager,
OutputStream output) throws PaintException {
// Set the cache
diff --git a/src/com/itmill/toolkit/terminal/ajax/VariableMap.java b/src/com/itmill/toolkit/terminal/web/AjaxVariableMap.java
index 54027ef703..2751c9b2bf 100644
--- a/src/com/itmill/toolkit/terminal/ajax/VariableMap.java
+++ b/src/com/itmill/toolkit/terminal/web/AjaxVariableMap.java
@@ -26,7 +26,7 @@
********************************************************************** */
-package com.itmill.toolkit.terminal.ajax;
+package com.itmill.toolkit.terminal.web;
import java.io.IOException;
import java.lang.ref.WeakReference;
@@ -56,7 +56,7 @@ import com.itmill.toolkit.terminal.VariableOwner;
* @version @VERSION@
* @since 3.1
*/
-public class VariableMap {
+public class AjaxVariableMap {
// Id <-> (Owner,Name) mapping
@@ -474,7 +474,8 @@ public class VariableMap {
Class varType = (Class) idToTypeMap.get(param);
Object varOldValue = idToValueMap.get(param);
if (varName == null || varType == null)
- Log.warn(
+ // TODO Remove this?
+ System.err.println(
"VariableMap: No variable found for parameter "
+ param
+ " ("
@@ -502,7 +503,7 @@ public class VariableMap {
param,
MultipartRequest.CONTENT_TYPE);
UploadStream upload =
- new HttpUploadStream(
+ new AjaxHttpUploadStream(
varName,
parser.getFileContents(param),
filename,
@@ -546,7 +547,8 @@ public class VariableMap {
changed
|= (!val.equals(varOldValue));
} else {
- Log.warn(
+ // TODO Remove this?
+ System.err.println(
"Empty variable '"
+ varName
+ "' of type "
@@ -554,9 +556,10 @@ public class VariableMap {
}
} catch (java.lang.ClassCastException e) {
- Log.except(
- "WebVariableMap conversion exception",
- e);
+ // TODO Remove this?
+ System.err.println(
+ "WebVariableMap conversion exception");
+ e.printStackTrace(System.err);
errorListener.terminalError(
new TerminalErrorImpl(e));
}
diff --git a/src/com/itmill/toolkit/terminal/web/WebAdapterServlet.java b/src/com/itmill/toolkit/terminal/web/ApplicationServlet.java
index 890bd63b43..15ce3f10f0 100644
--- a/src/com/itmill/toolkit/terminal/web/WebAdapterServlet.java
+++ b/src/com/itmill/toolkit/terminal/web/ApplicationServlet.java
@@ -89,16 +89,17 @@ import com.itmill.toolkit.ui.Window;
* @since 3.0
*/
-public class WebAdapterServlet extends HttpServlet
+public class ApplicationServlet extends HttpServlet
implements
Application.WindowAttachListener,
Application.WindowDetachListener,
Paintable.RepaintRequestListener {
// Versions
- private static final int VERSION_MAJOR = 3;
- private static final int VERSION_MINOR = 1;
- private static final int VERSION_BUILD = 1;
+ // TODO AUTOUPDATE VERSION NUMBER
+ private static final int VERSION_MAJOR = 4;
+ private static final int VERSION_MINOR = 0;
+ private static final int VERSION_BUILD = 0;
private static final String VERSION = "" + VERSION_MAJOR + "."
+ VERSION_MINOR + "." + VERSION_BUILD;
@@ -114,22 +115,23 @@ public class WebAdapterServlet extends HttpServlet
private static int DEFAULT_BUFFER_SIZE = 32 * 1024;
private static int DEFAULT_MAX_TRANSFORMERS = 1;
private static int MAX_BUFFER_SIZE = 64 * 1024;
- private static String SESSION_ATTR_VARMAP = "varmap";
- static String SESSION_ATTR_CONTEXT = "millstone_context";
- static String SESSION_ATTR_APPS = "apps";
- private static String SESSION_BINDING_LISTENER = "bindinglistener";
- private static String SESSION_DEFAULT_THEME = "default";
+ private static String SESSION_ATTR_VARMAP = "itmill-toolkit-varmap";
+ static String SESSION_ATTR_CONTEXT = "itmill-toolkit-context";
+ static String SESSION_ATTR_APPS = "itmill-toolkit-apps";
+ private static String SESSION_BINDING_LISTENER = "itmill-toolkit-bindinglistener";
+ private static String DEFAULT_THEME = "default";
private static String RESOURCE_URI = "/RES/";
+ private static String AJAX_UIDL_URI = "/UIDL/";
private static String THEME_DIRECTORY_PATH = "WEB-INF/lib/themes/";
private static String THEME_LISTING_FILE = THEME_DIRECTORY_PATH
+ "themes.txt";
- private static String DEFAULT_THEME_JAR_PREFIX = "millstone-web-themes";
+ private static String DEFAULT_THEME_JAR_PREFIX = "itmill-toolkit-web-themes";
private static String DEFAULT_THEME_JAR = "WEB-INF/lib/"
+ DEFAULT_THEME_JAR_PREFIX + "-" + VERSION + ".jar";
private static String DEFAULT_THEME_SNAPSHOT_JAR = "WEB-INF/lib/"
+ DEFAULT_THEME_JAR_PREFIX + "-" + VERSION_MAJOR + "."
+ VERSION_MINOR + "-SNAPSHOT.jar";
- private static String DEFAULT_THEME_TEMP_FILE_PREFIX = "WA_TMP_";
+ private static String DEFAULT_THEME_TEMP_FILE_PREFIX = "ITMILL_TMP_";
private static String SERVER_COMMAND_PARAM = "SERVER_COMMANDS";
private static int SERVER_COMMAND_STREAM_MAINTAIN_PERIOD = 15000;
private static int SERVER_COMMAND_HEADER_PADDING = 2000;
@@ -140,7 +142,6 @@ public class WebAdapterServlet extends HttpServlet
private UIDLTransformerFactory transformerFactory;
private CollectionThemeSource themeSource;
private String resourcePath = null;
- //private boolean enableBrowserProbe = false;
private boolean debugMode = false;
private int maxConcurrentTransformers;
private long transformerCacheTime;
@@ -149,6 +150,9 @@ public class WebAdapterServlet extends HttpServlet
private WeakHashMap applicationToServerCommandStreamLock = new WeakHashMap();
private WeakHashMap applicationToLastRequestDate = new WeakHashMap();
private List allWindows = new LinkedList();
+ private WeakHashMap applicationToAjaxAppMgrMap = new WeakHashMap();
+
+
/**
* Called by the servlet container to indicate to a servlet that the servlet
@@ -472,14 +476,29 @@ public class WebAdapterServlet extends HttpServlet
appContext.startTransaction(application, request);
}
+ // Set the last application request date
+ applicationToLastRequestDate.put(application, new Date());
+
// The rest of the process is synchronized with the application
// in order to guarantee that no parallel variable handling is
// made
synchronized (application) {
- // Set the last application request date
- applicationToLastRequestDate.put(application, new Date());
+ // Handle UIDL requests?
+ String resourceId = request.getPathInfo();
+ if (resourceId != null && resourceId.startsWith(AJAX_UIDL_URI)) {
+
+ getApplicationManager(application).handleXmlHttpRequest(
+ request, response);
+ // Notify transaction end
+ if (appContext != null) {
+ appContext.endTransaction(application, request);
+ }
+
+ return;
+ }
+
// Get the variable map
variableMap = getVariableMap(application, request);
if (variableMap == null)
@@ -581,7 +600,7 @@ public class WebAdapterServlet extends HttpServlet
// Use default theme if selected theme was not found.
if (transformerType == null) {
Theme defaultTheme = this.themeSource
- .getThemeByName(WebAdapterServlet.SESSION_DEFAULT_THEME);
+ .getThemeByName(ApplicationServlet.DEFAULT_THEME);
if (defaultTheme == null) {
throw new ServletException(
"Default theme not found in the specified theme source(s).");
@@ -1098,8 +1117,12 @@ public class WebAdapterServlet extends HttpServlet
try {
application = (Application) this.applicationClass.newInstance();
applications.add(application);
+
+ // Listen to window add/removes (for web mode)
application.addListener((Application.WindowAttachListener) this);
application.addListener((Application.WindowDetachListener) this);
+
+ // Set localte
application.setLocale(request.getLocale());
// Get application context for this session
@@ -1555,4 +1578,34 @@ public class WebAdapterServlet extends HttpServlet
return this.owner;
}
}
+
+ /** Get 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) {
+
+ // Create new manager
+ mgr = new AjaxApplicationManager(application);
+ applicationToAjaxAppMgrMap.put(application, mgr);
+
+ // Stop sending changes to this servlet because manager will take
+ // control
+ application.removeListener((Application.WindowAttachListener) this);
+ application.removeListener((Application.WindowDetachListener) this);
+
+ // Manager takes control over the application
+ mgr.takeControl();
+ }
+ return mgr;
+ }
}
diff --git a/src/com/itmill/toolkit/terminal/web/DebugWindow.java b/src/com/itmill/toolkit/terminal/web/DebugWindow.java
index ee760476bc..0be33ccd7b 100644
--- a/src/com/itmill/toolkit/terminal/web/DebugWindow.java
+++ b/src/com/itmill/toolkit/terminal/web/DebugWindow.java
@@ -66,7 +66,7 @@ public class DebugWindow extends Window {
private Application debuggedApplication;
private HashMap rawUIDL = new HashMap();
- private WebAdapterServlet servlet;
+ private ApplicationServlet servlet;
private HttpSession session;
private TabSheet tabs = new TabSheet();
@@ -81,7 +81,7 @@ public class DebugWindow extends Window {
protected DebugWindow(
Application debuggedApplication,
HttpSession session,
- WebAdapterServlet servlet) {
+ ApplicationServlet servlet) {
super("Debug window");
setName(WINDOW_NAME);
@@ -385,7 +385,7 @@ public class DebugWindow extends Window {
* Returns the servlet.
* @return WebAdapterServlet
*/
- protected WebAdapterServlet getServlet() {
+ protected ApplicationServlet getServlet() {
return servlet;
}
@@ -401,7 +401,7 @@ public class DebugWindow extends Window {
* Sets the servlet.
* @param servlet The servlet to set
*/
- protected void setServlet(WebAdapterServlet servlet) {
+ protected void setServlet(ApplicationServlet servlet) {
this.servlet = servlet;
}
diff --git a/src/com/itmill/toolkit/terminal/web/DirectoryThemeSource.java b/src/com/itmill/toolkit/terminal/web/DirectoryThemeSource.java
index b4628f1e18..f2d26e1465 100644
--- a/src/com/itmill/toolkit/terminal/web/DirectoryThemeSource.java
+++ b/src/com/itmill/toolkit/terminal/web/DirectoryThemeSource.java
@@ -47,7 +47,7 @@ public class DirectoryThemeSource implements ThemeSource {
private File path;
private Theme theme;
- private WebAdapterServlet webAdapterServlet;
+ private ApplicationServlet webAdapterServlet;
/** Collection of subdirectory entries */
private Collection subdirs = new LinkedList();
@@ -58,7 +58,7 @@ public class DirectoryThemeSource implements ThemeSource {
* @param url External URL of the repository
* @throws FileNotFoundException if no theme files are found
*/
- public DirectoryThemeSource(File path, WebAdapterServlet webAdapterServlet)
+ public DirectoryThemeSource(File path, ApplicationServlet webAdapterServlet)
throws ThemeException, FileNotFoundException, IOException {
this.path = path;
diff --git a/src/com/itmill/toolkit/terminal/web/JarThemeSource.java b/src/com/itmill/toolkit/terminal/web/JarThemeSource.java
index 9c6f403180..05b47f077b 100644
--- a/src/com/itmill/toolkit/terminal/web/JarThemeSource.java
+++ b/src/com/itmill/toolkit/terminal/web/JarThemeSource.java
@@ -58,7 +58,7 @@ public class JarThemeSource implements ThemeSource {
private Theme theme;
private String path;
private String name;
- private WebAdapterServlet webAdapterServlet;
+ private ApplicationServlet webAdapterServlet;
private Cache resourceCache = new Cache();
/** Collection of subdirectory entries */
@@ -72,7 +72,7 @@ public class JarThemeSource implements ThemeSource {
*/
public JarThemeSource(
File file,
- WebAdapterServlet webAdapterServlet,
+ ApplicationServlet webAdapterServlet,
String path)
throws ThemeException, FileNotFoundException, IOException {
diff --git a/src/com/itmill/toolkit/terminal/web/ServletThemeSource.java b/src/com/itmill/toolkit/terminal/web/ServletThemeSource.java
index c2db9c92bd..efbadea862 100644
--- a/src/com/itmill/toolkit/terminal/web/ServletThemeSource.java
+++ b/src/com/itmill/toolkit/terminal/web/ServletThemeSource.java
@@ -56,7 +56,7 @@ public class ServletThemeSource implements ThemeSource {
private ServletContext context;
private Theme theme;
private String path;
- private WebAdapterServlet webAdapterServlet;
+ private ApplicationServlet webAdapterServlet;
private Cache resourceCache = new Cache();
/** Collection of subdirectory entries */
@@ -71,7 +71,7 @@ public class ServletThemeSource implements ThemeSource {
*/
public ServletThemeSource(
ServletContext context,
- WebAdapterServlet webAdapterServlet,
+ ApplicationServlet webAdapterServlet,
String path)
throws IOException, ThemeException {
diff --git a/src/com/itmill/toolkit/terminal/web/ThemeFunctionLibrary.java b/src/com/itmill/toolkit/terminal/web/ThemeFunctionLibrary.java
index 51472578c3..cca9191a34 100644
--- a/src/com/itmill/toolkit/terminal/web/ThemeFunctionLibrary.java
+++ b/src/com/itmill/toolkit/terminal/web/ThemeFunctionLibrary.java
@@ -68,7 +68,7 @@ public class ThemeFunctionLibrary {
Window window,
WebBrowser webBrowser,
HttpSession session,
- WebAdapterServlet webAdapterServlet,
+ ApplicationServlet webAdapterServlet,
String theme) {
state.set(
new Object[] {
@@ -144,7 +144,7 @@ public class ThemeFunctionLibrary {
static public String resource(String resource, String theme) {
try {
return (
- (WebAdapterServlet)
+ (ApplicationServlet)
(
(Object[]) state
.get())[WEBADAPTERSERVLET])
@@ -161,7 +161,7 @@ public class ThemeFunctionLibrary {
static public String resource(String resource) {
try {
return (
- (WebAdapterServlet)
+ (ApplicationServlet)
(
(Object[]) state
.get())[WEBADAPTERSERVLET])
@@ -198,14 +198,14 @@ public class ThemeFunctionLibrary {
return generateWindowScript(
window(),
application(),
- (WebAdapterServlet) ((Object[]) state.get())[WEBADAPTERSERVLET],
+ (ApplicationServlet) ((Object[]) state.get())[WEBADAPTERSERVLET],
browser());
}
static protected String generateWindowScript(
Window window,
Application app,
- WebAdapterServlet wa,
+ ApplicationServlet wa,
WebBrowser browser) {
StringBuffer script = new StringBuffer();
diff --git a/src/com/itmill/toolkit/terminal/web/UIDLTransformer.java b/src/com/itmill/toolkit/terminal/web/UIDLTransformer.java
index 3588555e0e..2796cc3190 100644
--- a/src/com/itmill/toolkit/terminal/web/UIDLTransformer.java
+++ b/src/com/itmill/toolkit/terminal/web/UIDLTransformer.java
@@ -92,7 +92,7 @@ public class UIDLTransformer {
/** Theme repository used for late error reporting */
private ThemeSource themeSource;
- private WebAdapterServlet webAdapterServlet;
+ private ApplicationServlet webAdapterServlet;
/** UIDLTransformer constructor.
* @param type Type of the transformer
@@ -103,7 +103,7 @@ public class UIDLTransformer {
public UIDLTransformer(
UIDLTransformerType type,
ThemeSource themes,
- WebAdapterServlet webAdapterServlet)
+ ApplicationServlet webAdapterServlet)
throws UIDLTransformerException {
this.transformerType = type;
this.themeSource = themes;
diff --git a/src/com/itmill/toolkit/terminal/web/UIDLTransformerFactory.java b/src/com/itmill/toolkit/terminal/web/UIDLTransformerFactory.java
index fc57b71a84..557b42e4e4 100644
--- a/src/com/itmill/toolkit/terminal/web/UIDLTransformerFactory.java
+++ b/src/com/itmill/toolkit/terminal/web/UIDLTransformerFactory.java
@@ -69,7 +69,7 @@ public class UIDLTransformerFactory {
private Map transformerSpool = new HashMap();
private ThemeSource themeSource;
- private WebAdapterServlet webAdapterServlet;
+ private ApplicationServlet webAdapterServlet;
private int transformerCount = 0;
private int transformersInUse = 0;
@@ -82,7 +82,7 @@ public class UIDLTransformerFactory {
*/
public UIDLTransformerFactory(
ThemeSource themeSource,
- WebAdapterServlet webAdapterServlet,
+ ApplicationServlet webAdapterServlet,
int maxConcurrentTransformers,
long cacheTime) {
this.webAdapterServlet = webAdapterServlet;
diff --git a/src/com/itmill/toolkit/terminal/web/WebApplicationContext.java b/src/com/itmill/toolkit/terminal/web/WebApplicationContext.java
index 8fc19cfbca..84bc60a610 100644
--- a/src/com/itmill/toolkit/terminal/web/WebApplicationContext.java
+++ b/src/com/itmill/toolkit/terminal/web/WebApplicationContext.java
@@ -97,6 +97,7 @@ public class WebApplicationContext implements ApplicationContext {
*/
public File getBaseDirectory() {
String realPath = session.getServletContext().getRealPath("/");
+ if (realPath == null) return null;
return new File(realPath);
}
@@ -114,7 +115,7 @@ public class WebApplicationContext implements ApplicationContext {
public Collection getApplications() {
LinkedList applications =
(LinkedList) session.getAttribute(
- WebAdapterServlet.SESSION_ATTR_APPS);
+ ApplicationServlet.SESSION_ATTR_APPS);
return Collections.unmodifiableCollection(
applications == null ? (new LinkedList()) : applications);
@@ -175,4 +176,5 @@ public class WebApplicationContext implements ApplicationContext {
((ApplicationContext.TransactionListener)i.next()).transactionEnd(application,request);
}
}
+
}
diff --git a/src/com/itmill/toolkit/terminal/web/WebPaintTarget.java b/src/com/itmill/toolkit/terminal/web/WebPaintTarget.java
index 8f1b6672cb..7d0450ab0b 100644
--- a/src/com/itmill/toolkit/terminal/web/WebPaintTarget.java
+++ b/src/com/itmill/toolkit/terminal/web/WebPaintTarget.java
@@ -65,7 +65,7 @@ public class WebPaintTarget implements PaintTarget {
private StringBuffer tagBuffer;
private HttpVariableMap variableMap;
private boolean closed = false;
- private WebAdapterServlet webAdapterServlet;
+ private ApplicationServlet webAdapterServlet;
private Theme theme;
private static final int TAG_BUFFER_DEFAULT_SIZE = 20;
private boolean mSuppressOutput = false;
@@ -79,7 +79,7 @@ public class WebPaintTarget implements PaintTarget {
public WebPaintTarget(
HttpVariableMap variableMap,
UIDLTransformerType type,
- WebAdapterServlet webAdapterServlet,
+ ApplicationServlet webAdapterServlet,
Theme theme)
throws PaintException {
diff --git a/src/com/itmill/toolkit/terminal/web/XSLReader.java b/src/com/itmill/toolkit/terminal/web/XSLReader.java
index fecb08a2b1..f3d4b63548 100644
--- a/src/com/itmill/toolkit/terminal/web/XSLReader.java
+++ b/src/com/itmill/toolkit/terminal/web/XSLReader.java
@@ -101,7 +101,7 @@ public class XSLReader implements XMLReader, ContentHandler {
}
}
- private static final String MILLSTONE_PREFIX = "millstone://";
+ private static final String JAVA_PREFIX = "java://";
private Collection streams;
private boolean startTagHandled = false;
private String xslNamespace = "";
@@ -422,29 +422,29 @@ public class XSLReader implements XMLReader, ContentHandler {
String uri = original.getURI(index);
// Map millstone:// namespaces to transformer specific namespaces
- if (uri != null && uri.startsWith(MILLSTONE_PREFIX)) {
+ if (uri != null && uri.startsWith(JAVA_PREFIX)) {
System.out.print("DEBUG " + uri + " --> ");
switch (xsltProcessor) {
case XSLT_SAXON6 :
uri =
"saxon://"
- + uri.substring(MILLSTONE_PREFIX.length());
+ + uri.substring(JAVA_PREFIX.length());
break;
case XSLT_SAXON7 :
uri =
"saxon://"
- + uri.substring(MILLSTONE_PREFIX.length());
+ + uri.substring(JAVA_PREFIX.length());
break;
case XSLT_XALAN :
uri =
"xalan://"
- + uri.substring(MILLSTONE_PREFIX.length());
+ + uri.substring(JAVA_PREFIX.length());
break;
default :
uri =
"xalan://"
- + uri.substring(MILLSTONE_PREFIX.length());
+ + uri.substring(JAVA_PREFIX.length());
break;
}
System.out.println(uri);