Spring Webflow - IllegalStateException when using multipart/form-data and file upload - file-upload

I am trying to add file upload to my Spring Webflog form processing. As far as the form enctype is not set to multipart/form-data, form submition works just fine. But after I added enctype="multipart/form-data" to my Spring form, this Exception occurs:
java.lang.IllegalStateException: A flow execution action URL can only be obtained in a RenderRequest or a ResourceRequest
at org.springframework.webflow.context.portlet.PortletExternalContext.getFlowExecutionUrl(PortletExternalContext.java:215)
at org.springframework.webflow.engine.impl.RequestControlContextImpl.getFlowExecutionUrl(RequestControlContextImpl.java:178)
at org.springframework.webflow.mvc.view.AbstractMvcView.render(AbstractMvcView.java:189)
at org.springframework.webflow.engine.ViewState.render(ViewState.java:293)
at org.springframework.webflow.engine.ViewState.refresh(ViewState.java:242)
at org.springframework.webflow.engine.ViewState.resume(ViewState.java:220)
at org.springframework.webflow.engine.Flow.resume(Flow.java:537)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.resume(FlowExecutionImpl.java:259)
at org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:169)
at org.springframework.webflow.mvc.portlet.FlowHandlerAdapter.handleAction(FlowHandlerAdapter.java:161)
at org.springframework.web.portlet.DispatcherPortlet.doActionService(DispatcherPortlet.java:670)
at org.springframework.web.portlet.FrameworkPortlet.processRequest(FrameworkPortlet.java:520)
at org.springframework.web.portlet.FrameworkPortlet.processAction(FrameworkPortlet.java:461)
at com.liferay.portlet.FilterChainImpl.doFilter(FilterChainImpl.java:71)
I have added CommonsMultipartResolver to my spring context:
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- Limit uploads to one byte smaller than the server is allowed to handle -->
<property name="maxUploadSize" value="100000" />
</bean>
and have commons-fileupload.jar in my pom.xml:
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2.2</version>
</dependency>
My JSP looks like this:
<portlet:actionURL var="processFormAction" >
<portlet:param name="execution" value="${flowExecutionKey}"/>
</portlet:actionURL>
<form:form action="${processFormAction}" modelAttribute="customerModel" enctype="multipart/form-data" method="post" >
<form:input path="firstName" cssClass="input-size-1 valid-required" />
<form:input path="lastName" cssClass="input-size-1 valid-required" />
<input name="avatar" id="avatar" type="file"/>
<input type="submit" name="_eventId_submit" id="send" value="Submit"/>
</form:form>
My flow.xml definition:
<view-state id="state1" model="customerModel">
...
<transition on="submit" to="submitFormActions"/>
</view-state>
<action-state id="submitFormActions">
<evaluate expression="portletAction.processForm(customerModel, flowRequestContext)" />
<transition on="success" to="state2"/>
<transition on="error" to="state1" />
</action-state>
The model object:
public class CustomerModel implements Serializable{
private String firstName;
private String lastName;
private MutlipartFile avatar;
...
//public getters and setters
}
Any thoughts what could be wrong? As I said, without enctype="multipart/form-data" the form processing works well.
Thanks

You are using org.springframework.web.multipart.commons.CommonsMultipartResolver which is not aware about the portlet context.
You need to change CommonsMultipartResolver to:
<bean id="portletMultipartResolver"
class="org.springframework.web.portlet.multipart.CommonsPortletMultipartResolver">
<!-- one of the properties available; the maximum file size in bytes -->
<property name="maxUploadSize" value="100000"/>
</bean>
Also, for this bean to be recognised by DispatcherPortlet, you need to define this bean id as mentioned above. The doc says:
Any configured PortletMultipartResolver bean must have the following id (or name): "portletMultipartResolver".
If you have defined your PortletMultipartResolver with any other name, then the DispatcherPortlet will not
find your PortletMultipartResolver, and consequently no multipart support will be in effect.

Related

Camel file uri using property

