Archive for July, 2013

Backward compatibility configuration

Ensuring upgrade compatibility across LiveCycle versions is of prime importance for Adobe and our customers relish that. This means if a feature works in a certain way in a release it will continue to do so.
One can configure Mobile Form to get the behavior of a feature in older versions. You can browse through http://localhost:8080/lc/system/console/configMgr and search for “LC Forms Configuration”. On clicking, it should expand like the following:

version

If anyone is upgrading the Mobile Form specifically from ES4 to ES4 SP1, then to make sure the upgrade compatibility one should select “LiveCycle ES4″ from the browser. In ES4 SP1, we changed the way we submit the form for details refer to Mobile Form Service Proxy post. If you want to use the older way of submission, you can select “LiveCycle ES4″ version behavior.

Mobile Form goes Right To Left

With ES4 SP1, we added support for Right To Left languages like Hebrew in Mobile Form. Now you can see html for your hebrew forms. Not only that but you can also fill the fields in Hebrew. We also support mix and match of English or any Left to Right script for that matter with Hebrew in form fields. Based on form locale we even show the date and days info in localized form.
rtl

Limitations

Here comes the limitations. It works perfectly fine in all other supported browsers except IE. IE lacks basic support for Right To Left scripts so Mobile Form doesn’t support RTL in IE.

Passing parameters to Mobile Form

In LC ES4, we get this feedback from customers that they want to hide the parameters passed to Mobile Form profile to render a form. If you could see the There was only one way to pass parameters that is through request parameters (refer to Mobile Profile page). In ES4 SP1, we introduced couple more ways to pass parameters to Mobile Form.
You can pass parameters by using setAttribute(parameter_name, parameter_value) on the request object if you are forwarding a request from any other jsp/servlet to Mobile Form profile jsp/servlet. This will have highest precedence.
Another way to pass parameters is through profile node i.e. the node where request is made. For example, http://localhost:8080/lc/content/xfaforms/profiles/test.html /content/xfaforms/profiles/test is the profile node. You can specify parameters as node properties on this node using crxde.
profileNode

Mobile Form gives highest precedence to parameter values set using setAttribute then it falls back to profile node properties and in the last it reads values through request parameters.

Create custom Mobile Form profile

Mobile Form renders the form based on profile. If you want to change the look and feel or do other customization, you are required to make modifications in the default profile. In ES4, Mobile Form profile script was one single monolithic jsp file. So if you want to modify the profile script you have to copy the whole script and then make the changes as suggested in ES4 Adobe documentation. This way, you loose the updates provided in the script over different patches.

With ES4 SP1, we have modularized the various constituents of profile renderer instead of one monolithic profile. The profile script is still html.jsp and html.POST.jsp for GET and POST requests. One can choose to override or add his customization by copying and modifying one or more files. It is not recommended to modify any of the files in place or you will loose the changes after a patch.

You should create an application directory in /apps space and copy html.jsp and other files you want to modify. Before delving into the steps of customization, I will discuss the changed structure of html.jsp.

html.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<%@ page session="false"
               contentType="text/html; charset=utf-8"%><%
%><%@ taglib prefix="cq" uri="http://www.day.com/taglibs/cq/1.0" %><%
%><!DOCTYPE html>
<html manifest="${param.offlineSpec}">
    <head>
        <cq:include script="formRuntime.jsp"/>
    </head>
    <body id="formBody">
        <!--
        add pdf like toolbar to your profile page
        this same toolbar is use for showing browser support warning..
        -->
        <cq:include script="../toolbar/toolbar.jsp"/>
        <cq:include script="config.jsp"/>
        <!-- Form body -->
        <cq:include script="formBody.jsp"/>
        <!  --To assist in page transitions -- add navigation, based on scrolling -->
        <cq:include  script="../nav/scroll/nav_footer.jsp"/>
        <cq:include script="footer.jsp"/>
    </body>
</html>

As you can see html.jsp is just serves as composition jsp. Now customization means, you need to create new components and add them into the appropriate section of html.jsp.

In subsequent sections, I will explore all the components of html.jsp in detail.

