ADEP and the Correspondence Management Solution

With the release of the Adobe Digital Enterprise Platform, you are now presented with the all new Correspondence Management Solution. Powered by the Digital Enterprise Platform, the solution brings in a whole new set of exciting features and enhanced user experience for correspondence authoring and generation. By virtue of the new platform, the solution is now easily extendable and customizable, and is packaged with a set of production-ready building blocks, reusable components and technical guides to help accelerate development and deployment of customer experience applications.

Check out the ADEP Developer Center for trial downloads. Please take time to watch this short solution introduction video.

Here are some useful links related to the solution, that one must refer to:

Installation and Configuration guides:

Overall Solution guides:

Detailed technical guides for the Building Blocks used in the solution:

For those dealing with customizations and solution extensions may find this handy:

You may also check out some more information on adobe.com @ Customer Communications.

Troubleshoot the Create Correspondence interface of the Adobe Correspondence Management Solution

Create Correspondence interface is the agent facing (flex based) application of the Adobe Correspondence Management Solution that is used to create the final correspondence, using a given Letter template.

In the event of an unexpected behavior or an unlikely error or to get more details on the request processing, there could be a need to troubleshoot the application. Following are some of the ways to do so.

General Flash Logs

Flash Log output is obviously critical when debugging a flex application. All general log messages, including the Form Bridge log output that is redirected from both the PDF and the HTML layers, is output to the Flash logs.

Of course, you would need Flash Debug player, which can be downloaded from the flash download site, to enable such logging. You can appropriately configure the logs based on your operating system.

The application also keeps an in-memory log of all messages that can be displayed using Ctrl + Alt + D, once initialized (note that you must have your mouse focus on the Flex application when you do so). The main purpose of this is so that we can get log contents even when the application isn’t run in a Flash Debug Player.

URL parameters

The Create Correspondence application can be enforced to log additional information by invoking it with some special URL parameters. Note that this can adversely affect the application performance, given the large amount of data being logged.

cmDataDebug

This flag (that can be given as a URL parameter) is used to specifically enable data output to the Flash Log. The output in such cases can be very large (for a complex templates that use large data) but sometimes it is critical to see the generated data the way it is sent to the PDF.

One can set it by including the following parameter in the URL parameters when invoking the Create Correspondence application:

cmDataDebug=1

This is an ON/OFF flag, so anything other than “0″ will activate the mode.

cmFbDebug

This is yet another flag, that is used to enable debugging and logging in the Form Bridge layers, and help troubleshoot communication issues. One can set it by including the following parameter in the URL parameters when invoking the Create Correspondence application:

cmFbDebug=[a,[b,[c,[d]]]]

where,
a = debug level until a connection is established (0 = none; 9 = highest/most verbose)
b = debug level after a connection is established (0 – none; 9 – highest/most verbose)
c = delay in seconds (can be a decimal, as in .1) after the HTML has created the PDF <object> and the time it sets its messageHandler (its definition of listener functions) on that object
d = delay in seconds (can be a decimal, as in .001) after the PDF has got as far as the ‘docReady’ message, until it starts to send it’s “initialized” connection message.

The above parameters can hence be tweaked according to the intent of troubleshooting. For instance, if there is a communication issue wherein the PDF takes longer to be ‘ready’ (may be due to a slow connection), you can tweak (increase) the value of  ‘d‘ to a value that sets enough delay for the communication to be successful. If there is a need to log detailed HTML-to-PDF communication messages for a user interaction on the flex app., you can set an appropriate value for ‘b‘.

Transporting assets in Adobe Correspondence Management Solution Accelerator (CMSA) 2.5

Transporting assets in the Correspondence Management Solution Accelerator 2.5  across systems is a common requirement and a frequent activity.

Exporting assets from the source system

CMSA being based on LiveCycle Content Services as the content repository, assets are exported as an ACP from the source system using steps documented in the CMSA guide. Such an exported ACP will contain ALL assets on the source system, and their relationships.

Importing assets to the target system

Importing assets (ACP exported above) on the target system will be largely driven by the intention, and desired behavior.