I'm trying to use property file for routing from folder :
My property file has some property :
from.file = D:/Develop/resources
and I want to use it in camel context xml as file routing,
I tried:
<camel:route id="Main-Route">
<camel:from uri="file:${from.file}" />
<camel:to uri="seda:fooQueue" />
</camel:route>
But camel throws me exception :
Dynamic expressions with ${ } placeholders is not allowed. Use the fileName option to set the dynamic expression.
How can I do this ?
In Camel, you use {{property}} to inject properties in your routes.
Please read more here http://camel.apache.org/properties.html.
Your example would change to:
<camel:route id="Main-Route">
<camel:from uri="file:{{from.file}}" />
<camel:to uri="seda:fooQueue" />
</camel:route>
You also need to tell Camel where it can find your properties file. From the link above:
Spring XML offers two variations to configure. You can define a spring bean as a PropertiesComponent which resembles the way done in Java DSL. Or you can use the tag.
<bean id="properties" class="org.apache.camel.component.properties.PropertiesComponent">
<property name="location" value="classpath:com/mycompany/myprop.properties"/>
</bean>
Using the tag makes the configuration a bit more fresh such as:
<camelContext ...>
<propertyPlaceholder id="properties" location="com/mycompany/myprop.properties"/>
</camelContext>
In file component of apache camel,the starting directory should not contain dynamic expressions. If you want to provide dynamic starting directory also,you can set the whole path into CamelFileName header of file component from properties file with fileComponent defined as <to uri="file://">
the problem with this is that for reading place holder as :
${some-property} for some bean for example :
<bean id="bean" class="">
<property name="field Constructor" value="${some.property}" />
</bean>
I get error.
Solved it by defining also PropertyPlaceholderConfigurer:
<bean id="proprty" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<value>file:/D:/Proj/resources/myprop.properties
</value>
</bean>
<bean id="beanId" class="com.viewlinks.eim.properties.MyBean">
<property name="fieldConstructor" value="${some.property}" />
</bean>
<camel:camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<propertyPlaceholder id="properties" location="file:/D:/Proj/resources/myprop.properties"/>
<camel:route id="Main-Route">
<camel:from uri="file:{{from.file}}" />
<camel:to uri="file:{{to.file}}" />
</camel:route>
</camel:camelContext>

Enunciate Data Model Documentaton

I'm using Enunciate on a multi module maven project. I use version 1.28 and I just use it for documentation purposes on SOAP Services.
This works just fine for all the Services.
The targetNamespace and endpointInterface has to be declared in the #WebService annotation and everything works fine. I got my zip with wsdl/wadl/xsd/html output.
All javadoc is recognized and published through the output files.
BUT...I would not write here if there is no but...
All data model files won't! I tried the following options:
<api-import pattern="package.model.**" />
<modules>
<spring-app disabled="true" />
<docs docsDir="/docs" title="Web Service API" copyright="ME" />
<!-- Disable all the client generation tools -->
<basic-app disabled="true" />
<c disabled="true" />
<csharp disabled="true" />
<java-client disabled="true" />
<jaxws-client disabled="true" />
<jaxws-ri disabled="true" />
<jaxws-support disabled="true" />
<jersey disabled="true" />
<obj-c disabled="true" />
<xml forceExampleJson="true" />
<jaxws disabled="true" />
<amf disabled="true" />
</modules>
module is not included in webarchive but declared as dependency:
<dependency>
<groupId>package.model</groupId>
<artifactId>model</artifactId>
<version>${project.parent.version}</version>
<scope>provided</scope>
</dependency>
The DTOs and ENUMS in the Data Model are normally provided with:
#XmlType(namespace = "https://package/DTO")
And Javadoc on class and attributes.
But I tried Javadoc on getters and setters too.
I even tried some xml annotation from the example implementation in my project:
#javax.xml.bind.annotation.XmlType(name = "socialGroup", namespace = "http://api.ifyouwannabecool.com/link")
#javax.xml.bind.annotation.XmlRootElement(name = "socialGroup", namespace = "http://api.ifyouwannabecool.com/link")
Without success. The javadoc won't be included in xsd/wsdl/html files as it does for the SOAP Services.
Do you have any idea?
If the classes are in a different Maven module, as you have declared in a dependency, you have to explicitly tell Enunciate to "import" them in order to get the JavaDoc included.
So let's pretend your model classes are in a package called "org.mycompany.widgets.model" and in a package called "org.mycompany.gadgets.model". Tell Enunciate to import those like this:
<enunciate ...>
...
<api-import pattern="org.mycompany.gadgets.model.**"/>
<api-import pattern="org.mycompany.widgets.model.**"/>
...
Please add #XmlRootElement on top of the class so that enunciate will make them appear in Data Model documentation.
Example :
#XmlRootElement
public class Foo{
....
}
I think the problem is <scope>provided</scope>. If the classes aren't present in the classpath, enunciate will not be able to find them. Change it to <scope>compile</scope>, along with the #XmlRootElement annotations and it should work.

