Creating content in code

Hi,

We want to create code to migrate some existing content we have in Jekyll into Bloomreach.

In the past we have connected directly via JCR and written code to import the content we want. However I seem to remember hearing that this is not recommended.

What is the recommended way for me to create a content item in Java code? Could I expose a rest endpoint to allow me to create the content I want?

Thanks,

David

Hi David,

Probably Content-EXIM is the best way:

It provides brXM document workflow based API to export/import documents. The API is used in the groovy code examples, which could be converted into Java. Also, it is based on simple ContentNode POJO objects which could be created from xml or json or whatever.
It also provides a generic rest api endpoint to export/import documents and binaries in zip format.

Regards,

Woonsan

Thanks Woonsan, I will give that a go!

Hi Woonsan,

When you say that the Groovy code could be converted to Java do you mean I can use this code in a stand alone Java project? Or do you mean we could use it somewhere else from within the cms project?

Currently we have our own migration project we use as part of our deployment pipeline to make changes required for a release. Ideally we would like to continue doing this …

Thanks,

David

Hi David,

Ah, it is a bit confusing…
It is easily convertible to Java code, but you can’t run it in standalone application because the repository workflow API doesn’t allow it, outside its JVM. So, technically it is only possible to deploy some classes in the cms project and run it in the same JVM because Content-EXIM uses the repository workflow API by default through a DocumentManager [1].

[1] https://bloomreach-forge.github.io/content-export-import/apidocs/org/onehippo/forge/content/exim/core/DocumentManager.html

Is your migration project using JCR API directly to migrate content to CMS now? If so, is it accessing a remote JCR server or local vm JCR server?

Regards,

Woonsan

Hi,

We are connecting through rmi://localhost:1099/hipporepository right now.

Our main use case for migrations is that we can make adjustments to data in the repository as part of our delivery pipeline.

Until now the migration project has always been standalone and this has worked okay for us but we do want to be able to use higher level abstractions e.g. DocumentManager rather than write low level JCR code.

David

Hi David,

I don’t think RMI connection - “JCR over RMI” - is or will be supported officially in brXM any more.
“JCR over WebDAV” is supported in Apache Jackrabbit level and we have a community-driven forge plugin to allow it [2], but it is also not an official product support. Either alone cannot work with repository document workflow API because the workflow API is platform specific solution anyway.
So, IMHO, your options are narrowed down to REST API services which runs in the same JVM as the JCR repository’s, like Content-EXIM built-in rest services for export/import. [3]

Regards,

Woonsan

[2] https://bloomreach-forge.github.io/hippo-jcr-over-webdav/
[3] https://bloomreach-forge.github.io/content-export-import/builtin-rest-services.html

Thanks - I will investigate this route.

Hi Woonsan,

I have just been having a go at how we can get this work and have a question. I have decided to register a repository rest service to support the behaviour we need. I am following the instructions here:

However In my resource I have a method with this signature:
@POST
@Path("/publishingdocuments")
@Consumes(MediaType.APPLICATION_JSON)
public Response newPublishingDocument(PublishingDocument publishingDocument)

However when I post a request I am getting an HTTP 415 Unsupported Media Type response. Do I have to do something to register a JSON message body reader?

Thanks,

David

As your operation accepts only JSON content type, I think your client should provide a proper header like this:

curl --request POST --header "Content-Type: application/xml" --data ... http://localhost:8080/cms/ws/yourservice/publishingdocuments.

Regards,

Woonsan

Hi,

I am using postman and specifying the content type as application/json but I am getting a 415 and the logs say no message body reader was found. My class is a simple pojo with a few string fields with getters and setter.

[INFO] [talledLocalContainer] 21.08.2019 09:18:37 ERROR http-nio-8080-exec-6 [JAXRSUtils.logMessageHandlerProblem:1807] No message body reader has been found for class scot.gov.migration.model.PublishingDocument, ContentType: application/json
[INFO] [talledLocalContainer] 21.08.2019 09:18:37 WARN http-nio-8080-exec-6 [RepositoryJaxrsService$WebApplicationExceptionLogger.toResponse:299] javax.ws.rs.WebApplicationException: HTTP 415 Unsupported Media Type

I wondered if I had to register some kind of JSONProvider but from your message it should just work.

To summarise what I am doing: I have a new module that is part of my hippo project called migration-rest. Its parent pom is my hippo project. I have added a dependency on content-exim-core so that i can use WorkflowDocumentManagerImpl etc.

The module registers my resource using:
MigrationResource migrationResource = new MigrationResource(session);
RepositoryJaxrsEndpoint endpoint = new CXFRepositoryJaxrsEndpoint("/migration")
.invoker(new org.apache.cxf.jaxrs.JAXRSInvoker())
.singleton(migrationResource);
RepositoryJaxrsService.addEndpoint(endpoint);

My resource has this method like this:
@POST
@Path("/publishingdocuments")
@Consumes(MediaType.APPLICATION_JSON)
public Response newPublishingDocument(PublishingDocument publishingDocument){

I then plan to write code that uses WorkflowDocumentManagerImpl to do the work we need. Does this seem like an okay approach?

Thanks,

David

Hi,

you are right, you need to add a JSON provider as well in your JAX-RS endpoint. The related object mapper is needed by CXF to serialize your POJO. If your class is simple enough, you don’t need to use any annotation.

I have used the JacksonJsonProvider, that’s using an existing (static) object mapper
HTH,
Giacomo

Thanks Giacomo,

I am just not sure where / how to register the provider (I have never used). The docs I have found seem to indicate that json parsing parsing should just work out of the box …

David

Hi,
I tried this recently, but I wasn’t able to make it work without explicitly adding the JsonProvider.

What I did is basically to add this line

.singleton(new JacksonJsonProvider(myObjectMapper));

at the end of the CXFRepositoryJaxrsEndpoint definition (where the object mapper can be defined statically). That should be enough.

HTH,
Giacomo

1 Like

Great, that did the trick!

Thanks for your help!