Comments? Feedback?

This wiki does not yet support public comments (a limitation of Google Sites), so we encourage you to post your comments either:

On Twitter by responding to @orbeon.

On our community mailing list: subscribe sending an email to ops-users-subscribe@ow2.org (content of subject/body doesn't matter), you'll get a response with the email to use to send your message to the community mailing list.

Recent site activity

How-to guides‎ > ‎XForms Logic‎ > ‎

Upload a file to a servlet



The problem

In separate deployment, you want to create a form with an upload field, which when submitted sends the file to a servlet, which will then do some processing on the uploaded file.

The solution

The form

Let's consider that the form is a registration form, which allows you to upload a file (here assumed to be a photo):


The code for the form is pretty straight forward. The instance looks like:

<xforms:instance id="file">
    <registration>
        <email/>
        <password/>
        <photo filename="" mediatype="" size=""/>
    </registration>
</xforms:instance>

Make sure you define the type of <photo> to be xs:anyURI, so the XForms engine does not attempt to store the base64-encoded file that element, but instead creates a temporary file, and store the URI to that temporary file in the element. The upload control is defined as:

<xforms:upload ref="photo">
    <xforms:label>Photo</xforms:label>
    <xforms:filename ref="@filename"/>
    <xforms:mediatype ref="@mediatype"/>
    <xxforms:size ref="@size"/>
</xforms:upload>

The "submit" button is implemented here with an fr:button, but an xforms:trigger would work just as well:

<fr:button appearance="minimal">
    <xforms:label>Submit</xforms:label>
    <xforms:action ev:event="DOMActivate">
        <xforms:send submission="servlet-submission"/>
        <xforms:toggle case="show-size"/>
    </xforms:action>
</fr:button>

When the button is activated, it runs the servlet-submission submission which sends the data to the servlet. The servlet receives the file, computes its size, and returns it in an XML document. That file size will be displayed in an xforms:case. so that after having clicked on the "submit" button, you might see:


The submission is defined as follows:

<xforms:submission id="servlet-submission" method="post" ref="instance('file')"
    resource="/create-user" replace="instance" instance="servlet-response"/>

Note that the URI in the above xforms:submission is just /create-user. The form is deployed in your web app, so the context of your web app is at runtime automatically added to URLs that start with /. For instance, if your web app is deployed on http://localhost:8080/myapp, the instance will be posted to http://localhost:8080/myapp/create-user. (This way, you don't need to hard-code the context your web app will be deployed at the time you write the form.)

The servlet

The servlet will receive an XML document that looks like:

<registration>
    <email>me@example.com</email>
    <password>secret</password>
    <photo filename="image.jpg" mediatype="image/jpeg" size="37707">
        file:/temp/xforms_upload_857314018990145163.tmp
    </photo>
</registration>

Because the servlet is handling a POST, you'll want to override the doPost() method:

public void doPost (HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
{
    ...
}

First, you'll want to parse the XML posted to the servlet and extract the URI of the temporary file:

SAXReader xmlReader = new SAXReader();
Document queryDocument = xmlReader.read(request.getInputStream());
String photoURI = queryDocument.getRootElement().elementText("photo");

Since the servlet is running on the same server as Orbeon Forms, you can access that temporary file directly, and, say, compute its size:

String file = new URL(photoURI).getFile();
long length = new File(file).length();

Finally, you can return the size in an XML document:

response.setContentType("application/xml");
PrintWriter out = response.getWriter();
out.println("<size>" + length + "</size>");
out.close();


Get the source

The source for this how-to is two files: upload-to-servlet.xhtml and CreateUser.java, which you'll find attached to this page. To run this example:
  1. Deploy Orbeon Forms and create a new web app setup for separate deployment. In the web.xml for that app, setup all the URL /forms/* to go through Orbeon Forms.
  2. Create a directory forms at the top level of your web all, and copy the attached upload-to-servlet.xhtml into that directory.
  3. Copy the file dom4j-1_6_1.jar from the Orbeon's WEB-INF/lib to the WEB-INF/lib of your application.
  4. Copy the attached CreateUser.class in WEB-INF/classes. If instead you want to compile that file from the source, place the attached CreateUser.java in WEB-INF/classes and compile it with (this works on Tomcat; for other application you'll want to change the path to the servlet jar file):

    javac -cp ../../../../common/lib/servlet-api.jar:../lib/dom4j-1_6_1.jar CreateUser.java


  5. Declare the servlet in your web.xml and map /create-user to it, with:

    <servlet>
        <servlet-name>create-user</servlet-name>
        <servlet-class>CreateUser</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>create-user</servlet-name>
        <url-pattern>/create-user</url-pattern>
    </servlet-mapping>

  6. Access the form by going to: http://localhost:8080/myapp/forms/upload-to-servlet.xhtml
Č
ċ
ď
CreateUser.class
(2k)
Alessandro Vernet,
Nov 12, 2009 6:17 PM
ċ
ď
CreateUser.java
(1k)
Alessandro Vernet,
Nov 12, 2009 6:17 PM
ċ
ď
upload-to-servlet.xhtml
(3k)
Alessandro Vernet,
Nov 12, 2009 6:03 PM