Overview

In priint:comet ID and priint:renderer publications and related data are shown in the Publication panel and processed in several menu actions and cscript functions. The underlying data is usually retrieved from the priint:planner and managed in a SQL database.

The following diagram shows the raw architecture:

As can bee seen from this diagram, all requests from priint:comet ID resp. priint:renderer pass a component called CometPublication. So, by replacing this component, it should be possible to integrate arbitrary publication systems with priint:comet and priint:renderer.

This document shows what is required to do so.

Two important Notes

  1. The priint:planner is hard linked to a SQL Database. Currently there is no way to integrate 3d party publication systems in the priint:planner UI.
    Partially this can be done by implementing priint:planner UI plug-ins, which is not topic of the concept shown here.
    Certain operation will also be provided as an API, which is also not topic of this documentation.
    Implementing custom CometPublication plug-ins only affects priint:comet ID desktop and server and priint:renderer.

  2. Future releases of the priint:publishing server and related components may provide a more elegant way to integrate 3d party publication systems (such as an entity model and connectors similar to the approach for product data).
    As the API shown here uses Comet data types (i.e. data structures specific to priint:comet rendering and output applications) and mapping from entity view to Comet types is a common task done by the CometBridge, this will most probably not affect the concept shown here, though at the time this cannot be guaranteed.

Requirements

You need

In addition, accessing publication data other than from the priint:planner requires

Implementation is described in Section 3, the configuration is described in the following.

Configuration

Currently there is no UI in Ison for setting a custom publication plug-in except by editing the XML file directly.

Alternatives

Note, that this is not the recommended way.

Instead of configuring a publication provider plug-in in Ison, you could pack your custom plug-in into an EJB jar named CometPublication and use the same package and class names like in the default implementation (or find another way to ensure, that your plug-in will be deployed using the same JNDI name like the original plug-in)..
In this case, you must undeploy the original plug-in and replace by your own implementation. Despite the fact, that in this case you also would have to implement all interface methods (and not only the one that need adaptions according to your requirements), this would most probably cause problems whenever you update your priint:publishing server installation.

Therefore, this procedure is not recommended.

Implementation Approach

Interface Overview

The CometPublicationPluginLocal interface defines methods to

For a detailed description of all methods refer to the CometBridgeSDK (resp. CometBridgeSDK-javadoc.jar) delivered with the priint:publishing server devstack.

In most cases, you do not want to override all methods, so you have the choice to

in this case you will have to implement all methods

or

This will delegate all calls to the default CometPublication plug-in and allows to override only specific methods.

Example

The basic concept is best explained with this example:

package com.customer.publication;

@Stateless(mappedName=MyPublicationPlugin.MAPPED_NAME)
@LocalBean
@PubServerPlugin
public class MyPublicationPlugin extends CometPublicationPluginDefault 
    implements CometPublicationPluginLocal // (implied by inheritance)
{	
	public static final String MAPPED_NAME = 
                    "com.customer.publication.MyPublicationPlugin";
}   

This plug-in (hopefully) does, what it is supposed to do, i.e.: nothing (but delegate all method calls to the default publication plug-in as defined in the super class). From here you can start to override all methods according to your requirements.

Publication Structure

Publication Tree

getRootPublications

This method is supposed to return the root of the publication tree.

Return type: List<com.priint.pubserver.comet.bridge.entitydata.Publication>

Parameter hints:
The method does not have any parameters.

getSubPublications

Returns a list of direct descendants of a publication node. In case of publications, descendants will probably be sub-publications or documents, in case of documents descendants should be spreads (or none).

Return type: List<com.priint.pubserver.comet.bridge.entitydata.Publication>

Parameter hints:

Master Documents

getMasterDocuments

This method is supposed to return the list of (active) master documents.

Return type: List<com.priint.pubserver.comet.bridge.entitydata.Publication>

Parameter hints:
The method does not have any parameters.

Search

search

Returns a list of publications matching certain search criteria

Return type: List<com.priint.pubserver.comet.bridge.entitydata.Publication>

Parameter hints:

Publication and Document Properties

getDocumentProperty

Gets a document property

Return type: String

Parameter hints:

setDocumentProperty

Sets a document property

Return type: -

Parameter hints:

getDocumentRootPublicationId

Gets the root publication Id of a document

Return type: String

Parameter hints:

getDocumentPublicationId

Gets the Id of the direct parent of a document

Return type: String

Parameter hints:

getRootPublicationId

Gets the root publication Id of a publication

Return type: String

Parameter hints:

Publication Meta Data

getPublicationTypes

Gets the list of publication types configured on this system.

Return type: List<com.priint.pubserver.comet.bridge.entitydata.PublicationType>

Parameter hints:
The method does not have any parameters.

Publication Parameters

getParameters

