Szenario: Correspondence Management-Dienste in einem LiveCycle-Prozess aufrufen

Sie können die Correspondence Management Solution-APIs in der LiveCycle-Plattform (Prozess/Orchestrierung) als Teil eines größeren Workflows aufrufen.

Um einen benutzerdefinierten Dienstcontainer zu erstellen, sind die folgenden Bibliotheken erforderlich:
  • com.springsource.org.aopalliance-1.0.0.jar

  • spring-aop-3.0.2.RELEASE.jar

  • spring-asm-3.0.2.RELEASE.jar

  • spring-beans-3.0.2.RELEASE.jar

  • spring-context-3.0.2.RELEASE.jar

  • spring-core-3.0.2.RELEASE.jar

  • spring-expression-3.0.2.RELEASE.jar

  • spring-security-core-3.0.2.RELEASE.jar

  • spring-security-web-3.0.2.RELEASE.jar

  • spring-web-3.0.2.RELEASE.jar

  • dom4j-1.6.1.jar

  • commons-logging-1.1.jar

  • adobe-acm-client.jar

  • adobe-dct-client.jar

  • lc-content-api.jar

Übersicht über die Implementierung

In den folgenden Beispielen werden benutzerdefinierte Dienstcontainer erstellt, die Folgendes offenlegen (Dienstcontainervorgänge in der Orchestrierung):
  • Benutzerdefinierte Dienstvorgänge, die die Correspondence Management-APIs intern nutzen

  • Direkte Correspondence Management-APIs/-Vorgänge

Benutzerdefinierter Dienst als ein Dienstcontainervorgang

Sie können einen benutzerdefinierten Dienstvorgang implementieren, der die Correspondence Management-APIs verwendet, um einige Funktionen zu implementieren. Anschließend können Sie diesen Vorgang in Ihrem Dienstcontainer offenlegen. Führen Sie zu diesem Zweck die folgenden Aufgaben durch:
  1. Benutzerdefinierten Dienst erstellen

  2. Den Dienst als Bean registrieren

  3. Die offengelegte Eigenschaftsdatei für die Komponente erstellen

  4. Den benutzerdefinierten Dienst als einen LiveCycle-Dienst exportieren

  5. Dienstcontainerkomponente definieren

Benutzerdefinierten Dienst erstellen

Schreiben Sie einen schnittstellenbasierten benutzerdefinierten Dienst, der die offengelegten Correspondence Management-APIs verwendet, um die erforderliche benutzerdefinierte Aufgabe zu erfüllen. Im folgenden Beispiel wird ein Dienst offengelegt, um die verarbeitete Layout-Vorlage einer Korrespondenz und die verarbeiteten XML-Daten abzurufen, sodass sie zusammengeführt werden können, um die Korrespondenz in einem benutzerdefinierten Format zu erstellen:

Die Schnittstelle „IRenderServiceWrapper.java“:

package com.adobe.livecycle.cmsa; 
import java.util.Map; 
import com.adobe.idp.Document; 
public interface IRenderServiceWrapper { 
    public abstract Map<String, Document> getProcessedTemplate(String letterName, String initialXmlData, Boolean useTestData); 
}

Die Implementierung „RenderServiceWrapper.java“:

package com.adobe.livecycle.cmsa; 
 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 
 
import com.adobe.icc.dbforms.obj.Letter; 
import com.adobe.icc.dbforms.obj.Query; 
import com.adobe.icc.dbforms.obj.Statement; 
import com.adobe.icc.dbforms.obj.Statement.Operator; 
import com.adobe.icc.ddg.api.LetterRenderService; 
import com.adobe.icc.services.api.LetterService; 
import com.adobe.idp.Document; 
 
public class RenderServiceWrapper implements IRenderServiceWrapper { 
 
    private LetterRenderService renderService; 
    private LetterService letterService; 
 
