Join this online user group to communicate across IBM product users and experts by sharing advice and best practices with peers and staying up to date regarding product enhancements.
Sometimes it may be necessary to package a static file, for example a service description YAML file, and make it accessible to service clients. This recipe explains how it is possible to do that in IBM Integration Bus.
Requires experience with IBM Integration Bus / IBM App Connect and Java.
Ingredients
This recipe was tested with IBM Integration Bus 10.0.0.7 on Windows Server R2 Standard. It should also work with IBM App Connect and Linux.
Create a similar project structure:
The pets.yaml is defined here: https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v2.0/yaml/petstore.yaml
The fileResponse message flow is defined as follows:
This step defines the relevant code. Note that the whitespace may be collapsed, depending on the current Recipes framework version.
setInputVariables.esql
BROKER SCHEMA SandboxWorkspaceFileResponseSchemaCREATE COMPUTE MODULE setInputVariables CREATE FUNCTION Main() RETURNS BOOLEAN BEGIN SET OutputLocalEnvironment = InputLocalEnvironment; SET OutputLocalEnvironment.SBER.ReadFile.fileName = 'pets.yaml'; SET OutputLocalEnvironment.SBER.ReadFile.schemaName = 'SandboxWorkspaceFileResponseSchema'; SET OutputLocalEnvironment.SBER.ReadFile.resourceTypeFolder = 'YAML'; RETURN TRUE; END;END MODULE;
The resourceTypeFolder variable value depends on how Integration Bus / App Connect interprests the file. There are many possible values; to find which one, simply deploy the project and then search the file name on disk. For example, on Windows, pets.yaml can be found here:
C:\ProgramData\IBM\MQSI\components\<broker>\<euuid>\config\<auuid>\YAML\SandboxWorkspaceFileResponseSchema\pets.yaml
The entire path is constructed below in the ReadFile.java.
ReadFile.java:
package SandboxWorkspaceFileResponseSchema;import java.io.BufferedReader;import java.io.File;import java.nio.file.Files;import java.nio.file.Paths;import java.util.List;import com.ibm.broker.config.proxy.ApplicationProxy;import com.ibm.broker.config.proxy.BrokerProxy;import com.ibm.broker.config.proxy.ExecutionGroupProxy;import com.ibm.broker.javacompute.MbJavaComputeNode;import com.ibm.broker.plugin.MbElement;import com.ibm.broker.plugin.MbException;import com.ibm.broker.plugin.MbExecutionGroup;import com.ibm.broker.plugin.MbMessage;import com.ibm.broker.plugin.MbMessageAssembly;import com.ibm.broker.plugin.MbOutputTerminal;import com.ibm.broker.plugin.MbUserException;public class ReadFile extends MbJavaComputeNode { @SuppressWarnings("unchecked") public void evaluate(MbMessageAssembly inAssembly) throws MbException { MbOutputTerminal out = getOutputTerminal("out"); MbMessage env = inAssembly.getLocalEnvironment(); MbMessage inMessage = inAssembly.getMessage(); MbMessageAssembly outAssembly = null; try { // create new message as a copy of the input MbMessage outMessage = new MbMessage(inMessage); MbMessage newEnv = new MbMessage(env); outAssembly = new MbMessageAssembly(inAssembly, newEnv, inAssembly.getExceptionList(), outMessage); // ---------------------------------------------------------- // Add user code below BrokerProxy bp = null; BufferedReader br = null; String serverName = MbExecutionGroup.getExecutionGroup().getName(); String applicationName = getMessageFlow().getApplicationName(); String fileName = ((List<MbElement>) env.getRootElement() .evaluateXPath("SBER/ReadFile/fileName")).get(0) .getValueAsString(); String resourceTypeFolder = ((List<MbElement>) env.getRootElement() .evaluateXPath("SBER/ReadFile/resourceTypeFolder")).get(0) .getValueAsString(); String schemaName = ((List<MbElement>) env.getRootElement() .evaluateXPath("SBER/ReadFile/schemaName")).get(0) .getValueAsString(); try { bp = BrokerProxy.getLocalInstance(); ExecutionGroupProxy egp = bp .getExecutionGroupByName(serverName); ApplicationProxy ap = egp.getApplicationByName(applicationName); String n = bp.getName(); String euuid = egp.getUUID(); String auuid = ap.getUUID(); String base = System.getenv("MQSI_WORKPATH"); String s = File.separator; String filePath = base + s + "components" + s + n + s + euuid + s + "config" + s + auuid + s + resourceTypeFolder + s + schemaName + s + fileName; byte[] fileContents = Files.readAllBytes(Paths.get(filePath)); ((List<MbElement>) newEnv.getRootElement() .evaluateXPath("SBER/ReadFile")).get(0).createElementAsLastChild(MbElement.TYPE_NAME_VALUE, fileName, fileContents); } finally { if (br != null) br.close(); if (bp != null) bp.disconnect(); } // End of user code // ---------------------------------------------------------- } catch (MbException e) { // Re-throw to allow Broker handling of MbException throw e; } catch (RuntimeException e) { // Re-throw to allow Broker handling of RuntimeException throw e; } catch (Exception e) { // Consider replacing Exception with type(s) thrown by user code // Example handling ensures all exceptions are re-thrown to be // handled in the flow throw new MbUserException(this, "evaluate()", "", "", e.toString(), null); } // The following should only be changed // if not propagating message to the 'out' terminal out.propagate(outAssembly); }}
setFileResponse.esql:
BROKER SCHEMA SandboxWorkspaceFileResponseSchemaCREATE COMPUTE MODULE setFileResponse CREATE FUNCTION Main() RETURNS BOOLEAN BEGIN SET OutputRoot = InputRoot; SET OutputLocalEnvironment = InputLocalEnvironment; SET OutputRoot.BLOB.BLOB = OutputLocalEnvironment.SBER.ReadFile.{OutputLocalEnvironment.SBER.ReadFile.fileName}; DELETE FIELD OutputLocalEnvironment.SBER.ReadFile.{OutputLocalEnvironment.SBER.ReadFile.fileName}; SET OutputRoot.Properties.ContentType = 'text/yaml'; -- Set to application/x-yaml and browsers will download the response as a file RETURN TRUE; END;END MODULE;
Simply deploy the project to a server, open a browser or SoapUI and invoke the following URL: http://<host>:<port>/SandboxWorkspaceFileResponse
The browser should return the file specified in the flow variables. Note that while it may be possible to serve files specified by a request parameter, constraints should be placed on possible file names, for security. The described pattern is applicable to small files which won’t cause out of memory problems due to large object allocation failures. Small file responses can also be cached.
Thanks to Matthew SeGall from IBM Integration Bus / IBM App Connect support team for explaining how to construct the file path of a deployed BAR file.