Gets the list of all parameters configured on this system.

Return type: List<com.priint.pubserver.comet.bridge.entitydata.Parameter>

Parameter hints:
The method does not have any parameters.

getParameterDropDownValues

Gets the list of applicable drop down values for a certain parameter.

Return type: List<com.priint.pubserver.comet.bridge.entitydata.Parameter>

Parameter hints:

getDocumentParameters

Gets parameters and their values for a particular document

Return type: Map<String, String>

Parameter hints:

setDocumentParameters

Sets a parameter value for a particular document.

Return type: -

Parameter hints:

Publication Workflow

getWorkflowStates

Gets all workflow states configured on this system

Return type: List<com.priint.pubserver.comet.bridge.entitydata.WorkflowStatus>

Parameter hints:
The method does not have any parameters.

getDocumentWorkflowStatus

Gets the current workflow status for a particular document

Return type: com.priint.pubserver.comet.bridge.entitydata.WorkflowStatus

Parameter hints:

getDocumentWorkflowStates

Gets all workflow states applicable for a particular document

Return type: List<com.priint.pubserver.comet.bridge.entitydata.WorkflowStatus>

Parameter hints:

getNextDocumentWorkflowStates

Gets the next workflow states, which can be assigned to a a particular document

Return type: List<com.priint.pubserver.comet.bridge.entitydata.WorkflowStatus>

Parameter hints:

setDocumentWorkflowStatus

Sets the workflow status for a document

Return type: -

Parameter hints:

Planning

getDocumentProductSelection

Gets the product selection ("old planning") for a document

Return type: List<com.priint.pubserver.comet.bridge.entitydata.Product>

Parameter hints:

getDocumentProductPlanning

Gets the product planning (-> Planning and Briefing, "new planning") for a document

Return type: List<com.priint.pubserver.comet.bridge.entitydata.Product>

Parameter hints:

Checkout and Checkin of Documents

Configuration of Checkout / Checkin

The behavior of the publication panel and checkout / checkin process is controlled by a couple of panelstatements (or publication event scripts, some of the functionality is implemented in document event scripts also). These scripts are generated for each Comet Project and can be adapted to custom requirements in ISON later.

Usually you do not have to change the standard configuration scripts, unless for special requirements (e.g. open documents from file system instead of downloading, check in automatically when closing a document etc.).

Overview of Publication Scripts

The implementation examples below refer to the standard configuration. The following list explains the basic functionality of the standard configuration scripts

Login

In the Login script, some preferences for the publication panel are set. You can change this by editing the session::after login script in the Events > Login section in ISON.

// Control, if files should be 
//    kPriintAlwaysDownload = downloaded via SOAP
//    kPriintNeverDownload  = accessed from file system
//    kPriintAutoDownload   = accessed from file system if possible,
//                            download via SOAP otherwise
priint::set_pref(kPriintDownloadPolicy, kPriintAlwaysDownload);
  
// do not allow users to change these settings.
// You should not change this value
priint::set_prefs_editable(0);
  
// use soap proxy to access publication structure
// Required for backward compatibility with old (Comet 3) projects
priint::use_soap_proxy(1);

publication::status

This script is responsible for getting status information (available, opened / checked out etc.) for each publication node shown in the panel. The document status should be assigned to the global variable gDocumentStatus and thus be propagated to the panel.

The standard script requests the document status from the server (by calling priint::document_status):

// ...
status = priint::document_status("<Content_StringID>");
if (status >= 0) {
  if (status == kOpenedByUser) {
    status = kOpenedOnClient;
  }
  *gDocumentStatus = status;
}
else {
  *gDocumentStatus = kNotRegistered;
}
// ... 

publication::checkout

This script is called, when the user clicks the ckeckout button or the cscript publication::checkout method is called. If successfull, the script must copy the local path of the checked out document to the global variable gDocumentPath.

The standard configuration does some checks and then calls the priint:checkout function, which does all the downloading, saving local copy of document etc.

// check status again right before downloading:
status = priint::document_status("<Content_StringID>");
if (status != kAvailable  && status != kOpenedInSession) {
  return -1;
}

// call the checkout function, this will trigger a couple of server operations:
result = priint::checkout("<Content_StringID>", path);
if (result == 0) {
  // if successfull, copy path to the global (result) variable
  strcpy(gDocumentPath, path);
}
else {
  wlog("", "* FAILED with result code %d\n", result);
  return result;
}

publication::after checkout

This script is called after a checked out document is opened for the first time.

The standard script requests some properties and parameters for the current document from server and transfers these values to document XML attributes:

int result = 0;
result = xml::set_document_attribute(gDocument,
                 "publication", 
                 publication::get_rootpublication_id(gDocumentID));
result = xml::set_document_attribute(gDocument,
                 "documentId", 
                 gDocumentID);
