Post Composition Operations SDK
Introduction
The Post Composition Operations feature of PersonalEffect was introduced in version 25.2. Post Composition Operations allow users to perform one or more operations or tasks on the output files created by uProduce.
The Post Composition Operations feature is implemented as a plugin so that developers can easily add custom operations to perform other tasks.
By default, there are operations to:
-
Zip or compress the output files
-
Copy the output to:
-
an FTP or FTPS server
-
a Windows file server
-
an AWS S3 bucket
-
an SFTP server
-
-
Delete the output from the uProduce server, or
-
Create a Job Definition (JDF) file.
Developers can easily create plugins to pass the output to other systems, for example, prepress workflow or imposition software that is totally outside of the XMPie environment.
The Post Composition Operations feature is designed to be very flexible and extensible so you can use it for many different tasks – and is limited only to your imagination and the abilities of the developer creating the plugin.
Note: Initially, Post Composition Operations are available only on the uProduce server. The feature will be added to uCreate Connectivity on the desktop in a future version.
Technology overview
The Post Composition Operations plugin is designed in a way that decouples the plugin from the uProduce server so that the developer does not need to update the plugin each time there is a new uProduce version.
The developer needs to create:
-
An executable which uProduce calls when a job is processed with the custom Post Composition Operation.
-
An ASP.NET Web User Control file that is loaded into the uProduce dashboard to allow an administrator to configure the settings (known as TypeProperties) needed for the custom plugin.
The executable can be created in any programming language that can compile an executable for Windows Server.
The user control and executable are added to specific folders on the uProduce server (refer to deployment), and the custom plugin is registered in the SQL database. When an administrator creates a Post Composition Operation of the custom type, the custom user control is displayed in the dashboard to gather the required settings which are then stored in the database.
When a dashboard user processes a document, Post Composition Operations can be added to the job ticket to perform the custom task with the composed output files.
uProduce creates a temporary working folder and saves there an XML file (named Input.xml) that contains all the job settings (TypeProperties) and other core information like the Job Id, uProduce REST API URL and UserToken. uProduce then calls the custom executable passing the path to the temporary working folder as a parameter.
The executable is able to read the XML file in the temporary folder to obtain the settings and perform the required task while passing status information back to the uProduce dashboard via the uProduce REST API, and recording any errors via the uProduce Logger interface.
The temporary working folder is automatically deleted by the uProduce system so the developer needs only to focus on the core task.
Adding Post Composition Operations to a job ticket
The uProduce REST API can apply Post Composition Operations onto a JobTicket when programmatically submitting documents to production. For more information, refer to the uProduce REST API documentation.
Accessing the SDK
XMPie provides a Post Composition Operations SDK that includes a sample Visual Studio solution that demonstrates how to create a custom Post Composition Operation C#.
Customers who have purchased the uProduce API license can request the Post Composition Operations SDK from XMPie Support.
SDK walkthrough
The SDK consists of a Visual Studio Solution that includes a C# project that demonstrates the file compression or zip operation.
It is recommended to review the Developing custom Post Composition Operations video tutorial.
Executable
The first task of the executable is to read the arguments passed by uProduce when it is executed. The path is cleaned and set as the current working directory.
// getting the input arguments
if (args == null || args.Length != 1)
{
Logger.LogError("Invalid number of arguments");
return 1; // return non-zero to indicate error
}
// setting the working directory to the input temporary folder
// this folder can be used for any data needed as part of the operation processing, it is deleted automatically at the end.
string tempWorkingFolder = args[0].Trim('\"', '\'', ' ', '\t', '\n', '\r');
Directory.SetCurrentDirectory(tempWorkingFolder);
The Input.xml file is read from the working directory to get information about:
-
The job and the operation.
-
Read the TypeProperties defined by the administrator when the Post Composition Operation was created in the uProduce Settings area.
-
Read the parameters (if provided) by the user when they add the operation to the job.
// read the "Input.xml" file that contain all the operation input
XmlDocument inputXmlDocument = new XmlDocument();
inputXmlDocument.Load("Input.xml");
File.Delete("Input.xml");
// get the operation context information
string operationName = inputXmlDocument.DocumentElement.SelectSingleNode(./@OpName)?.Value;
string operationId = inputXmlDocument.DocumentElement.SelectSingleNode(./@OpId)?.Value;
string jobId = inputXmlDocument.DocumentElement.SelectSingleNode(./@JobId)?.Value;
string sourceFolder = inputXmlDocument.DocumentElement.SelectSingleNode(./@SourceFolder)?.Value;
string restAPIBaseURL = inputXmlDocument.DocumentElement.SelectSingleNode(./@RestAPIBaseURL)?.Value;
string restAPIUserToken = inputXmlDocument.DocumentElement.SelectSingleNode(./@RestAPIUserToken)?.Value;
string jobPersistentFolder = inputXmlDocument.DocumentElement.SelectSingleNode(./@JobPersistentFolder)?.Value; // persistent storage across PCO operations for this job and type
// get the properties configured for the operation
Dictionary<string, object> typeProperties = new Dictionary<string, object>();
foreach (XmlNode nodeListElement in inputXmlDocument.DocumentElement.SelectNodes("./PROPS/P"))
typeProperties[nodeListElement.Attributes["N"].Value] = nodeListElement.InnerText;
The main task of the executable is performed in a try/catch statement to allow exceptions to be caught and handled.
The executable should return 0 for success and non-zero for error.
Errors can be passed to the uProduce Logger interface, and status updates can be passed to the dashboard job center by the uProduce REST API.
// creating a uProduce API client
using (XMPieRestAPI.Client apiClient = new XMPieRestAPI.Client(restAPIUserToken, restAPIBaseURL))
{
try
{
// get the compression level from the operation configuration
CompressionLevel compressionLevel = (CompressionLevel)Enum.Parse(typeof(CompressionLevel), typeProperties["CompressionLevel"].ToString(), true);
// use the first file in the directory as the name of the zip
string zipFilePath = Directory.EnumerateFiles(sourceFolder).First();
zipFilePath = Path.ChangeExtension(zipFilePath, ".zip");
// create the zip file into the temporary directory
ZipFile.CreateFromDirectory(sourceFolder, Path.GetFileName(zipFilePath), compressionLevel, false);
// remove all files from the source folder
Directory.Delete(sourceFolder, true);
Directory.CreateDirectory(sourceFolder);
// move the zip from the temp location to the source folder
File.Move(Path.GetFileName(zipFilePath), zipFilePath);
// return zero to indicate success
return 0;
}
catch (Exception ex)
{
// logging the error
Logger.LogError("Job {0} Operation {1} failed: {2}", jobId, operationName, XMPieRestAPI.Helpers.GetMostRelevantMessage(ex));
// reporting an error message to the job center
try
{
apiClient.CreateJobMessage(jobId, new XMPieRestAPI.JobMessage()
{
ContextId = XMPieRestAPI.MessageContext.OPERATIONS_CONTEXT,
SeverityType = XMPieRestAPI.MessageSeverity.Error,
MessageId = XMPieRestAPI.MessageType.POST_COMPOSITION_OPERATION_GENERIC_MESSAGE,
MessageArgs = new List<string>() { operationName, XMPieRestAPI.Helpers.GetMostRelevantMessage(ex) }
});
}
catch { }
return 1; // return non-zero to indicate error
}
}
Deployment
-
Compile the Visual Studio solution:
-
Open the PostCompositionOperationSDK.sln.
-
Select the SamplePostCompositionOperation project and compile it with a release build.
-
-
Register the plugin type in the XMPDB2 database:
-
Open SQL Server Management Studio.
-
Connect to the uProduce database server.
-
Copy the SQL script provided in the DashboardConfig folder.
-
Confirm the script is relevant for the plugin you are deploying.
-
Run the query.
-
-
Register the UI Dashboard configuration:
-
Go to uProduce dashboard folder X:\XMPie\XMPieDashboard\.
-
Edit the file PrecompiledApp.config, and change updatable from false to true if needed.
-
If you changed the PrecompiledApp.config file, run iisreset.
-
Copy the ASP.NET user control files from the relevant project’s DashboardConfig folder.
-
Paste the files in: X:\XMPie\XMPieDashboard\Settings\PostCompositionOperationTypes.
(In configurations with multiple director servers, the user controls should be copied to all directors.)
-
-
Copy the binaries you compiled with Visual Studio to the uProduce server:
-
Go to uProduce binaries folder X:\XMPie\XMPieExec\PostCompositionOperations\.
-
Create a new folder named by the relevant project, for example SamplePostCompositionOperation.
-
Copy the compiled binaries from your VS Solution in \bin\x64\Release\.
-
Paste the binaries into the new folder.
(In configurations with multiple extension servers, the binaries should be copied to all production extensions and any director servers that also do production.)
-
5. Test it.
uProduce server upgrades
As mentioned above, it is not necessary to update the Post Composition Operation plugin for uProduce server upgrades.
However, upgrades (and also repairs) to the uProduce server can remove custom plugins from the XMPieExec and XMPieDashboard folders.
Therefore, it is recommended to:
-
Keep a copy of the custom files outside of the XMPie folders in case they need to be deployed again after an upgrade or repair.
-
After each uProduce upgrade or repair, check the executable, user controls, PrecompiledApp.config file and SQL database to confirm that your custom plugin is still configured correctly.