Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Section
Column

So you've decided to use the Data Java client library to have a deeper integration between your application and . Our aim with this tutorial is to quickly get you started in using the Java client library by guiding you through the implementation of a simple application.

We will first help you configure your development environment and then jump straight into the Java code. This tutorial assumes that you have already installed a recent version of the Java JDK (5.0 or 6.0) and that you have already downloaded Tomcat bundle from LiveForms web site. The Tomcat bundle contains all the required Java Client jars.

Column
width240px

On this page:

Table of Contents
maxLevel2
 

What are we going to build?

We are going to build a simple contacts application using  and the Data API Java Client Library.

...

  • Login/logout and session management
  • Upload a sample application into
  • List the existing submissions for a sample form
  • Create a new submission
  • View a submission
  • Edit a submission
  • Query submissions & pagination
  • Delete a submission

Installing the Client Library and Dependencies

The  Java Client Library has the following dependencies:

...

Note

The actual jar versions may be different depending on the version of being used.

Contacts application

We have created a simple Contacts command-line application and we'll use it to demonstrate some of the API features. The idea is so that the user will start the command-line Contacts application and issue interactive commands to perform the main functions mentioned earlier: create new contact, edit or view a contact, delete contact, list contacts, etc. At times, the Contacts application will need to render a form and will then launch a browser window so the user can see or fill in the Contact form.

...

But first, let's go over the Contact form and how to get it's API ID...

The Contact Form

Once you are logged in to , create an application named Contacts and then create a Contact form with a set of contact controls such as first name, last name, address, zip code, etc.

...

In case you need to search across all controls in the form (not only the ones specified as key fields) you can also select any number of controls to be saved in the Saved Fields tab. Note that at this point searches across non-key fields are slower for larger data sets.

Now save your form.

Get the Contact Form API ID

When using the Data API, you can find this Contact Form you just created either by getting a list of existing forms and finding the right one by name. This approach works but is a bit error prone in case another form could be created with the same name. In addition, it is also slower than getting the form directly by id.

...

Note that we plan to make this a bit more straightforward in future releases.

Download/Upload the Contacts application

Now that we have already created the Contact Form, we will manually download it from the UI, by going to the applications page and clicking the download button, and then use the application .zip to automatically upload it to aForms install the first time our command line app is executed. This simplifies the deployment since you only need to download command-line .jar and run it, i.e. no other configuration steps, and it also shows how you can use the API to upload an application (the same applies to forms, flows, schemas and themes) programmatically.

I will not get into the details of how this .zip file will be packaged into the command-line .jar, since all the sources for this tutorial are available to be downloaded.

Authentication & Session Management

When interacting with , the Contacts application will first need to establish a session using the Data API. This is done by using the com.frevvo.forms.client.FormsService class and by providing proper credentials to authenticate.

...

When this command-line program is terminating we make sure that we properly logout from . This ensures that  will release any unneeded resources and the user count will be decremented (licensing).

LoginAs

 supports an additional way of logging into  using the Data API: the loginAs() method. This new method allows you to login to  as any of the existing tenant users provided you can pass in the tenant's admin user and password. This is quite convenient when you want login to  using the same user that is logged into your application without having to know their password.

...

Code Block
   
        ...
	String tenantAdmin = getUsername() + '@' + getTenant();
	String tenantAdminPwd = getPassword();
	String username = getAsUsername();
	List<String> roles = new ArrayList<String>();
	roles.add("frevvo.Designer");
	FormsService s = new FormsService(getProtocol(), getHost(), getPort(), null);
	s.loginAs(username, tenantAdmin, tenantAdminPwd, true, roles, null, null, null, null);
	...
   

Upload Contact form

As described earlier, we have downloaded the Contacts application .zip file and embedded it in the command-line .jar. This .zip file is available from the JVM Classpath and will be automatically uploaded if it cannot be found in the server, i.e. usually the first time you connect to a /tenant install.

...

Code Block
 
public class ApiHelper {
	...
	static public ApplicationEntry uploadNewApplication(FormsService service, ApplicationFeed feed, InputStream is) throws ServiceException, IOException {
		MediaStreamSource ms = new MediaStreamSource(is, "application/zip");
		ApplicationEntry entry = feed.insert(ms);
		return entry;
	}
	...
	public static UserEntry getUserEntry(FormsService service) throws IOException, ServiceException {
		// strip away the tenant from the user name if any
		String username = service.getUsername();
		if (username.contains("@"))
			username = username.split("@")[0];
		return getEntry(service, UserEntry.class, username);
	}
	...
}

Download the form's XML Schema

Now that you have the Contacts application, you can also get the XML Schema for the Contact form using the API. You can try this out in our sample command line program by entering the view-xsd command:

...