result = publication::apply_parameters(gDocument, gDocumentID);
result = document::set_display_name(gDocument, publication::get_label (gDocumentID));
return result;

document::after open

This script is called, after an arbitrary document has been opened. In the server context, the publication::aftercheckout script is called:

if (system::is_server()) {
  publication::aftercheckout(gDocumentID, gDocumentPath);
}

publication::doubleclick

This script is called, when an entry in the publication panel has been double clicked. Also this script is called during the checkout process after the document has been opened.

The standard script just checks, in which context the script was called and outputs a log message:

wlog("", "# Publication doubleclick or checkout: row %d : %d (%s of %s of %s)\n\.",
       gClicked+1,
       gRecordID,
       "<Name>",
       "<DokumentInfo>",
       "<parent.DokumentInfo>");
// Finish script in case of a double click
if (!document::is_valid(gDocument)) return 0;

// if gDocument refers a valid document, this script is 
// executed in a checkout / open context. We can operate on
// that document below, if required.
return 0;
  

publication::before close

This script allows to react to closing of publication documents and is called, before the document is closed (i.e. gDocument can be used to refer to the current document).

The standard script just outputs a log message.

publication::after close

This script allows to react to closing of publication documents and is called after the document has been closed (i.e. gDocument is undefined).

The standard script just outputs a log message.

publication::after save

This script is called, after a publication document has been saved.

The standard script just outputs a log message.

document::after save

This script is called, when an arbitrary document is saved.

In the server context, the publication::checkin script is invoked, which will - on the server - not actually checkin the document, but update all metadata (including previews) for the current document.

if (system::is_server()) {
  publication::aftersave(gDocumentID, gDocumentPath);
  publication::checkin(gDocumentID, gDocumentPath);
}

publication::checkin

This script is called, when the user clicks the checkin button or the cscript publication::checkin function is called.

The standard script basically calls the priint::checkin function, which does all the packing, cleaning, uploading etc.:

int result = priint::checkin(gDocumentID, gDocumentPath);

publication::revert

THis script is called, when the user clicks the revert button or the cscript publication::revert function is called.

The standard script calls the priint::revert function, which does all cleaning, server communication etc.

int result = priint::revert("<Content_StringID>", gDocumentPath);

Document Transfer Format

A document consists of

For both kind of files (or binary data) we use the com.werkii.comet.soap.CometPriintRemote.ServerDocument class in Java.

This class defines the following properties:

Binary Document

The binary document representation is either an InDesign document or a W2ML document.

Meta Data Archive

The meta data archive is a folder containing several XML files and JPG previews of each individual spread of the document. None of the XML files or previews must be present, usually the folder and it's content is generated by InDesign Desktop when checkin in a document or by InDesignServer / priint::pdf renderer when saving a document.

If a meta data folder for the document does not (yet) exist, an empty folder should be zipped and set as ServerDocument.content.

Checkout Sequence

The typical checkout sequence (unless changed in the configuration) is as follows:

Checkin Sequence

The typical checkin sequence (unless changed in the configuration) is as follows:

Method Details

documentStatus

The documentStatus method is usually called fromthe publication::status script or any other cscript, that uses the priint:document_status function.

Depending on the document status, certain functions for this document are visible / enabled in the publication panel or not.
In Java, you should use the CometPublicationPluginLocal.DocumentStatus enumeration to set the appropriate status for the document. Use

Parameter hints

Implementation Example

public DocumentStatusResult documentStatus(String sessionID, 
                                           String documentID,
                                           String callback) throws RemoteException {
    DocumentStatusResult result = new DocumentStatusResult();
    result.setResultCode(0);
    CometPublicationPluginLocal.DocumentStatus status = 
                           CometPublicationPluginLocal.DocumentStatus.NOT_REGISTERED;
    
    // TODO: evaluate and set actual document status

    result.setStatus(status.getId());
    return result;
}

checkoutDocument

The checkoutDocument method is usually called from the publication::checkout script during the checkout sequence or any other cscript, that uses the priint::checkout function.

The method should return the zipped content of the InDesign document resp. W2ML document, see Document transfer format for further information.

Parameter hints

Implementation example

public CheckoutDocumentResult checkoutDocument(String sessionID, 
                                               String documentID, 
                                               String masterDocumentID, 
                                               String callback,
                                               String options) throws RemoteException {
  CheckoutDocumentResult result = new CheckoutDocumentResult();
  try {		
    ServerDocument document = new ServerDocument();
    String filename = documentID + ".indd";
    String filePath = File.separator + "var" + File.separator + "priint" + 
                      File.separator + "documents" + File.separator + 
                      filename;
    
    document.setFilename(filename);
    document.setDocumentID(documentID);
    document.setPath(""); // empty
    
    String zipFilename = filePath + ".zip";
    com.werkii.server.utils.Zip.zip(filePath);
    document.setContent(new DataHandler(new FileDataSource(new File(zipFilename))));
    result.setDocument(document);
    result.setResultCode(0);
  } catch (ServerException | IOException e) {
    result.setResultCode(1);
  }
  return result;
}
    
    

