Sample custom transport service
The following example shows how to write a custom transport. In this case, the example shows how to write File Transport.
File Transport supports the following parameters:
BaseDirectory- For each call to the transport method of the File transport, a separate subdirectory is created in which the export document is written.
FileName- The name of the file to which the form export document is written.
You must include these parameters in the File transport service declaration in the WebForms configuration file (webforms_conf.xml).
File transport writes the export document to a text file. The name of this text file can be overwritten as a parameter in the transport service declaration.
To write a custom transport for File Transport, do the following:
Implement the
FileTransportclass. This class must implement the following interfaces:- the
com.tridion.webforms.transport.Transportinterface - the
Configurableinterface, which retrieves the values of the parameters listed above
To implement these interfaces, implement the following two methods:
configure(com.tridion.configuration.Configuration)transport(org.wc3.dom.Document, java.util.Map, java.util.List)
package com.tridion.webforms.transport; import org.w3c.dom.Document; import java.util.List; import com.tridion.configuration.Configurable; import com.tridion.configuration.Configuration; import com.tridion.configuration.ConfigurationException; import javax.xml.transform.TransformerException; public class FileTransport implements Transport, Configurable { public void configure(Configuration configuration) throws ConfigurationException { } public void transport(Document document, Map attachmentMap, List parameters) throws TransportException { } }- the
In the
configure()method, retrieve the base directory and filename as follows:public class FileTransport implements Transport, Configurable { private String baseDirectory; private String defaultFileName; public void configure(Configuration configuration) throws ConfigurationException { baseDirectory = configuration.getStringParameterValue("BaseDirectory"); defaultFileName = configuration.getStringParameterValue("FileName"); } public void transport(Document document, Map attachmentMap, List parameters) throws TransportException { } }- Within the directory specified by the
BaseDirectoryparameter, create a separate subdirectory for each call to the transport method. This directory stores the Form export document and any attachments. As a result, you can distinguish between different sessions and prevent overwriting existing files. The
generateExportDirectoryName()method generates the name of a subdirectory:private static final String PREFIX_EXPORT_DIRECTORY = "export_"; private long lastGeneratedExportDirectoryTime = Long.MIN_VALUE; private synchronized String generateExportDirectoryName() { long time = System.currentTimeMillis(); if (time <= lastGeneratedExportDirectoryTime) { time = lastGeneratedExportDirectoryTime + 1; } lastGeneratedExportDirectoryTime = time; return PREFIX_EXPORT_DIRECTORY + time; }Implement the
transport()method to do the following:- Create a subdirectory in the base directory using the
generateExportDirectoryName()method. - Write the form export document to file.
- Store the supplied attachments.
public void transport(Document document, Map attachmentMap, List parameters) throws TransportException { // (1) construct the directory in which to store the document and attachments String directoryName = baseDirectory + File.separator + generateExportDirectoryName(); File directory = new File(directoryName); if (!directory.mkdir()) { // the directory could not be created; if the directory already exists then something went // seriously wrong with generating a unique name of that directory if (directory.exists()) { String errorMessage = "Directory '" + directoryName + "' already exists"; throw new IllegalStateException(errorMessage); } // something else went wrong (probably an I/O error or no permissions) String errorMessage = "Failed to create directory: " + directoryName; throw new TransportException(errorMessage); } // (2) write the form data writeFormData(new File(directory, defaultFileName), document); // (3) write any attachments writeAttachments(directory, attachmentMap); }- Create a subdirectory in the base directory using the
Implement the
writeFormData()method:private void writeFormData(File file, Document document) throws TransportException { // write the document to the file try { Source source = new DOMSource((Document) content); Result result = new StreamResult(file); TransformerFactory.newInstance().newTransformer().transform(source, result); } catch (TransformerException exception) { String errorMessage = "An error occurred while writing the document to file: " + file.getName(); throw new TransportException(errorMessage, exception); } finally { if (out != null) { try { out.close(); } catch (IOException exception) { String errorMessage = "An error occurred while closing file: " + file.getName(); throw new TransportException(errorMessage, exception); } } }Store the attachments. Each attachment is represented as a
com.tridion.webforms.storage.Attachmentinstance. This class contains methods to retrieve the attachment data. Use thewriteAttachments()method to store the attachments. The first parameter defines the directory in which the attachments must be stored and the second parameter is the map containing the attachments.public void writeAttachments(File directory, Map attachmentMap) throws TransportException { for (Iterator attachmentIterator = attachmentMap.keySet().iterator(); attachmentIterator.hasNext();) { String identifier = (String) attachmentIterator.next(); Attachment attachment = (Attachment) attachmentMap.get(identifier); // open the file to which the attachment must be written File attachmentFile = new File(directory, attachment.getFilename()); FileOutputStream fileOutputStream; try { fileOutputStream = new FileOutputStream(attachmentFile); } catch (FileNotFoundException exception) { String errorMessage = "Unable to open file: " + attachmentFile; throw new TransportException(errorMessage, exception); } // write the attachment try { // get an InputStream containing the attachment data InputStream inputStream; try { inputStream = attachment.getInputStream(); } catch (StorageException exception) { String errorMessage = "Failed to get InputStream from attachment."; throw new TransportException(errorMessage, exception); } // write the attachment data to the output stream try { byte[] buffer = new byte[8192]; int read = 0; while ((read = inputStream.read(buffer)) > 0) { fileOutputStream.write(buffer, 0, read); } } catch (IOException exception) { String errorMessage = "An error occurred while writing attachment: " + identifier; throw new TransportException(errorMessage, exception); } finally { // close the inputstream try { inputStream.close(); } catch (IOException exception) { String errorMessage = "An error occurred while closing InputStream from attachment."; throw new TransportException(errorMessage, exception); } } } finally { // close the output stream try { fileOutputStream.close(); } catch (IOException exception) { String errorMessage = "An error occurred while closing file: " + attachmentFile; throw new TransportException(errorMessage, exception); } } } }This method iterates over all attachments in the
java.util.Mapinstance. Each attachment is stored in a separate file. The name of this file is retrieved by calling thegetFilename()method on the currentcom.tridion.webforms.storage.Attachmentinstance. Ajava.io.InputStreamfrom which the actual data of the attachment can be read is retrieved by calling thegetInputStream()method.Declare the
FileTransportin the WebForms configuration file as follows:<TransportServiceManager> <TransportService Name="File" Class="com.tridion.webforms.transport.FileTransport"> <Param> <Name>BaseDirectory</Name> <Value>C:\home\WebForms\PS\data</Value> </Param> <Param> <Name>FileName</Name> <Value>export.xml</Value> </Param> </TransportService> </TransportServiceManager>The
serviceBusiness Rule refers to this transport service as follows:<transport> <getFormExportDocument/> <getFormAttachmentMap/> <service> <literal>File</literal> </service> </transport>Note how the
Fileparameter for service corresponds to theFilevalue of theNameattribute of theTransportServiceelement in the previous step.If you want to overwrite the file name in the
serviceBusiness Rule, change the implementation of the transport method as follows:public void transport(Document document, Map attachmentMap, List parameters) throws TransportException { // (1) construct the directory in which to store the document and attachments String directoryName = baseDirectory + File.separator + generateExportDirectoryName(); File directory = new File(directoryName); if (!directory.mkdir()) { // the directory could not be created; if the directory already exists then something went // seriously wrong with generating a unique name of that directory if (directory.exists()) { String errorMessage = "Directory '" + directoryName + "' could not be created because it already exists"; throw new IllegalStateException(errorMessage); } // something else went wrong (probably an I/O error or permissions) String errorMessage = "Failed to create directory: " + directoryName; throw new TransportException(errorMessage); } // determine the filename of the document String fileName; if (parameters.size() > 0) { fileName = (String) parameters.get(0); } else { fileName = defaultFileName; } // (2) write the form data writeFormData(new File(directory, fileName), document); // (3) write any attachments writeAttachments(directory, attachmentMap); }- Determine the file name if the parameter list contains at least one element. If so, the first element is used as the filename, otherwise the default filename specified in the transport service declaration is used.
You can use the following application of the
serviceBusiness Rule:<transport> <getFormExportDocument/> <getFormAttachmentMap/> <service> <literal>File</literal> <literal>export2.xml</literal> </service> </transport>In this example, the form export document is written to export2.xml.
Add an optional third parameter in the
FileTransportconfiguration that contains the URI of an XSLT stylesheet that must be applied to the form export document. Assume that the name of the parameter isTransformation. Extend theconfigure()method as follows:private String fileName; private URI xsltStyleSheetURI; public void configure(Configuration configuration) throws ConfigurationException { fileName = configuration.getStringParameterValue("FileName"); String transformation = configuration.getStringParameterValue("Transformation", null); if (transformation != null) { try { xsltStyleSheetURI = new URI(transformation); } catch (URISyntaxException exception) { String errorMessage = "Invalid URI specified for XSLT stylesheet: " + xsltStyleSheetURI; LogFactory.error(errorMessage, exception); throw new ConfigurationException(errorMessage, exception); } } }The
configure(com.tridion.configuration.Configuration)method checks if theTransformationparameter is set. If so, it constructs a URI object given its value.The transport method applies the XSLT style sheet to the Form export document using the com.tridion.webforms.transport.XSLTProcessor class.
The
writeTransportData(java.io.File, org.w3c.dom.Document)method looks as follows:private void writeFormData(File file, Document document) throws TransportException { // determine the content that must be written to file Object content; if (xsltStyleSheetURI != null) { XSLTProcessor processor = new XSLTProcessor(xsltStyleSheetURI); content = processor.processTransportDocument(document); } else { content = document; } // write the content to the file if it is a DOM document if (content instanceof Document) { try { Source source = new DOMSource((Document) content); Result result = new StreamResult(file); TransformerFactory.newInstance().newTransformer().transform(source, result); } catch (TransformerException exception) { String errorMessage = "An error occurred while writing the document to file: " + file.getName(); throw new TransportException(errorMessage, exception); } // write the content to the file if it is not a DOM document } else { BufferedWriter out = null; try { out = new BufferedWriter(new FileWriter(file)); out.write(content.toString()); } catch (IOException exception) { String errorMessage = "An error occurred while writing the document to file: " + file.getName(); throw new TransportException(errorMessage, exception); } finally { if (out != null) { try { out.close(); } catch (IOException exception) { String errorMessage = "An error occurred while closing file: " + file.getName(); throw new TransportException(errorMessage, exception); } } } } }You can now extend the transport service declaration in the WebForms configuration file by adding the
Transformationparameter with the URI of a stylesheet as its value (for example, defaultss.xsl).<TransportServiceManager> <TransportService Name="File" Class="com.tridion.webforms.transport.FileTransport"> <Param> <Name>FileName</Name> <Value>export.xml</Value> </Param> <Param> <Name>Transformation</Name> <Value>file:///C:/Stylesheets/defaultss.xsl</Value> </Param> </TransportService> </TransportServiceManager>