Code Block
public class Contacts {
	...
	@Command
	public String viewXsd() {
		try {
			FormTypeEntry contactForm = getContactForm(getContactFormId());
			Link contactXsd = contactForm.getFormTypeSchemaLink();
			if (contactXsd != null && contactXsd.getHref() != null) {
				Util.openURL(contactXsd.getHref());
			}
			return "Viewing XML Schema for form "
					+ ApiHelper.getName(contactForm) + " [rel="
					+ contactXsd.getRel() + ",type=" + contactXsd.getType()
					+ ",href=" + contactXsd.getHref() + "] ...\n";
		} catch (Exception e) {
			return "Could not view XML Schema for form: " + e.getMessage();
		}
	}
}

List existing Contacts

Now that we are logged in to  and have the Contact application uploaded, let's list the current contacts we have in the submission's repository. This is done by entering the list command:

...

Code Block
public class Contacts {
    ...
    public String list() {
            try {
                FormTypeEntry contactForm = getContactForm();
                SubmissionFeed contacts = getContacts(contactForm.getSubmissionFeedLink());
                return ApiHelper.print(contacts);
            } catch (Exception e) {
                    return "Could not get the contacts: " + e.getMessage();
            }
    }
    ...
    protected FormTypeEntry getContactForm() throws IOException,
                    ServiceException {
            FormsService s = getService();
            try {
                    URL url = s.getEntryURL(FormTypeEntry.class, getContactFormId());
                    return s.getEntry(url, FormTypeEntry.class);
            } catch (ResourceNotFoundException e) {
                    return null;
            }
    }
    ...
    private SubmissionFeed getContacts(Link contactsLink) throws IOException,
                    ServiceException {
            URL contactsUrl = new URL(contactsLink.getHref());
            SubmissionQuery q = new SubmissionQuery(contactsUrl);
            if (getFilter() != null)
                    q.setFilter(getFilter());
            if (getOrderBy() != null)
                    q.setOrderby(getOrderBy());
            if( startIndex != null && startIndex >= 1 )
                    q.setStartIndex(startIndex);
            if( maxResults != null && maxResults >= 0 )
                    q.setMaxResults(maxResults);
            if( updatedMax != null )
                    q.setUpdatedMax(updatedMax);
            if( updatedMin != null )
                    q.setUpdatedMin(updatedMin);
            return getService().getFeed(q, SubmissionFeed.class);
    }
    ...

Create a new Contact

At this point we have no contacts in the repository. Let's go ahead and add one. This can be done by entering the create command in the command prompt:

...

See Url Parameters for more details on these parameters and note that the FormTypeEntry class has a variety of constants that can be of help (FormTypeEntry.EMBED_* and FormTypeEntry.FORMTYPE_*)

View an existing Contact

Now that we have at least one contact in our simple contacts database, lets view one of them. This is done by entering the view command followed by the index of the contact you want to view (the 1st column in the list command).

...