formRuntime.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<%@ page import="java.util.ArrayList" %><%
%><%@taglib prefix="cq" uri="http://www.day.com/taglibs/cq/1.0" %><%
%><%
    String acceptLang = request.getHeader("accept-language");
    if(acceptLang == null || "".equals(acceptLang.trim()))
        acceptLang = "en-US";
    acceptLang = acceptLang.trim();
 
    String[] locales = acceptLang.split(",");
    ArrayList<String> localeChainList = new ArrayList<String>();
    for(int i=0; i<locales.length; i++)
    {
        String locale =locales[i];
        if(locale.trim().startsWith("en") && !localeChainList.contains("en_US"))
            localeChainList.add("en_US");
        if(locale.trim().startsWith("de") && !localeChainList.contains("de_DE"))
            localeChainList.add("de_DE");
        if(locale.trim().startsWith("ja") && !localeChainList.contains("ja"))
            localeChainList.add("ja");
        if(locale.trim().startsWith("fr") && !localeChainList.contains("fr_FR"))
            localeChainList.add("fr_FR");
    }
 
    String locale = "";
    if (localeChainList.isEmpty())
        locale = "en_US";
    else
    {
        locale = localeChainList.get(0).trim();
    }
    request.setAttribute("xfaLocale",locale.replace("_",""));
%><%
%>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta charset="UTF-8">
<title>LC Forms</title>
<cq:includeClientLib categories="xfaforms.I18N.${xfaLocale},xfaforms.profile.default" />

As you can see it contains the references to the client libraries to include. It also depicts how one can extract locale information from the request and include the localized messages related to Mobile Forms runtime. You can create a JSP like this to include your own scripts and styles and add it to the head section of html.jsp.

config.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<%@ page session="false"
               import="com.adobe.forms.service.LCFormsOptionService,
                       com.adobe.forms.admin.LCFormsAdminService
               " %>
<%@ page import="org.apache.sling.settings.SlingSettingsService" %>
<%
%><%@taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling/1.0"%><%
%><sling:defineObjects/><%
%><%
    LCFormsOptionService lcFormsOptionService = sling.getService(LCFormsOptionService.class);
    //read debugDir to pass it along with server API endpoint -- use it for debugging.
    String debugDir = lcFormsOptionService.get(slingRequest, "debugDir");
 
    if(debugDir != null && !debugDir.isEmpty()) {
        debugDir = "?debugDir="+debugDir;
    }
    else {
        debugDir = "";
    }
 
    SlingSettingsService slingSettingsService = sling.getService(SlingSettingsService.class);
    boolean  isLCEmbedded = slingSettingsService.getRunModes().contains("livecycle");
 
    //lcServerProxy that will handle forms server api requests and also submission...
    String submitServiceProxy = lcFormsOptionService.get(slingRequest, "submitServiceProxy");
    if(submitServiceProxy == null) //if running into lc embedded mode then append /lc
        submitServiceProxy = (isLCEmbedded ? "/lc" : "") + "/bin/xfaforms/submitaction"+debugDir;
    String logServiceProxy = lcFormsOptionService.get(slingRequest, "logServiceProxy");
 
    if(logServiceProxy == null)
        logServiceProxy = (isLCEmbedded ? "/lc" : "") + "/bin/xfaforms/logger";
 
    String submitUrl = lcFormsOptionService.get(slingRequest, "submitUrl");
    if(submitUrl == null)
        submitUrl = "";
    //to enable logging options...
    LCFormsAdminService formsAdminService = sling.getService(LCFormsAdminService.class);
    formsAdminService.setupLogging (slingRequest);
    String originalVersion = formsAdminService.getOriginalVersion();
%><%
%><script>
    //Set logger config for client side logging and troubleshooting --
    window.formBridge.registerConfig("behaviorConfig", {
        "originalVersion": <%=originalVersion%>
    });
 
    window.formBridge.registerConfig("LoggerConfig",
            {
                "on":"${loggingEnabled}",
                "category":["xfa", "xfaView", "xfaPerf"],
                "level":[${xfaLevel}, ${xfaViewLevel}, ${xfaPerfLevel}],
                "type":"${loggerType}"
            }
    );
 
    //config to specify endpoint for submission.You can add as many parameters as you want
    window.formBridge.registerConfig("submitServiceProxyConfig",
            {
                "submitServiceProxy" : "<%=submitServiceProxy%>",
                "logServiceProxy": "<%=logServiceProxy%>",
                "submitUrl" : "<%=submitUrl%>"
            }
    );
</script>

As you can see this component of profile contains the various configurations like logging, proxy services, behaviour version etc. If you want to add you own config then this is the place. You can add various configurations like custom widget registration etc just like this in a JSP of your own.

toolbar.jsp

