Skip to content

Latest commit

 

History

History
284 lines (217 loc) · 11.6 KB

File metadata and controls

284 lines (217 loc) · 11.6 KB

Implementing a Content Hub Adapter for CoreMedia Assets

Introduction

In this tutorial we show how a Headless Server client can be implemented with Java in order to access CoreMedia assets. It can be used for integrations into a digital asset management systems (DAM), social media or marketing tools.

We simulate a DAM here by writing an integration for the CoreMedia Content Hub as well. While it is not useful to access CoreMedia through the Content Hub/Headless Server from CoreMedia, this example shows

  • how easy the Headless Server can be integrated into external systems.
  • how the Content Hub can be used to connect with external systems.

Headless Server in Studio Library

Because this example is more complex, we start the tutorial by adding all sources to a CoreMedia workspace. We then explain the details and important parts of the code.

Prerequisites

This tutorial assumes that you have already developed with the CoreMedia Blueprint workspace. It also assumes that you already know what the CoreMedia Content Hub is.

Project Setup

The sources of this tutorial are provided as a CoreMedia extension. Install the extension by copying the content-hub-adapter-headless-server-dam folder into the modules/extensions/ folder of your CoreMedia workspace. If they do not exist, just create these folders.

After copying, use the extension tool in the root folder of the workspace to link the extensions into the CoreMedia apps:

mvn -f workspace-configuration/extensions com.coremedia.maven:extensions-maven-plugin:LATEST:sync -Denable=content-hub-adapter-headless-server-dam

Once the extension tool has been executed successfully, rebuild the workspace and afterwards start your Studio. The Content Hub extension "Headless DAM" is now part of your Studio, but you have to provide a configuration in order to enable the extension.

The Content Hub allows global, site-specific and user-specific connections. Simply create the connection settings document Headless DAM in the global settings folder of the Content Hub:

Headless Server Configuration

Inside the document configure the settings section as described below:

Headless Server Configuration

Property Description
siteId The site ID of the CoreMedia site from which the adapter should retrieve assets
displayName The display name of the root node inside the Studio library
headlessServerUrl The headless server URL (without 'graphql' suffix!)

Note that the value of the headlessServerUrl can be the preview or live URL of the headless server.

The XML export of the "Head DAM" settings document looks like this:

<?xml version="1.0" encoding="UTF-8" ?>
<CMSettings folder="/Settings/Options/Settings/Content Hub/Connections" name="Headless DAM">
  <externalRefId></externalRefId>
  <locale></locale>
  <master>
  </master>
  <settings>
    <Struct xmlns="http://www.coremedia.com/2008/struct">
      <StructListProperty Name="connections">
        <Struct>
          <StringProperty Name="connectionId">headlessdam1</StringProperty>
          <StringProperty Name="factoryId">headlessdam</StringProperty>
          <BooleanProperty Name="enabled">true</BooleanProperty>
          <StructProperty Name="settings">
            <Struct>
              <StringProperty Name="displayName">Headless DAM</StringProperty>
              <StringProperty Name="siteId">abffe57734feeee</StringProperty>
              <StringProperty Name="headlessServerUrl">https://headless-server-preview.sherlock-labs.testsystem.coremedia.io/</StringProperty>
            </Struct>
          </StructProperty>
        </Struct>
      </StructListProperty>
    </Struct>
  </settings>
  <identifier></identifier>
</CMSettings>

After creating the settings document, reload Studio. The headless server folder inside the Studio library should be visible, and assets can be browsed.

Content Hub Adapter Setup

Although this tutorial focuses on the Headless Server, let's have a brief look on the Content Hub adapter setup. The sources of this tutorial consist of two Maven modules:

Module headless-server-dam-studio

This module contains the Studio sources for the Content Hub adapter. It contains only resource bundles and no additional logic.