  • We are now using a slightly different link: instead of using the FormTypeEntry.getFormTypePopupLink(Map) we are using the FormTypeEntry.getFormTypeLink(Map). The former embeds the form in an outer HTML page using a script tag and the latter renders the form directly as html (this is the same raw url found in the Share Dialog).
  • We are setting the FormTypeEntry.FORMTYPE_READONLY_PARAMETER to TRUE.

View a PDF snapshot of the Contact form

Since we have configured the Contact Form to save a PDF snapshot (see the designer screenshot above) on submission, we have also implemented a variation of the view command that renders the PDF snapshot instead of the readonly form. Using our sample command line program you can view the PDF by entering the view-pdf command with the index of a given entry:

...

Code Block
<feed xmlns="http://www.w3.org/2005/Atom"
        xmlns:fd="http://schemas.frevvo.com/fdata/2008"
        xml:base="http://localhost:8080">
    ...
    <entry>
        <id>_8kuHuxK9EeCkOMNSkDQKVw</id>
        <title type="text">Contact Form</title>
        ...
        <link rel="document" type="application/pdf;frevvo-snapshot=true"
        href="/frevvo/web/tn/tutorial/user/admin/app/_lJ8_ERH8EeCl2et9BuDRPg/formtype/_pkMVwBH8EeCl2et9BuDRPg/document/b6281b35-1b01-41c5-9c82-dd12ff75a3b5?
        apikey=naVSbFS9HmazmoxGj3VFKybKGZnAQl2wE8VuS5dOMIfCXlKKUiBhhyhJw%252BWeD9uwftNR1zOQExM%253D"/>
    </entry>
    ...
</feed>

Download the Submission XML

So far we have viewed and edited the submission data, and have opened the PDF snapshot. You can also view the submitted XML document for a given contact.

...

Code Block
...
                MediaSource source = getService().getMedia(doc.getHref());
                saveXML(source.getInputStream());
...

Edit a Contact

Now that we can list and view contacts, and create new ones, let's edit one. This is done in this sample implementation by entering the edit command at the prompt.

...

Code Block
public class Contacts {
    ...
    public String edit(int i) {
        try {
                FormTypeEntry contactForm = getContactForm();
                SubmissionFeed contacts = getContacts(contactForm
                                .getSubmissionFeedLink());
                if (i < 1 || i > contacts.getEntries().size())
                        return "Invalid contact #: " + i;
                SubmissionEntry contact = contacts.getEntries().get(i - 1);
                Map<String, Object> params = new HashMap<String, Object>();
                params.put(FormTypeEntry.FORMTYPE_READONLY_PARAMETER, Boolean.FALSE);
                Link contactFormLink = contact.getFormTypeLink(params);
                Util.openURL(contactFormLink.getHref());
                return "Editing contact #" + i + " ...";
        } catch (Exception e) {
                return "Could not edit the contacts: " + e.getMessage();
                }
    }
    ...
}

Editing an External Contact

Note that editing a contact here is nothing more than rendering a form and initializing it with the XML document(s) stored in 's submission repository. Since this repository is embedded in , we have automated some of the work of instantiating a form and initializing it from an XML document(s). However, what if you are integrating  with your own application and have your own database of contacts? Not a problem. You can use the API to instantiate the form passing in a list of XML documents.

...

At this point we have taken an external XML document, which in our case was just an xml file sitting somewhere but could have been anywhere or even dynamically generated by your application, and instantiate a form with it. Here the user is in control and can modify the contact data using the form interface. When the Contact Form is submitted, you can also get a hold of the updated XML document to update your own contact database. This can be done by configuring a Doc Action in the form designer or even finding the submission entry for the submission and downloading the XML document.

Delete an existing Contact

How do we remove a contact? This is also quite simple. We do that by entering the delete command at the prompt with the contact index seen when listing the contacts.

...

Code Block
public class Contacts {
        ...
        public String delete(int i) {
             try {
                    FormTypeEntry contactForm = getContactForm();
                    SubmissionFeed contacts = getContacts(contactForm.getSubmissionFeedLink());

                    if (i < 1 || i > contacts.getEntries().size())
                            return "Invalid contact #: " + i;

                    SubmissionEntry contact = contacts.getEntries().get(i - 1);

                    contact.delete();

                    return "Deleted contact " + contact.getId() + "\n" + list();
             } catch (Exception e) {
                    return "Could not edit the contacts: " + e.getMessage();
             }
        }
        ...
}

Querying our simple Contacts repository

By default the list command we have been using so far is a simple query that returns the first page of all Contact Form submissions. There are situations where you may want to customize this query to return a subset of the results. Although we dont provide an extensive query API there are a few things you can do.

...

Now, let's go over some of the query parameters at your disposal in more detail.

Start Index

By default, submission queries will return entries starting from the first one. You can explicitly set a different start-index when paginating through a large set of entries (in SubmissionQuery.setStartIndex(Integer). In our sample program, you can do that by entering the start-index command at the prompt. Note that there is a bug in version 4.1.2 and earlier where start-index is interpreted as a 0-based index. This is fixed in version 4.1.3. So for instance:

...

Code Block
http://admin@localhost:8080/tutorial[start-index=1]> start-index -1
start-index query param updated to null ...
URL ! http://localhost:8080/frevvo/web/tn/tutorial/api/submissions?filter=%24formTypeId+eq+%27_pkMVwBH8EeCl2et9BuDRPg%27
  # | ID                      | CREATED                 | UPDATED                 | KIND   | STATE      | PDF? | LASTNAME         | FIRSTNAME        | ZIPCODE          | CITY             | STREET          
  1 | _MxibGhRzEeCkOMNSkDQKVw | 2010-12-30T19:16:23.000 | 2010-12-30T19:16:23.000 | FORM   | SUBMITTED  | true | Doe              | John             | 70778            | Atlanta          | 1 Main Street   
  2 | _QMZ_YRRzEeCkOMNSkDQKVw | 2010-12-30T19:16:46.000 | 2010-12-30T19:49:04.000 | FORM   | SUBMITTED  | true | Smarts           | Dave             | 06511            | New Haven        | 1 Ground Street 
http://admin@localhost:8080/tutorial> 

Max Results

You can also control the number of entries returned when executing a query. This is done by setting the max-results query parameter (SubmissionQuery.setMaxResults(Integer)):

...

Code Block
<context-param>
	<param-name>frevvo.submission.maxresults</param-name>
	<param-value>20</param-value>
	<description>Limit the maximum number of submissions that can be queried</description>
</context-param>

Order by

One thing you can do is order the results by a certain criteria:

...

Code Block
http://admin@localhost:8080/tutorial[orderBy=FirstName]> order-by ""
URL ! http://localhost:8080/frevvo/web/tn/tutorial/api/submissions?filter=%24formTypeId+eq+%27_pkMVwBH8EeCl2et9BuDRPg%27
  # | ID                      | CREATED                 | UPDATED                 | KIND   | STATE      | PDF? | LASTNAME         | FIRSTNAME        | ZIPCODE          | CITY             | STREET          
  1 | _MxibGhRzEeCkOMNSkDQKVw | 2010-12-30T19:16:23.000 | 2010-12-30T19:16:23.000 | FORM   | SUBMITTED  | true | Doe              | John             | 70778            | Atlanta          | 1 Main Street   
  2 | _QMZ_YRRzEeCkOMNSkDQKVw | 2010-12-30T19:16:46.000 | 2010-12-30T19:49:04.000 | FORM   | SUBMITTED  | true | Smarts           | Dave             | 06511            | New Haven        | 1 Ground Street 
http://admin@localhost:8080/tutorial>

Updated max/min

You can also filter submissions based on a date range using the updated-max and updated-min query parameters (SubmissionQuery.setUpdatedMax(DateTime) and SubmissionQuery.setUpdatedMin(DateTime)). These two parameters will filter submissions based on the last updated date (the updated date changes every time you save or submit a form/flow). So, back to your sample program, you can set the updated-min parameter as follows:

...

Code Block
http://admin@localhost:8080/tutorial[updated-max=2010-12-30T19:49:03.000]> updated-max ""
updated-max query param updated to null ...
URL ! http://localhost:8080/frevvo/web/tn/tutorial/api/submissions?filter=%24formTypeId+eq+%27_pkMVwBH8EeCl2et9BuDRPg%27
  # | ID                      | CREATED                 | UPDATED                 | KIND   | STATE      | PDF? | LASTNAME         | FIRSTNAME        | ZIPCODE          | CITY             | STREET          
  1 | _MxibGhRzEeCkOMNSkDQKVw | 2010-12-30T19:16:23.000 | 2010-12-30T19:16:23.000 | FORM   | SUBMITTED  | true | Doe              | John             | 70778            | Atlanta          | 1 Main Street   
  2 | _QMZ_YRRzEeCkOMNSkDQKVw | 2010-12-30T19:16:46.000 | 2010-12-30T19:49:04.000 | FORM   | SUBMITTED  | true | Smarts           | Dave             | 06511            | New Haven        | 1 Ground Street 
http://admin@localhost:8080/tutorial> 

Filtering

You can also do some basic filtering based on control values using the filter query parameter (SubmissionQuery.setFilter(String...)). This query parameter takes the following syntax: <field> eq '<value> (at this point we only support the equality operator eq). Here <field> can be any of the following:

...

Code Block
http://admin@localhost:8080/tutorial[filter=LastName eq 'Smarts'][filter=FirstName eq 'Dave']> filter "" 
URL ! http://localhost:8080/frevvo/web/tn/tutorial/api/submissions?filter=%24formTypeId+eq+%27_pkMVwBH8EeCl2et9BuDRPg%27
  # | ID                      | CREATED                 | UPDATED                 | KIND   | STATE      | PDF? | LASTNAME         | FIRSTNAME        | ZIPCODE          | CITY             | STREET          
  1 | _QMZ_YRRzEeCkOMNSkDQKVw | 2010-12-30T19:16:46.000 | 2010-12-30T19:49:04.000 | FORM   | SUBMITTED  | true | Smarts           | Dave             | 06511            | New Haven        | 1 Ground Street 
  2 | _MxibGhRzEeCkOMNSkDQKVw | 2010-12-30T19:16:23.000 | 2010-12-31T14:42:34.000 | FORM   | SUBMITTED  | true | Doe              | Dave             | 70778            | Atlanta          | 1 Main Street   
http://admin@localhost:8080/tutorial> 

Paginating

Listing the submissions for the Contacts' form will return only the first 20 entries (this can be configured using the context parameter ''frevvo.submission.maxresults found in WEB-INF/web.xml) and so you will need to paginate through the SubmissionFeed 20 entries at a time. This can be done by using a simple pattern as you can see in the com.frevvo.forms.cli.ApiHelper.print(SubmissionFeed) found in the Tutorial sources.

...

Pagination is only supported in the SubmissionFeed at this point and by default the feed will contain at most 20 entries. This can be configured per server using the frevvo.submission.maxresults context parameter found in the WEB-INF/web.xml.

What's next?

This very simple application shows how to interact with a static Contact form using the Data API and the browser. Except for when querying the contact submissions, most of the other steps could probably have been implemented by just copying the right form url, adding the correct parameters (readonly, etc) and embedding it directly inside your own web application.

...