1
2
3
4
5
6
7
<%@taglib prefix="cq" uri="http://www.day.com/taglibs/cq/1.0" %><%
%>
<div class="toolbarheader" style="display:inline-block;width:100%" role="toolbar">
    <span id="toolbartext" class="toolbarformslogo"></span><span id="toolbartextinternal" class="toolbartext" style="line-height: 33px;">Please fill out the following form.</span>
    <button id="toolbarhighlight" tabindex="1" role="button" aria-labelledby="toolbartext" class="toolbarfieldhighlight"><span class="toolbartext">Highlight Existing Fields</span></button>
    <button id="toolbarloggerbtn" class="toolbarlogger" style="display: none"><span class="toolbartext">Send Logs</span></button>
</div>

This component is responsible for the red coloured toolbar you notice at the top. In case you want to get rid of the toolbar, you can remove this from the html.jsp.

formBody.jsp

1
2
<%@taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling/1.0"%>
<sling:include resourceType="xfaforms/render"/>

This component is for the html presentation of the XFA form. As shown in html.jsp, you can include this component in the body section of the html.

nav_footer.jsp

1
2
3
4
5
6
7
8
9
10
11
12
<footer>
     <div class="pagingfooter" style="display:inline-block;width:100%" role="status">
        <div id="loadingpage" style="width:100%;display:inline-block" align="center">
            <span  class="pageloadinglogo"></span>
            <span class="pageloadtext" style="line-height: 33px;">Loading...</span>
            <a class="pageloadnow" style="float:right" href="javascript:renderNextPage()"><span class="pageloadtext">--Load now--</span></a>
        </div>
        <div id="nomorepages" style="display: none;width:100%" align="center">
            </span><span class="pageloadtext" style="line-height: 33px;">--No more pages--</span>
        </div>
    </div>
</footer>

Mobile Form only renders the first page of the form at first and then subsequently load the pages on scroll to give faster loading experience. This component contains all the styles and required elements to facilitate this.

footer.jsp

1
<!-- Empty for now -->

This is empty for now. But in case you want to add any scripts that is used in user interaction only then you should include that in this section.

Creating Custom profile

Now that we understand what all components does then one can choose to modify a component. Here are the steps on how to create a custom profile.

Creating profile node:

Note: The name of the newly created folders (hrform and demo) can be anything as per your preference.

  1. Navigate to the CRX DE interface at the URL: http://<server>:<port>/lc/crx/de and log in to the interface with administrator credentials.
  2. In the left pane, navigate to the location: /content/xfaforms/profiles.
  3. Copy the node default, and paste the node in different folder e.g. (/content/yourapp/profiles) with the name: hrform.
  4. Select the new node, hrform, and add a string property: sling:resourceType with value: hrform/demo.
  5. Click Save All in toolbar menu to save the changes.

Creating the profile renderer script:

After creating a custom profile, add render information to this profile. On receiving a request for the new profile, CRX verifies the existence of the /apps folder for the JSP page to be rendered. Create the JSP page in the /apps folder.

  1. In the left pane, navigate to the /apps folder.
  2. Right-click on the /apps folder and choose to create a folder with name: hrform.
  3. Insider the hrform folder create a folder: demo.
  4. Click the Save All button.
  5. Navigate to /libs/xfaforms/profile/html.jsp and copy the node html.jsp.
  6. Paste html.jsp node into the /apps/hrform/demo folder created above with same name html.jsp and click Save.
  7. You copy any of the other components of profile script as described above and paste it in the same folder.

Verifying the updates

Render a form using Mobile Forms IVS with the custom profile:

  1. Navigate to http://localhost:8080/mobileformsivs.
  2. Choose and update the form demo.xdp.
  3. Select the demo.xdp form. Choose Custom in profile, and specify hrform as the profile name.

Debugging Mobile Form

Logging in Mobile Form or any application for that matter is of utmost importance. It helps our customers in debugging the various issues in forms including performance. Mobile Form is a distributed application. It has a server component that generates data for the XFA runtime. XFA runtime is a javascript implementation of XFA reference that runs inside the browser and interprets the data generated by the Mobile Form server to render an XFA template and data in html5. In distributes scenario, logging helps a lot in keeping tab at what is going on at various sites.

Mobile Form has two distinct sites or two different components the Mobile Form server and XFA runtime.  One can configure Logger, individually (server and client), based on the requirements and set the levels for any specific request.

I will first describe on how to enable fine level logging in Mobile Form server and how to make sense out of it.

The steps are outlined as following:

  1. Go to http://<server>:<port>/lc/system/console/configMgr and look for “Apace Sling logging logger configuration” and click on it. You see a dialog like following:
  2. Select the Log Level to Debug.
  3. Specify a log file name. If you want to generate logs in the same directory i.e. <lc-install-dir>/crx-repository/logs, where other log files are kept then specify ../logs/<logfilename>.
  4. Specify Logger to HTMLFormsPerfLogger and save the configuration.