downloadMetaData

The downloadMetaData method is usually called from the publication::checkout script or any other cscript, that uses the priint::checkout function. From the InDesign client side, this method cannot be called separately, it will always be invoked during a checkout sequence.

The method should return the zipped content of the meta data folder, see Document transfer format for further information.

Parameter hints

Implementation example

public DownloadMetaDataResult downloadMetaData(String sessionID, 
                                               String documentID,
                                               String callback) throws RemoteException {
  DownloadMetaDataResult result = new DownloadMetaDataResult();
  try {
    ServerDocument document = new ServerDocument();
    String filename     = documentID + ".indd";
    String metaDataPath = File.separator + "var" + 
                          File.separator + "priint" + 
                          File.separator + "documents" + 
                          File.separator + filename + ".meta";

    // create new / empty meta data folder, if it does not yet exist:
    if (!(new File(metaDataPath)).exists()) {
      (new File(metaDataPath)).mkdirs();
    }
	
    document.setFilename(filename);
    document.setDocumentID(documentID);
    document.setPath(""); // empty
    
    String zipFilename = metaDataPath + ".zip";
	
    com.werkii.server.utils.Zip.zip(metaDataPath);
    
    document.setContent(new DataHandler(new FileDataSource(new File(zipFilename))));
    result.setDocument(document);
    result.setResultCode(0);
  } catch (ServerException | IOException e) {
    result.setResultCode(1);	
  }
  return result;
}

checkinDocument

The checkinDocument method is usually called from the publication::checkin script or any other cscript, that uses the priint::checkin function.

The method should save and unzip the document data uploaded from the client (see Document Transfer Format for further information) and reset the document status, if checkin succeeded.

Parameter hints:

Implementation example

public CheckinDocumentResult checkinDocument(String sessionID, 
                                             ServerDocument document,
                                             String callback) throws RemoteException {
  CheckinDocumentResult result = new CheckinDocumentResult();
  try {
    String documentID = document.getDocumentID();
    String filename = documentID + ".indd";
    String filePath = File.separator + "var" + 
                      File.separator + "priint" + 
                      File.separator + "documents" + 
                      File.separator + filename;

    String zipPath  = filePath + ".zip"; 
    
    // probably further check / cleanup is required, before trying
    // to save the uploaded data...
	
    if (document.getContent() != null) {				
      if (!CASUtils.saveBytes(new File(zipPath), document.getContent())) {
        throw new Exception("Saving uploaded data failed.");
      }
      com.werkii.server.utils.Zip.unZip(zipPath, (new File(filePath)).getParent());
    }
    result.setResultCode(0);
    // + reset document status etc.
  }
  catch (Exception e) {
    result.setResultCode(1);
  }
  return result;
}

uploadMetaData

The uploadMetaData method is usually called from the publication::checkin script or any other cscript, that uses the priint::checkin function. From the InDesign client side, this method cannot be called separately, it will always be invoked during a checkin sequence.

The method should save and unzip the meta data uploaded from the client (see Document Transfer Format for further information).

Parameter hints:

Implementation example

public UploadMetaDataResult uploadMetaData(String sessionID,
                                           String documentID,
                                           ServerDocument document, 
                                           String callback) throws RemoteException {		
  UploadMetaDataResult result = new UploadMetaDataResult();
  try {
    String filename     = documentID + ".indd";
    String metaDataPath = File.separator + "var" + 
                          File.separator + "priint" + 
                          File.separator + "documents" + 
                          File.separator + filename + ".meta";
    String zipPath      = metaDataPath + ".zip"; 
	
    if (document.getContent() != null) {				
      if (!CASUtils.saveBytes(new File(zipPath), document.getContent())) {
        throw new Exception("Saving uploaded data failed.");
	  }
      com.werkii.server.utils.Zip.unZip(zipPath, (new File(metaDataPath)).getParent());
    }
    result.setResultCode(0);
  }
  catch (Exception e) {
    result.setResultCode(1);
  }
  return result;
}

revertDocument

The revertDocument method is usually called from the publication::revert script or any other cscript, that uses the priint:revert function

Basically the method should reset the document status (e.g. unlock)

Parameter hints

Implementation example

public RevertDocumentResult revertDocument(String sessionID, 
                                           String documentID, 
                                           String callback) throws RemoteException {
  RevertDocumentResult result = new RevertDocumentResult();		
  // TODO: check, if document can be reverted, unlock document, cleanup etc.
  result.setResultCode(0);
  return result;
}