擴展多站點管理器

本頁可協助您擴充多網站管理員的功能:

  • 瞭解MSM Java API的主要成員。
  • 建立可用於轉出設定的新同步動作。
  • 修改預設語言和國家/地區代碼。
注意

此頁應與重複使用內容一起讀取:多站點管理器

AEM 6.4中的「Sites Repository Restructing」(網站資料庫重組)的下列章節可能也會受到關注:

注意

「多網站管理員」及其API是在製作網站時使用的,因此僅適用於作者環境。

Java API概觀

多站點管理由以下軟體包組成:

主要MSM API物件的互動方式如下(另請參閱使用的詞語):

chlimage_1-73

  • Blueprint

    Blueprint(如blueprint configuration中)指定即時副本可繼承內容的頁面。

    chlimage_1-74

    • 藍圖配置(Blueprint)的使用是可選的,但:

      • 允許作者在源上使用​Rovolt​選項(將修改(顯式)推送到繼承自此源的即時拷貝)。
      • 允許作者使用​Create Site;這可讓使用者輕鬆選擇語言並設定即時副本的結構。
      • 為任何產生的即時副本定義預設轉出設定。
  • LiveRelationshipLiveRelationship 定即時副本分支中的資源與其等效源/藍圖資源之間的連接(關係)。

    • 在實現繼承和轉出時,會使用這些關係。

    • LiveRelationship 對象提供對轉出配置()的訪問( RolloutConfig引用), LiveCopy以及與 LiveStatus 關係相關的對象。

    • 例如,在/content/copy/us中,從/content/we-retail/language-masters的來源/藍圖建立即時副本。 資源/content/we.retail/language-masters/en/jcr:content/content/copy/us/en/jcr:content形成關係。

  • LiveCopy LiveCopy 保存即時副本資源與其源/ LiveRelationshipBlueprint資源之間關係()的配置詳細資訊。

    • 使用LiveCopy類訪問頁面路徑、源/藍圖頁面的路徑、轉出配置以及子頁面是否也包含在LiveCopy中。

    • 每次使用「建立站點」(Create Site)「」(Create Site)「」(Create Live Copy)「建立即時副本」(A4/)時,都建立LiveCopy節點。

  • LiveStatus

    LiveStatus 對象提供對的運行時狀態的訪問 LiveRelationship。用於查詢即時副本的同步狀態。

  • LiveAction

    LiveAction是在轉出中涉及的每個資源上執行的動作。

    • LiveActions僅由RovoltConfigs產生。
  • LiveActionFactory

    建立給定LiveAction配置的LiveAction對象。 配置作為資源儲存在儲存庫中。

  • RolloutConfigRolloutConfig 清單包含一 LiveActions個清單,在觸發時使用。LiveCopy繼承RolloutConfig,結果出現在LiveRelationship中。

    • 首次設定即時副本時,也會使用RovoltConfig(會觸發LiveActions)。

建立新同步操作

建立自訂同步動作,以便用於轉出設定。 當安裝的操作不符合您的特定應用程式要求時,建立同步操作。 若要這麼做,請建立兩個類別:

LiveActionFactory會為給定配置建立LiveAction類的實例:

  • LiveAction 類包括以下方法:

    • getName:傳回動作的名稱。名稱是用來參考動作的,例如在轉出設定中。
    • execute:執行動作的任務。
  • LiveActionFactory 類包括以下成員:

    • LIVE_ACTION_NAME:包含關聯名稱的欄位 LiveAction。此名稱必須與LiveAction類別的getName方法返回的值一致。

    • createAction:建立實例 LiveAction。可選Resource參數可用於提供配置資訊。

    • createsAction:傳回關聯的名稱 LiveAction

訪問LiveAction Configuration Node

使用儲存庫中的LiveAction配置節點來儲存影響LiveAction實例的運行時行為的資訊。 儲存LiveAction配置的儲存庫中的節點在運行時可用於LiveActionFactory對象。 因此,您可以將屬性添加到配置節點中,並根據需要在LiveActionFactory實施中使用這些屬性。

例如,LiveAction需要儲存Blueprint作者的名稱。 配置節點的屬性包括儲存資訊的藍圖頁的屬性名稱。 在運行時,LiveAction從配置中檢索屬性名稱,然後獲取屬性值。