For details of how to customize labels and icons for a Content Hub adapter, please check the section "Customizing Labels and Icons" in the Content Hub chapter of the Studio Developer Guide (https://documentation.coremedia.com/cmcc-10/artifacts/2001/webhelp/studio-developer-en/content/Content_Hub.html).

Module headless-server-dam-studio-lib

This module contains the Java sources of the Headless DAM Content Hub adapter. It consists of two parts:

  • The classes required for the adapter
  • The classes which implement access to the Headless Server

The setup of the adapter is pretty straight forward:

The entry point of the adapter is the Spring configuration class HeadlessDAMConfiguration, which creates the HeadlessDAMContentHubAdapterFactory, which then creates instances of the HeadlessDAMContentHubAdapter for each connection configuration found during runtime.

As shown in the screenshot below, the folder structure generated by the HeadlessDAMContentHubAdapter is pretty simple: it contains one root folder with three different subfolders, one for each media type.

Headless DAM Folders

The folder structure is static. The folder objects are created inside the constructor of the HeadlessDAMContentHubAdapter:

rootId = new ContentHubObjectId(connectionId, HeadlessDAMFolder.ROOT_FOLDER);
rootFolder = new HeadlessDAMFolder(headlessServerUrl, rootId, new ContentHubType("headlessdam"));

ContentHubObjectId audioId = new ContentHubObjectId(connectionId, HeadlessDAMFolder.AUDIO_FOLDER);
audioFolder = new HeadlessDAMFolder("Audio", audioId, new ContentHubType("headlessdam"));

ContentHubObjectId videoId = new ContentHubObjectId(connectionId, HeadlessDAMFolder.VIDEO_FOLDER);
videoFolder = new HeadlessDAMFolder("Videos", videoId, new ContentHubType("headlessdam"));

ContentHubObjectId picturesId = new ContentHubObjectId(connectionId, HeadlessDAMFolder.PICTURES_FOLDER);
picturesFolder = new HeadlessDAMFolder("Pictures", picturesId, new ContentHubType("headlessdam"));

They are returned by the getFolder method, which returns the folder depending on the given externalId stored in the ContentHubObjectId.

  @Nullable
  @Override
  public Folder getFolder(@NonNull ContentHubContext context, @NonNull ContentHubObjectId id) {
    String externalId = id.getExternalId();
    switch (externalId) {
      case HeadlessDAMFolder.ROOT_FOLDER:
        return rootFolder;
      case HeadlessDAMFolder.AUDIO_FOLDER:
        return audioFolder;
      case HeadlessDAMFolder.VIDEO_FOLDER:
        return videoFolder;
      case HeadlessDAMFolder.PICTURES_FOLDER:
        return picturesFolder;
      default:
        throw new UnsupportedOperationException("Invalid headless DAM id '" + externalId + "'");
    }
  }

You only need two different Headless Server calls to retrieve the Content Hub items for each of these folders.

  • One call to search all items of the given media type, returned by the method public List getItems(@NonNull ContentHubContext context, @NonNull Folder folder).
  • One call to retrieve the details of each item, returned by the method public Item getItem(@NonNull ContentHubContext context, @NonNull ContentHubObjectId id).

Both calls are implemented in class HeadlessServerConnector, which is created for every instance of HeadlessDAMContentHubAdapter.

Note that for the sake of simplicity we did not implement methods to support searching and content creation via Content Hub!

Headless Server Requests

The Headless Server is accessed through an instance of the class HeadlessServerConnector. Instances of this class are created with the URL of the Headless Server. It executes requests using a Spring Rest Template, which is responsible for converting the returned JSON into Java objects.

The GraphQL is passed in JSON format as payload for these requests. This JSON is generated through the utility classes SearchQuery and ContentQuery.

Every call generates an instance of QueryResponseDocument, which contains the content details or the search results.

Class SearchQuery

The class SearchQuery generates a JSON string with a GraphQL query to retrieve all assets of a specific type from a specific CoreMedia site. It requires the parameters sideId and type, which are then replaced inside the query template string.

For example, for siteId "abffe57734feeee" and type "CMPicture", the YAML of the GraphQL query would look like this:

{
  content {
    search(query: "*", offset: 0, limit: 1000, docTypes: ["CMPicture"], sortFields: [MODIFICATION_DATE_ASC], siteId:"abffe57734feeee") {
     numFound,
     result {
       ... on CMTeasable {
          creationDate, 
          name,           
          title,           
          type,           
          link {id}, 
          picture {            
            data { 
              size ,
              contentType
            },
            uriTemplate,
            crops {
              name,
              minWidth              
            }          
          }
        }
    }
    }
  }
}

Since the repository view of the Studio library does not support any additional filtering, we simply extend the search limit to 1000 entries.

The query executed by the HeadlessServerConnector returns a QueryResponseDocument. The HeadlessDAMContentHubAdapter accesses the search results via queryResponseDocument.getData().getContent().getSearch().getResults() and converts every CMTeaseableDocument into a Content Hub item.

Class ContentQuery

The class ContentQuery generates a JSON string with a GraphQL query to retrieve the details of an asset. It requires the parameter, id, which is then replaced inside the query template string.

For example, for id "2022" the YAML of the GraphQL query would look like this:

{
  content {
    content(id:"2022") {
       ... on CMTeasable {
          creationDate, 
          modificationDate,
          title,           
          name,
          type,
          teaserText,
          remoteLink,
          link {id},
          picture {            
            data { 
              size ,
              contentType
            },
            uriTemplate,
            crops {
              name,
              minWidth              
            }          
          }
        }
    }
  }
}

The query executed by the HeadlessServerConnector returns a QueryResponseDocument. The HeadlessDAMContentHubAdapter accesses the result via queryResponseDocument.getData().getContent().getContent() and converts the CMTeaseableDocument into a Content Hub item.

Conclusion

We've demonstrated how the Headless Server can be used to access assets, and we've shown how these assets can be accessed through the Content Hub in CoreMedia Studio.

We've shown how the Headless Server requests can be implemented via Spring Rest Templates. If you have to build more complex GraphQL queries for the Headless Server, it's worth it to try the Apollo framework (https://www.apollographql.com/), which is the industry-standard GraphQL implementation, providing the data graph layer that connects modern apps to the cloud.