    /** 
     * {@inheritDoc} 
     */ 
    public Map<String, Document> getProcessedTemplate(String letterName, String initialXmlData, Boolean useTestData) 
    { 
        Map<String, Document> result = new HashMap<String, Document>(); 
         
        if (letterName != null && !"".equals(letterName)) 
        {         
            Statement st = new Statement(); 
            st.setAttributeName("name"); 
            st.setOperator(Operator.EQUALS); 
            st.setAttributeValue(letterName); 
 
            Query query = new Query(); 
            query.setObjectType(Letter.class.getSimpleName()); 
            query.addStatement(st); 
            List<Letter> letters = letterService.getAllLetters(query); 
             
            if (letters.size() > 0) 
            { 
             
                Map<String, Object> processedData = renderService.processLetter(letters.get(0).getId(), initialXmlData, useTestData); 
                 
                Document xdp = new Document((byte[])processedData.get(LetterRenderService.LAYOUT_TEMPLATE_KEY)); 
                Document xml = new Document((byte[])processedData.get(LetterRenderService.XML_DATA_KEY)); 
                 
                result.put(LetterRenderService.LAYOUT_TEMPLATE_KEY, xdp); 
                result.put(LetterRenderService.XML_DATA_KEY, xml); 
            } 
            else 
                System.out.println("No Letter found with name : " + letterName); 
                 
        } 
        else 
            System.out.println("No Letter name provided."); 
         
        return result; 
    } 
     
    public LetterRenderService getRenderService() { 
        return renderService; 
    } 
 
    public void setRenderService(LetterRenderService renderService) { 
        this.renderService = renderService; 
    } 
 
    public LetterService getLetterService() { 
        return letterService; 
    } 
 
    public void setLetterService(LetterService letterService) { 
        this.letterService = letterService; 
    } 
}

Als Spring-Bean registrieren

Nachdem der oben genannte Dienst implementiert wurde, registrieren Sie ihn als ein Spring-Bean in Ihrem (Spring-basierten) benutzerdefinierten Dienstcontainer:

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> 
 
 
    <bean name="lc.remotingClientParent" 
        class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean" 
        abstract="true"> 
        <property name="httpInvokerRequestExecutor" ref="CRXAuthHttpInvokerRequestExecutor" /> 
    </bean> 
 
    <bean id="CRXAuthHttpInvokerRequestExecutor" 
        class="com.adobe.livecycle.spring.remoting.CRXAuthHttpInvokerRequestExecutor"> 
        <property name="appRoot" value="/content/apps/cm"/> 
    </bean> 
 
    <bean name="LetterService" parent="lc.remotingClientParent"> 
        <property name="serviceUrl" 
            value="${crx.serverUrl}/bin/remoting/lc.icc.dbservices.letterService" /> 
        <property name="serviceInterface" value="com.adobe.icc.services.api.LetterService" /> 
    </bean> 
     
    <bean name="LetterRenderService" parent="lc.remotingClientParent"> 
        <property name="serviceUrl" 
            value="${crx.serverUrl}/bin/remoting/lc.icc.renderlib.letterRenderService" /> 
        <property name="serviceInterface" value="com.adobe.icc.ddg.api.LetterRenderService" /> 
    </bean> 
 
    <bean name="RenderServiceWrapper" class="com.adobe.livecycle.cmsa.RenderServiceWrapper"> 
        <property name="renderService" ref="LetterRenderService" /> 
        <property name="letterService" ref="LetterService" /> 
    </bean> 
 
    <bean id="testProps" 
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
        <property name="locations"> 
            <list> 
                <value>classpath:cmsa.properties</value> 
                <value>file:C:/Adobe/config/cmsa.properties</value> 
            </list> 
        </property> 
    </bean> 
    
</beans>

Die offengelegte Eigenschaftsdatei für die Komponente erstellen

Nachstehend finden Sie ein Beispiel der standardmäßigen Eigenschaftendatei (cmsa.properties) in der Komponente im Klassenpfad:
# URL to the Spring app. 
crx.serverUrl=http://localhost:4502 
 
# more propeties here>

Den benutzerdefinierten Dienst als einen LiveCycle-Dienst exportieren