Spring security 3.2: Does a custom UserDetails & UserDetailsService need a custom AuthenticationManager?

I'm working with spring security 3.2, JSF2 , Hibernate4.
I'have done 3/4 of the work :) but my authentication system doesn't work yet.
I have a UserService who implements UserDetailsService, a domain Class User who implements UserDetails.
THe login system never stop user to access secured pages, i tried user name and password who doesn't exist in my database...
Thanks for the help.
I have a loginBean who is trying to authenticate the user when he connects via login form :
public String login() {
try {
Authentication request = new UsernamePasswordAuthenticationToken(this.getUsername(), this.getPassword());
Authentication result = authenticationManager.authenticate(request);
SecurityContextHolder.getContext().setAuthentication(result);
} catch (AuthenticationException e) { e.printStackTrace();}
return "secured";
}
My spring security looks like this :
`<security:global-method-security jsr250-annotations="enabled" pre-post-annotations="enabled" secured-annotations="enabled" />
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/Admin" access="isAuthenticated()" />
<security:form-login login-page="/login.xhtml" authentication-failure-url="/" > </security:form-login>
</security:http>
<!-- User Data Access Object -->
<beans:bean id="userDao" class="com.clb.genomic.lyon.dao.UserDaoImpl" >
<beans:property name="sessionFactory" ref="sessionFactory"></beans:property>
</beans:bean>
<!-- User Business Object -->
<beans:bean id="userBo" class="com.clb.genomic.lyon.bo.UserBoImpl" >
<beans:property name="userDao" ref="userDao" />
</beans:bean>
<beans:bean id="login" class="com.clb.genomic.lyon.beans.LoginBean" scope ="request">
<beans:property name="authenticationManager" ref="authenticationManager" />
</beans:bean>
<beans:bean id="standardPasswordEncoder" class="org.springframework.security.crypto.password.StandardPasswordEncoder"/>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider user-service-ref="userBo" >
<security:password-encoder ref="standardPasswordEncoder"/>
</security:authentication-provider>
</security:authentication-manager>`
This is the error who show up...
org.springframework.security.authentication.AuthenticationServiceException: 1
at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:109)
at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:132)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156)
at com.clb.genomic.lyon.beans.LoginBean.login(LoginBean.java:47).....
Caused by: java.lang.ArrayIndexOutOfBoundsException: 1
at com.clb.genomic.lyon.dao.UserDaoImpl.loadUserByUsername(UserDaoImpl.java:59)
at com.clb.genomic.lyon.bo.UserBoImpl.loadUserByUsername(UserBoImpl.java:68)
at com.clb.genomic.lyon.bo.UserBoImpl$$FastClassByCGLIB$$9ea98abf.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204).....
The exception from stack trace shows you are getting ArrayIndexOutOfBoundsException and it seems that you are reading from an empty array.
You should also check what value is being passed to loadUserByUsername() method, and if that user exists.

asp.net mvc4 clientside validation doesn't work