[LiveActionFactory](https://helpx.adobe.com/tw/experience-manager/6-5/sites/developing/using/reference-materials/javadoc/com/day/cq/wcm/msm/api/LiveActionFactory.html).createAction方法的參數是Resource對象。 此Resource物件代表轉出設定中此即時動作的cq:LiveSyncAction節點;請參閱建立轉出設定。 使用配置節點時,應將其調整為ValueMap對象:

public LiveAction createAction(Resource resource) throws WCMException {
        ValueMap config;
        if (resource == null || resource.adaptTo(ValueMap.class) == null) {
            config = new ValueMapDecorator(Collections.<String, Object>emptyMap());
        } else {
            config = resource.adaptTo(ValueMap.class);
        }
        return new MyLiveAction(config, this);
}

訪問目標節點、源節點和LiveRelationship

以下對象是LiveAction對象的execute方法的參數:

  • Resource物件,代表即時副本的來源。

  • Resource物件,代表即時副本的目標。

  • 即時副本的 LiveRelationship物件。

  • autoSave值指示您的LiveAction是否應保存對儲存庫所做的更改。

  • 重設值指示轉出重設模式。

您可以從這些對象中獲取有關LiveCopy的所有資訊。 您也可以使用Resource物件來取得ResourceResolverSessionNode物件。 這些對象對於控制儲存庫內容非常有用:

在以下代碼的第一行中,原始碼是原始碼頁的Resource對象:

ResourceResolver resolver = source.getResourceResolver();
Session session = resolver.adaptTo(javax.jcr.Session.class);
Node sourcenode = source.adaptTo(javax.jcr.Node.class);
注意

Resource引數可以是nullResources物件,這些物件不適應Node物件,例如 NonExistingResource物件。

建立新的轉出設定

當安裝的轉出設定不符合您的應用程式需求時,請建立轉出設定:

然後,當在藍圖或即時副本頁面上設定轉出設定時,您便可使用新的轉出設定。

注意

另請參閱自訂推廣的最佳實務

建立轉出設定

若要建立新的轉出設定:

  1. 開啟CRXDE Lite;例如:
    http://localhost:4502/crx/de

  2. 導航到 :
    /apps/msm/<your-project>/rolloutconfigs

    注意

    這是您專案的自訂版本:
    /libs/msm/wcm/rolloutconfigs
    如果這是您的第一個配置,則必須建立。

    注意

    您不得更改/libs路徑中的任何內容。
    這是因為下次升級實例時會覆寫/libs的內容(套用修補程式或功能套件時很可能會覆寫)。
    配置和其他更改的建議方法為:

    • 在/apps下重新建立必要項目(亦即,在/libs中存在)
    • 在/apps中進行任何變更
  3. 在此​Create​下,建立具有以下屬性的節點:

    • 名稱:轉出配置的節點名稱。md#installed-synchronization-actions),例如contentCopyworkflow
    • 類型: cq:RolloutConfig
  4. 將以下屬性添加到此節點:

    • 名稱: jcr:title

      類型: String
      :UI中將會顯示的識別標題。

    • 名稱: jcr:description

      類型: String
      :可選說明。

    • 名稱: cq:trigger

      類型: String
      :要使用 轉出觸發器。從中選擇:

      • rollout
      • modification
      • publish
      • deactivate
  5. 按一下​保存全部

將同步操作添加到轉出配置

轉出配置儲存在您在/apps/msm/<your-project>/rolloutconfigs節點下建立的轉出配置節點下。

添加類型cq:LiveSyncAction的子節點,以將同步操作添加到轉出配置中。 同步操作節點的順序決定操作的發生順序。

  1. 仍然在CRXDE Lite中,選擇Rovolt Configuration節點。

    例如:
    /apps/msm/myproject/rolloutconfigs/myrolloutconfig

  2. 建立 具有以下節點屬性的節點:

    • 名稱:同步操作的節點名。名稱必須與同步操作下表中的​操作名稱​相同,例如contentCopyworkflow
    • 類型: cq:LiveSyncAction
  3. 根據需要添加和配置任意數量的同步操作節點。 重新排列動作節點,使其順序符合您希望動作節點發生的順序。 最頂端的操作節點首先出現。

建立和使用Simple LiveActionFactory類

請依照本節中的程式來開發LiveActionFactory,並將它用於轉出設定。 這些程式使用Maven和Eclipse來開發和部署LiveActionFactory:

  1. 建立主要 專案並匯入至Eclipse。
  2. 將相 關內容添加到POM檔案。
  3. 實作 LiveActionFactory 介面並部署OSGi套件。
  4. 建立轉出設定
  5. 建立即時副本

Maven項目和Java類的原始碼可在公共Git儲存庫中使用。

GITHUB代碼

您可以在GitHub上找到此頁面的程式碼

建立Maven項目

下列程式要求您將adobe-public設定檔新增至Maven設定檔。

  1. 開啟終端或命令行會話並更改目錄以指向建立項目的位置。

  2. 輸入以下命令:

    mvn archetype:generate -DarchetypeGroupId=com.day.jcr.vault -DarchetypeArtifactId=multimodule-content-package-archetype -DarchetypeVersion=1.0.0 -DarchetypeRepository=adobe-public-releases
    
  3. 在互動式提示時指定下列值:

    • groupId: com.adobe.example.msm
    • artifactId: MyLiveActionFactory
    • version: 1.0-SNAPSHOT
    • package: MyPackage
    • appsFolderName: myapp
    • artifactName: MyLiveActionFactory package
    • packageGroup: myPackages
  4. 啟動Eclipse並匯入Maven專案

向POM檔案添加相關性

新增相依性,讓Eclipse編譯器可以參考LiveActionFactory程式碼中使用的類別。

  1. 從Eclipse專案總管開啟檔案:

    MyLiveActionFactory/pom.xml

  2. 在編輯器中,按一下pom.xml頁籤並找到project/dependencyManagement/dependencies部分。

  3. dependencyManagement元素中新增下列XML,然後儲存檔案。

     <dependency>
      <groupId>com.day.cq.wcm</groupId>
      <artifactId>cq-msm-api</artifactId>
      <version>5.6.2</version>
      <scope>provided</scope>
     </dependency>
     <dependency>
      <groupId>org.apache.sling</groupId>
      <artifactId>org.apache.sling.api</artifactId>
      <version>2.4.3-R1488084</version>
      <scope>provided</scope>
     </dependency>
     <dependency>
      <groupId>com.day.cq.wcm</groupId>
      <artifactId>cq-wcm-api</artifactId>
      <version>5.6.6</version>
      <scope>provided</scope>
     </dependency>
     <dependency>
      <groupId>org.apache.sling</groupId>
      <artifactId>org.apache.sling.commons.json</artifactId>
      <version>2.0.6</version>
      <scope>provided</scope>
     </dependency>
     <dependency>
      <groupId>com.day.cq</groupId>
      <artifactId>cq-commons</artifactId>
      <version>5.6.4</version>
      <scope>provided</scope>
     </dependency>
     <dependency>
      <groupId>org.apache.sling</groupId>
      <artifactId>org.apache.sling.jcr.jcr-wrapper</artifactId>
      <version>2.0.0</version>
      <scope>provided</scope>
     </dependency>
     <dependency>
      <groupId>com.day.cq</groupId>
      <artifactId>cq-commons</artifactId>
      <version>5.6.4</version>
      <scope>provided</scope>
     </dependency>
    
  4. 從​Project Explorer​的MyLiveActionFactory-bundle/pom.xml開啟包的POM檔案。

  5. 在編輯器中,按一下pom.xml頁籤並找到項目/依賴項部分。 在相依性元素中新增下列XML,然後儲存檔案:

     <dependency>
      <groupId>com.day.cq.wcm</groupId>
      <artifactId>cq-msm-api</artifactId>
     </dependency>
     <dependency>
      <groupId>org.apache.sling</groupId>
      <artifactId>org.apache.sling.api</artifactId>
     </dependency>
     <dependency>
      <groupId>com.day.cq.wcm</groupId>
      <artifactId>cq-wcm-api</artifactId>
     </dependency>
     <dependency>
      <groupId>org.apache.sling</groupId>
      <artifactId>org.apache.sling.commons.json</artifactId>
     </dependency>
     <dependency>
      <groupId>com.day.cq</groupId>
      <artifactId>cq-commons</artifactId>
     </dependency>
     <dependency>
      <groupId>org.apache.sling</groupId>
      <artifactId>org.apache.sling.jcr.jcr-wrapper</artifactId>
     </dependency>
     <dependency>
      <groupId>com.day.cq</groupId>
      <artifactId>cq-commons</artifactId>
     </dependency>
    

實作LiveActionFactory

以下LiveActionFactory類實現了LiveAction ,該類記錄有關源和目標頁的消息,並將cq:lastModifiedBy屬性從源節點複製到目標節點。 即時動作的名稱為exampleLiveAction

  1. 在Eclipse項目瀏覽器中,按一下右鍵MyLiveActionFactory-bundle/src/main/java/com.adobe.example.msm包,然後按一下​新建 > 。 對於​名稱,輸入ExampleLiveActionFactory,然後按一下​完成

  2. 開啟ExampleLiveActionFactory.java檔案,以下列程式碼取代內容,並儲存檔案。

    package com.adobe.example.msm;
    
    import java.util.Collections;
    
    import org.apache.felix.scr.annotations.Component;
    import org.apache.felix.scr.annotations.Property;
    import org.apache.felix.scr.annotations.Service;
    import org.apache.sling.api.resource.Resource;
    import org.apache.sling.api.resource.ResourceResolver;
    import org.apache.sling.api.resource.ValueMap;
    import org.apache.sling.api.wrappers.ValueMapDecorator;
    import org.apache.sling.commons.json.io.JSONWriter;
    import org.apache.sling.commons.json.JSONException;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import javax.jcr.Node;
    import javax.jcr.RepositoryException;
    import javax.jcr.Session;
    
    import com.day.cq.wcm.msm.api.ActionConfig;
    import com.day.cq.wcm.msm.api.LiveAction;
    import com.day.cq.wcm.msm.api.LiveActionFactory;
    import com.day.cq.wcm.msm.api.LiveRelationship;
    import com.day.cq.wcm.api.WCMException;
    
    @Component(metatype = false)
    @Service
    public class ExampleLiveActionFactory implements LiveActionFactory<LiveAction> {
     @Property(value="exampleLiveAction")
     static final String actionname = LiveActionFactory.LIVE_ACTION_NAME;
    
     public LiveAction createAction(Resource config) {
      ValueMap configs;
      /* Adapt the config resource to a ValueMap */
            if (config == null || config.adaptTo(ValueMap.class) == null) {
                configs = new ValueMapDecorator(Collections.<String, Object>emptyMap());
            } else {
                configs = config.adaptTo(ValueMap.class);
            }
    
      return new ExampleLiveAction(actionname, configs);
     }
     public String createsAction() {
      return actionname;
     }
     /************* LiveAction ****************/
     private static class ExampleLiveAction implements LiveAction {
      private String name;
      private ValueMap configs;
      private static final Logger log = LoggerFactory.getLogger(ExampleLiveAction.class);
    
      public ExampleLiveAction(String nm, ValueMap config){
       name = nm;
       configs = config;
      }
    
      public void execute(Resource source, Resource target,
        LiveRelationship liverel, boolean autoSave, boolean isResetRollout)
          throws WCMException {
    
       String lastMod = null;
    
       log.info(" *** Executing ExampleLiveAction *** ");
    
       /* Determine if the LiveAction is configured to copy the cq:lastModifiedBy property */
       if ((Boolean) configs.get("repLastModBy")){
    
        /* get the source's cq:lastModifiedBy property */
        if (source != null && source.adaptTo(Node.class) !=  null){
         ValueMap sourcevm = source.adaptTo(ValueMap.class);
         lastMod = sourcevm.get(com.day.cq.wcm.msm.api.MSMNameConstants.PN_PAGE_LAST_MOD_BY, String.class);
        }
    
        /* set the target node's la-lastModifiedBy property */
        Session session = null;
        if (target != null && target.adaptTo(Node.class) !=  null){
         ResourceResolver resolver = target.getResourceResolver();
         session = resolver.adaptTo(javax.jcr.Session.class);
         Node targetNode;
         try{
          targetNode=target.adaptTo(javax.jcr.Node.class);
          targetNode.setProperty("la-lastModifiedBy", lastMod);
          log.info(" *** Target node lastModifiedBy property updated: {} ***",lastMod);
         }catch(Exception e){
          log.error(e.getMessage());
         }
        }
        if(autoSave){
         try {
          session.save();
         } catch (Exception e) {
          try {
           session.refresh(true);
          } catch (RepositoryException e1) {
           e1.printStackTrace();
          }
          e.printStackTrace();
         }
        }
       }
      }
      public String getName() {
       return name;
      }
    
      /************* Deprecated *************/
      @Deprecated
      public void execute(ResourceResolver arg0, LiveRelationship arg1,
        ActionConfig arg2, boolean arg3) throws WCMException {
      }
      @Deprecated
      public void execute(ResourceResolver arg0, LiveRelationship arg1,
        ActionConfig arg2, boolean arg3, boolean arg4)
          throws WCMException {
      }
      @Deprecated
      public String getParameterName() {
       return null;
      }
      @Deprecated
      public String[] getPropertiesNames() {
       return null;
      }
      @Deprecated
      public int getRank() {
       return 0;
      }
      @Deprecated
      public String getTitle() {
       return null;
      }
      @Deprecated
      public void write(JSONWriter arg0) throws JSONException {
      }
     }
    }
    
  3. 使用終端或命令會話,將目錄更改為MyLiveActionFactory目錄(Maven項目目錄)。 然後,輸入以下命令:

    mvn -PautoInstallPackage clean install
    

    AEM error.log檔案應指示已啟動套件。

    例如,https://localhost:4502/system/console/status-slinglogs

    13.08.2013 14:34:55.450 *INFO* [OsgiInstallerImpl] com.adobe.example.msm.MyLiveActionFactory-bundle BundleEvent RESOLVED
    13.08.2013 14:34:55.451 *INFO* [OsgiInstallerImpl] com.adobe.example.msm.MyLiveActionFactory-bundle BundleEvent STARTING
    13.08.2013 14:34:55.451 *INFO* [OsgiInstallerImpl] com.adobe.example.msm.MyLiveActionFactory-bundle BundleEvent STARTED
    13.08.2013 14:34:55.453 *INFO* [OsgiInstallerImpl] com.adobe.example.msm.MyLiveActionFactory-bundle Service [com.adobe.example.msm.ExampleLiveActionFactory,2188] ServiceEvent REGISTERED
    13.08.2013 14:34:55.454 *INFO* [OsgiInstallerImpl] org.apache.sling.audit.osgi.installer Started bundle com.adobe.example.msm.MyLiveActionFactory-bundle [316]
    

建立範例轉出設定

建立使用您建立之LiveActionFactory的MSM轉出設定:

  1. 使用標準過程🔗建立並配置轉出配置——並使用屬性:

    • 標題:範例轉出設定
    • 名稱:examplerolloutconfig
    • cq:trigger: publish

將即時動作新增至範例轉出設定

配置您在上一個過程中建立的轉出配置,使其使用ExampleLiveActionFactory類。

  1. 開啟CRXDE Lite;例如,https://localhost:4502/crx/de

  2. /apps/msm/rolloutconfigs/examplerolloutconfig/jcr:content下建立以下節點:

    • 名稱: exampleLiveAction
    • 類型: cq:LiveSyncAction
  3. 按一下​保存全部

  4. 選擇exampleLiveAction節點並添加以下屬性:

    • 名稱: repLastModBy
    • 類型: Boolean
    • : true

    此屬性向ExampleLiveAction類指示cq:LastModifiedBy屬性應從源節點複製到目標節點。

  5. 按一下​保存全部

建立即時副本

使用您的 轉出設定,建立We.Retail參考網站英文/產品分支的即時版本:

  • 來源: /content/we-retail/language-masters/en/products

  • 轉出設定:範例轉出設定

激活源分支的​產品(英文)頁,並觀察LiveAction類生成的日誌消息:

16.08.2013 10:53:33.055 *INFO* [Thread-444535] com.adobe.example.msm.ExampleLiveActionFactory$ExampleLiveAction  ***ExampleLiveAction has been executed.***
16.08.2013 10:53:33.055 *INFO* [Thread-444535] com.adobe.example.msm.ExampleLiveActionFactory$ExampleLiveAction  ***Target node lastModifiedBy property updated: admin ***

變更語言名稱和預設國家/地區

AEM使用預設的語言和國家代碼集。

  • 預設語言代碼是由ISO-639-1定義的小寫雙字母代碼。
  • 預設的國家/地區代碼為小寫或大寫,由ISO 3166定義的雙字母代碼。

MSM會使用儲存的語言和國家代碼清單來判斷與您頁面的語言版本名稱相關聯的國家/地區名稱。 如有需要,您可以變更清單的下列方面:

  • 語言標題
  • 國家/地區名稱
  • 語言的預設國家(例如ende等程式碼)

語言清單儲存在/libs/wcm/core/resources/languages節點下。 每個子節點代表語言或語言國家:

  • 節點的名稱是語言代碼(如ende),或language_country代碼(如en_usde_ch)。

  • 節點的language屬性儲存代碼語言的完整名稱。

  • 節點的country屬性儲存代碼的國家的完整名稱。

  • 當節點名稱只包含語言代碼(如en)時,國家屬性為*,而另外的defaultCountry屬性則儲存語言國家的代碼,以指出要使用的國家。

chlimage_1-76

要修改語言:

  1. 在網頁瀏覽器中開啟CRXDE Lite;例如https://localhost:4502/crx/de

  2. 選擇/apps資料夾,然後按一下​建立,然後按一下​建立資料夾。

    為新資料夾命名wcm

  3. 重複上一步以建立/apps/wcm/core資料夾樹。 在core中建立名為resourcessling:Folder類型的節點。

  4. 按一下右鍵/libs/wcm/core/resources/languages節點,然後按一下​Copy

  5. 按一下右鍵/apps/wcm/core/resources資料夾,然後按一下​貼上。 根據需要修改子節點。

  6. 按一下​保存全部

  7. 按一下​工具操作,然後按一下​Web控制台。 在此控制台中,按一下​OSGi ,然後按一下​Configuration

  8. 找到並按一下​Day CQ WCM Language Manager ,將​Language List​的值更改為/apps/wcm/core/resources/languages ,然後按一下​Save

    chlimage_1-78

在頁面屬性上配置MSM鎖(啟用觸控的UI)

建立自訂頁面屬性時,您可能需要考慮新屬性是否符合推廣至任何即時副本的資格。

例如,如果新增兩個新頁面屬性:

  • 連絡人電子郵件:

    • 此屬性不需要推出,因為每個國家(或品牌等)都不同。
  • 關鍵視覺樣式:

    • 項目要求是,此屬性應以(通常)所有國家(或品牌等)共同的方式推出。

然後,您需要確保:

  • 連絡人電子郵件:

  • 關鍵視覺樣式:

    • 請確定您不允許在觸控式使用者介面中編輯此屬性,除非繼承已取消,您也可以重新建立繼承;通過按一下切換以指示連接狀態的鏈/斷鏈連結來控制此操作。

頁面屬性是否要開始,因此,在編輯時要取消/恢復繼承,由對話框屬性控制:

  • cq-msm-lockable

    • 適用於啟用觸控的UI對話方塊中的項目

    • 將在對話框中建立連結符號

    • 僅當繼承取消(連結斷開)時才允許編輯

    • 僅適用於資源的第一個子級

    • 類型: String

    • :持有被代價物業之名稱(及與物業價值相若 name;例如,請參閱

      /libs/foundation/components/page/cq:dialog/content/items/tabs/items/basic/items/column/items/title/items/title

cq-msm-lockable已定義時,斷開/關閉鏈將通過以下方式與MSM相互作用:

  • 如果cq-msm-lockable的值為:

    • 相對 (例如 myProperty./myProperty)

      • 它將從cq:propertyInheritanceCancelled中添加和刪除屬性。
    • 絕對 (例如 /image)

      • 斷開鏈將通過將cq:LiveSyncCancelled混頻添加到./image並將cq:isCancelledForChildren設定為true來取消繼承。

      • 關閉鏈將恢復繼承。

注意

cq-msm-lockable 應用於要編輯的資源的第一個子級別,而且無論該值定義為絕對或相對值,它在任何更深層級別上都不起作用。

注意

當您重新啟用繼承時,即時副本頁面屬性不會自動與source屬性同步。 如果需要,可以手動請求同步。

本頁內容

Adobe Maker Awards Banner

Time to shine!

Apply now for the 2021 Adobe Experience Maker Awards.

Apply now
Adobe Maker Awards Banner

Time to shine!

Apply now for the 2021 Adobe Experience Maker Awards.

Apply now