If the intention is to *create a replica of the source system* (and ignore whatever is on the target system), then perform the following on the target system:

  1. Delete DataStore (under Company Home).
  2. Ensure to delete the same from Deleted Itemsas well. To do so :
    1. Go to User Profile.
    2. Click Manage Deleted Items
    3. Click Show All
    4. Click Delete Listed Items
    5. Click Yes
  3. Delete files within Models (under Company Home > Data Dictionary).
    1. DO NOT delete the Models space itself.
  4. Delete files within lcc_persistence (under Company Home)
  5. Restart your server
  6. Bootstrap CMSA (http://server:port/cmsa/Bootstrap)
  7. Use the Import Utility to import the source system’s ACP
    1. “importWithDD” or “importWithoutDD” would depend on which Data Dictionaries do you wish to honor. The ones from the source system (use ‘importWithDD’) or the ones on the target system (use ‘importWithoutDD’).
  8. Restart your server

However, if the intention is to *keep the existing assets* and import whatever is in the ACP from the source system, then you should IGNORE steps 1. to 6., and simply execute step 7. (i.e., “Use the Import Utility to import the source system’s ACP”) and 8.

It is important to note that in such cases there could be a possibility of duplicate assets in the system, if the source and target systems contain assets by the same ‘name’; since we enforce the uniqueness in asset names via the CMSA interface only, but here we are directly importing assets onto the repository (bypassing the solution’s constraints).  

Fetching details of the User submitting a Correspondence

Often, there is a need (due to various auditing/logging purposes) to know the details (perhaps, just the user name) of the user who submits the final correspondence.

The Correspondence Management SA provides appropriate extension points to be able to do so. Here’s how…

One approach is to extend the default Submit Servlet (i.e., com.adobe.icc.submit.SubmitServlet available in adobe-acm-webmodules.jar), and introduce your own custom Servlet (which will be invoked when the user clicks ‘Submit’ in Create Correspondence, a.k.a Document Composer).

In that case, before you pass on the invocation to the “super” class (i.e., our default Submit servlet), all you need to do is fetch the current user and add an additional request parameter (the name of which should begin with ‘cm_’ — for instance, ‘cm_user’, and the fetched username as its value). Here’s a sample snippet:

—————————————————————————————————————-


UserDetails user = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); // fetches the current user details
Map extraParams = new HashMap();
extraParams.put(“cm_user”, new String[] { user.getUsername() }); // put the necessary details in a map (of parameters)

// wrap the request in a custom request wrapper (since the original request would be  immutable

—————————————————————————————————————-

The default Submit servlet will then take care of injecting this into the XML data (within the <icc:meta> tag, stripping off the ‘cm_’ from the parameter name). So, say if you added a request parameter ‘cm_user’, with a value of ‘John’, then here’s how the metadata (within the ICC Control Data) would look like:

 

<icc:meta>

<letter>letterName</letter>

<modificationDate>2010-10-27T17:57:49</modificationDate>

<user>John</user>

</icc:meta>

 

You could then fetch this data back within the post process, from within the submitted XML data (from within the <icc:meta> node).

See more on this (adding metadata to XML data) here.

Apart from adding this custom servlet implementation to the solution, you’ll also need to replace the default servlet registry entry (for the “/Submit” URL) with your servlet (within springServletWrapper-servlet.xml), as shown below:

 

1.       Define you servlet bean:

<!– Custom Submit Servlet –>

<bean id=“customSubmitServlet” class=com.adobe.icc.submit.CustomSubmitServlet>

<property name=“submitServlet” ref=“lc.icc.webapps.submit” />

</bean>

 

2.       Register your bean for the /Submit URL:

<!– Maps request paths at /* to the Servlets –>

<bean class=”org.springframework.web.servlet.handler.SimpleUrlHandlerMapping”>

<property name=”mappings”>

<value>

/UM=lc.icc.webapps.UM

/Render=lc.icc.webapps.render

/Submit=customSubmitServlet <!– replaces /Submit=lc.icc.webapps.submit –>

/Bootstrap=lc.cm.bootstrap

</value>

</property>

</bean>

Creating Text using the Correspondence Management APIs

While the classic way of creating Text in the Correspondence Management SA is using the Text Editor UI component, one may also want to create one or more Text modules using an API.

Following are the objects/services involved in creation of a Text Module using the APIs:

Here’s a sample of how to use these:

Creating the Text Module instance

TextModule tm = new TextModule(); // no-arg constructor
text.setName(textModuleName);
text.setDesc(description); // a meaningful description of the Text
text.setComment(comment); // a comment associated with the Text
text.setLcat(subCategory); // 'subCategory' is the SubCategory for the Text, and is of type 'com.adobe.icc.dbforms.obj.Category'
text.setUcat(category); // 'category' is the main Category for the Text, and is of type 'com.adobe.icc.dbforms.obj.Category'
text.setDataDictionaryRef(dataDictionaryName); // Name of the Data Dictionary used in this Text, if any.
text.setTBXXML(tbxXMLString); // tbxXMLString is a well-formed XML, that should comply to the expectations of a Text Module XML format. You could import/read this XML from a file using any of the standard java File reading utilities. It should have details such as the Text's plain text content, flash-html text content, xfa-xhtml content, etc. See the description on the TextModule API for more...

Here’s a sample XML that could be provided:

<content>
<guid/>
<name>text_test</name>
<desc>the description</desc>
<plainText>This is a paragraph with a variable: {^var^}</plainText>
<flashRichText><TEXTFORMAT LEADING="2" TABSTOPS="36,72,108,144,180,216,252,288,324,360,396,432,468,504,540,576,612,648,684,720"> <P ALIGN="LEFT"><FONT FACE="Times New Roman" SIZE="12" COLOR="#000000" LETTERSPACING="0" KERNING="0"> This is a paragraph with a variable: {^var^}</FONT></P></TEXTFORMAT>
</flashRichText>
<xfaXhtml><body xfa:APIVersion="2.4.5277.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/"> <p xml:space="preserve" style="text-align:left"><span style="letter-spacing: 0px; color: #000000; font-size: 12px; font-family: Times New Roman; xfa-spacerun:yes"> This is a paragraph with a variable: {^var^}</span></p></body>
</xfaXhtml>
</content>

The TextModule object API also exposes a comprehensive constructor that could be used to create a Text Module.

Persisting the Text Module instance

Now, once you have defined the above ‘text‘ object, you can persist that using the DataModuleService APIs. Here’s how:

DataModule dm = dataModuleService.createDataModule(text); // the returned 'dm' is the persisted Text module. you may further cast this into a 'TextModule'.

Managing the Text Module instance

You could also perform other actions  such as activate, update, etc. on the created Text (or already existing Texts) using the DataModuleService APIs such as activateDataModule(DataModule), updateDataModule(dataModule), etc. Please refer to the DataModuleService API docs for more.

See here for a comprehensive list of the CMSA documentation.

Role based access control on the Correspondence generation interface

More often that not would there be a need to prevent Correspondence generation access for non-eligible users, i.e. the user interface for creating a correspondence (Create Correspondence aka Document Composer UI) should not allow entry to such users and throw an (Access Denied) error.

Such access control can be achieved with a quick and simple customization in the solution’s security configurations (which is, by the way, backed by Spring Security). Here’s how…

The solution exposes a security configuration XML (placed @ [LiveCycle_ES_Home]\sa_resources\SA_SDK_9.5\CorrespondenceManagement\FSIApp\Portal\resources\spring-config.xml in the Solution Template). In order to secure the Create Correspondence UI to allow access to only people with a pre-defined role, say Correspondence Management Create Correspondence User, you need to:

  1. Create the above role (Correspondence Management Create Correspondence User) using the LiveCycle Administration UI), if it does not already exist.
  2. Add the following in the security configuration file (security-config.xml, indicated above), along with the other <sec:intercept-url…> elements in it:

<sec:intercept-url pattern=“/dc” access=“lcAuth:Correspondence Management Create Correspondence User” />

The above interception basically means that, when a user tries to invoke the application (which is exposed at the URL http://server:port/cmsa/dc), the system intercepts the request to check for the mentioned roles in the current user’s roles. Hence, as per the above configuration, this would only allow those users who have the “Correspondence Management Create Correspondence User” role to access the Create Correspondence UI.

Note: You can provide access to any other or more such roles by adding those roles (comma-separated) in the access attribute in the configuration above (do remember to prefix the LC roles names with lcAuth:).

Retrieving latest ACTIVE asset in the Correspondence Management Solution Accelerator

The Correspondence Management Solution Accelerator involves the concept of activating and versioning assets; if an Active asset is chosen for EDIT, you are prompted to create an Inactive copy of the asset which can then be edited. You can edit that Inactive copy and finally Activate it once completed with the editing. This Inactive copy now becomes the Active version, and the original version will be Archived. This process may continue as the asset is edited (and activated) again and again, thereby creating multiple versions of the asset in the system.

However, at any given time, there will only be a single ACTIVE version of the asset in the system (others being in ARCHIVE state). Hence, often may arise, due to various customization requirement, the need to search for this latest ACTIVE version for a given asset in the system. The Asset Composer Building Block provides APIs to easily achieve this.

Here’s an example to fetch the latest ACTIVE version of a given Letter (identified by its name) in the system:

// Build the Query object
Query qry = new Query();
Statement st1 = new Statement();
Statement st2 = new Statement();

// Set the statement attribute 'name'
// and value to name of the Letter
st1.setAttributeName("name");
st1.setOperator(Operator.EQUALS);
st1.setAttributeValue(letterName);

// Set the statement attribute name value to state
// and value to 'ACTIVE'
st2.setAttributeName("state");
st2.setOperator(Operator.EQUALS);
st2.setAttributeValue(DBConstants.ACTIVE);

// building query
qry.addStatement(st1);
qry.addStatement(st2);

List letterList;

try {
// fetching the Letter with the query constructed above
// must have an instance of the LetterService here (may be via Spring Dependency injection).
letterList = letterService.getAllLetters(qry);

String letterId = letterList.get(0).getId();
// Obtaining Form object, as getAllLetters query does not return
// 'full' form object
Letter letter = letterService.getLetter(letterId);

} catch (Exception e) {
// handle exception
}

Re-Activating old, archived assets in the Correspondence Management Solution Accelerator

The Manage Assets user interface of the  Correspondence Management Solution Accelerator allows various operations on assets, such as Create New, Active, Edit, Delete etc. When an asset (that should be in Inactive state) is Activated, any existing Active asset by the same name is Archived and this asset becomes the new Active asset (with an incremented version number; thus creating a new version of the asset).

Now, there could be a need to re-Activate the previous (now archived) version of that asset. The Manage Assets UI does not (out-of-the-box) allow you to do so (these actions are disabled on the UI, and the APIs also restrict the same). However, there are set of server side APIs that you could use/invoke to achieve the same (perhaps, configuring it as a custom Action on the Manage Assets UI, that in-turn invokes a custom service/operation which wraps the below steps/functionality).

Here are the (logical) steps that you’d need to take to be able to do so:

  1. Firstly, move any existing Active version to Archive, since you are not allowed to have multiple Active versions of the same asset. Obviously, this Active version MUST NOT be in use by any other asset.
  2. Fetch and Update the (archived) version of the asset object (that you wish to activate), setting its state to “Active” and version to “[version of the previous active asset] + 1″.

In terms of API calls, here is what you’d do/invoke (refer the API listing for details on usage of these APIs):

  1. Fetch the latest available Active asset object (if you already do not have that) — you could use the getAll[Asset-type]() like APIs to search for such an object (Asset-type being either DataModule, Letter, Form, etc., depending upon the asset that you are working on). For example, to fetch the current Active version of a Letter, you could use the LetterService.getAllLetters(Query query) API (building the appropriate Query for this).
  2. Delete the object fetched in (step 1) above, using the delete[Asset-type]() like APIs; this will move the current Active asset to Archive. For example, to delete/archive the current Active version of a Letter, you could use the LetterService.deleteLetter(String letterID) API (where letterID is the ID of the asset to be deleted).
  3. Fetch the asset object that you wish to (re)activate — again, searching for it using the getAll[Asset-type]() like APIs, as mentioned above. You’ll need to retrieve the full object by invoking the corresponding get[Asset-type]() API; for instance, LetterService.getLetter(String letterID) if you are working with Letters (where letterID is the ID of the Letter that you have searched for).
  4. Set the state of the object fetched in (step 3) to Active, using the Asset.setState(DBConstants.STATE_ACTIVE) API.
  5. Set the version of the object fetched in (step 3) to ([version of object fetched in (step 1)] + 1)
  6. Then, update this (state and version modified) object using the update[Asset-type]() like API; for instance, LetterService.updateLetter(Letter letter).

One important point to be noted here is that it is not advisable to (re)Activate an asset that in-turn uses/references other Archive assets (reason being, the Manage Assets UI does not allow you to work with or use/select/de-select Archived assets when authoring an asset; so, it may be difficult for you to work with (EDIT, in particular) such assets on the Manage Assets UI). Hence, one should first (re)activate the dependent assets (using the above steps) and then (re)activate the parent asset.

Extending the LiveCycle ES 2.5 Correspondence Management Solution Template to enlist additional Letters

The LiveCycle Correspondence Management Solution Accelerator’s Solution Template comes with a default set of Letter Templates (a.k.a Correspondence Templates) that are enlisted on the ST as shown below:

However, one can easily extend the Solution Template (ST) to enlist more such Templates that have been designed (and present) in the system. This can be done by adding the necessary details for the Letter in the InsuranceCorrespondece.xml file of the ST (available @ [LiveCycle_ES_Home]\sa_resources\SA_SDK_9.5\CorrespondenceManagement\FSIApp\Portal\resources).  Basically, one needs to add an entry in it for the Letter to be listed, with the entry containing the  “Display name” for Letter (in the drop-down) and the actual ‘name’ of the Letter, as given during the Letter Template authoring. Here’s an example:

Obviously, when a Template is selected on the ST, the Create Correspondence (CCR) UI is invoked for that Letter with the XML data for the corresponding user. The name of the XML data file, used to invoke the CCR UI with, should be of the form: <Username>.xml and should be placed in a folder under the following structure “assets/Letter/<Letter name>/Data/<Username>.xml“, where the “assets” folder is present at the root of the ST (i.e., @ [LiveCycle_ES_Home]\sa_resources\SA_SDK_9.5\CorrespondenceManagement).

For instance, the XML file name, containing data for the user “Akira Tananka” for a Letter named “SampleLetter”, should be placed as “assets/Letter/SampleLetter/Data/AkiraTanaka.xml” (just as you would find for the other Letters).

That’s it! You could go ahead and add any number of Letters this way….

Adobe LiveCycle ES 2.5 and the Correspondence Management

Adobe LiveCycle ES 2.5 and the Correspondence Management Solution Accelerator together revolutionize the way we create, author and manage correspondence. It provides a platform that helps enterprises quickly build and deploy applications that enhance customer experiences and overall productivity via compelling interactions. The various UI tools provided enable enterprises to create a custom and enhanced user experience right from correspondence authoring to generation.

The solution accelerator, along with the LiveCycle platform, allows interactive as well as system-driven correspondence generation in the form of a single PDF document (interactive or non-interactive) or a PDF Portfolio (with the ability to arrange documents in a hierarchical folder structure), with custom navigators, cover pages, etc. A comprehensive correspondence authoring is achieved via the use of Data Dictionaries (logical, hierarchical representation of the underlying data schema), Categories/Subcategories, reusable Layouts (XDP templates that can be used to define any number of Letter templates), and complex pre-approved content.

When integrated with LiveCycle Process Management (and possibly other solution accelerators and LiveCycle components such as Managed Review & Approval), one can design and achieve a complete workflow for the enterprise. The solution also provides integration mechanism with external third party systems for correspondence generation.

Also visit the LiveCycle Developer Center for more.