logconfig

 

That’s it. Now you can find the logs with performance for each render request. The log entries should look like the following:

04.07.2012 17:58:14.054 *DEBUG* [10.40.54.72 [1341404888673] GET /content/xfaforms/profiles/test.html HTTP/1.1] HTMLFormsPerfLogger !PERFORMANCE! <RenderOsgiServiceImpl.render>

04.07.2012 17:58:14.142 *DEBUG* [10.40.54.72 [1341404888673] GET /content/xfaforms/profiles/test.html HTTP/1.1] HTMLFormsPerfLogger !PERFORMANCE! <time>4004644004ns</time></RenderOsgiServiceImpl.render>

We are interested only in the last word of these log line. That will give you a valid xml file containing all the timings. Each label of the node represents the name of the API and <time> node contains the time taken by that API. You can use awk to generate that xml file. The following command would do: awk ‘{ print $11 }’ <logfilepath>

It is called perf logger because it generates performance information along with the trace. That is it about Mobile Form server logging. Now let’s move to client side logging.

There are two ways to enable XFA runtime client side logging. Like Mobile Form server logging, one way is to enable logs via configuration another via request parameter log. If you just want to generate logs for one particular request, you should use the 2nd approach i.e. pass the request parameter. The log parameter takes log configuration that is defined as follows:

{destination}-{a level}-{b level}-{c level}

For example:

Log Configuration Description
2-a4-b5-c6 Destination: Server
xfa level: INFO
xfaView level: DEBUG
xfaPerf level: TRACE

 

Let’s explore various constituents of log configuration. destination  is where log is redirected:

Log Destination

Log Destination Description
1 Logs are directed to the browser Console
2 Logs are collected in a JavaScript object on client side and can be posted to the Server
3 Both of the above options

 

Log Levels and Logger Categories are other constituents.

Log Levels

Log Level Description
0 OFF
1 FATAL
2 ERROR
3 WARN
4 INFO
5 DEBUG
6 TRACE
7 ALL

Logger Categories

Log Category Description
a xfa (Scripting engine related logs)
b xfaView (Layout engine related logs)
c xfaPerf (Performance related logs)

The default log level for each log category a (xfa), b (xfaView), and c (xfaPerf) is 2 (ERROR). Accordingly, for log configuration: 2-b6, the log levels for different categories are:

a (xfa): 2 (default level ERROR)
b (xfaView): 6 (user specified TRACE)
a (xfaPerf): 2 (default level ERROR)

 

You specify the log configuration using LC Forms Configuration:

  1. Search for and click LC Forms Configurations on http://<server>:<port>/lc/system/console/configMgr page.
  2. In the Debug Options text box, enter the log configurations as described in the previous section e.g. 2-a4-b5-c6.

 

using_config_mgr

 

If the destination is set as 1, all client script log messages are directed to the console. But at times Admin might need these logs along with server logs to co relate the two and for such cases destination level can be set to 2. At this level, all logs would be collected in a JS object on client side and if form is rendered with default Profile then a Send Logs button would appear to the left of Highlight Existing Fields button in toolbar. On click of this link all collected logs would be posted to the server and will be logged in the configured error log file on the server.

With ES4 SP1, you can also redirect client logs to a separate log file like Mobile Form server logs using the same steps mentioned to configure “Apace Sling logging logger configuration”  above in server logging section.

 

POST data size limit

A generic Mobile Form workflow involves rendering a form, filling up fields and then submit it for further processing. Mobile Form submits data to server on HTTP POST. If the form is very big or it is merged with large size data, sometimes there is chance that the submission payload exceeds the default limit of the server. In this case, you might see HTTP 500 error on form submission. If you inspect the server logs, you will see this exception – “Template is not specified”.

On jboss server, POST size limit is 2MB as per its documentation. You can increase the POST size limits and here is how to do it for JBOSS.

  • Go to <jboss_dir>/server/<server_name>/deploy/jbossweb.sar directory and look for server.xml.
  • There is a <Connector> specified for “HTTP/1.1″ protocol like this

<Connector protocol=”HTTP/1.1″ port=”8080″ ….>

  • Add an attribute “maxPostSize” to this if not already added. Specify its value as per the requirement. ’0′ means there is no limit on POST size.

After changing the settings, you have to restart the app server to affect these changes. After this you should be able to submit the form.