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.
-
If required, a second user control can be used to allow the user to select more settings (known as Parameters) when the production job is submitted.
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. Optionally, additional runtime parameters can be applied by the user to configure the task for the particular job.
Note: Runtime parameters will be available only on the uProduce server. It is not possible to display runtime parameters in InDesign on the desktop with uCreate Print Connectivity.
uProduce creates a temporary working folder and saves there an XML file (named Input.xml) that contains all the job settings (TypeProperties and Parameters) 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 two C# projects that demonstrate the file compression or zip operation. The difference between the two projects is that one shows how to use runtime parameters for the uProduce user to set the name of the zip file when adding the operation to the job ticket.
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;
// 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;
// get the parameters sent to the operation (if relevant)
Dictionary<string, object> runTimeParameters = new Dictionary<string, object>();
foreach (XmlNode nodeListElement in inputXmlDocument.DocumentElement.SelectNodes("./PARAMS/P"))
runTimeParameters[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
uProduceAPIs.Actions apiClient = CreateAPIsClient(restAPIBaseURL, restAPIUserToken);
try
{
// get the compression level from the operation configuration
CompressionLevel compressionLevel = (CompressionLevel)Enum.Parse(typeof(CompressionLevel), typeProperties["CompressionLevel"].ToString(), true);
// use the input runtime parameter as the name of the zip
string zipFilePath = Path.Combine(sourceFolder, runTimeParameters["FileName"].ToString() + ".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, GetMostRelevantMessage(ex));
// reporting an error message to the job center
try
{
apiClient.CreateJobMessageAsync(jobId, new uProduceAPIs.JobMessage()
{
ContextId = uProduceAPIs.MessageContext.OPERATIONS_CONTEXT,
SeverityType = uProduceAPIs.MessageSeverity.Error,
MessageId = uProduceAPIs.MessageType.POST_COMPOSITION_OPERATION_GENERIC_MESSAGE,
MessageArgs = new List<string>() { operationName, GetMostRelevantMessage(ex) }
}).Wait();
}
catch { }
return 1; // return non-zero to indicate error
}
TypeProperties user control
The TypeProperties user control simply displays the ASP.NET form controls to capture the admin settings when the operation is defined in the dashboard settings area.
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="SamplePostCompositionOperationWithParameters.ascx.cs"
Inherits="SamplePostCompositionOperationWithParameters" %>
<asp:Panel ID="PostCompositionOperationTypePanel" runat="server">
<table border="0" cellspacing="4" cellpadding="0" width="100%" style="padding-left: 10px">
<tr>
<td style="width: 160px;">
<asp:Label runat="server" CssClass="form-prompt" Text="Compression Level:"></asp:Label>
</td>
<td>
<asp:DropDownList ID="CompressionLevelDropDownList" Width="508px" runat="server">
<asp:ListItem Selected="True" Text="Optimal" Value="0"> </asp:ListItem>
<asp:ListItem Selected="False" Text="Fastest" Value="1"></asp:ListItem>
<asp:ListItem Selected="False" Text="NoCompression" Value="2"></asp:ListItem>
</asp:DropDownList>
</td>
</tr>
</table>
</asp:Panel>
In the code behind, user control class should inherit the IPostCompositionOperationTypeControl interface from the XMPieDashboard namespace and override the SetTypeProperties() and GetTypeProperties() methods.
If your user control will cause post back, you should be aware that the user control is reloaded on the page, and some settings may revert to the default settings. To avoid this problem, the sample solution includes the parent page view state in a variable called ParentViewState. While it is not needed or used in the SDK example, you can use the variable to set and get your settings at the page level to avoid the problem. For example:
private string MyControlSetting
{
get { return (string)ParentViewState["MyControlStateData::MySettingId"]; }
set { ParentViewState["MyControlStateData::MySettingId"] = value; }
}
Deployment
-
Compile the Visual Studio solution:
-
Open the PostCompositionOperationSDK.sln.
-
Select either the SamplePostCompositionOperation, or SamplePostCompositionOperationWithParameters 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 of the relevant project.
-
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 SamplePostCompositionOperation or SamplePostCompositionOperationWithParameters.
-
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.