Nachdem die Dienste als Spring-Bean verfügbar sind, können Sie sie als LiveCycle-Dienst exportieren. Definieren Sie eine com.adobe.idp.dsc.component.ServiceInstanceFactory-Implementierung (SpringServiceFactory.java) wie folgt:

package com.adobe.livecycle.spring; 
 
import com.adobe.idp.dsc.DSCException; 
import com.adobe.idp.dsc.component.ComponentContext; 
import com.adobe.idp.dsc.component.support.AbstractServiceInstanceFactory; 
import com.adobe.idp.dsc.registry.infomodel.ServiceConfiguration; 
import org.springframework.beans.factory.BeanFactory; 
import org.springframework.context.access.ContextSingletonBeanFactoryLocator; 
 
public class SpringServiceFactory extends AbstractServiceInstanceFactory { 
    public void activateInstance(ServiceConfiguration serviceConfiguration, 
            Object o) { 
    } 
 
    public Object createInstance(ServiceConfiguration serviceConfiguration) 
            throws DSCException { 
        return getBeanFactory(serviceConfiguration).getBean( 
                serviceConfiguration.getServiceId()); 
    } 
 
    public void destroyInstance(ServiceConfiguration serviceConfiguration, 
            Object o) throws DSCException { 
    } 
 
    public void passivateInstance(ServiceConfiguration serviceConfiguration, 
            Object o) { 
    } 
 
    public boolean validateInstance(ServiceConfiguration serviceConfiguration, 
            Object o) { 
        return true; 
    } 
 
    private BeanFactory getBeanFactory(ServiceConfiguration serviceConfiguration) { 
        String componentId = serviceConfiguration.getComponentId(); 
        ComponentContext ctx = getComponentContext(); 
        ClassLoader cl = Thread.currentThread().getContextClassLoader(); 
        try { 
            Thread.currentThread().setContextClassLoader(ctx.getClassLoader()); 
            return ContextSingletonBeanFactoryLocator.getInstance( 
                    "classpath:/spring/beanRefContext.xml").useBeanFactory( 
                    componentId).getFactory(); 
        } finally { 
            Thread.currentThread().setContextClassLoader(cl); 
        } 
    } 
}

Die Factory im obigen Beispiel erwartet eine Spring-Konfigurationsdatei mit dem Namen beanRefContext.xml unter „classpath:/spring“, die die eigentliche Spring-Konfiguration/-Beans des Clients lädt. Beispiel:

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="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" 
    xmlns:context="http://www.springframework.org/schema/context"> 
 
 
    <!-- 
     Note: The beanId must be same as the componentId 
    --> 
    <bean name="com.adobe.livecycle.cmsa.RenderWrapper" class="org.springframework.context.support.ClassPathXmlApplicationContext"> 
        <property name="configLocations"> 
            <value> 
                classpath:cmsa-spring-config.xml 
            </value> 
            </property> 
    </bean> 
 
</beans>

Folgen Sie folgenden Konventionen, um die Komponenten-/Dienstdefinitionen zu vereinfachen und die Beans als einen LiveCycle-Dienst offenzulegen:

  • Die Bean-ID oder der Bean-Name in beanRefContext.xml ist derselbe wie die Komponenten-ID, wie in der „component.xml“ des Dienstcontainers definiert.

  • Das benutzerdefinierte Dienst-Bean weist denselben Namen wie die LiveCycle-Dienst-ID auf, wie in der component.xml des Dienstcontainers definiert.

Dienstcontainerkomponente definieren

Anschließend definieren Sie die Details der Dienstcontainerkomponente in der component.xml wie folgt:

<component xmlns="http://adobe.com/idp/dsc/component/document"> 
    <component-id>com.adobe.livecycle.cmsa.RenderWrapper</component-id> 
    <version>1.0</version> 
    <services> 
        <!-- Service name must be same as the name of the corresponding Spring 
            bean --> 
        <service name="RenderServiceWrapper" orchestrateable="true"> 
            <implementation-class>com.adobe.livecycle.cmsa.IRenderServiceWrapper 
            </implementation-class> 
            <auto-deploy service-id="RenderServiceWrapper" 
                minor-version="0" major-version="1" category-id="Correspondence Management" /> 
            <operations> 
                <operation name="getProcessedTemplate"> 
                    <input-parameter name="letterName" title="Letter Name" 
                        type="java.lang.String" /> 
                    <input-parameter name="initialXmlData" title="Initial XML Data (for DDI)" 
                        type="java.lang.String" /> 
                    <input-parameter name="useTestData" title="Use Letter Test Data?" 
                        type="java.lang.Boolean" /> 
                    <output-parameter name="result" 
                        title="Result Map with Layout and Data" type="java.util.Map" /> 
                </operation> 
            </operations> 
        </service> 
 
                  <!-- Mandatory service to capture CRX credentials --> 
        <service name="CRXUserCredentialService"> 
            <implementation-class>com.adobe.livecycle.crx.CRXUserCredentialService 
            </implementation-class> 
            <factory-method>getInstance</factory-method> 
            <supported-connectors></supported-connectors> 
            <auto-deploy major-version="1" service-id="CRXUserCredentialService" 
                category-id="Correspondence Management" /> 
            <config-parameter name="username" type="java.lang.String" 
                title="Username"> 
                <description>User name with which to connect to CM</description> 
                <default-value>admin</default-value> 
            </config-parameter> 
            <config-parameter name="password" type="java.lang.String" 
                title="Password"> 
                <description>Password for the above user</description> 
                <default-value>admin</default-value> 
                <property-editor editor-id="com.adobe.idp.dsc.propertyeditor.system.PasswordPropertyEditorComponent" /> 
            </config-parameter> 
            <operation-config> 
                <operation-name>*</operation-name> 
                <transaction-type>None</transaction-type> 
            </operation-config> 
        </service> 
    </services> 
    <supports-export>false</supports-export> 
    <class-path>lib/dom4j-1.6.1.jar lib/lc-content-api.jar lib/adobe-acm-client.jar lib/adobe-dct-client.jar lib/com.springsource.org.aopalliance-1.0.0.jar lib/spring-aop-3.0.2.RELEASE.jar lib/spring-asm-3.0.2.RELEASE.jar lib/spring-beans-3.0.2.RELEASE.jar lib/spring-context-3.0.2.RELEASE.jar lib/spring-core-3.0.2.RELEASE.jar lib/spring-expression-3.0.2.RELEASE.jar lib/spring-web-3.0.2.RELEASE.jar lib/spring-security-core-3.0.2.RELEASE.jar</class-path> 
 
    <service-factory-class>com.adobe.livecycle.spring.SpringServiceFactory 
    </service-factory-class> 
</component>

Correspondence Management-Dienste direkt als einen Dienstcontainervorgang offenlegen

Sie können auch den gesamten Correspondence Management-Dienst, der bereits über HTTP-Remoting offengelegt ist, und seine Vorgänge als einen LiveCycle-Dienst offenlegen, anstatt ihn innerhalb eines benutzerdefinierten Dienstes aufzunehmen. Um beispielsweise den FormService und seine Vorgänge offenzulegen, fügen Sie einfach der component.xml die folgenden Einträgen hinzu:

<component xmlns="http://adobe.com/idp/dsc/component/document"> 
  ... 
  ... 
  <services> 
 
    <!-- Again, the Service name/id must be same as the name of the corresponding Spring bean, defined in cmsa-spring-config.xml --> 
 
    <service name="FormService" orchestrateable="true"> 
      <implementation-class>com.adobe.livecycle.cmsa.FormQueryService</implementation-class> 
      <auto-deploy service-id="FormService" minor-version="0" major-version="1" category-id="CMSA"/> 
    </service> 
 
    ... 
    <!-- more services here --> 
    ... 
  </services> 
  ... 
  ... 
</component>

Authentifizierungsübertragung

Sie können einen Aufrufkontext für CRX festlegen, sodass die Dienstcontainerkonfiguration ausgefüllt werden kann, um Correspondence Management-APIs aufzurufen. Erstellen Sie eine benutzerdefinierte Dienstkonfiguration, die einen Satz Benutzeranmeldedaten für CRX erfasst, die über Berechtigungen für Correspondence Management-Inhalt verfügen. Die folgende Definition legt die Konfigurationen auf der LiveCycle Document Services Platform-Administratorbenutzeroberfläche offen.:

<service name="CRXUserCredentialService"> 
    <implementation-class>com.adobe.livecycle.crx.CRXUserCredentialService 
    </implementation-class> 
    <factory-method>getInstance</factory-method> 
    <supported-connectors></supported-connectors> 
    <auto-deploy major-version="1" service-id="CRXUserCredentialService" 
        category-id="Correspondence Management" /> 
    <config-parameter name="username" type="java.lang.String" 
        title="Username"> 
        <description>User name with which to connect to CM</description> 
        <default-value>admin</default-value> 
    </config-parameter> 
    <config-parameter name="password" type="java.lang.String" 
        title="Password"> 
        <description>Password for the above user</description> 
        <default-value>admin</default-value> 
        <property-editor editor-id="com.adobe.idp.dsc.propertyeditor.system.PasswordPropertyEditorComponent" /> 
    </config-parameter> 
    <operation-config> 
        <operation-name>*</operation-name> 
        <transaction-type>None</transaction-type> 
    </operation-config> 
</service>
Konfiguration:
  1. Navigieren Sie zu Administratorbenutzeroberfläche > Dienste > Anwendungen und Dienste > Dienstverwaltung.

  2. Wählen Sie Correspondence Management als Kategorie.

  3. Wählen Sie den CRXUserCredentialService-Dienst.

  4. Geben Sie den für die CRX-Instanz erstellten Benutzernamen und das Kennwort an, mit dem auf Correspondence Management zugegriffen werden kann.

  5. Klicken Sie auf Speichern.

Benutzerdefinierte Authentifizierungs-Ausführungsfunktion

Die folgende CRXAuthHttpInvokerRequestExecutor.java-Datei ist die benutzerdefinierte Ausführungsfunktion der Authentifizierungsanforderung. Diese API überschreibt die grundlegende Ausführungsfunktion der Authentifizierungsanforderung und verwendet CRXUserCredentialService, um einen Systemkontext für API-Aufrufe zu erstellen.
package com.adobe.livecycle.spring.remoting; 
 
import java.io.IOException; 
import java.net.HttpURLConnection; 
 
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 
import org.springframework.security.core.context.SecurityContext; 
import org.springframework.security.core.context.SecurityContextHolder; 
import org.springframework.security.remoting.httpinvoker.AuthenticationSimpleHttpInvokerRequestExecutor; 
 
import com.adobe.livecycle.content.appcontext.AppContextManager; 
import com.adobe.livecycle.crx.CRXUserCredentialService; 
 
public class CRXAuthHttpInvokerRequestExecutor extends 
        AuthenticationSimpleHttpInvokerRequestExecutor { 
     
    private String appRoot; 
    public String getAppRoot() { 
        return appRoot; 
    } 
    public void setAppRoot(String appRoot) { 
        this.appRoot = appRoot; 
    } 
    @Override 
    protected void prepareConnection(HttpURLConnection con, int contentLength) 
            throws IOException { 
        boolean clearContext = false; 
        try { 
            if (SecurityContextHolder.getContext().getAuthentication() == null) { 
                clearContext = true; 
                CRXUserCredentialService credentialService = CRXUserCredentialService 
                        .getInstance(); 
                UsernamePasswordAuthenticationToken ut = new UsernamePasswordAuthenticationToken( 
                        credentialService.getUsername(), 
                        credentialService.getPassword()); 
                SecurityContext sctx = SecurityContextHolder 
                        .createEmptyContext(); 
                sctx.setAuthentication(ut); 
                SecurityContextHolder.setContext(sctx); 
            } 
            super.prepareConnection(con, contentLength); 
            con.setRequestProperty(AppContextManager.APP_CONTEXT_HEADER_NAME, appRoot); 
        } finally { 
            if (clearContext) { 
                SecurityContextHolder.clearContext(); 
            } 
        } 
 
    } 
}