I have clientside validation enabled in my config and I'm also including the appropriate jquery files for validation, but every time I submit, the page posts to server without first doing clientside validation. I have pasted the markup generated in the source below. It seems to be generating the data- validation messages fine. Just somehow not triggering validation.
I'm using the BeginCollection library that's available on Nuget to build my dynamic form. Could that be a reason for my clientside validation for somehow not working?
<input class="text-box single-line valid" data-val="true"
data-val-number="The field DaysAbsent must be a number."
data-val-required="The DaysAbsent field is required."
id="students_471abdc8-b190-42da-9f72-ed30a1e33b10__DaysAbsent"
name="students[471abdc8-b190-42da-9f72-ed30a1e33b10].DaysAbsent"
type="text" value="0">
My web.config:
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
_Layout.cshtml:
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/jqueryui")
#Scripts.Render("~/bundles/jqueryval")
#RenderSection("scripts", required: false)
BundleConfig.cs:
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.unobtrusive*",
"~/Scripts/jquery.validate*"));
You mentioned dynamic form, so if you are loading your inputs dynamically jquery.validate doesn't know they are there. You have to "refresh" your form validations to validate your new inputs.
After adding a new input, use this code to "refresh" the validations for your form:
$('form').removeData('validator');
$('form').removeData('unobtrusiveValidation');
$.validator.unobtrusive.parse($('form'));

Image upload component for OpenLaszlo with drag & drop support and preview

