Scenario: Reader Extending PDF preview

You can configure Correspondence Management solution to use Adobe® LiveCycle® Reader Extensions module. This facilitates processing of PDF documents, such as saving, printing, and sharing, before they are rendered. Note that configuring Reader Extensions is not necessary if a client machine has Adobe® Acrobat® installed on it.

Implementation overview

The implementation for this user story involves code changes, re-building, and re-deploying the solution. Before you begin, ensure that you have performed the steps outlined in the Setting up your development environment chapter. After this, perform the following steps before you implement the user story.

Add the following Document Services client JARs to the classpath of the Services project of the Solution Template:
  • adobe-reader-extensions-client.jar

  • adobe-livecycle-client.jar

  • adobe-usermanager-client.jar

To add these client JARs to your classpath:
  1. Copy these to a folder named DS_SDK under the CorrespondenceManagementSolutionTemplate folder.

  2. In your Eclipse environment, right-click on the Services project, select Build Path > Configure Build Path.

  3. In the Properties pop-up window, click on Add External JARs...

  4. Browse to the DS_SDK folder, select all three JARs and click Open.

  5. Notice the three client JARs added to the Build path. Click OK to save your changes.

Next, provide a custom implementation of the DocumentRenderHandler interface that will reader-extend the PDF.

  1. Provide a custom implementation of the DocumentRenderHandler interface that will help extend the PDF document. See the code snippet below for an example:
    package com.adobe.icc; 
    import java.io.InputStream; 
    import java.util.HashMap; 
    import java.util.Map; 
    import org.slf4j.Logger; 
    import org.slf4j.LoggerFactory; 
    import com.adobe.icc.ddg.api.DocumentRenderHandler; 
    import com.adobe.idp.Document; 
    import com.adobe.idp.dsc.clientsdk.ServiceClientFactory; 
    import com.adobe.livecycle.readerextensions.client.ReaderExtensionsOptionSpec; 
    import com.adobe.livecycle.readerextensions.client.ReaderExtensionsServiceClient; 
    import com.adobe.livecycle.readerextensions.client.UsageRights; 
    /** 
     * Register document processing handler for Reader extending PDFs. 
     */ 
    public class ReaderExtendDocumentHandler implements DocumentRenderHandler { 
        protected final Logger logger = LoggerFactory.getLogger(getClass()); 
        private ServiceClientFactory serviceClientFactory; 
        public ServiceClientFactory getServiceClientFactory() { 
            return serviceClientFactory; 
        } 
        public void setServiceClientFactory( 
                ServiceClientFactory serviceClientFactory) { 
            this.serviceClientFactory = serviceClientFactory; 
        } 
        @Override 
        public int getHandlerType() { 
        return INTERACTIVE_DOCUMENT_HANDLER; 
        } 
        @Override 
        public Map<String, byte[]> preProcessDocument(byte[] xdp, byte[] xml) { 
            Map<String, byte[]> result = new HashMap<String, byte[]>(); 
            result.put(XDP_KEY, xdp); 
            result.put(XML_KEY, xml); 
            // doing nothing here - just return what we are given 
            return result; 
        } 
        @Override 
        public byte[] postProcessDocument(byte[] inputDoc) { 
            logger.info("[CUSTOMIZATION] RE document..."); 
            try { 
                return readerExtendDocument(inputDoc); 
            } catch (Exception e) { 
                logger.error("Failed to RE document : " + e.getMessage()); 
                e.printStackTrace(); 
            } 
            return inputDoc; 
        } 
        private byte[] readerExtendDocument(byte[] doc) throws Exception { 
            Document inputPDF = new Document(doc); 
            // Create a UsageRight object and specify specific usage rights 
            UsageRights useRight = new UsageRights(); 
            useRight.setEnabledDynamicFormFields(true); 
            useRight.setEnabledComments(true); 
            useRight.setEnabledFormFillIn(true); 
            useRight.setEnabledDigitalSignatures(true); 
            useRight.setEnabledFormDataImportExport(true); 
            // Create a ReaderExtensionsOptions object 
            ReaderExtensionsOptionSpec reOptions = new ReaderExtensionsOptionSpec(); 
            // Set the usage rights 
            reOptions.setUsageRights(useRight); 
            reOptions.setMessage("This is a Rights-Enabled PDF Document"); 
            ReaderExtensionsServiceClient readerExtensionClient = new ReaderExtensionsServiceClient( 
                    serviceClientFactory); 
            logger.info("Performing RE now..."); 
            // Apply usage rights to a PDF document 
            Document rightsEnabledPDF = readerExtensionClient.applyUsageRights( 
                    inputPDF, "PRODUCTION", null, reOptions); 
            InputStream is = rightsEnabledPDF.getInputStream(); 
            long length = is.available(); 
            byte[] bytes = new byte[(int) length]; 
            is.read(bytes); 
            logger.info("RE done. Returning bytes..."); 
            return bytes; 
        } 
    }
    The following APIs have to be implemented for the DocumentRenderHandler interface:
    Map<String, byte[]> preProcessDocument(byte[] xdpBytes, byte[] xmlBytes)
    The pre process API where you can use the XDP and XML data used for rendering the document. We are not doing anything with it for this user story.

    byte[] postProcessDocument(byte[])
    The API invoked from IRenderService that determines the post processing of the document. Use this API for your custom implementation.

    int getHandlerType()
    The API that determines type of the document being processed (interactive or non-interactive).

    Note: The above class is present in the com.adobe.icc package of the Services project.
  2. Register the custom implementation to the IRenderService by defining the following Spring initializing bean:
    package com.adobe.icc.bootstrap; 
    import java.util.ArrayList; 
    import java.util.List; 
    import org.slf4j.Logger; 
    import org.slf4j.LoggerFactory; 
    import org.springframework.beans.factory.InitializingBean; 
    import org.springframework.beans.factory.annotation.Autowired; 
    import com.adobe.icc.ReaderExtendDocumentHandler; 
    import com.adobe.icc.ddg.api.DocumentRenderHandler; 
    import com.adobe.icc.render.IRenderService; 
    /** 
     * Register document processing handlers. 
     */ 
    public class DocumentHandlerRegistration implements InitializingBean { 
        protected final Logger logger = LoggerFactory.getLogger(getClass()); 
        @Autowired 
        IRenderService renderService; // catch hold of the RenderService reference 
        @Autowired 
        ReaderExtendDocumentHandler readerExtendDocumentHandler; // your handler's instance 
         
        public void afterPropertiesSet() throws Exception 
        { 
            List<DocumentRenderHandler> handlers = new ArrayList<DocumentRenderHandler>(); 
            handlers.add(readerExtendDocumentHandler); // we have only one handler at this time, so add this to the list 
             
            renderService.setRenderHandlers(handlers); // register handlers 
        } 
    }
    Note: The above class is present in the com.adobe.icc.bootstrap package of the Services project.
  3. Define appropriate beans for the custom implementation in the adobe-cm-spring-config.xml file present at CorrespondenceManagementSolutionTemplate\Services\resources\META-INF\spring\cm\adobe-cm-spring-config.xml. See the following example for a sample bean definition:
    <?xml version="1.0" encoding="UTF-8"?> 
    <beans xmlns="http://www.springframework.org/schema/beans" 
        xmlns:flex="http://www.springframework.org/schema/flex" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:lang="http://www.springframework.org/schema/lang" 
        xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 
        xmlns:context="http://www.springframework.org/schema/context" 
        xmlns:sec="http://www.springframework.org/schema/security" 
        xsi:schemaLocation=" 
            http://www.springframework.org/schema/flex http://www.springframework.org/schema/flex/spring-flex-1.0.xsd 
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
            http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.5.xsd 
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd 
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd 
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd 
            http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd" 
            default-init-method="init"> 
           //IMPORTANT: If the following higlighted lines are not defined in the adobe-cm-spring-config.xml, you need to include them 
        <bean id="serviceClientFactory" 
            factory-bean="serviceClientFactoryProvider" factory-method="getDefaultServiceClientFactory" scope="prototype"> 
        </bean> 
        <bean id="lc.cm.readerExtendHandler" class="com.adobe.icc.ReaderExtendDocumentHandler"> 
            <property name="serviceClientFactory" ref="serviceClientFactory" /> 
        </bean> 
         
        <bean id="lc.cm.documentRegistration" class="com.adobe.icc.bootstrap.DocumentHandlerRegistration" />  
        <!-- ___________________ BootStraper beans _____________________ --> 
         
        <bean id="lc.cm.assetDefinitionsDeployer" class="com.adobe.icc.bootstrap.AssetDefinitionsDeployer"> 
            <property name="assetDefinitions"> 
                <list> 
                    <value>/apps/solutions/cm/assetDefinitions/ConditionalDataModule.fml</value> 
                    <value>/apps/solutions/cm/assetDefinitions/ImageModule.fml</value> 
                    <value>/apps/solutions/cm/assetDefinitions/Letter.fml</value> 
                    <value>/apps/solutions/cm/assetDefinitions/Layout.fml</value> 
                    <value>/apps/solutions/cm/assetDefinitions/ListDataModule.fml</value> 
                    <value>/apps/solutions/cm/assetDefinitions/TextModule.fml</value> 
                    <value>/apps/solutions/cm/assetDefinitions/DataDictionary.fml</value> 
                    <value>/apps/solutions/cm/assetDefinitions/Category.fml</value> 
                    <value>/apps/solutions/cm/assetDefinitions/DataModule.fml</value> 
                    <value>/apps/solutions/cm/assetDefinitions/FragmentLayout.fml</value> 
                    <value>/apps/solutions/cm/assetDefinitions/Asset.fml</value> 
                </list> 
            </property> 
            <property name="defaultCharacterEncoding" value="${defaultCharacterEncoding}"/> 
        </bean> 
         
         
    </beans>
    Note: Ensure that the text highlighted above is found in the adobe-cm-spring-config.xml file. Else, you need to include this text in the file.
    The IRenderService is exposed by the ACM Building Block. Hence, import it within the CM solution bundle by adding a reference to it in the osgi-context.xml present at CorrespondenceManagementSolutionTemplate\Services\resources\META-INF\spring\osgi-context.xml. The bean would reflect the following changes:
    <beans xmlns="http://www.springframework.org/schema/beans" 
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
           xmlns:bp="http://www.osgi.org/xmlns/blueprint/v1.0.0" 
           xmlns:context="http://www.springframework.org/schema/context" 
           xmlns:osgix="http://www.springframework.org/schema/osgi-compendium" 
           xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd 
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 
            http://www.springframework.org/schema/osgi-compendium http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd"> 
    //IMPORTANT: If the following higlighted line is not defined in the adobe-cm-spring-config.xml, you need to include it 
        <import resource="cm/adobe-cm-spring-config.xml"/> 
        <bp:blueprint> 
            <!-- <bp:service interface="com.adobe.icc.ddg.api.LetterRenderService" ranking="10" ref="customRenderService"> 
                   <bp:service-properties> 
                           <entry key="connectors.httpinvoker" value="true" /> 
                           <entry key="connectors.httpinvoker.alias" value="/lc.icc.renderlib.letterRenderService" /> 
                    </bp:service-properties> 
            </bp:service> --> 
             
            <bp:reference id="osgi.resourceResolverFactory" interface="org.apache.sling.api.resource.ResourceResolverFactory"/> 
            <bp:reference interface="org.apache.sling.settings.SlingSettingsService"/> 
             
            <bp:reference interface="com.adobe.livecycle.content.config.ApplicationManager" /> 
            
            <bp:reference id="serviceClientFactoryProvider" interface="com.adobe.livecycle.dsc.clientsdk.ServiceClientFactoryProvider" /> 
            
            <!-- <bp:reference interface="com.adobe.idp.applicationmanager.service.ApplicationManager" /> --> 
             
    //IMPORTANT: If the following higlighted line is not defined in the adobe-cm-spring-config.xml, you need to include it 
            <bp:reference interface="com.adobe.icc.render.IRenderService" /> 
            <bp:reference interface="com.adobe.dct.service.DataDictionaryUtilService" /> 
            <bp:reference interface="com.adobe.dct.service.DataDictionaryRegistryService" /> 
            <bp:reference interface="com.adobe.livecycle.content.activate.ActivateBootstrapper" /> 
            <bp:reference id="lc.content.remote.fileService" interface="com.adobe.livecycle.content.repository.FileService" /> 
                     
        </bp:blueprint> 
        <osgix:cm-properties id="cmProps" persistent-id="com.adobe.livecycle.cm"> 
            <prop key="tmpfolder">C:/temp</prop> 
            <prop key="xmlfile.name">/WEB-INF/classes/ExampleData.xml</prop> 
            <prop key="letterfile.name">/WEB-INF/classes/InsuranceCorrespondance.xml</prop> 
            <prop key="icc.letter.id.name">cmLetterName=</prop> 
            <prop key="icc.user.testdata.name">cmLetterState=1&amp;cmUseTestData=1</prop> 
            <prop key="icc.data.url">cmDataUrl=assets/</prop> 
            <prop key="icc.preview.name">cmPreview=0</prop> 
            <prop key="defaultCharacterEncoding">UTF-8</prop> 
        </osgix:cm-properties> 
        <context:property-placeholder properties-ref="cmProps" /> 
        
        <!-- IMPORTANT: This tag is responsible for enabling annotations like autowiring etc --> 
    //IMPORTANT: If the following higlighted lines are not defined in the adobe-cm-spring-config.xml, you need to include them 
        <context:annotation-config/> 
        <bean id="serviceClientFactory" 
                factory-bean="serviceClientFactoryProvider" factory-method="getDefaultServiceClientFactory"> 
        </bean>  
         
    </beans>
    Note: Ensure that the text highlighted above is found in the the osgi-context.xml file. Else, you need to include this text in the file.
  4. Import packages of Services/APIs found in the LiveCycle SDK (com.adobe.idp and com.adobe.idp.dsc) into the BND configuration file (cmsa.bnd) of the Correspondence Management bundle present at CorrespondenceManagementSolutionTemplate\Services\bnd\cmsa.bnd. See the following code snippet of the BND file for an example:
    version=1.0.0 
    Export-Package: com.adobe.icc;com.adobe.icc.bootstrap;version=${version} 
    //IMPORTANT: If the following higlighted line is not defined in the adobe-cm-spring-config.xml, you need to include it 
    Import-Package: com.adobe.idp,com.adobe.idp.dsc,com.adobe.livecycle.readerextensions.client.* 
    Bundle-Version: ${version} 
    Bundle-Description: Adobe Correspondence Management Solution Bundle 
    Bundle-SymbolicName: com.adobe.livecycle.cm 
    X-Spring-Context: META-INF/spring/cm 
    Spring-Context: META-INF/spring/osgi-context.xml
    Note: Ensure that the text highlighted above is found in the BND configuration file. Else, you need to include this text in the file.
  5. Perform the following steps to make necessary changes to the build.xml file of the Services project present at CorrespondenceManagementSolutionTemplate\Services\build.xml:
    • Add client jars to the build classpath by adding the following fileset entry:
      ... 
               <fileset dir="../DS_SDK"> 
              <include name="*.jar"/> 
           </fileset> 
      ...
    • Embed classes within the client JAR within the bundle.

    The build.xml file will reflect the above changes:
    <?xml version="1.0" encoding="UTF-8"?> 
    <!-- 
    /* 
     * ADOBE SYSTEMS INCORPORATED 
     * Copyright 2010 Adobe Systems Incorporated 
     * All Rights Reserved. 
     * 
     * NOTICE:  Adobe permits you to use, modify, and distribute this file in accordance with the 
     * terms of the Adobe license agreement accompanying it.  If you have received this file from a 
     * source other than Adobe, then your use, modification, or distribution of it requires the prior 
     * written permission of Adobe. 
     */ 
    --> 
    <project name="solution-template-build" default="build-bundle" basedir="."> 
         
        <property file="../build/build.properties"/> 
        <property file="build.properties"/> 
         
        <target name="compile" description="Compile and copy the source" depends="clean"> 
            <echo>Compile classes ...</echo> 
            <path id="build.class.path"> 
                <fileset dir="../"> 
                    <include name="*.jar"/> 
                </fileset> 
                <fileset dir="../DS_SDK"> 
                    <include name="*.jar"/> 
                </fileset> 
                <fileset dir="${tp.lib.dir}"> 
                    <include name="*.jar"/> 
                </fileset> 
                <fileset dir="${[SDK]}/riaservices/assetcomposer/10.0.0.0/java"> 
                    <include name="*.jar"/> 
                </fileset> 
                <fileset dir="${[SDK]}/riaservices/datadictionary/10.0.0.0/java"> 
                    <include name="*.jar"/> 
                </fileset> 
                <fileset dir="${[SDK]}/riaservices/riacore/10.0.0.0/java"> 
                    <include name="*.jar"/> 
                </fileset> 
            </path> 
            <mkdir dir="dist/classes"/> 
            <javac destdir="dist/classes" srcdir="./src" classpathref="build.class.path" debug="true" verbose="false"/> 
            <jar destfile="dist/cmsa.jar"> 
                <fileset dir="dist/classes"> 
                    <include name="**/*"/> 
                </fileset> 
                <fileset dir="./resources"> 
                    <include name="**/*"/> 
                </fileset> 
            </jar> 
        </target> 
         
        <target name="clean"> 
            <echo>Cleanup..</echo> 
            <delete dir="dist"/> 
        </target> 
         
        <target name="build-bundle" depends="compile"> 
           <taskdef resource="aQute/bnd/ant/taskdef.properties" classpath="${tp.lib.dir}/biz.aQute.bnd.jar"/> 
           <bndwrap definitions="bnd" output="dist" jars="dist/cmsa.jar">  
            </bndwrap> 
            <zip destfile="dist/cmsa_withRE.bar"> 
                <zipgroupfileset dir="../" 
                    includes="Services/dist/cmsa.bar,DS_SDK/adobe-reader-extensions-client.jar"/> 
            </zip> 
            <move file="dist/cmsa_withRE.bar" overwrite="true" tofile="dist/cmsa.jar"/> 
        </target> 
    </project>
  6. Build and deploy the solution template to complete your custom implementation of Reader Extensions API for Correspondence Management. See Building and deploying the Solution Template for more information.

Note: ReaderExtentionsServices must be added in dscserviceWhiteList before you build and deploy this solution. For details, see Associate Letter with Post Process.

// Ethnio survey code removed