I haven't seen any good file upload component for OpenLaszlo. Is there an open source version of a file upload component, which supports drag & drop for DHTML and Adobe AIR, and a preview functionality for both runtimes?
Technically it is possible to support the following features:
drag and drop file upload in DHTML for all desktop browsers http://caniuse.com/#feat=dragndrop
preview of images for Webkit browsers and Firefox in DHTML, and for all browsers using a SWF runtime
drag and drop support for Adobe Air applications
Maybe someone has an existing component which could be made open source, and maintained or improved by the community.
There is currently no way to do a File Upload in DHTML (aka HTML5) mode of an OpenLaszlo application since unfortunately there is no way to set the form type to enctype=multipart/form-data in that run-time.
However, you can do a File Upload with the SWF(Flash) mode of an OpenLaszlo application by accessing the low-level Flash API. It is not obvious how to do this so I wrote a class to do this myself a while back, it will work under (Flash) SWF8, SWF9 and SWF10 mode of OpenLaszlo.
I have never tried compiling an OpenLaszlo application to AIR but I believe the Flash Upload will probably work for that case too.
Here is my class, feel free to use it:
( The code is also avaiable here: http://forum.openlaszlo.org/showthread.php?t=14566&highlight=fileReference )
<library>
<switch>
<when property="$as3"><!-- SWF9/SWF10 -->
<!---
CLASS: <fileuploadhelper>
EXTENDS: <node> (lz.node)
DESCRIPTION:
This is the ActionScript3 (AS3) (SWF9/SWF8) version of the Flash file
upload object.
This allows users to upload files when compiled to a Flash Version that
uses ActionScript3 such as Flash 9 or Flash 10.
-->
<class name="fileuploadhelper" extends="node">
<!---
#param string uploadurl: (optional) default upload url to use if none
passed to this.upload()
-->
<attribute name="uploadurl" type="string" />
<!-- #keywords private -->
<!--- #param flash.net.FileReference file_reference: Flash file reference object -->
<attribute name="file_reference" type="expression" value="null" />
<!-- Imports Required for SWF9/SWF10 -->
<passthrough>
import flash.net.FileReference;
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.net.URLRequest;
</passthrough>
<!-- *** METHODS *** -->
<handler name="oninit">
<![CDATA[
#passthrough {
this.file_reference = new FileReference();
file_reference.addEventListener(Event.SELECT,this.onSelect);
file_reference.addEventListener(Event.COMPLETE, this.onComplete);
file_reference.addEventListener(ProgressEvent.PROGRESS, this.progressHandler);
file_reference.addEventListener(IOErrorEvent.IO_ERROR, this.ioErrorHandler);
file_reference.addEventListener(SecurityErrorEvent.SECURITY_ERROR, this.securityErrorHandler);
}#
]]>
</handler>
<!---
Displays file browsing window and allows the user to select a file (or
cancel to close the window).
-->
<method name="browse">
<![CDATA[
#passthrough {
file_reference.browse();
}#
]]>
</method>
<!---
Return name of selected file
#returns string: the filename of the selected file
-->
<method name="getName">
return this.file_reference.name;
</method>
<!--- #keywords private -->
<!---
#param string submit_url: SWF9/10 #passthrough{...} requires URL to be
referenced in an attribute rather than a
locally defined OpenLaszlo variable or
a compilation error occurs.
-->
<attribute name="submit_url" type="string" />
<!---
Uploads the currently selected file.
#param string strURL: (optional) If defined upload the file to this
URL, otherwise upload to this.uploadurl
Note: required if this.uploadurl is not defined.
-->
<method name="upload" args="strURL = false">
<![CDATA[
if (strURL === false)
var strURL = this.uploadurl; // workaround for SWF9/10 compatibility
this.setAttribute('submit_url', strURL);
#passthrough {
var request:URLRequest = new URLRequest(submit_url);
file_reference.upload(request);
}#
]]>
</method>
<!-- * ABSTRACT handlers: Override to do something useful in instance * -->
<!--- #keywords abstract -->
<!---
ABSTRACT METHOD: OVERRIDE IN YOUR APPLICATION TO DO SOMETHING USEFUL
Called when user selects a file.
#param flash.events.Event ev: the select event
-->
<method name="onSelect" args="ev=null">
if ($debug) Debug.info('as3 (SWF9/10): fileuploadhelper.onSelect(): WARNING: This is an abstract method that should be overridden in your application to do something useful...');
</method>
<!--- #keywords abstract -->
<!---
ABSTRACT METHOD: OVERRIDE IN YOUR APPLICATION TO DO SOMETHING USEFUL
Called when progress event is captured.
#param {anything} objDummy: SWF8 requires file_reference object here, does nothing in SWF9/10
#param number bytesLoaded: the number of bytes of the file uploaded
#param number bytesTotal: the number of total bytes of the file to be uploaded
-->
<method name="onProgress" args="objDummy, bytesLoaded, bytesTotal">
if ($debug) Debug.info('as3 (SWF9/10): fileuploadhelper.onProgress(): WARNING: This is an abstract method that should be overridden in your application to do something useful...');
</method>
<!--- #keywords abstract -->
<!---
ABSTRACT METHOD: OVERRIDE IN YOUR APPLICATION TO DO SOMETHING USEFUL
Called when a file upload is complete.
#param flash.events.Event ev: the complete event
-->
<method name="onComplete" args="ev=null">
if ($debug) Debug.info('as3 (SWF9/10): fileuploadhelper.onComplete(): WARNING: This is an abstract method that should be overridden in your application to do something useful...');
</method>
<!--- #keywords abstract -->
<!---
ABSTRACT METHOD: OVERRIDE IN YOUR APPLICATION TO DO SOMETHING USEFUL
Called when the file upload fails.
#param flash.events.IOErrorEvent/flash.events.securityErrorEvent ev: the Flash Error Event
-->
<method name="onError" args="ev=null">
if ($debug) Debug.info('as3 (SWF9/10): fileuploadhelper.onError(): WARNING: This is an abstract method that should be overridden in your application to do something useful...');
</method>
<!-- * Internal Private Handlers * -->
<!--- #keywords private -->
<!---
This will pass the progress values to method this.onProgress()
#param flash.events.ProgressEvent ev: the Flash Progress Event
-->
<method name="progressHandler" args="ev=null">
this.onProgress(false, ev.bytesLoaded, ev.bytesTotal);
</method>
<!--- #keywords private -->
<!---
This will catch an ioError and call method this.onError()
#param flash.events.IOErrorEvent ev: the Flash Error Event
-->
<method name="ioErrorHandler" args="ev=null">
if ($debug) Debug.error('as3 (SWF9/10): fileuploadhelper.ioErrorHandler(): ERROR: ioError detected, could not upload file.');
this.onError(ev);
</method>
<!--- #keywords private -->
<!---
This will catch a securityError and call method this.onError()
#param flash.events.securityErrorEvent ev: the Flash Error Event
-->
<method name="securityErrorHandler" args="ev=null">
if ($debug) Debug.error('as3 (SWF9/10): fileuploadhelper.securityErrorHandler(): ERROR: securityError detected. Are you sure you are uploading to same domian as this application is being served from?');
this.onError(ev);
</method>
</class>
</when>
<when property="$as2"><!-- SWF8 -->
<!---
CLASS: <fileuploadhelper>
EXTENDS: <node> (lz.node)
DESCRIPTION:
This is the ActionScript2(AS2) (SWF8) version of the Flash file
upload object.
This allows users to upload files when compiled to a Flash Version that
uses ActionScript2 such as Flash 8
-->
<class name="fileuploadhelper" extends="node">
<!---
#param string uploadurl: (optional) default upload url to use if none
passed to this.upload()
-->
<attribute name="uploadurl" />
<!--- #keywords private -->
<!--- #param flash.net.FileReference file_reference: Flash file reference object -->
<attribute name="file_reference" />
<!-- *** METHODS *** -->
<handler name="oninit" args="invoker">
fr = new flash.net.FileReference();
this.setAttribute('file_reference', fr);
fr.addListener(invoker);
</handler>
<!-- *** METHODS *** -->
<!---
Displays file browsing window and allows the user to select a file (or
cancel to close the window).
-->
<method name="browse">
this.file_reference.browse();
</method>
<!---
Return name of selected file
#returns string: the filename of the selected file
-->
<method name="getName">
return this.file_reference.name;
</method>
<!---
Uploads the currently selected file.
#param string strURL: (optional) If defined upload the file to this
URL, otherwise upload to this.uploadurl
Note: required if this.uploadurl is not defined.
-->
<method name="upload" args="strURL">
if (strURL == null)
var strURL = this.uploadurl;
this.file_reference.upload(strURL);
</method>
<!-- * ABSTRACT HANDLERS * -->
<!--- #keywords abstract -->
<!---
ABSTRACT METHOD: OVERRIDE IN YOUR APPLICATION TO DO SOMETHING USEFUL
Called when user selects a file.
#param flash.events.Event ev: the select event
-->
<method name="onSelect" args="ev=null">
if ($debug) Debug.info('as3 (SWF9/10): fileuploadhelper.onSelect(): WARNING: This is an abstract method that should be overridden in your application to do something useful...');
</method>
<!--- #keywords abstract -->
<!---
ABSTRACT METHOD: OVERRIDE IN YOUR APPLICATION TO DO SOMETHING USEFUL
Called when progress event is captured.
#param flash.net.fileReference fr: file_reference object here
#param number bytesLoaded: the number of bytes of the file uploaded
#param number bytesTotal: the number of total bytes of the file to be uploaded
-->
<method name="onProgress" args="fr, bytesLoaded, bytesTotal">
if ($debug) Debug.info('as3 (SWF9/10): fileuploadhelper.onProgress(): WARNING: This is an abstract method that should be overridden in your application to do something useful...');
</method>
<!--- #keywords abstract -->
<!---
ABSTRACT METHOD: OVERRIDE IN YOUR APPLICATION TO DO SOMETHING USEFUL
Called when a file upload is complete.
#param flash.events.Event fr: the file_reference object
-->
<method name="onComplete" args="fr=null">
if ($debug) Debug.info('as3 (SWF9/10): fileuploadhelper.onComplete(): WARNING: This is an abstract method that should be overridden in your application to do something useful...');
</method>
<!--- #keywords abstract -->
<!---
ABSTRACT METHOD: OVERRIDE IN YOUR APPLICATION TO DO SOMETHING USEFUL
Called when the file upload fails.
#param flash.events.Event fr: the file_reference object
-->
<method name="onError" args="fr=null">
if ($debug) Debug.info('as3 (SWF9/10): fileuploadhelper.onError(): WARNING: This is an abstract method that should be overridden in your application to do something useful...');
</method>
</class>
</when>
</switch>
</library>
Note: This works similar to an HTML form where you post the file upload to a receiving script on the backend (could be in PHP, ASP, etc.) which would process the file and store it somewhere, there are many tutorials on the web on how to do that so I have not included it. As for drag and drop and preview you would have to write a fairly complicated application in OpenLaszlo yourself to do this, I suggest you view the tutorials and OpenLaszlo documentation to learn how to do that.